http://hi.baidu.com/ballmillsap/item/c2f3cf6f43d3220aa1cf0fe4e820简介操作系统内存布局中断 int 0x15e820简介 收藏本文系转载,原文地址:http://wangcong.org/blog/?p=320,其中附录部分 为本人所加… e820是和BIOS的一个中断相关的,具体说是int 0x15。之所以叫e820是因为在用这个中断时ax必须是0xe820。这个中断的作用是得到系统的内存布局。因为系统内存会有很多段,每段的类型属性 也不一样,所以这个查询是“迭代式”的,每次求得一个段。 我们看内核源代码。主要涉及两个文件:arch/x86/boot/memory.c和arch/x86/kernel /e820_32.c。我们 已经很幸运了,这部分代码已经用C重写过了。你可能会奇怪,启动调用e820时我们还在实模式,怎么能用C呢?答案是,这里用的是16位的C。gcc早已 经支持.code16 gcc模式了。 看detect_memory_e820()函数,里面就是e820的本质。它把int 0x15放到一个do-while循环里,每次得到的一个内存段放到struct e820entry里,而struct e820entry的结构正是e820返回结果的结构!而像其它启动时获得的结果一样,最终都会被放到boot_params里,e820被放到了 boot_params.e820_map。如果你对struct e820entry还有疑问,你可以看一下arch/x86/kernel/e820_32.c::print_memory_map(),看看里面是怎 么使用它的。 当然了,在arch/x86/boot/memory.c里,你还会看到另外两个利用int 0x15查询内存的函数,不过用途不一样了。附:boot_params 结构体定义,其中E820MAX 定义为128:struct e820entry {__u64 addr; /* start of memory segment */__u64 size; /* size of memory segment */__u32 type; /* type of memory segment */} __attribute__((packed));struct boot_params { struct screen_info screen_info; /* 0x000 */ struct apm_bios_info apm_bios_info; /* 0x040 */ __u8 _pad2[12]; /* 0x054 */ struct ist_info ist_info; /* 0x060 */ __u8 _pad3[16]; /* 0x070 */ __u8 hd0_info[16]; /* obsolete! */ /* 0x080 */ __u8 hd1_info[16]; /* obsolete! */ /* 0x090 */ struct sys_desc_table sys_desc_table; /* 0x0a0 */ __u8 _pad4[144]; /* 0x0b0 */ struct edid_info edid_info; /* 0x140 */ struct efi_info efi_info; /* 0x1c0 */ __u32 alt_mem_k; /* 0x1e0 */ __u32 scratch; /* Scratch field! */ /* 0x1e4 */ __u8 e820_entries; /* 0x1e8 */ __u8 eddbuf_entries; /* 0x1e9 */ __u8 edd_mbr_sig_buf_entries; /* 0x1ea */ __u8 _pad6[6]; /* 0x1eb */ struct setup_header hdr; /* setup header */ /* 0x1f1 */ __u8 _pad7[0x290-0x1f1-sizeof(struct setup_header)]; __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 0x290 */ struct e820entry e820_map[E820MAX]; /* 0x2d0 */ __u8 _pad8[48]; /* 0xcd0 */ struct edd_info eddbuf[EDDMAXNR]; /* 0xd00 */ __u8 _pad9[276]; /* 0xeec */} __attribute__((packed));通 过bios获取系统内存布局代码如下:static int detect_memory_e820(void){ int count = 0; u32 next = 0; u32 size, id; u8 err; struct e820entry *desc = boot_params.e820_map; do { size = sizeof(struct e820entry); /* Important: %edx is clobbered by some BIOSes, so it must be either used for the error output or explicitly marked clobbered. */ asm(“int $0x15; setc %0” : “=d” (err), “+b” (next), “=a” (id), “+c” (size), “=m” (*desc) : “D” (desc), “d” (SMAP), “a” (0xe820)); /* BIOSes which terminate the chain with CF = 1 as opposed to %ebx = 0 don’t always report the SMAP signature on the final, failing, probe. */ if (err) break; /* Some BIOSes stop returning SMAP in the middle of the search loop. We don’t know exactly how the BIOS screwed up the map at that point, we might have a partial map, the full map, or complete garbage, so just return failure. */ if (id != SMAP) { count = 0; break; } count++; desc++; } while (next && count < E820MAX); return boot_params.e820_entries = count;}这个函数执行完毕后,boot_params.e820_map 就含有了系统内存布局图。函数关键部分解释如下:07 获取启动参数boot_params里的e820_map数 组首地址。15-18 通过中断0x15调用bios例程获得一个内存段的信息,这条语句是按照AT&T的汇编语法格式写的,具体语法可以查看相关资料。当然了,在arch/x86/boot/memory.c里,你还会看到另外两个利用int 0×15查询内存的函数,不过用途不一样了。凡是弄过操作系统启动这块的,肯定都有这么一个感慨:我的东西该往哪里放啊!怎么个放法啊!恩,或许Linux这种方式值得我们借鉴,它的虽然很科学,但也很复杂。那有啥办法呢,BIOS这块本来就已经很乱了!
【zz】linux内核e820来源及相关知识