这样,当调用完毕,(E820NR)这块内存就保存了entries数目。
Linu引导时,设置memmap的调用路径是:
start_kernel() > setup_arch() > memory_setup() > sanitize_e820_map(E820_MAP, &E820_MAP_NR)
> copy_e820_map(E820_MAP, E820_MAP_NR)
其中E820_MAP和E820_MAP_NR的定义:
#define E820_MAP_NR (*(char*) (PARAM+E820NR))
#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
//FIXME:PARAM是什么意思? 猜测是Linux用来保存boot parameters的页面,见arch/i386/kernel/ head.S
其中E820NR和E820MAP是两个16位的内存地址,已经在setup.S中调用bios call时设置好了。见上边 的笔记。
/**
* 一个个range地添加从bios获得的内存布局信息 *
* 作者注释:
* =========
* 我们检查一下从BIOS获得的memmap是不是至少包含2个区间。 因为setup.S中的探测结果可能不
* 那么完美,而我们又知道大多数PC机有两个内存区域:一个从0到640k,另一个从1M往上。 *
* 如果BIOS得来的结果是正确的,那么我们就使用它给的memmap;如果不正确,我们就自己伪造
* 一个(案,即是在这里返回-1,让调用者machine_specific_memory_setup()去伪造。) */
int __init copy_e820_map(struct e820entry *biosmap, int nr_map) {
/* 只有一个,或者竟然是负的?那么就忽略它 */ if (nr_map < 2) return -1;
do {
unsigned long long start = biosmap->addr; unsigned long long size = bisomap->size; unsigned long long end = start + size; unsigned long type = biosmap->type; ...
if ( type = E820_RAM ) { //是ACPI中可用的RAM类型,那么我们就设置它 if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL)
add_memory_region(start, 0xA0000ULL-start, type); if (end <= 0x100000ULL) continue;
start = 0x100000ULL;
size = end - start; } }
/* 添加一个Memory Range。
* 注意! e820这个全局变量,就是在该函数中设置的值! */
add_memory_region(start, size, type);
} while (biosmap++, --nr_map);
return 0; }
这个copy_e820_map()函数执行完毕,则memory map就已经设置到全局变量e820中了。
14. ACPI Namespace 和 Definition Block
只有Unload一个Definition Block时,name才会从名空间中移除。
只有Load/Unload 定义块 时,Namespace中内容才可能改变。
Definition Block只可能出现在DSDT和SSDT(s)中。其它表没有。 Linux内核中加载namespace的
函数为acpi_tb_load_namespace(),其注释说:Load the namespace from the DSDT and all SSDTs/PSDTs found in the RSDT/XSDT.
(FIXME: 就Dell Optiplex 745机器用acpidump,acpixtract,iasl -d反汇编出来的.dsl 来看,一个DSDT或SSDT只有一个DefinitionBlock。 不知道这是否是ACPI规范了的)
Name的命名约定:
1. 每个Name都是固定的32bit(4字节)大小。
2. Name的第一个字符必须是'A'-'Z',或者下划线'_'
3. Name不足4个字节的,ASL编译器会对它进行填充。 惯用的填充方式就是在 结尾填充下划线'_'。
4. 以下划线'_'开头的Name是由ACPI规范预留的,也就是说,只有ACPI规范定义了 一个以'_'开头的Name, 供应商才能提供它。 不允许自己定义以'_'开头的Name
5. 以'\\'开头的Name,表示引用namespace的根。('\\'不算在4字节长度之内)
6. 以'^'开头的Name,表示引用本namespace的parent。('^'不算在4字节长 度之内)
预定义了的namespaces(见规范3.0之5.3.1部分)
\\_GPE : General events in GPE register block \\_PR : ACPI 1.0 Processor Namespace.
\\_SB : All Device/Bus Objects under this namespace \\_SI : System Indicator.
\\_TZ : ACPI 1.0 Thermal Zonen namespace.
15. Linux至少加载ACPI的3个Tables: FADT, FACS, DSDT (RSDT不算在内)
见acpi_tb_tables_loaded()函数:
if (acpi_gbl_root_table_list.count >= 3) { return (TRUE); else
return (FALSE);
其中DSDT和FACS在acpi_gbl_root_table_list数组中的索引是固定的,DSDT是0, FACS是1: