1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * purgatory: Runs between two kernels 4 * 5 * Copyright (C) 2014 Red Hat Inc. 6 * 7 * Author: 8 * Vivek Goyal <vgoyal@redhat.com> 9 */ 10 11 #include <linux/bug.h> 12 #include <linux/sha256.h> 13 #include <asm/purgatory.h> 14 15 #include "../boot/string.h" 16 17 unsigned long purgatory_backup_dest __section(.kexec-purgatory); 18 unsigned long purgatory_backup_src __section(.kexec-purgatory); 19 unsigned long purgatory_backup_sz __section(.kexec-purgatory); 20 21 u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory); 22 23 struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX] __section(.kexec-purgatory); 24 25 /* 26 * On x86, second kernel requries first 640K of memory to boot. Copy 27 * first 640K to a backup region in reserved memory range so that second 28 * kernel can use first 640K. 29 */ 30 static int copy_backup_region(void) 31 { 32 if (purgatory_backup_dest) { 33 memcpy((void *)purgatory_backup_dest, 34 (void *)purgatory_backup_src, purgatory_backup_sz); 35 } 36 return 0; 37 } 38 39 static int verify_sha256_digest(void) 40 { 41 struct kexec_sha_region *ptr, *end; 42 u8 digest[SHA256_DIGEST_SIZE]; 43 struct sha256_state sctx; 44 45 sha256_init(&sctx); 46 end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions); 47 48 for (ptr = purgatory_sha_regions; ptr < end; ptr++) 49 sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len); 50 51 sha256_final(&sctx, digest); 52 53 if (memcmp(digest, purgatory_sha256_digest, sizeof(digest))) 54 return 1; 55 56 return 0; 57 } 58 59 void purgatory(void) 60 { 61 int ret; 62 63 ret = verify_sha256_digest(); 64 if (ret) { 65 /* loop forever */ 66 for (;;) 67 ; 68 } 69 copy_backup_region(); 70 } 71