1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_X86_BOOTPARAM_UTILS_H
3#define _ASM_X86_BOOTPARAM_UTILS_H
4
5#include <asm/bootparam.h>
6
7/*
8 * This file is included from multiple environments.  Do not
9 * add completing #includes to make it standalone.
10 */
11
12/*
13 * Deal with bootloaders which fail to initialize unknown fields in
14 * boot_params to zero.  The list fields in this list are taken from
15 * analysis of kexec-tools; if other broken bootloaders initialize a
16 * different set of fields we will need to figure out how to disambiguate.
17 *
18 * Note: efi_info is commonly left uninitialized, but that field has a
19 * private magic, so it is better to leave it unchanged.
20 */
21
22#define sizeof_mbr(type, member) ({ sizeof(((type *)0)->member); })
23
24#define BOOT_PARAM_PRESERVE(struct_member)				\
25	{								\
26		.start = offsetof(struct boot_params, struct_member),	\
27		.len   = sizeof_mbr(struct boot_params, struct_member),	\
28	}
29
30struct boot_params_to_save {
31	unsigned int start;
32	unsigned int len;
33};
34
35static void sanitize_boot_params(struct boot_params *boot_params)
36{
37	/*
38	 * IMPORTANT NOTE TO BOOTLOADER AUTHORS: do not simply clear
39	 * this field.  The purpose of this field is to guarantee
40	 * compliance with the x86 boot spec located in
41	 * Documentation/arch/x86/boot.rst .  That spec says that the
42	 * *whole* structure should be cleared, after which only the
43	 * portion defined by struct setup_header (boot_params->hdr)
44	 * should be copied in.
45	 *
46	 * If you're having an issue because the sentinel is set, you
47	 * need to change the whole structure to be cleared, not this
48	 * (or any other) individual field, or you will soon have
49	 * problems again.
50	 */
51	if (boot_params->sentinel) {
52		static struct boot_params scratch;
53		char *bp_base = (char *)boot_params;
54		char *save_base = (char *)&scratch;
55		int i;
56
57		const struct boot_params_to_save to_save[] = {
58			BOOT_PARAM_PRESERVE(screen_info),
59			BOOT_PARAM_PRESERVE(apm_bios_info),
60			BOOT_PARAM_PRESERVE(tboot_addr),
61			BOOT_PARAM_PRESERVE(ist_info),
62			BOOT_PARAM_PRESERVE(hd0_info),
63			BOOT_PARAM_PRESERVE(hd1_info),
64			BOOT_PARAM_PRESERVE(sys_desc_table),
65			BOOT_PARAM_PRESERVE(olpc_ofw_header),
66			BOOT_PARAM_PRESERVE(efi_info),
67			BOOT_PARAM_PRESERVE(alt_mem_k),
68			BOOT_PARAM_PRESERVE(scratch),
69			BOOT_PARAM_PRESERVE(e820_entries),
70			BOOT_PARAM_PRESERVE(eddbuf_entries),
71			BOOT_PARAM_PRESERVE(edd_mbr_sig_buf_entries),
72			BOOT_PARAM_PRESERVE(edd_mbr_sig_buffer),
73			BOOT_PARAM_PRESERVE(secure_boot),
74			BOOT_PARAM_PRESERVE(hdr),
75			BOOT_PARAM_PRESERVE(e820_table),
76			BOOT_PARAM_PRESERVE(eddbuf),
77			BOOT_PARAM_PRESERVE(cc_blob_address),
78		};
79
80		memset(&scratch, 0, sizeof(scratch));
81
82		for (i = 0; i < ARRAY_SIZE(to_save); i++) {
83			memcpy(save_base + to_save[i].start,
84			       bp_base + to_save[i].start, to_save[i].len);
85		}
86
87		memcpy(boot_params, save_base, sizeof(*boot_params));
88	}
89}
90
91#endif /* _ASM_X86_BOOTPARAM_UTILS_H */
92