kexec, x86/purgatory: Unbreak it and clean it up

The purgatory code defines global variables which are referenced via a
symbol lookup in the kexec code (core and arch).

A recent commit addressing sparse warnings made these static and thereby
broke kexec_file.

Why did this happen? Simply because the whole machinery is undocumented and
lacks any form of forward declarations. The variable names are unspecific
and lack a prefix, so adding forward declarations creates shadow variables
in the core code. Aside of that the code relies on magic constants and
duplicate struct definitions with no way to ensure that these things stay
in sync. The section placement of the purgatory variables happened by
chance and not by design.

Unbreak kexec and cleanup the mess:

- Add proper forward declarations and document the usage
- Use common struct definition
- Use the proper common defines instead of magic constants
- Add a purgatory_ prefix to have a proper name space
- Use ARRAY_SIZE() instead of a homebrewn reimplementation
- Add proper sections to the purgatory variables [ From Mike ]

Fixes: 72042a8c7b01 ("x86/purgatory: Make functions and variables static")
Reported-by: Mike Galbraith <<efault@gmx.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Nicholas Mc Guire <der.herr@hofr.at>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: "Tobin C. Harding" <me@tobin.cc>
Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1703101315140.3681@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Changed files
+78 -46
arch
powerpc
purgatory
x86
include
linux
kernel
+6 -6
arch/powerpc/purgatory/trampoline.S
··· 116 116 117 117 .data 118 118 .balign 8 119 - .globl sha256_digest 120 - sha256_digest: 119 + .globl purgatory_sha256_digest 120 + purgatory_sha256_digest: 121 121 .skip 32 122 - .size sha256_digest, . - sha256_digest 122 + .size purgatory_sha256_digest, . - purgatory_sha256_digest 123 123 124 124 .balign 8 125 - .globl sha_regions 126 - sha_regions: 125 + .globl purgatory_sha_regions 126 + purgatory_sha_regions: 127 127 .skip 8 * 2 * 16 128 - .size sha_regions, . - sha_regions 128 + .size purgatory_sha_regions, . - purgatory_sha_regions
+20
arch/x86/include/asm/purgatory.h
··· 1 + #ifndef _ASM_X86_PURGATORY_H 2 + #define _ASM_X86_PURGATORY_H 3 + 4 + #ifndef __ASSEMBLY__ 5 + #include <linux/purgatory.h> 6 + 7 + extern void purgatory(void); 8 + /* 9 + * These forward declarations serve two purposes: 10 + * 11 + * 1) Make sparse happy when checking arch/purgatory 12 + * 2) Document that these are required to be global so the symbol 13 + * lookup in kexec works 14 + */ 15 + extern unsigned long purgatory_backup_dest; 16 + extern unsigned long purgatory_backup_src; 17 + extern unsigned long purgatory_backup_sz; 18 + #endif /* __ASSEMBLY__ */ 19 + 20 + #endif /* _ASM_PURGATORY_H */
+6 -3
arch/x86/kernel/machine_kexec_64.c
··· 194 194 195 195 /* Setup copying of backup region */ 196 196 if (image->type == KEXEC_TYPE_CRASH) { 197 - ret = kexec_purgatory_get_set_symbol(image, "backup_dest", 197 + ret = kexec_purgatory_get_set_symbol(image, 198 + "purgatory_backup_dest", 198 199 &image->arch.backup_load_addr, 199 200 sizeof(image->arch.backup_load_addr), 0); 200 201 if (ret) 201 202 return ret; 202 203 203 - ret = kexec_purgatory_get_set_symbol(image, "backup_src", 204 + ret = kexec_purgatory_get_set_symbol(image, 205 + "purgatory_backup_src", 204 206 &image->arch.backup_src_start, 205 207 sizeof(image->arch.backup_src_start), 0); 206 208 if (ret) 207 209 return ret; 208 210 209 - ret = kexec_purgatory_get_set_symbol(image, "backup_sz", 211 + ret = kexec_purgatory_get_set_symbol(image, 212 + "purgatory_backup_sz", 210 213 &image->arch.backup_src_sz, 211 214 sizeof(image->arch.backup_src_sz), 0); 212 215 if (ret)
+17 -18
arch/x86/purgatory/purgatory.c
··· 10 10 * Version 2. See the file COPYING for more details. 11 11 */ 12 12 13 + #include <linux/bug.h> 14 + #include <asm/purgatory.h> 15 + 13 16 #include "sha256.h" 14 - #include "purgatory.h" 15 17 #include "../boot/string.h" 16 18 17 - struct sha_region { 18 - unsigned long start; 19 - unsigned long len; 20 - }; 19 + unsigned long purgatory_backup_dest __section(.kexec-purgatory); 20 + unsigned long purgatory_backup_src __section(.kexec-purgatory); 21 + unsigned long purgatory_backup_sz __section(.kexec-purgatory); 21 22 22 - static unsigned long backup_dest; 23 - static unsigned long backup_src; 24 - static unsigned long backup_sz; 23 + u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory); 25 24 26 - static u8 sha256_digest[SHA256_DIGEST_SIZE] = { 0 }; 27 - 28 - struct sha_region sha_regions[16] = {}; 25 + struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX] __section(.kexec-purgatory); 29 26 30 27 /* 31 28 * On x86, second kernel requries first 640K of memory to boot. Copy ··· 31 34 */ 32 35 static int copy_backup_region(void) 33 36 { 34 - if (backup_dest) 35 - memcpy((void *)backup_dest, (void *)backup_src, backup_sz); 36 - 37 + if (purgatory_backup_dest) { 38 + memcpy((void *)purgatory_backup_dest, 39 + (void *)purgatory_backup_src, purgatory_backup_sz); 40 + } 37 41 return 0; 38 42 } 39 43 40 44 static int verify_sha256_digest(void) 41 45 { 42 - struct sha_region *ptr, *end; 46 + struct kexec_sha_region *ptr, *end; 43 47 u8 digest[SHA256_DIGEST_SIZE]; 44 48 struct sha256_state sctx; 45 49 46 50 sha256_init(&sctx); 47 - end = &sha_regions[sizeof(sha_regions)/sizeof(sha_regions[0])]; 48 - for (ptr = sha_regions; ptr < end; ptr++) 51 + end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions); 52 + 53 + for (ptr = purgatory_sha_regions; ptr < end; ptr++) 49 54 sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len); 50 55 51 56 sha256_final(&sctx, digest); 52 57 53 - if (memcmp(digest, sha256_digest, sizeof(digest))) 58 + if (memcmp(digest, purgatory_sha256_digest, sizeof(digest))) 54 59 return 1; 55 60 56 61 return 0;
-8
arch/x86/purgatory/purgatory.h
··· 1 - #ifndef PURGATORY_H 2 - #define PURGATORY_H 3 - 4 - #ifndef __ASSEMBLY__ 5 - extern void purgatory(void); 6 - #endif /* __ASSEMBLY__ */ 7 - 8 - #endif /* PURGATORY_H */
+1 -1
arch/x86/purgatory/setup-x86_64.S
··· 9 9 * This source code is licensed under the GNU General Public License, 10 10 * Version 2. See the file COPYING for more details. 11 11 */ 12 - #include "purgatory.h" 12 + #include <asm/purgatory.h> 13 13 14 14 .text 15 15 .globl purgatory_start
-1
arch/x86/purgatory/sha256.h
··· 10 10 #ifndef SHA256_H 11 11 #define SHA256_H 12 12 13 - 14 13 #include <linux/types.h> 15 14 #include <crypto/sha.h> 16 15
+23
include/linux/purgatory.h
··· 1 + #ifndef _LINUX_PURGATORY_H 2 + #define _LINUX_PURGATORY_H 3 + 4 + #include <linux/types.h> 5 + #include <crypto/sha.h> 6 + #include <uapi/linux/kexec.h> 7 + 8 + struct kexec_sha_region { 9 + unsigned long start; 10 + unsigned long len; 11 + }; 12 + 13 + /* 14 + * These forward declarations serve two purposes: 15 + * 16 + * 1) Make sparse happy when checking arch/purgatory 17 + * 2) Document that these are required to be global so the symbol 18 + * lookup in kexec works 19 + */ 20 + extern struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX]; 21 + extern u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE]; 22 + 23 + #endif
+4 -4
kernel/kexec_file.c
··· 614 614 ret = crypto_shash_final(desc, digest); 615 615 if (ret) 616 616 goto out_free_digest; 617 - ret = kexec_purgatory_get_set_symbol(image, "sha_regions", 618 - sha_regions, sha_region_sz, 0); 617 + ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha_regions", 618 + sha_regions, sha_region_sz, 0); 619 619 if (ret) 620 620 goto out_free_digest; 621 621 622 - ret = kexec_purgatory_get_set_symbol(image, "sha256_digest", 623 - digest, SHA256_DIGEST_SIZE, 0); 622 + ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha256_digest", 623 + digest, SHA256_DIGEST_SIZE, 0); 624 624 if (ret) 625 625 goto out_free_digest; 626 626 }
+1 -5
kernel/kexec_internal.h
··· 15 15 extern struct mutex kexec_mutex; 16 16 17 17 #ifdef CONFIG_KEXEC_FILE 18 - struct kexec_sha_region { 19 - unsigned long start; 20 - unsigned long len; 21 - }; 22 - 18 + #include <linux/purgatory.h> 23 19 void kimage_file_post_load_cleanup(struct kimage *image); 24 20 #else /* CONFIG_KEXEC_FILE */ 25 21 static inline void kimage_file_post_load_cleanup(struct kimage *image) { }