http://lxr.linux.no/linux+v3.3.2/arch/x86/include/asm/e820.h#L58
58struct e820entry { 59 __u64 addr; /* start of memory segment */ 60 __u64 size; /* size of memory segment */ 61 __u32 type; /* type of memory segment */ 62} __attribute__((packed));
http://lxr.linux.no/linux+v3.3.2/arch/x86/include/asm/bootparam.h#L96
95/* The so-called "zeropage" */ 96struct boot_params { 97 struct screen_info screen_info; /* 0x000 */ 98 struct apm_bios_info apm_bios_info; /* 0x040 */ 99 __u8 _pad2[4]; /* 0x054 */ 100 __u64 tboot_addr; /* 0x058 */ 101 struct ist_info ist_info; /* 0x060 */ 102 __u8 _pad3[16]; /* 0x070 */ 103 __u8 hd0_info[16]; /* obsolete! */ /* 0x080 */ 104 __u8 hd1_info[16]; /* obsolete! */ /* 0x090 */ 105 struct sys_desc_table sys_desc_table; /* 0x0a0 */ 106 struct olpc_ofw_header olpc_ofw_header; /* 0x0b0 */ 107 __u8 _pad4[128]; /* 0x0c0 */ 108 struct edid_info edid_info; /* 0x140 */ 109 struct efi_info efi_info; /* 0x1c0 */ 110 __u32 alt_mem_k; /* 0x1e0 */ 111 __u32 scratch; /* Scratch field! */ /* 0x1e4 */ 112 __u8 e820_entries; /* 0x1e8 */ 113 __u8 eddbuf_entries; /* 0x1e9 */ 114 __u8 edd_mbr_sig_buf_entries; /* 0x1ea */ 115 __u8 _pad6[6]; /* 0x1eb */ 116 struct setup_header hdr; /* setup header */ /* 0x1f1 */ 117 __u8 _pad7[0x290-0x1f1-sizeof(struct setup_header)]; 118 __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 0x290 */ 119 struct e820entry e820_map[E820MAX]; /* 0x2d0 */ 120 __u8 _pad8[48]; /* 0xcd0 */ 121 struct edd_info eddbuf[EDDMAXNR]; /* 0xd00 */ 122 __u8 _pad9[276]; /* 0xeec */ 123} __attribute__((packed)); 124 125enum { 126 X86_SUBARCH_PC = 0, 127 X86_SUBARCH_LGUEST, 128 X86_SUBARCH_XEN, 129 X86_SUBARCH_MRST, 130 X86_SUBARCH_CE4100, 131 X86_NR_SUBARCHS, 132};中断号int 0x15,通过0xe820参数取得内存布局,将内存信息复制到boot_params.e820_map中。20static int detect_memory_e820(void) 21{ 22 int count = 0; 23 struct biosregs ireg, oreg; 24 struct e820entry *desc = boot_params.e820_map; 25 static struct e820entry buf; /* static so it is zeroed */ 26 27 initregs(&ireg); 28 ireg.ax = 0xe820; 29 ireg.cx = sizeof buf; 30 ireg.edx = SMAP; 31 ireg.di = (size_t)&buf; 32 33 /* 34 * Note: at least one BIOS is known which assumes that the 35 * buffer pointed to by one e820 call is the same one as 36 * the previous call, and only changes modified fields. Therefore, 37 * we use a temporary buffer and copy the results entry by entry. 38 * 39 * This routine deliberately does not try to account for 40 * ACPI 3+ extended attributes. This is because there are 41 * BIOSes in the field which report zero for the valid bit for 42 * all ranges, and we don't currently make any use of the 43 * other attribute bits. Revisit this if we see the extended 44 * attribute bits deployed in a meaningful way in the future. 45 */ 46 47 do { 48 intcall(0x15, &ireg, &oreg); 49 ireg.ebx = oreg.ebx; /* for next iteration... */ 50 51 /* BIOSes which terminate the chain with CF = 1 as opposed 52 to %ebx = 0 don't always report the SMAP signature on 53 the final, failing, probe. */ 54 if (oreg.eflags & X86_EFLAGS_CF) 55 break; 56 57 /* Some BIOSes stop returning SMAP in the middle of 58 the search loop. We don't know exactly how the BIOS 59 screwed up the map at that point, we might have a 60 partial map, the full map, or complete garbage, so 61 just return failure. */ 62 if (oreg.eax != SMAP) { 63 count = 0; 64 break; 65 } 66 67 *desc++ = buf; 68 count++; 69 } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map)); 70 71 return boot_params.e820_entries = count; 72}函数detect_memory_e820连续地调用中断,并将所获取的内容复制到boot_params中去。http://lxr.linux.no/linux+v3.3.2/arch/x86/kernel/e820.c#L10061006char *__init default_machine_specific_memory_setup(void) 1007{ 1008 char *who = "BIOS-e820"; 1009 u32 new_nr; 1010 /* 1011 * Try to copy the BIOS-supplied E820-map. 1012 * 1013 * Otherwise fake a memory map; one section from 0k->640k, 1014 * the next section from 1mb->appropriate_mem_k 1015 */ 1016 new_nr = boot_params.e820_entries; 1017 sanitize_e820_map(boot_params.e820_map, 1018 ARRAY_SIZE(boot_params.e820_map), 1019 &new_nr); 1020 boot_params.e820_entries = new_nr; 1021 if (append_e820_map(boot_params.e820_map, boot_params.e820_entries) 1022 < 0) { 1023 u64 mem_size; 1024 1025 /* compare results from other methods and take the greater */ 1026 if (boot_params.alt_mem_k 1027 < boot_params.screen_info.ext_mem_k) { 1028 mem_size = boot_params.screen_info.ext_mem_k; 1029 who = "BIOS-88"; 1030 } else { 1031 mem_size = boot_params.alt_mem_k; 1032 who = "BIOS-e801"; 1033 } 1034 1035 e820.nr_map = 0; 1036 e820_add_region(0, LOWMEMSIZE(), E820_RAM); 1037 e820_add_region(HIGH_MEMORY, mem_size << 10, E820_RAM); 1038 } 1039 1040 /* In case someone cares... */ 1041 return who; 1042}函数append_e820_map 调用__append_e820_map将探测到的e820_map添加到379static int __init __append_e820_map(struct e820entry *biosmap, int nr_map) 380{ 381 while (nr_map) { 382 u64 start = biosmap->addr; 383 u64 size = biosmap->size; 384 u64 end = start + size; 385 u32 type = biosmap->type; 386 387 /* Overflow in 64 bits? Ignore the memory map. */ 388 if (start > end) 389 return -1; 390 391 e820_add_region(start, size, type); 392 393 biosmap++; 394 nr_map--; 395 } 396 return 0; 397}对此函数传进来的两个参数分别为:数组boot_params.e820_map, 个数boot_params.e820_entries,做简单判断后调用e820_add_region->__e820_add_region(&e820, start, size, type);有两个全局变量struct e820map e820; struct e820map e820_saved; //参考原文注释7/* 108 * Add a memory region to the kernel e820 map. 109 */ 110static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size, 111 int type) 112{ 113 int x = e820x->nr_map; 114 115 if (x >= ARRAY_SIZE(e820x->map)) { 116 printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); 117 return; 118 } 119 120 e820x->map[x].addr = start; 121 e820x->map[x].size = size; 122 e820x->map[x].type = type; 123 e820x->nr_map++; 124}