e820参数的存储
在setup.S中,
311 meme820:
312 xorl %ebx, %ebx # continuation counter
313 movw $E820MAP, %di # point into the whitelist
314 # so we can have the bios
315 # directly write into it.
316
317 jmpe820:
318 movl $0x0000e820, %eax # e820, upper word zeroed
319 movl $SMAP, %edx # ascii 'SMAP'
320 movl $20, %ecx # size of the e820rec
321 pushw %ds # data record.
322 popw %es
323 int $0x15 # make the call
324 jc bail820 # fall to e801 if it fails
325
326 cmpl $SMAP, %eax # check the return is `SMAP'
327 jne bail820 # fall to e801 if it fails
328
329 # cmpl $1, 16(%di) # is this usable memory?
330 # jne again820
331
332 # If this is usable memory, we save it by simply advancing %di by
333 # sizeof(e820rec).
334 #
335 good820:
336 movb (E820NR), %al # up to 32 entries
337 cmpb $E820MAX, %al
338 jnl bail820
339
340 incb (E820NR)
341 movw %di, %ax
342 addw $20, %ax
343 movw %ax, %di
344 again820:
345 cmpl $0, %ebx # check to see if
346 jne jmpe820 # %ebx is set to EOF
347 bail820:
在文件include/asm-i386/e820.h 中
15 #define E820MAP 0x2d0 /* our map */
16 #define E820MAX 32 /* number of entries in E820MAP */
17 #define E820NR 0x1e8 /* # entries in E820MAP */
流程:
1)setup.S代码被搬移到0x90000处。此时CS=DS=0x9000,处于实模式
2) $E820MAP, %di ,将0x9000:0x2d0(物理地址0x902d0),赋值给di
3)调用BIOS查询820内存中断,然后将查询的值放到di寄存器指向的地址,也就是把返回的查询值放入到物理地址0x902d0中。
4)同时中断返回的长度值放在al中,通过 movb (E820NR), %al语句,将长度值返回到物理地址0x901e8中。
*(0x901e8)=6,代表6条e820内存信息。下图中是,e820信息返回在0x902d0处的信息。
e820map的结构体如下:
28 struct e820map {
29 int nr_map;
30 struct e820entry {
31 unsigned long long addr; /* start of memory segment */
32 unsigned long long size; /* size of memory segment */
33 unsigned long type; /* type of memory segment */
34 } map[E820MAX];
35 };
可以看出,addr代表着红色的框,size代表着黄色的框,type代表着蓝色的框。
将0x90000处的信息赋值给boot_params变量
在kernel/head.S中
219 /*
220 * Copy bootup parameters out of the way.
221 * Note: %esi still has the pointer to the real-mode data.
222 */
223 movl $boot_params,%edi
224 movl $(PARAM_SIZE/4),%ecx
225 cld
226 rep
227 movsl
因为esi=0x90000处,把boot_params的地址传递给edi,然后通过movsl,完成把0x90000处的内容搬移到变量boot_params指向的地址。
通过E20_MAP或者E820_MAP_NR信息访问e820的内存
34 #define PARAM (boot_params)
35 #define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
36 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
37 #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
38 #define E820_MAP_NR (*(char*) (PARAM+E820NR))
39 #define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
sanitize_e820_map内存规整函数
说明:这个横线从左到右,代表着这个内存。在同一个内存地址被几种类型的内存包含着。
地址从低到高也就是,横线从左到右,找出对应纵线在纵向的同一水平位置,第一个出现的,然后往下顺。
这样完成内存规整。
调试的E820是规整的,不包含重复的。
流程
setup_arch---->machine_specific_memory_setup()---->sanitize_e820_map------->copy_e820_map–>add_memory_region
说明:
- sanitize_e820_map是把E820_MAP中的数据规整下,然后通过add_memory_region把E820_MAP数据保存到e820。
- parse_cmdline_early(cmdline_p),也就是通过启动内核参数传递内存相关参数,修改变量e820。