diff options
-rw-r--r-- | arch/x86/kernel/kexec-bzimage64.c | 146 | ||||
-rw-r--r-- | drivers/firmware/efi/runtime-map.c | 21 | ||||
-rw-r--r-- | include/linux/efi.h | 19 |
3 files changed, 174 insertions, 12 deletions
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index a8e646458a10..623e6c58081f 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
@@ -18,10 +18,12 @@ | |||
18 | #include <linux/kexec.h> | 18 | #include <linux/kexec.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/efi.h> | ||
21 | 22 | ||
22 | #include <asm/bootparam.h> | 23 | #include <asm/bootparam.h> |
23 | #include <asm/setup.h> | 24 | #include <asm/setup.h> |
24 | #include <asm/crash.h> | 25 | #include <asm/crash.h> |
26 | #include <asm/efi.h> | ||
25 | 27 | ||
26 | #define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */ | 28 | #define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */ |
27 | 29 | ||
@@ -90,7 +92,7 @@ static int setup_cmdline(struct kimage *image, struct boot_params *params, | |||
90 | return 0; | 92 | return 0; |
91 | } | 93 | } |
92 | 94 | ||
93 | static int setup_memory_map_entries(struct boot_params *params) | 95 | static int setup_e820_entries(struct boot_params *params) |
94 | { | 96 | { |
95 | unsigned int nr_e820_entries; | 97 | unsigned int nr_e820_entries; |
96 | 98 | ||
@@ -107,8 +109,93 @@ static int setup_memory_map_entries(struct boot_params *params) | |||
107 | return 0; | 109 | return 0; |
108 | } | 110 | } |
109 | 111 | ||
110 | static int setup_boot_parameters(struct kimage *image, | 112 | #ifdef CONFIG_EFI |
111 | struct boot_params *params) | 113 | static int setup_efi_info_memmap(struct boot_params *params, |
114 | unsigned long params_load_addr, | ||
115 | unsigned int efi_map_offset, | ||
116 | unsigned int efi_map_sz) | ||
117 | { | ||
118 | void *efi_map = (void *)params + efi_map_offset; | ||
119 | unsigned long efi_map_phys_addr = params_load_addr + efi_map_offset; | ||
120 | struct efi_info *ei = ¶ms->efi_info; | ||
121 | |||
122 | if (!efi_map_sz) | ||
123 | return 0; | ||
124 | |||
125 | efi_runtime_map_copy(efi_map, efi_map_sz); | ||
126 | |||
127 | ei->efi_memmap = efi_map_phys_addr & 0xffffffff; | ||
128 | ei->efi_memmap_hi = efi_map_phys_addr >> 32; | ||
129 | ei->efi_memmap_size = efi_map_sz; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int | ||
135 | prepare_add_efi_setup_data(struct boot_params *params, | ||
136 | unsigned long params_load_addr, | ||
137 | unsigned int efi_setup_data_offset) | ||
138 | { | ||
139 | unsigned long setup_data_phys; | ||
140 | struct setup_data *sd = (void *)params + efi_setup_data_offset; | ||
141 | struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data); | ||
142 | |||
143 | esd->fw_vendor = efi.fw_vendor; | ||
144 | esd->runtime = efi.runtime; | ||
145 | esd->tables = efi.config_table; | ||
146 | esd->smbios = efi.smbios; | ||
147 | |||
148 | sd->type = SETUP_EFI; | ||
149 | sd->len = sizeof(struct efi_setup_data); | ||
150 | |||
151 | /* Add setup data */ | ||
152 | setup_data_phys = params_load_addr + efi_setup_data_offset; | ||
153 | sd->next = params->hdr.setup_data; | ||
154 | params->hdr.setup_data = setup_data_phys; | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int | ||
160 | setup_efi_state(struct boot_params *params, unsigned long params_load_addr, | ||
161 | unsigned int efi_map_offset, unsigned int efi_map_sz, | ||
162 | unsigned int efi_setup_data_offset) | ||
163 | { | ||
164 | struct efi_info *current_ei = &boot_params.efi_info; | ||
165 | struct efi_info *ei = ¶ms->efi_info; | ||
166 | |||
167 | if (!current_ei->efi_memmap_size) | ||
168 | return 0; | ||
169 | |||
170 | /* | ||
171 | * If 1:1 mapping is not enabled, second kernel can not setup EFI | ||
172 | * and use EFI run time services. User space will have to pass | ||
173 | * acpi_rsdp=<addr> on kernel command line to make second kernel boot | ||
174 | * without efi. | ||
175 | */ | ||
176 | if (efi_enabled(EFI_OLD_MEMMAP)) | ||
177 | return 0; | ||
178 | |||
179 | ei->efi_loader_signature = current_ei->efi_loader_signature; | ||
180 | ei->efi_systab = current_ei->efi_systab; | ||
181 | ei->efi_systab_hi = current_ei->efi_systab_hi; | ||
182 | |||
183 | ei->efi_memdesc_version = current_ei->efi_memdesc_version; | ||
184 | ei->efi_memdesc_size = efi_get_runtime_map_desc_size(); | ||
185 | |||
186 | setup_efi_info_memmap(params, params_load_addr, efi_map_offset, | ||
187 | efi_map_sz); | ||
188 | prepare_add_efi_setup_data(params, params_load_addr, | ||
189 | efi_setup_data_offset); | ||
190 | return 0; | ||
191 | } | ||
192 | #endif /* CONFIG_EFI */ | ||
193 | |||
194 | static int | ||
195 | setup_boot_parameters(struct kimage *image, struct boot_params *params, | ||
196 | unsigned long params_load_addr, | ||
197 | unsigned int efi_map_offset, unsigned int efi_map_sz, | ||
198 | unsigned int efi_setup_data_offset) | ||
112 | { | 199 | { |
113 | unsigned int nr_e820_entries; | 200 | unsigned int nr_e820_entries; |
114 | unsigned long long mem_k, start, end; | 201 | unsigned long long mem_k, start, end; |
@@ -140,7 +227,7 @@ static int setup_boot_parameters(struct kimage *image, | |||
140 | if (ret) | 227 | if (ret) |
141 | return ret; | 228 | return ret; |
142 | } else | 229 | } else |
143 | setup_memory_map_entries(params); | 230 | setup_e820_entries(params); |
144 | 231 | ||
145 | nr_e820_entries = params->e820_entries; | 232 | nr_e820_entries = params->e820_entries; |
146 | 233 | ||
@@ -161,6 +248,12 @@ static int setup_boot_parameters(struct kimage *image, | |||
161 | } | 248 | } |
162 | } | 249 | } |
163 | 250 | ||
251 | #ifdef CONFIG_EFI | ||
252 | /* Setup EFI state */ | ||
253 | setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz, | ||
254 | efi_setup_data_offset); | ||
255 | #endif | ||
256 | |||
164 | /* Setup EDD info */ | 257 | /* Setup EDD info */ |
165 | memcpy(params->eddbuf, boot_params.eddbuf, | 258 | memcpy(params->eddbuf, boot_params.eddbuf, |
166 | EDDMAXNR * sizeof(struct edd_info)); | 259 | EDDMAXNR * sizeof(struct edd_info)); |
@@ -214,6 +307,15 @@ int bzImage64_probe(const char *buf, unsigned long len) | |||
214 | return ret; | 307 | return ret; |
215 | } | 308 | } |
216 | 309 | ||
310 | /* | ||
311 | * Can't handle 32bit EFI as it does not allow loading kernel | ||
312 | * above 4G. This should be handled by 32bit bzImage loader | ||
313 | */ | ||
314 | if (efi_enabled(EFI_RUNTIME_SERVICES) && !efi_enabled(EFI_64BIT)) { | ||
315 | pr_debug("EFI is 32 bit. Can't load kernel above 4G.\n"); | ||
316 | return ret; | ||
317 | } | ||
318 | |||
217 | /* I've got a bzImage */ | 319 | /* I've got a bzImage */ |
218 | pr_debug("It's a relocatable bzImage64\n"); | 320 | pr_debug("It's a relocatable bzImage64\n"); |
219 | ret = 0; | 321 | ret = 0; |
@@ -229,7 +331,7 @@ void *bzImage64_load(struct kimage *image, char *kernel, | |||
229 | 331 | ||
230 | struct setup_header *header; | 332 | struct setup_header *header; |
231 | int setup_sects, kern16_size, ret = 0; | 333 | int setup_sects, kern16_size, ret = 0; |
232 | unsigned long setup_header_size, params_cmdline_sz; | 334 | unsigned long setup_header_size, params_cmdline_sz, params_misc_sz; |
233 | struct boot_params *params; | 335 | struct boot_params *params; |
234 | unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr; | 336 | unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr; |
235 | unsigned long purgatory_load_addr; | 337 | unsigned long purgatory_load_addr; |
@@ -239,6 +341,7 @@ void *bzImage64_load(struct kimage *image, char *kernel, | |||
239 | struct kexec_entry64_regs regs64; | 341 | struct kexec_entry64_regs regs64; |
240 | void *stack; | 342 | void *stack; |
241 | unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr); | 343 | unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr); |
344 | unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset; | ||
242 | 345 | ||
243 | header = (struct setup_header *)(kernel + setup_hdr_offset); | 346 | header = (struct setup_header *)(kernel + setup_hdr_offset); |
244 | setup_sects = header->setup_sects; | 347 | setup_sects = header->setup_sects; |
@@ -285,12 +388,29 @@ void *bzImage64_load(struct kimage *image, char *kernel, | |||
285 | 388 | ||
286 | pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); | 389 | pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); |
287 | 390 | ||
288 | /* Load Bootparams and cmdline */ | 391 | |
392 | /* | ||
393 | * Load Bootparams and cmdline and space for efi stuff. | ||
394 | * | ||
395 | * Allocate memory together for multiple data structures so | ||
396 | * that they all can go in single area/segment and we don't | ||
397 | * have to create separate segment for each. Keeps things | ||
398 | * little bit simple | ||
399 | */ | ||
400 | efi_map_sz = efi_get_runtime_map_size(); | ||
401 | efi_map_sz = ALIGN(efi_map_sz, 16); | ||
289 | params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + | 402 | params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + |
290 | MAX_ELFCOREHDR_STR_LEN; | 403 | MAX_ELFCOREHDR_STR_LEN; |
291 | params = kzalloc(params_cmdline_sz, GFP_KERNEL); | 404 | params_cmdline_sz = ALIGN(params_cmdline_sz, 16); |
405 | params_misc_sz = params_cmdline_sz + efi_map_sz + | ||
406 | sizeof(struct setup_data) + | ||
407 | sizeof(struct efi_setup_data); | ||
408 | |||
409 | params = kzalloc(params_misc_sz, GFP_KERNEL); | ||
292 | if (!params) | 410 | if (!params) |
293 | return ERR_PTR(-ENOMEM); | 411 | return ERR_PTR(-ENOMEM); |
412 | efi_map_offset = params_cmdline_sz; | ||
413 | efi_setup_data_offset = efi_map_offset + efi_map_sz; | ||
294 | 414 | ||
295 | /* Copy setup header onto bootparams. Documentation/x86/boot.txt */ | 415 | /* Copy setup header onto bootparams. Documentation/x86/boot.txt */ |
296 | setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset; | 416 | setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset; |
@@ -298,13 +418,13 @@ void *bzImage64_load(struct kimage *image, char *kernel, | |||
298 | /* Is there a limit on setup header size? */ | 418 | /* Is there a limit on setup header size? */ |
299 | memcpy(¶ms->hdr, (kernel + setup_hdr_offset), setup_header_size); | 419 | memcpy(¶ms->hdr, (kernel + setup_hdr_offset), setup_header_size); |
300 | 420 | ||
301 | ret = kexec_add_buffer(image, (char *)params, params_cmdline_sz, | 421 | ret = kexec_add_buffer(image, (char *)params, params_misc_sz, |
302 | params_cmdline_sz, 16, MIN_BOOTPARAM_ADDR, | 422 | params_misc_sz, 16, MIN_BOOTPARAM_ADDR, |
303 | ULONG_MAX, 1, &bootparam_load_addr); | 423 | ULONG_MAX, 1, &bootparam_load_addr); |
304 | if (ret) | 424 | if (ret) |
305 | goto out_free_params; | 425 | goto out_free_params; |
306 | pr_debug("Loaded boot_param and command line at 0x%lx bufsz=0x%lx memsz=0x%lx\n", | 426 | pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n", |
307 | bootparam_load_addr, params_cmdline_sz, params_cmdline_sz); | 427 | bootparam_load_addr, params_misc_sz, params_misc_sz); |
308 | 428 | ||
309 | /* Load kernel */ | 429 | /* Load kernel */ |
310 | kernel_buf = kernel + kern16_size; | 430 | kernel_buf = kernel + kern16_size; |
@@ -365,7 +485,9 @@ void *bzImage64_load(struct kimage *image, char *kernel, | |||
365 | if (ret) | 485 | if (ret) |
366 | goto out_free_params; | 486 | goto out_free_params; |
367 | 487 | ||
368 | ret = setup_boot_parameters(image, params); | 488 | ret = setup_boot_parameters(image, params, bootparam_load_addr, |
489 | efi_map_offset, efi_map_sz, | ||
490 | efi_setup_data_offset); | ||
369 | if (ret) | 491 | if (ret) |
370 | goto out_free_params; | 492 | goto out_free_params; |
371 | 493 | ||
diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 97cdd16a2169..018c29a26615 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c | |||
@@ -138,6 +138,27 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr) | |||
138 | return entry; | 138 | return entry; |
139 | } | 139 | } |
140 | 140 | ||
141 | int efi_get_runtime_map_size(void) | ||
142 | { | ||
143 | return nr_efi_runtime_map * efi_memdesc_size; | ||
144 | } | ||
145 | |||
146 | int efi_get_runtime_map_desc_size(void) | ||
147 | { | ||
148 | return efi_memdesc_size; | ||
149 | } | ||
150 | |||
151 | int efi_runtime_map_copy(void *buf, size_t bufsz) | ||
152 | { | ||
153 | size_t sz = efi_get_runtime_map_size(); | ||
154 | |||
155 | if (sz > bufsz) | ||
156 | sz = bufsz; | ||
157 | |||
158 | memcpy(buf, efi_runtime_map, sz); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
141 | void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) | 162 | void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) |
142 | { | 163 | { |
143 | efi_runtime_map = map; | 164 | efi_runtime_map = map; |
diff --git a/include/linux/efi.h b/include/linux/efi.h index efc681fd5895..45cb4ffdea62 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -1156,6 +1156,9 @@ int efivars_sysfs_init(void); | |||
1156 | #ifdef CONFIG_EFI_RUNTIME_MAP | 1156 | #ifdef CONFIG_EFI_RUNTIME_MAP |
1157 | int efi_runtime_map_init(struct kobject *); | 1157 | int efi_runtime_map_init(struct kobject *); |
1158 | void efi_runtime_map_setup(void *, int, u32); | 1158 | void efi_runtime_map_setup(void *, int, u32); |
1159 | int efi_get_runtime_map_size(void); | ||
1160 | int efi_get_runtime_map_desc_size(void); | ||
1161 | int efi_runtime_map_copy(void *buf, size_t bufsz); | ||
1159 | #else | 1162 | #else |
1160 | static inline int efi_runtime_map_init(struct kobject *kobj) | 1163 | static inline int efi_runtime_map_init(struct kobject *kobj) |
1161 | { | 1164 | { |
@@ -1164,6 +1167,22 @@ static inline int efi_runtime_map_init(struct kobject *kobj) | |||
1164 | 1167 | ||
1165 | static inline void | 1168 | static inline void |
1166 | efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {} | 1169 | efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {} |
1170 | |||
1171 | static inline int efi_get_runtime_map_size(void) | ||
1172 | { | ||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | static inline int efi_get_runtime_map_desc_size(void) | ||
1177 | { | ||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static inline int efi_runtime_map_copy(void *buf, size_t bufsz) | ||
1182 | { | ||
1183 | return 0; | ||
1184 | } | ||
1185 | |||
1167 | #endif | 1186 | #endif |
1168 | 1187 | ||
1169 | /* prototypes shared between arch specific and generic stub code */ | 1188 | /* prototypes shared between arch specific and generic stub code */ |