Chinaunix首页 | 论坛 | 博客
  • 博客访问: 545967
  • 博文数量: 469
  • 博客积分: 50
  • 博客等级: 民兵
  • 技术积分: 1495
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-15 21:04
文章分类

全部博文(469)

文章存档

2015年(81)

2014年(125)

2013年(261)

2012年(2)

分类: LINUX

2013-12-25 14:05:47

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里面,代码如下:
  1. void __init i386_start_kernel(void)
  2. {
  3.     memblock_init();

  4. #ifdef CONFIG_X86_TRAMPOLINE
  5.     /*
  6.      * But first pinch a few for the stack/trampoline stuff
  7.      * FIXME: Don't need the extra page at 4K, but need to fix
  8.      * trampoline before removing it. (see the GDT stuff)
  9.      */
  10.     memblock_x86_reserve_range(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
  11. #endif

  12.     memblock_x86_reserve_range(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS"); //保留kernel本身

  13. #ifdef CONFIG_BLK_DEV_INITRD
  14.     /* Reserve INITRD */
  15.     if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
  16.         /* Assume only end is not page aligned */
  17.         u64 ramdisk_image = boot_params.hdr.ramdisk_image;
  18.         u64 ramdisk_size = boot_params.hdr.ramdisk_size;
  19.         u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
  20.         memblock_x86_reserve_range(ramdisk_image, ramdisk_end, "RAMDISK"); //如果使用initrd,则将boot_params.hdr.ramdisk_image指向的initrd空间进行保留。
  21.     }
  22. #endif

  23.     /* Call the subarch specific early setup function */
  24.     switch (boot_params.hdr.hardware_subarch) {
  25.     case X86_SUBARCH_MRST:
  26.         x86_mrst_early_setup();
  27.         break;
  28.     default:
  29.         i386_default_early_setup();
  30.         break;
  31.     }

  32.     /*
  33.      * At this point everything still needed from the boot loader
  34.      * or BIOS or kernel text should be early reserved or marked not
  35.      * RAM in e820. All other memory is free game.
  36.      */

  37.     start_kernel();
  38. }

1. memblock_init()在mm/Memblock.c里面被定义。其作用就是初始化memblock这个结构。memblock包含两个重要的成员,分别是memblock.memory和memblock.reserved.其分别代表系统中可用的内存和已经被保留的内存。
memblock.memory和memblock.reserved被定义为以下结构:
  1. struct memblock_type {
  2.     unsigned long cnt;    /* number of regions */
  3.     unsigned long max;    /* size of the allocated array */
  4.     struct memblock_region *regions;
  5. };
在初始化的时候,memblock.memory和memblock.reserved分别被指向两个静态数组:
  1. static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock;
  2. 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这个结构的一部分。
  1. static void __init i386_default_early_setup(void)
  2. {
  3.     /* Initialize 32bit specific setup functions */
  4.     x86_init.resources.probe_roms = probe_roms;
  5.     x86_init.resources.reserve_resources = i386_reserve_resources;
  6.     x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc;

  7.     reserve_ebda_region();
  8. }
x86_init的结构和相关结构在arch/x86/include/asm/X86_init.h中定义,详细的解释可以参考这个文件中的注解。它已经写得很清楚了。
  1. /**
  2.  * struct x86_init_ops - functions for platform specific setup
  3.  *
  4.  */
  5. struct x86_init_ops {
  6.     struct x86_init_resources    resources;
  7.     struct x86_init_mpparse        mpparse;
  8.     struct x86_init_irqs        irqs;
  9.     struct x86_init_oem        oem;
  10.     struct x86_init_paging        paging;
  11.     struct x86_init_timers        timers;
  12.     struct x86_init_iommu        iommu;
  13.     struct x86_init_pci        pci;
  14. };
reserve_ebda_region的作用是保留给PS/2设备使用的EBDA( Extended BIOS Data Area )空间。由于低地址空间实际上是映射到0xC0000000上面去了,所以其保留的空间实际上是基于0xC0000000的虚拟地址。

关于start_kernel.明天再看吧





阅读(528) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~