|
发表于 2007-7-19 05:22:16
|
显示全部楼层
原帖由 jamesxuruo 于 2003-10-9 21:46 发表 ![](http://www.linuxfans.org/bbs/images/common/back.gif)
我有一个问题:
我们知道在oxc0000000以上的虚存是给进程系统空间的,可是这一部分在对应于物理内存的时候有没有什么特别的地方?
内核是在0x100000开始的,里面静态的装着一些数据和代码,可是在这之后呢?也就是那 ...
0xc0000000只是一个偏移
我们大部分人用的还是grub启动,在2.6.x的内核里,根据不同的加载情况定义了不同的加载协议(具体请看内核/Documentatio/i386/ 里有个好像是叫boot.txt的文件)
linux的启动过程如下:
1。 首先电源启动,电脑执行加电自检,根据你的bios配置,读取电脑的一些基础信息,比如时间,硬盘等
2。BIOS然后把控制权交由grub。因为grub的源代码我没有看过,所以我说通用的情况。
现在BIOS跳到BOOTSEG = 0x07C0这个位置执行指令,在linux里,这个代码在/arch/i386/boot/bootsect.S,因为现在的2.6.x的内核都很大(>= 1.5M),所以现在已经不能从软盘启动了,这个文件相当于也就废除了。
所以现在只能采用grub,lilo等加载工具加载linux。
3。 加载完毕以后就执行 /arch/i386/boot/setup.S,这个文件的主要作用就是从BIOS中读取 系统时间/内存大小/硬盘/其他 信息,然后保存到0x90000-0x901FF这个位置,后来就是根据内核的大小(压缩情况)采取不同的移动策略移动到0x90200。
因为现在还是在实模式下,所以还不能寻址大于1M的内存。所以现在要启动cpu的A20端口,然后设置gdt和idt,现在已经是保护模式了,但是中断还是关闭的。
4。 接着控制流就到达/arch/i386/boot/compressed/head.S的startup_32,这里的主要工作就是解压缩我们的内核,然后跳到解压缩以后的内核的入口在/arch/i386/kernel/head.S中的startup_32,这里把内核启动的参数保存起来以备后用。
然后初始化页表目录,启动页寻址机制,然后call setup_idt,setup_idt的主要作用是把所有的中断都定义到early_printk(一般都会启用吧!)。
5。下来就是最主要的call start_kernel,因为现在已经采用了页寻址机制,所以这里的start_kernel是在体系无关的代码部分/init/main.c中。
asmlinkage void __init start_kernel(void)这个函数就是内核启动的重点。
这时中断还是关闭的,做好一些初始的准备就打开中断。
453 /*
454 * Interrupts are still disabled. Do necessary setups, then
455 * enable them
456 */
457 lock_kernel();
458 boot_cpu_init();
459 page_address_init();
460 printk(KERN_NOTICE);
461 printk(linux_banner);
462 setup_arch(&command_line);
463 setup_per_cpu_areas();
464 smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
其中的setup_arch(&command_line) 就是把把这个“页”内存管理机制建立起来。详细见 linux/arch/i386/kernel/setup.c中的
1494 if (!MOUNT_ROOT_RDONLY)
1495 root_mountflags &= ~MS_RDONLY;
1496 init_mm.start_code = (unsigned long) _text;
1497 init_mm.end_code = (unsigned long) _etext;
1498 init_mm.end_data = (unsigned long) _edata;
1499 init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
1500
1501 code_resource.start = virt_to_phys(_text);
1502 code_resource.end = virt_to_phys(_etext)-1;
1503 data_resource.start = virt_to_phys(_etext);
1504 data_resource.end = virt_to_phys(_edata)-1;
1505
1506 parse_cmdline_early(cmdline_p);
其中把内核空间定义到线性的内存0xc0000000(可能根据你的编译选项有所不同,如3:1,2:2,1:3),kernel很聪明把内核的空间永远映射到物理地址0x00000000。
我这里所说的,情景分析都由讲到,而且比我的详细多了,推荐你好好看看! |
|