上一篇 x86系统引导(1)主要是整体上对系统的引导有个概括的理解,没有深入到具体的源码中,这一篇,我们将深入到源码中,进行分析。系统引导过程中很多都是汇编写的,我们就不分析那些了,从start_kernel函数开始。
源码如下:
/*
* Activate the first processor.
*/
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[];
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them现在中断被禁止。
*/
lock_kernel();
page_address_init();
这函数在/* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */这个条件满足时,才能执行,应该和高端内存有关。
printk(linux_banner);
在屏幕上显示出内核的版本信息。如下:
const char *linux_banner =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
setup_arch(&command_line);
这个函数所处理的是系统结构的设置,就是这部分的主体。源码如下,其中很多我省略了:
/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
* for initialization. Note, the efi init code path is determined by the
* global efi_enabled. This allows the same kernel image to be used on existing
* systems (with a traditional BIOS) as well as on EFI systems.
*/
void __init setup_arch(char **cmdline_p)
{
unsigned long max_low_pfn;
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
pre_setup_arch_hook();空函数
void __init pre_setup_arch_hook(void)
{
}
early_cpu_init();/* 设置获取的cpu信息 */
void __init early_cpu_init(void)
{
intel_cpu_init();
cyrix_init_cpu();
nsc_init_cpu();
amd_init_cpu();
centaur_init_cpu();
transmeta_init_cpu();
rise_init_cpu();
nexgen_init_cpu();
umc_init_cpu();
early_cpu_detect();
......
}
......
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
edid_info = EDID_INFO;
apm_info.bios = APM_BIOS_INFO;
ist_info = IST_INFO;
saved_videomode = VIDEO_MODE;
if( SYS_DESC_TABLE.length != 0 ) {
MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
machine_id = SYS_DESC_TABLE.table[0];
machine_submodel_id = SYS_DESC_TABLE.table[1];
BIOS_revision = SYS_DESC_TABLE.table[2];
}
aux_device_present = AUX_DEVICE_INFO;
#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
#endif
从setup中取得BIOS自检后取得的信息,复制到内核内存空间中(原来保存在一个临时页面中) ,如果在引导命令行中另有所指,则处理命令行时再加以修改。
ARCH_SETUP
if (efi_enabled)
efi_init();
else {
printk(KERN_INFO "BIOS-provided physical RAM map:\n");
print_memory_map(machine_specific_memory_setup());
}
/**这个函数主要是有setup在引导阶段对物理内存的查询,并根据获得的信息生成一张物理内存的构成图,成为e820图,在通过参数传给内核,使内核知道系统中内存资源的配置。
主要和下面的结构有关:
#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
struct e820map {
int nr_map;
struct e820entry {
unsigned long long addr;/* start of memory segment */
unsigned long long size;/* size of memory segment */
unsigned long type;/* type of memory segment */
} map[E820MAX];
};
extern struct e820map e820;
数组中的每一项都是对一个物理内存的描述。
* machine_specific_memory_setup - Hook for machine specific memory setup.
*
* Description:
* This is included late in kernel/setup.c so that it can make
* use of all of the static functions.
**/
static char * __init machine_specific_memory_setup(void)
{
char *who;
who = "BIOS-e820";
/*
* Try to copy the BIOS-supplied E820-map.
*
* Otherwise fake a memory map; one section from 0k->640k,
* the next section from 1mb->appropriate_mem_k
*/
sanitize_e820_map(E820_MAP, &E820_MAP_NR);
if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
unsigned long mem_size;
/* compare results from other methods and take the greater */
if (ALT_MEM_K < EXT_MEM_K) {
mem_size = EXT_MEM_K;
who = "BIOS-88";
} else {
mem_size = ALT_MEM_K;
who = "BIOS-e801";
}
e820.nr_map = 0;
add_memory_region(0, LOWMEMSIZE(), E820_RAM);
add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
}
return who;
}
......
下一篇从这里接着说。
if (!MOUNT_ROOT_RDONLY)
root_mountflags &= ~MS_RDONLY;
init_mm.start_code = (unsigned long) _text;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
code_resource.start = virt_to_phys(_text);
code_resource.end = virt_to_phys(_etext)-1;
data_resource.start = virt_to_phys(_etext);
data_resource.end = virt_to_phys(_edata)-1;
parse_cmdline_early(cmdline_p);
max_low_pfn = setup_memory();
.......
}
x86系统引导(1)的链接
x86系统引导(3)的连接