jamesxuruo 发表于 2003-10-9 21:46:04

关于gdt/pte初始化时的具体情况

我有一个问题:
我们知道在oxc0000000以上的虚存是给进程系统空间的,可是这一部分在对应于物理内存的时候有没有什么特别的地方?
内核是在0x100000开始的,里面静态的装着一些数据和代码,可是在这之后呢?也就是那位可以比较详细的阐述一下从初始化到以后用户程序执行的时候虚存的页式管理是怎样建立起来的.
谢谢.

zhiwood 发表于 2003-10-16 16:04:38

in file head.S( i386 )
physical memory are mapped into kernel address space, from 0xc0000000.
where physical address = virtual address - 0xc0000000
before page unit set to run, the code use any addresses by subtracting 0xc00000000 from the normal one in kernel image.
that is all i know.

bierdaci 发表于 2003-12-20 15:03:29

老兄,要是能用一句两句跟你说清楚那还用看什么源码,自己看源码去

jackyhong 发表于 2004-6-12 08:35:30

Linux内核情景分析说的好像比较清楚。(不过我也没有完全看懂)

mm_tiger 发表于 2004-9-24 09:42:59

这一部分对应于物理空间0开始的内存,内核是在0x100000开始的,里面静态的装着一些数据和代码,紧随其后的空间在刚起动时用于bootmem的位图,后来释放掉,用于系统分配内存,和用户进程获取内存
虚拟内存的建立与保护摸式的建立分不开的,这方面可以参考清华的《80x86汇编语言程序设计》一书(封面黑底绿字),在参考源码,就可得到答案

zhllg 发表于 2005-2-16 18:06:09

内核空间的虚拟地址与物理地址之间的对应关系简单,两者就差一个0xc0000000
当然这是默认的情况,也就是user space: kernel space = 3:1
现在还有其他分法2:2, 1:3,

iamathinker 发表于 2006-6-23 21:21:34

就我现在所知,与大家探讨

内核使用的虚拟地址空间是0xc0000000~0xffffffff这高端的1G;但内核实际上是加载到物理内存的0x100000处的。因此内核为自己建立了一个页面映射把虚拟地址空间高端的1G映射到了物理内存的底端1G。

也即虚拟地址vaddr直接减去0xc0000000就得到了在内存中的物理地址。当然这样一来也会存在一个问题,如果物理内存大于1G怎么办呢?不可能映射到“第5G”吧,根本就没有这个虚拟地址空间呀。所以有了高端内存的概念;物理地址 > 896MB以上的页框只能用某种方式临时或者永久映射到 4G - 3G896MB这个范围内的虚拟地址空间,内核才可以使用高端的物理内存。

jarodlau 发表于 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。
   
      我这里所说的,情景分析都由讲到,而且比我的详细多了,推荐你好好看看!
页: [1]
查看完整版本: 关于gdt/pte初始化时的具体情况