diff --git a/src/arch/i386/boot/acpi.c b/src/arch/i386/boot/acpi.c index 271de845de..ca9b66f744 100644 --- a/src/arch/i386/boot/acpi.c +++ b/src/arch/i386/boot/acpi.c @@ -13,8 +13,11 @@ #define RSDT_NAME "RSDT" #define HPET_NAME "HPET" -#define RSDT_TABLE " RSDT " +#define MADT_NAME "APIC" + +#define RSDT_TABLE "RSDT " #define HPET_TABLE "AMD64 " +#define MADT_TABLE "MADT " #define OEM_ID "LXBIOS" #define ASLC "NONE" @@ -29,6 +32,10 @@ static u8 acpi_checksum(u8 *table, u32 length) return -ret; } +/* + * add an acpi table to rsdt structure, and recalculate checksum + */ + static void acpi_add_table(acpi_rsdt_t *rsdt, void *table) { int i; @@ -50,6 +57,99 @@ static void acpi_add_table(acpi_rsdt_t *rsdt, void *table) printk_warning("ACPI: could not ACPI table. failed.\n"); } + +static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic) +{ + lapic->type=0; + lapic->length=sizeof(acpi_madt_lapic_t); + lapic->flags=1; + + lapic->processor_id=cpu; + lapic->apic_id=apic; + + return(lapic->length); +} + +static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr) +{ + ioapic->type=1; + ioapic->length=sizeof(acpi_madt_ioapic_t); + ioapic->reserved=0x00; + ioapic->gsi_base=0x00000000; + + ioapic->ioapic_id=id; + ioapic->ioapic_addr=addr; + + return(ioapic->length); +} + +static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride, + u8 bus, u8 source, u32 gsirq, u16 flags) +{ + irqoverride->type=2; + irqoverride->length=sizeof(acpi_madt_irqoverride_t); + irqoverride->flags=0x0001; + + irqoverride->bus=bus; + irqoverride->source=source; + irqoverride->gsirq=gsirq; + irqoverride->flags=flags; + + return(irqoverride->length); +} + +static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu, + u16 flags, u8 lint) +{ + lapic_nmi->type=4; + lapic_nmi->length=sizeof(acpi_madt_lapic_nmi_t); + + lapic_nmi->flags=flags; + lapic_nmi->processor_id=cpu; + lapic_nmi->lint=lint; + + return(lapic_nmi->length); +} + +static void acpi_create_madt(acpi_madt_t *madt) +{ +#define LOCAL_APIC_ADDR 0xfee00000ULL +#define IO_APIC_ADDR 0xfec00000UL + acpi_header_t *header=&(madt->header); + unsigned long current=(unsigned long)madt+sizeof(acpi_madt_t); + + memset((void *)madt, 0, sizeof(acpi_madt_t)); + + /* fill out header fields */ + memcpy(header->signature, MADT_NAME, 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, MADT_TABLE, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_madt_t); + header->revision = 1; + + madt->lapic_addr= LOCAL_APIC_ADDR; + madt->flags = 0x1; /* PCAT_COMPAT */ + + /* create all subtables for 1p */ + current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, 0, 0); + current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current, 2, + IO_APIC_ADDR); + current += acpi_create_madt_irqoverride( (acpi_madt_irqoverride_t *) + current, 0, 0, 2, 1 /* active high */); + current += acpi_create_madt_irqoverride( (acpi_madt_irqoverride_t *) + current, 0, 9, 9, 0xf /* active low, level triggered */); + current += acpi_create_madt_lapic_nmi( (acpi_madt_lapic_nmi_t *) + current, 0, 5, 1); + + /* recalculate length */ + header->length= current - (unsigned long)madt; + + header->checksum = acpi_checksum((void *)madt, header->length); +} + + static void acpi_create_hpet(acpi_hpet_t *hpet) { #define HPET_ADDR 0xfed00000ULL @@ -121,6 +221,7 @@ unsigned long write_acpi_tables(unsigned long start) acpi_rsdp_t *rsdp; acpi_rsdt_t *rsdt; acpi_hpet_t *hpet; + acpi_madt_t *madt; /* Align ACPI tables to 16byte */ start = ( start + 0x0f ) & -0x10; @@ -151,6 +252,16 @@ unsigned long write_acpi_tables(unsigned long start) current += sizeof(acpi_hpet_t); acpi_create_hpet(hpet); acpi_add_table(rsdt,hpet); + + /* If we want to use HPET Timers Linux wants an MADT */ + printk_debug("ACPI: * MADT\n"); + + madt = (acpi_madt_t *) current; + acpi_create_madt(madt); + current+=madt->header.length; + acpi_add_table(rsdt,madt); + + #endif printk_info("ACPI: done.\n"); return current; diff --git a/src/arch/i386/include/arch/acpi.h b/src/arch/i386/include/arch/acpi.h index 6b6965684c..e840d42195 100644 --- a/src/arch/i386/include/arch/acpi.h +++ b/src/arch/i386/include/arch/acpi.h @@ -80,6 +80,62 @@ typedef struct acpi_hpet { u8 attributes; } __attribute__ ((packed)) acpi_hpet_t; +typedef struct acpi_madt { + struct acpi_table_header header; + u32 lapic_addr; + u32 flags; +} __attribute__ ((packed)) acpi_madt_t; + +enum acpi_apic_types { + LocalApic = 0, + IOApic = 1, + IRQSourceOverride = 2, + NMI = 3, + LocalApicNMI = 4, + LApicAddressOverride = 5, + IOSApic = 6, + LocalSApic = 7, + PlatformIRQSources = 8 +}; + +typedef struct acpi_madt_lapic { + u8 type; + u8 length; + u8 processor_id; + u8 apic_id; + u32 flags; +} __attribute__ ((packed)) acpi_madt_lapic_t; + +typedef struct acpi_madt_lapic_nmi { + u8 type; + u8 length; + u8 processor_id; + u16 flags; + u8 lint; +} __attribute__ ((packed)) acpi_madt_lapic_nmi_t; + + +typedef struct acpi_madt_ioapic { + u8 type; + u8 length; + u8 ioapic_id; + u8 reserved; + u32 ioapic_addr; + u32 gsi_base; +} __attribute__ ((packed)) acpi_madt_ioapic_t; + +typedef struct acpi_madt_irqoverride { + u8 type; + u8 length; + u8 bus; + u8 source; + u32 gsirq; + u16 flags; +} __attribute__ ((packed)) acpi_madt_irqoverride_t; + + + + unsigned long write_acpi_tables(unsigned long addr);