MADT: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Candy (talk | contribs)
No edit summary
Remove unreadable example code
 
(8 intermediate revisions by 7 users not shown)
Line 1:
{{ACPI}}
''This page is about the ACPI MADT (Multiple APIC Description Table)''
 
It describes how the [[APIC]] works.
The '''Multiple APIC Description Table''' ('''MADT''') is an [[ACPI]] table which provides informations necessary for operation on systems with [[APIC]], [[SAPIC]], [[GIC]], or [[LPIC]] implementations. As of June 17th, 2023, its latest definition is provided in the [[ACPI]] Specification Version 6.5, section [https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt 5.2.12. ''Multiple APIC Description Table (MADT)''].
 
==Introduction==
The MADT describes all of the interrupt controllers in the system. It can be used to enumerate the processors currently available.
Line 45 ⟶ 47:
|}
 
If bit 10 in the flags field is set then you need to mask all the 8259 PIC's interrupts, but you should probably do this anyway.
 
After the Flags field, starting at offset 0x2C, the rest of the MADT table contains a sequence of variable length records which enumerate the interrupt devices on this machine. Each record begins with the following header fields.
Line 61 ⟶ 63:
Based on the Entry Type field value, the rest of the record layout can be determined.
 
== Entry Type 0 : Processor Local APIC ==
 
This type represents a single physicallogical processor and its local interrupt controller.
 
{| {{wikitable}}
Line 79 ⟶ 81:
If flags bit 0 is set the CPU is able to be enabled, if it is not set you need to check bit 1. If that one is set you can still enable it, if it is not the CPU can not be enabled and the OS should not try.
 
== Entry Type 1 : I/O APIC ==
 
This type represents a I/O APIC. The global system interrupt base is the first interrupt number that this I/O APIC handles. You can see how many interrupts it handles using the register by getting the number of redirection entries from register 0x01, as described in [[APIC#IO_APIC_Registers|IO APIC Registers]].
Line 97 ⟶ 99:
|}
 
== Entry Type 2 : IOI/O APIC Interrupt Source Override ==
 
This entry type contains the data for an Interrupt Source Override.
Line 117 ⟶ 119:
|}
 
== Entry type 3 : IOI/O APIC Non-maskable interrupt source ==
 
Specifies which IOI/O APIC interrupt inputs should be enabled as non-maskable.
 
{| {{wikitable}}
Line 135 ⟶ 137:
|}
 
== Entry Type 4 : Local APIC Non-maskable interrupts ==
 
Configure these with the LINT0 and LINT1 entries in the Local vector table of the relevant processor(')s(') local APIC.
Line 151 ⟶ 153:
|}
 
== Entry Type 5 : Local APIC Address Override ==
 
Provides 64 bit systems with an override of the physical address of the Local APIC. There can only be one of these defined in the MADT. If this structure is defined, the 64-bit Local APIC address stored within it should be used instead of the 32-bit Local APIC address stored in the MADT header.
Line 165 ⟶ 167:
|}
 
== Entry Type 9 : Processor Local x2APIC ==
 
== Entry Type 9 : Processor Local x2APIC ==
 
Represents a physical processor and its Local x2APIC. Identical to Local APIC; used only when that struct would not be able to hold the required values.
Line 188 ⟶ 189:
 
Here is a diagram of the interrupt types:
http://i.imgur.com/HRDwoa6.png
 
== Example Code ==
The following code snippet detects and parses MADT table to collect Local APIC data on SMP systems. Works with both [[RSDT]] and [[XSDT]], and compiles for both protected mode and long mode.
<source lang="c">
uint8_t lapic_ids[256]={0}; // CPU core Local APIC IDs
uint8_t numcore=0; // number of cores detected
uint64_t lapic_ptr=0; // pointer to the Local APIC MMIO registers
uint64_t ioapic_ptr=0; // pointer to the IO APIC MMIO registers
 
void detect_cores(uint8_t *rsdt)
{
uint8_t *ptr, *ptr2;
uint32_t len;
 
// iterate on ACPI table pointers
for(len = *((uint32_t*)(rsdt + 4)), ptr2 = rsdt + 36; ptr2 < rsdt + len; ptr2 += rsdt[0]=='X' ? 8 : 4) {
ptr = (uint8_t*)(uintptr_t)(rsdt[0]=='X' ? *((uint64_t*)ptr2) : *((uint32_t*)ptr2));
if(!memcmp(ptr, "APIC", 4)) {
// found MADT
lapic_ptr = (uint64_t)(*((uint32_t)(ptr+0x24)));
ptr2 = ptr + *((uint32_t*)(ptr + 4));
// iterate on variable length records
for(ptr += 44; ptr < ptr2; ptr += ptr[1]) {
switch(ptr[0]) {
case 0: if(ptr[4] & 1) lapic_ids[numcore++] = ptr[3]; break; // found Processor Local APIC
case 1: ioapic_ptr = (uint64_t)*((uint32_t*)(ptr+4); break; // found IOAPIC
case 5: lapic_ptr = *((uint64_t*)(ptr+4); break; // found 64 bit LAPIC
}
}
break;
}
}
}
 
// detect SMP cores and print out results
detect_cores(rsd_ptr->rsdt_address);
 
printf("Found %d cores, IOAPIC %lx, LAPIC %lx, Processor IDs:", numcore, ioapic_ptr, lapic_ptr);
for(i = 0; i < numcore; i++)
printf(" %d", lapic_ids[i]);
printf("\n");
 
[[File:Edge_vs_level.png]]
</source>
 
==See also==