int elf_x86_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)//******************
{ struct mem_ehdr ehdr; const char *command_line; char *modified_cmdline; int command_line_len; int modified_cmdline_len; const char *ramdisk; unsigned long entry, max_addr; int arg_style; #define ARG_STYLE_ELF 0 #define ARG_STYLE_LINUX 1 #define ARG_STYLE_NONE 2 int opt; #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_REUSE_CMDLINE (OPT_ARCH_MAX+1) #define OPT_RAMDISK (OPT_ARCH_MAX+2) #define OPT_ARGS_ELF (OPT_ARCH_MAX+3) #define OPT_ARGS_LINUX (OPT_ARCH_MAX+4) #define OPT_ARGS_NONE (OPT_ARCH_MAX+5)
static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "reuse-cmdline", 1, NULL, OPT_REUSE_CMDLINE }, { "initrd", 1, NULL, OPT_RAMDISK }, { "ramdisk", 1, NULL, OPT_RAMDISK }, { "args-elf", 0, NULL, OPT_ARGS_ELF }, { "args-linux", 0, NULL, OPT_ARGS_LINUX }, { "args-none", 0, NULL, OPT_ARGS_NONE }, { 0, 0, NULL, 0 }, };
static const char short_options[] = KEXEC_OPT_STR "";
/* * Parse the command line arguments */ arg_style = ARG_STYLE_ELF; command_line = 0; modified_cmdline = 0; modified_cmdline_len = 0; ramdisk = 0; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case '?': usage(); return -1; case OPT_APPEND: command_line = optarg; break; case OPT_REUSE_CMDLINE: command_line = get_command_line(); break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_ARGS_ELF:
arg_style = ARG_STYLE_ELF; break; case OPT_ARGS_LINUX: arg_style = ARG_STYLE_LINUX; break; case OPT_ARGS_NONE: #ifdef __i386__ arg_style = ARG_STYLE_NONE; #else die("--args-none only works on arch i386\n"); #endif break; } } command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) +1; }
/* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & (KEXEC_ON_CRASH|KEXEC_PRESERVE_CONTEXT)) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (command_line) { strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } modified_cmdline_len = strlen(modified_cmdline); }
/* Load the ELF executable 加载新内核,解析elf头并加载elf data,最终就是将内核各segmants(内核本质上就是一个ELF文件)弄到info中*/*/ elf_exec_build_load(info, &ehdr, buf, len, 0);//========================>
entry = ehdr.e_entry; max_addr = elf_max_addr(&ehdr);
/* Do we want arguments? */ if (arg_style != ARG_STYLE_NONE) { /* Load the setup code */ elf_rel_build_load(info, &info->rhdr, (char *) purgatory, purgatory_size, 0, ULONG_MAX, 1, 0); } if (arg_style == ARG_STYLE_NONE) { info->entry = (void *)entry;
} else if (arg_style == ARG_STYLE_ELF) { unsigned long note_base; struct entry32_regs regs; uint32_t arg1, arg2;
/* Setup the ELF boot notes */ note_base = elf_boot_notes(info, max_addr, (unsigned char *) command_line, command_line_len);
/* Initialize the stack arguments */ arg2 = 0; /* No return address */ arg1 = note_base; elf_rel_set_symbol(&info->rhdr, "stack_arg32_1", &arg1, sizeof(arg1)); elf_rel_set_symbol(&info->rhdr, "stack_arg32_2", &arg2, sizeof(arg2)); /* Initialize the registers */ elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs)); regs.eip = entry; /* The entry point */ regs.esp = elf_rel_get_addr(&info->rhdr, "stack_arg32_2"); elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
if (ramdisk) { die("Ramdisks not supported with generic elf arguments"); } } else if (arg_style == ARG_STYLE_LINUX) { struct x86_linux_faked_param_header *hdr; unsigned long param_base; const unsigned char *ramdisk_buf; off_t ramdisk_length; struct entry32_regs regs; int rc = 0;
/* Get the linux parameter header */ hdr = xmalloc(sizeof(*hdr));
/* Hack: With some ld versions, vmlinux program headers show * a gap of two pages between bss segment and data segment * but effectively kernel considers it as bss segment and * overwrites the any data placed there. Hence bloat the * memsz of parameter segment to 16K to avoid being placed * in such gaps. * This is a makeshift solution until it is fixed in kernel */ param_base = add_buffer(info, hdr, sizeof(*hdr), 16*1024, 16, 0, max_addr, 1);
/* Initialize the parameter header */ memset(hdr, 0, sizeof(*hdr)); init_linux_parameters(&hdr->hdr);
/* Add a ramdisk to the current image */ ramdisk_buf = NULL; ramdisk_length = 0; if (ramdisk) { ramdisk_buf = (unsigned char *) slurp_file(ramdisk, &ramdisk_length); }
/* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & (KEXEC_ON_CRASH|KEXEC_PRESERVE_CONTEXT)) { rc = load_crashdump_segments(info, modified_cmdline, max_addr, 0); if (rc < 0) return -1; /* Use new command line. */ command_line = modified_cmdline; command_line_len = strlen(modified_cmdline) + 1; }
/* Tell the kernel what is going on */ setup_linux_bootloader_parameters(info, &hdr->hdr, param_base,
offsetof(struct x86_linux_faked_param_header, command_line), command_line, command_line_len, ramdisk_buf, ramdisk_length);
/* Fill in the information bios calls would usually provide */ setup_linux_system_parameters(&hdr->hdr, info->kexec_flags);
/* Initialize the registers */ elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs)); regs.ebx = 0; /* Bootstrap processor */ regs.esi = param_base; /* Pointer to the parameters */ regs.eip = entry; /* The entry point */ regs.esp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */ elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs)); } else { die("Unknown argument style\n"); } return 0; }
|