全部博文(44)
分类:
2010-03-08 11:31:10
MADT表的entry和MP table大同小异。
MADT表头结构:该结构拥有很多字段,例如版本号、OEM信息等,其中和本文内容相关的字段有3个,见下表:
字段 |
长度(bytes) |
偏移 |
描述 |
LAPIC Address |
4 |
36 |
32bit物理地址,用于CPU访问自身LAPIC |
Flags |
4 |
40 |
Bit1表示系统是否有PIC存在。 1:有,当APIC使用时,PIC的各管脚必须被mask; 0:无。 其它bit预留 |
APIC structures |
- |
44 |
各种中断的描述条目 |
2-4 MADT表头
的地址
Spec规定,LAPIC和IOAPIC的寄存器必须被实现成MMIO方式。对于LAPIC来说,每个CPU使用同样的地址访问自己的LAPIC,默认地址是FEE0_0000H。对于IOAPIC,默认基地址是FEC0_0000H,每个IOAPIC占4k地址,从基地址开始连续。
LAPIC地址对齐到4K边界,IOAPIC地址对齐到1K边界。
笔者:每个CPU都用同样的物理地址访问自己的LAPIC。这说明除了x86平台的port I/O具有64K独立的物理地址空间外,LAPIC也拥有独立的物理地址。我能想到的理由是防止CPU访问不属于自己的LAPIC。
LAPIC相关的MADT条目共有三个,分别是:LAPIC entry、LAPIC NMI entry、LAPIC address override entry。
字段 |
长度(bytes) |
偏移 |
描述 |
Type |
1 |
0 |
0(LAPIC) |
Length |
1 |
1 |
8 |
ACPI Processor ID |
1 |
2 |
在ACPI processor operator中列出的processorID |
APIC ID |
1 |
3 |
LAPIC ID |
Flags |
4 |
4 |
Bit0:enable位, 0:disable; 1:enable。 其它bit预留 |
表2-5 LAPIC entry
字段 |
长度(byte) |
偏移 |
描述 |
Type |
1 |
0 |
4(LAPIC NMI) |
Length |
1 |
1 |
6 |
APCI Processor ID |
1 |
2 |
Processor object中的CPU的ID。0xff代表所有CPU |
Flags |
2 |
3 |
MPS INIT flags |
LAPIC LINT# |
1 |
5 |
LINT管脚号(0 or 1) |
表2-6 LAPIC NMI entry
该表描述NMI中断接LAPIC LINTx管脚的情况,其中MPS INI flags为和MP spec兼容的属性,见下面的MPS INI flags表。
字段 |
长度(byte) |
偏移 |
描述 |
Type |
1 |
0 |
5(LAPIC Address Override) |
Length |
1 |
1 |
12 |
Reserved |
2 |
2 |
全0 |
LAPIC address |
8 |
4 |
LAPIC的物理地址 |
表2-7 LAPIC address override entry
该表用于重载MADT表头中的LAPIC地址,整个MADT表中只应该包含一个LAPIC address override entry。
LAPIC Flags |
长度(bit) |
偏移 |
描述 |
Polarity |
2 |
0 |
IOAPIC管脚有效电平极性 00 由总线决定极性(例如EISA总线为低电平有效,电平触发) 01 高电平有效 10 预留 11 低电平有效 |
Trigger Mode |
2 |
2 |
管脚触发模式 00 总线决定(例如ISA总线为edge触发) 01 edge 10 预留 11 level |
预留 |
12 |
4 |
全0 |
表2-8 MPS INIT flags
IOAPIC相关MADT条目:IOAPIC entry、Interrupt Source Overrides entry、NMI entry。
字段 |
长度(bytes) |
偏移 |
描述 |
Type |
1 |
0 |
1(IOAPIC) |
Length |
1 |
1 |
12 |
IOAPIC ID |
1 |
2 |
IOAPIC ID |
Reserved |
1 |
3 |
0 |
IOAPIC address |
4 |
4 |
32bit物理地址,CPU通过该地址访问IOAPIC。该地址对于每个IOAPIC都是唯一的 |
GSI Base |
4 |
8 |
该IOAPIC在GSI空间中的起始号。GSI=GSI base+管脚号 |
表2-9 IOAPIC entry
字段 |
长度(bytes) |
偏移 |
描述 |
Type |
1 |
0 |
2(interrupt source override) |
Length |
1 |
1 |
10 |
Bus |
1 |
2 |
0(ISA) |
Source |
1 |
3 |
在ISA上的IRQ号 |
GSI |
4 |
4 |
Map到GSI空间后的GSI号 |
Flags |
2 |
8 |
见MP INIT flags表 |
表2-10 Interrupt Source Overrides(ISO)
ISA中断接PIC的0~15脚,通常需要identify mapping到GSI空间。具体的说,ISA中断应该按接PIC的顺序接0号IOAPIC的0~15脚。若平台实现有差异,某个ISA中断没有被identify mapping的时候,需要一个ISO结构来描述。特别需要注意的是,管脚极性不同时,也需要一个ISO结构描述。
举两个例子:
例1:PIT接PIC的0号脚,即IRQ0。当接IOAPIC时,它通常接在2号管脚上,即INTN2。此时需要一个ISO来描述此差异,source字段为0,GSI字段为2(0号IOAPIC的GSI base为0)。
例2:SCI,System Control Interrupt,通常接PIC的管脚9,即IRQ9,FADT会在SCI_INT字段里报告该值。如接到IOAPIC的11号脚,则需要一个ISO描述。Source字段为9,GSI字段为11。
字段 |
长度(bytes) |
偏移 |
描述 |
Type |
1 |
0 |
3(NMI) |
Length |
1 |
1 |
8 |
Flags |
2 |
2 |
见MPS INIT Flags |
GSI |
4 |
4 |
该NMI的GSI号 |
表2-11 NMI entry
描述IOAPIC某个管脚被配置成NMI的情况。NMI不应该被设备使用。
中断探测过程X86的ACPI相关代码位于arch/i386/kernel/acpi目录,其中对各表的解析位于boot.c文件。MADT表的解析经过下列路径:
1、 acpi_boot_initv()调用acpi_process_madt(),后者是解析MADT表的主函数。
2、 acpi_process_madt()首先检查MADT表头,确定MADT表包含多少个描述APIC部件的entry,以及获得LAPIC的默认地址并放入acpi_lapic_addr全局变量中。这在acpi_parse_madt()函数中完成。
3、 紧接着,acpi_parse_madt_lapic_entries()被调用以获得和LAPIC相关的信息。该函数做的事情比较多,依次执行下列步骤:
a、 调用acpi_parse_lapic_addr_ovr()检查是否有LAPIC address override entry,如有,用其中的LAPIC地址覆盖acpi_lapic_addr全局变量。
b、 至此,系统的LAPIC地址就已确定了。调用mp_register_lapic_address()注册,如下:
mp_lapic_addr = (unsigned long) acpi_lapic_addr;
set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
set_fixmap_nocache()建立一个un-cacheable的identify mapping映射。
c、 调用acpi_parse_lapic()解析LAPIC entry。如果LAPIC entry的flag字段为enable,将LAPIC ID和ProcessorID的对应关系维护在x86_acpiid_to_apicid全局数组中。并调用mp_register_lapic()注册LAPIC信息。
笔者:ACPI的LAPIC entry和MP spec的processor entry对应。mp_register_lapic()最终调用MP_processor_info()注册CPU信息。为了不把话题铺的太开,我们不介绍这个过程。
d、 最后调用acpi_parse_lapic_nmi(),该函数除打印一些信息,以及在NMI没有接到LINT1脚时打印一条警告信息,并没有实际用处。
4、 如果解析到了LAPIC信息,并且没有错误发生,acpi_parse_madt_lapic_entries()函数返回0表示执行成功,此时会继续解析IOAPIC entry。 acpi_parse_madt_ioapic_entries()进行如下工作:
a、 调用acpi_parse_ioapic()解析IOAPIC entry,并调用mp_register_ioapic()注册IOAPIC信息,等同mp_ioapic_info()。此外,它还注册IOAPIC对应的struct mp_ioapic_routing结构。
b、 调用acpi_parse_int_src_ovr()解析ISO条目,如发现override,调用acpi_sci_ioapic_setup()重载SCI中断,以及调用mp_override_legacy_irq()重载ISA中断。
c、 至此,ISA中断的信息已经全部获得了,调用mp_config_acpi_legacy_irqs()配置ISA中断。该函数功能等同construct_default_ioirq_mptable()。
d、 调用acpi_parse_nmi_src()解析NMI entry,仅打印相关信息。从kernel的注释来看,Linux还不支持IOAPIC管脚配置成NMI。
到此为止,无论是从MP spec路径,还是ACPI路径。Linux完成了平台APIC系统的探测。我们来看看目前得到了些什么东西:
u LAPIC地址
u IOAPIC相关信息,在mp_ioapics数组中
u 中断源相关信息,在mp_irqs数组中
嗯,看上去够了。