Kernel是从header_32.S里面跳转到i386_start_kernel的。回忆一下在进入i386_start_kernel之前已经建立起来的运行环境:
1. CR3已经指向PMD或者PT的起始地址。
2. PMD或者PT已经完全建立起来,其所指向的页框已经覆盖了从0起始到_end+MAPPING_BEYOND_END的空间。
3. GDT已经指向了gdt_page
4. LDT为空
5. IDT已经初始化
6. boot_params已经保存在0xC0000000以上的空间
7. 堆栈已经建立
8. CPU已经进入保护模式,并且启用了页面。
在以上的基础上,来看看kernel的启动还将怎样进行:
i386_start_kernel在arch/x86/kernel/header32.c里面,代码如下:
- void __init i386_start_kernel(void)
-
{
-
memblock_init();
-
-
#ifdef CONFIG_X86_TRAMPOLINE
-
/*
-
* But first pinch a few for the stack/trampoline stuff
-
* FIXME: Don't need the extra page at 4K, but need to fix
-
* trampoline before removing it. (see the GDT stuff)
-
*/
-
memblock_x86_reserve_range(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
-
#endif
-
-
memblock_x86_reserve_range(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS"); //保留kernel本身
-
-
#ifdef CONFIG_BLK_DEV_INITRD
-
/* Reserve INITRD */
-
if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
-
/* Assume only end is not page aligned */
-
u64 ramdisk_image = boot_params.hdr.ramdisk_image;
-
u64 ramdisk_size = boot_params.hdr.ramdisk_size;
-
u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
-
memblock_x86_reserve_range(ramdisk_image, ramdisk_end, "RAMDISK"); //如果使用initrd,则将boot_params.hdr.ramdisk_image指向的initrd空间进行保留。
-
}
-
#endif
-
-
/* Call the subarch specific early setup function */
-
switch (boot_params.hdr.hardware_subarch) {
-
case X86_SUBARCH_MRST:
-
x86_mrst_early_setup();
-
break;
-
default:
-
i386_default_early_setup();
-
break;
-
}
-
-
/*
-
* At this point everything still needed from the boot loader
-
* or BIOS or kernel text should be early reserved or marked not
-
* RAM in e820. All other memory is free game.
-
*/
-
-
start_kernel();
-
}
1. memblock_init()在mm/Memblock.c里面被定义。其作用就是初始化memblock这个结构。memblock包含两个重要的成员,分别是memblock.memory和memblock.reserved.其分别代表系统中可用的内存和已经被保留的内存。
memblock.memory和memblock.reserved被定义为以下结构:
- struct memblock_type {
-
unsigned long cnt; /* number of regions */
-
unsigned long max; /* size of the allocated array */
-
struct memblock_region *regions;
-
};
在初始化的时候,memblock.memory和memblock.reserved分别被指向两个静态数组:
- static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock;
-
static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock;
2. memblock_x86_reserve_range(u64 start, u64 end, char * name)的作用是将起始地址为start, 终止地址为end的内存块标注为系统保留,其结果就是在memblock.reserved中增加一个region.
所以kernel一共建立了三块系统保留的空间。第一是tramponline, 第二是initrd所使用的空间,第三是kernel本身。
3. i386_default_early_setup如下所述初始化了x86_init这个结构的一部分。
- static void __init i386_default_early_setup(void)
-
{
-
/* Initialize 32bit specific setup functions */
-
x86_init.resources.probe_roms = probe_roms;
-
x86_init.resources.reserve_resources = i386_reserve_resources;
-
x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc;
-
-
reserve_ebda_region();
-
}
x86_init的结构和相关结构在arch/x86/include/asm/X86_init.h中定义,详细的解释可以参考这个文件中的注解。它已经写得很清楚了。
- /**
-
* struct x86_init_ops - functions for platform specific setup
-
*
-
*/
-
struct x86_init_ops {
-
struct x86_init_resources resources;
-
struct x86_init_mpparse mpparse;
-
struct x86_init_irqs irqs;
-
struct x86_init_oem oem;
-
struct x86_init_paging paging;
-
struct x86_init_timers timers;
-
struct x86_init_iommu iommu;
-
struct x86_init_pci pci;
-
};
reserve_ebda_region的作用是保留给PS/2设备使用的EBDA( Extended BIOS Data Area )空间。由于低地址空间实际上是映射到0xC0000000上面去了,所以其保留的空间实际上是基于0xC0000000的虚拟地址。
关于start_kernel.明天再看吧
阅读(528) | 评论(0) | 转发(0) |