Yinghai Lu <yinghai at kernel.org> writes: > also need to make sure pass right 64bit start address to go there > directly later. There are some silly things here but I think the clean way to handle this is to create a kexec/arch/i386/kexec-bzImage64.c that handles loading a bzImage with a 64bit entry point. That should keep the code simpler and easier to read. Although it will probably introduce a bit more code. Eric > Signed-off-by: Yinghai Lu <yinghai at kernel.org> > --- > kexec/arch/i386/kexec-bzImage.c | 53 ++++++++++++++++++++++++++++++++++++-- > 1 files changed, 50 insertions(+), 3 deletions(-) > > diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c > index 6998587..3e705ca 100644 > --- a/kexec/arch/i386/kexec-bzImage.c > +++ b/kexec/arch/i386/kexec-bzImage.c > @@ -18,8 +18,10 @@ > */ > > #define _GNU_SOURCE > +#include <stddef.h> > #include <stdio.h> > #include <string.h> > +#include <limits.h> > #include <stdlib.h> > #include <errno.h> > #include <sys/types.h> > @@ -35,6 +37,7 @@ > #include "../../kexec-elf.h" > #include "../../kexec-syscall.h" > #include "kexec-x86.h" > +#include "../x86_64/kexec-x86_64.h" > #include "x86-linux-setup.h" > #include "crashdump-x86.h" > #include <arch/options.h> > @@ -111,12 +114,15 @@ int do_bzImage_load(struct kexec_info *info, > size_t size; > int kern16_size; > unsigned long setup_base, setup_size; > + struct entry64_regs regs64; > struct entry32_regs regs32; > struct entry16_regs regs16; > unsigned int relocatable_kernel = 0; > unsigned long kernel32_load_addr; > char *modified_cmdline; > unsigned long cmdline_end; > + unsigned long code64_start_offset = 0; > + unsigned long kernel64_load_addr = 0; > > /* > * Find out about the file I am about to load. > @@ -154,6 +160,13 @@ int do_bzImage_load(struct kexec_info *info, > dbgprintf("bzImage is relocatable\n"); > } > > + if (setup_header.protocol_version >= 0x020C) { > + code64_start_offset = setup_header.code64_start_offset; > + if (code64_start_offset) > + dbgprintf("code64_start_offset: 0x%lx\n", > + code64_start_offset); > + } > + > /* Can't use bzImage for crash dump purposes with real mode entry */ > if((info->kexec_flags & KEXEC_ON_CRASH) && real_mode_entry) { > fprintf(stderr, "Can't use bzImage for crash dump purposes" > @@ -250,7 +263,26 @@ int do_bzImage_load(struct kexec_info *info, > kernel32_max_addr = real_mode->initrd_addr_max; > } > > - kernel32_load_addr = add_buffer(info, kernel + kern16_size, > + if (!real_mode_entry && code64_start_offset) { > + /* align to 1G to avoid cross the PUD_SIZE boundary */ > + kernel64_load_addr = add_buffer( > + info, kernel + kern16_size, > + size, size, 1UL<<30, > + 1UL<<32, ULONG_MAX, > + -1); > + if (!kernel64_load_addr) > + kernel64_load_addr = add_buffer( > + info, kernel + kern16_size, > + size, size, 1UL<<30, > + 1UL<<30, 1UL<<32, > + -1); > + if (kernel64_load_addr) > + kernel64_load_addr += code64_start_offset; > + } > + > + if (!kernel64_load_addr) > + kernel32_load_addr = add_buffer( > + info, kernel + kern16_size, > size, size, kern_align, > 0x100000, kernel32_max_addr, > 1); > @@ -260,8 +292,11 @@ int do_bzImage_load(struct kexec_info *info, > add_segment(info, kernel + kern16_size, size, > kernel32_load_addr, size); > } > - > - dbgprintf("Loaded 32bit kernel at 0x%lx\n", kernel32_load_addr); > + > + if (kernel64_load_addr) > + dbgprintf("Loaded 64bit kernel at 0x%lx\n", kernel64_load_addr); > + else > + dbgprintf("Loaded 32bit kernel at 0x%lx\n", kernel32_load_addr); > > /* Tell the kernel what is going on */ > setup_linux_bootloader_parameters(info, real_mode, setup_base, > @@ -271,6 +306,16 @@ int do_bzImage_load(struct kexec_info *info, > /* Get the initial register values */ > elf_rel_get_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16)); > elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s32, sizeof(regs32)); > + if (kernel64_load_addr) { > + elf_rel_get_symbol(&info->rhdr, "entry64_regs", ®s64, sizeof(regs64)); > + regs64.rbx = 0; /* Bootstrap processor */ > + regs64.rsi = setup_base; /* Pointer to the parameters */ > + regs64.rip = kernel64_load_addr; /* the entry point */ > + regs64.rsp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */ > + elf_rel_set_symbol(&info->rhdr, "entry64_regs", ®s64, sizeof(regs64)); > + > + goto cmd_line; > + } > /* > > * Initialize the 32bit start information. > @@ -320,6 +365,8 @@ int do_bzImage_load(struct kexec_info *info, > elf_rel_set_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16)); > elf_rel_set_symbol(&info->rhdr, "entry16_debug_regs", ®s16, sizeof(regs16)); > elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s32, sizeof(regs32)); > + > +cmd_line: > cmdline_end = setup_base + kern16_size + command_line_len - 1; > elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end, > sizeof(unsigned long));