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[]
= {//参见http://xuwenzhang.org/blog/tag/getopt_long/ noted by peter.guo
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)
{
//属于gnu体系
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_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 *///===========>pay more attention to purgatory!!!!!!
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)
{//=====>got it !!!!!!
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))
{
/*
Command line: ro root=LABEL=/ rhgb quiet irqpoll maxcpus=1 reset_devices
memmap=exactmap memmap=640K@0K memmap=5264K@16384K
memmap=125152K@22288K elfcorehdr=147440K (0x8ffc000)
memmap=56K#1834688K memmap=136K#1834744K memmap=128K#1834880K memmap=1024K$4193280K //红色部分'#'代表specific memory forACPI data. '$'代表specific memory as reserved. 没在代码中查找到?
/此处得到相关的memmap和elfcorehdr参数并存入新的命令行参数中
*/
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);//======>got it !!!!!!
/* 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;
}
|