X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Facpi.c;h=107469f2d3ff1be104a190da0d5b0a3928da55f2;hb=refs%2Fheads%2Fcoreboot;hp=fc7867ac8a6e23636948cccea1b28d75e5c61b30;hpb=278b19f49bc5f62380322f5d2f375a9fceb42a1b;p=seabios.git diff --git a/src/acpi.c b/src/acpi.c index fc7867a..107469f 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -7,7 +7,7 @@ #include "acpi.h" // struct rsdp_descriptor #include "util.h" // memcpy -#include "pci.h" // pci_find_device +#include "pci.h" // pci_find_init_device #include "biosvar.h" // GET_EBDA #include "pci_ids.h" // PCI_VENDOR_ID_INTEL #include "pci_regs.h" // PCI_INTERRUPT_LINE @@ -52,6 +52,11 @@ struct facs_descriptor_rev1 } PACKED; +/* + * Differentiated System Description Table (DSDT) + */ +#define DSDT_SIGNATURE 0x54445344 // DSDT + /* * MADT values and structures */ @@ -134,6 +139,14 @@ struct madt_intsrcovr { u16 flags; } PACKED; +struct madt_local_nmi { + ACPI_SUB_HEADER_DEF + u8 processor_id; /* ACPI processor id */ + u16 flags; /* MPS INTI flags */ + u8 lint; /* Local APIC LINT# */ +} PACKED; + + /* * ACPI 2.0 Generic Address Space definition. */ @@ -156,7 +169,9 @@ struct acpi_20_hpet { u16 min_tick; u8 page_protect; } PACKED; -#define ACPI_HPET_ADDRESS 0xFED00000UL + +#define HPET_ID 0x000 +#define HPET_PERIOD 0x004 /* * SRAT (NUMA topology description) table @@ -205,9 +220,9 @@ build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev) h->revision = rev; memcpy(h->oem_id, CONFIG_APPNAME6, 6); memcpy(h->oem_table_id, CONFIG_APPNAME4, 4); - memcpy(h->asl_compiler_id, CONFIG_APPNAME4, 4); memcpy(h->oem_table_id + 4, (void*)&sig, 4); h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, CONFIG_APPNAME4, 4); h->asl_compiler_revision = cpu_to_le32(1); h->checksum -= checksum(h, len); } @@ -234,14 +249,23 @@ static const struct pci_device_id fadt_init_tbl[] = { PCI_DEVICE_END }; +static void fill_dsdt(struct fadt_descriptor_rev1 *fadt, void *dsdt) +{ + if (fadt->dsdt) { + free((void *)le32_to_cpu(fadt->dsdt)); + } + fadt->dsdt = cpu_to_le32((u32)dsdt); + fadt->checksum -= checksum(fadt, sizeof(*fadt)); + dprintf(1, "ACPI DSDT=%p\n", dsdt); +} + static void * build_fadt(struct pci_device *pci) { struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt)); struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs)); - void *dsdt = malloc_high(sizeof(AmlCode)); - if (!fadt || !facs || !dsdt) { + if (!fadt || !facs) { warn_noalloc(); return NULL; } @@ -251,13 +275,11 @@ build_fadt(struct pci_device *pci) facs->signature = FACS_SIGNATURE; facs->length = cpu_to_le32(sizeof(*facs)); - /* DSDT */ - memcpy(dsdt, AmlCode, sizeof(AmlCode)); - /* FADT */ memset(fadt, 0, sizeof(*fadt)); fadt->firmware_ctrl = cpu_to_le32((u32)facs); - fadt->dsdt = cpu_to_le32((u32)dsdt); + fadt->dsdt = 0; /* dsdt will be filled later in acpi_bios_init() + by fill_dsdt() */ fadt->model = 1; fadt->reserved1 = 0; int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE); @@ -286,7 +308,9 @@ build_madt(void) int madt_size = (sizeof(struct multiple_apic_table) + sizeof(struct madt_processor_apic) * MaxCountCPUs + sizeof(struct madt_io_apic) - + sizeof(struct madt_intsrcovr) * 16); + + sizeof(struct madt_intsrcovr) * 16 + + sizeof(struct madt_local_nmi)); + struct multiple_apic_table *madt = malloc_high(madt_size); if (!madt) { warn_noalloc(); @@ -338,7 +362,15 @@ build_madt(void) intsrcovr++; } - build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (void*)madt, 1); + struct madt_local_nmi *local_nmi = (void*)intsrcovr; + local_nmi->type = APIC_LOCAL_NMI; + local_nmi->length = sizeof(*local_nmi); + local_nmi->processor_id = 0xff; /* all processors */ + local_nmi->flags = 0; + local_nmi->lint = 1; /* LINT1 */ + local_nmi++; + + build_header((void*)madt, APIC_SIGNATURE, (void*)local_nmi - (void*)madt, 1); return madt; } @@ -364,32 +396,24 @@ encodeLen(u8 *ssdt_ptr, int length, int bytes) return ssdt_ptr + bytes; } -// AML Processor() object. See src/ssdt-proc.dsl for info. -static unsigned char ssdt_proc[] = { - 0x5b,0x83,0x42,0x05,0x43,0x50,0x41,0x41, - 0xaa,0x10,0xb0,0x00,0x00,0x06,0x08,0x49, - 0x44,0x5f,0x5f,0x0a,0xaa,0x08,0x5f,0x48, - 0x49,0x44,0x0d,0x41,0x43,0x50,0x49,0x30, - 0x30,0x30,0x37,0x00,0x14,0x0f,0x5f,0x4d, - 0x41,0x54,0x00,0xa4,0x43,0x50,0x4d,0x41, - 0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x53, - 0x54,0x41,0x00,0xa4,0x43,0x50,0x53,0x54, - 0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x45, - 0x4a,0x30,0x01,0x43,0x50,0x45,0x4a,0x49, - 0x44,0x5f,0x5f,0x68 -}; -#define SD_OFFSET_CPUHEX 6 -#define SD_OFFSET_CPUID1 8 -#define SD_OFFSET_CPUID2 20 +#include "ssdt-proc.hex" + +/* 0x5B 0x83 ProcessorOp PkgLength NameString ProcID */ +#define SD_OFFSET_CPUHEX (*ssdt_proc_name - *ssdt_proc_start + 2) +#define SD_OFFSET_CPUID1 (*ssdt_proc_name - *ssdt_proc_start + 4) +#define SD_OFFSET_CPUID2 (*ssdt_proc_id - *ssdt_proc_start) +#define SD_SIZEOF (*ssdt_proc_end - *ssdt_proc_start) +#define SD_PROC (ssdp_proc_aml + *ssdt_proc_start) #define SSDT_SIGNATURE 0x54445353 // SSDT + static void* build_ssdt(void) { int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs; // length = ScopeOp + procs + NTYF method + CPON package int length = ((1+3+4) - + (acpi_cpus * sizeof(ssdt_proc)) + + (acpi_cpus * SD_SIZEOF) + (1+2+5+(12*acpi_cpus)) + (6+2+1+(1*acpi_cpus))); u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length); @@ -410,12 +434,12 @@ build_ssdt(void) // build Processor object for each processor int i; for (i=0; i> 4); ssdt_ptr[SD_OFFSET_CPUHEX+1] = getHex(i); ssdt_ptr[SD_OFFSET_CPUID1] = i; ssdt_ptr[SD_OFFSET_CPUID2] = i; - ssdt_ptr += sizeof(ssdt_proc); + ssdt_ptr += SD_SIZEOF; } // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}" @@ -460,11 +484,58 @@ build_ssdt(void) return ssdt; } -#define HPET_SIGNATURE 0x54455048 //HPET +#include "ssdt-pcihp.hex" + +#define PCI_RMV_BASE 0xae0c + +extern void link_time_assertion(void); + +static void* build_pcihp(void) +{ + u32 rmvc_pcrm; + int i; + + u8 *ssdt = malloc_high(sizeof ssdp_pcihp_aml); + memcpy(ssdt, ssdp_pcihp_aml, sizeof ssdp_pcihp_aml); + + /* Runtime patching of EJ0: to disable hotplug for a slot, + * replace the method name: _EJ0 by EJ0_. */ + if (ARRAY_SIZE(aml_ej0_name) != ARRAY_SIZE(aml_adr_dword)) { + link_time_assertion(); + } + + rmvc_pcrm = inl(PCI_RMV_BASE); + for (i = 0; i < ARRAY_SIZE(aml_ej0_name); ++i) { + /* Slot is in byte 2 in _ADR */ + u8 slot = ssdp_pcihp_aml[aml_adr_dword[i] + 2] & 0x1F; + /* Sanity check */ + if (memcmp(ssdp_pcihp_aml + aml_ej0_name[i], "_EJ0", 4)) { + warn_internalerror(); + free(ssdt); + return NULL; + } + if (!(rmvc_pcrm & (0x1 << slot))) { + memcpy(ssdt + aml_ej0_name[i], "EJ0_", 4); + } + } + + return ssdt; +} + +#define HPET_SIGNATURE 0x54455048 // HPET static void* build_hpet(void) { - struct acpi_20_hpet *hpet = malloc_high(sizeof(*hpet)); + struct acpi_20_hpet *hpet; + const void *hpet_base = (void *)BUILD_HPET_ADDRESS; + u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16; + u32 hpet_period = readl(hpet_base + HPET_PERIOD); + + if (hpet_vendor == 0 || hpet_vendor == 0xffff || + hpet_period == 0 || hpet_period > 100000000) + return NULL; + + hpet = malloc_high(sizeof(*hpet)); if (!hpet) { warn_noalloc(); return NULL; @@ -475,7 +546,7 @@ build_hpet(void) * emulated hpet */ hpet->timer_block_id = cpu_to_le32(0x8086a201); - hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS); + hpet->addr.address = cpu_to_le32(BUILD_HPET_ADDRESS); build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1); return hpet; @@ -487,7 +558,7 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem, { numamem->type = SRAT_MEMORY; numamem->length = sizeof(*numamem); - memset (numamem->proximity, 0 ,4); + memset(numamem->proximity, 0 ,4); numamem->proximity[0] = node; numamem->flags = cpu_to_le32(!!enabled); numamem->base_addr_low = base & 0xFFFFFFFF; @@ -496,7 +567,7 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem, numamem->length_high = len >> 32; } -#define SRAT_SIGNATURE 0x54415253 //HPET +#define SRAT_SIGNATURE 0x54415253 // SRAT static void * build_srat(void) { @@ -616,13 +687,7 @@ acpi_bios_init(void) // Device not found return; - // Create initial rsdt table - struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp)); - if (!rsdp) { - warn_noalloc(); - return; - } - + // Build ACPI tables u32 tables[MAX_ACPI_TABLES], tbl_idx = 0; #define ACPI_INIT_TABLE(X) \ @@ -632,43 +697,66 @@ acpi_bios_init(void) tbl_idx++; \ } while(0) - // Add tables - ACPI_INIT_TABLE(build_fadt(pci)); + struct fadt_descriptor_rev1 *fadt = build_fadt(pci); + ACPI_INIT_TABLE(fadt); ACPI_INIT_TABLE(build_ssdt()); ACPI_INIT_TABLE(build_madt()); ACPI_INIT_TABLE(build_hpet()); ACPI_INIT_TABLE(build_srat()); + ACPI_INIT_TABLE(build_pcihp()); u16 i, external_tables = qemu_cfg_acpi_additional_tables(); - for(i = 0; i < external_tables; i++) { + for (i = 0; i < external_tables; i++) { u16 len = qemu_cfg_next_acpi_table_len(); void *addr = malloc_high(len); if (!addr) { warn_noalloc(); continue; } - ACPI_INIT_TABLE(qemu_cfg_next_acpi_table_load(addr, len)); + struct acpi_table_header *header = + qemu_cfg_next_acpi_table_load(addr, len); + if (header->signature == DSDT_SIGNATURE) { + if (fadt) { + fill_dsdt(fadt, addr); + } + } else { + ACPI_INIT_TABLE(header); + } if (tbl_idx == MAX_ACPI_TABLES) { warn_noalloc(); break; } } + if (fadt && !fadt->dsdt) { + /* default DSDT */ + void *dsdt = malloc_high(sizeof(AmlCode)); + if (!dsdt) { + warn_noalloc(); + return; + } + memcpy(dsdt, AmlCode, sizeof(AmlCode)); + fill_dsdt(fadt, dsdt); + } + // Build final rsdt table struct rsdt_descriptor_rev1 *rsdt; size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx; rsdt = malloc_high(rsdt_len); - if (!rsdt) { warn_noalloc(); return; } memset(rsdt, 0, rsdt_len); memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx); - build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1); // Build rsdp pointer table + struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp)); + if (!rsdp) { + warn_noalloc(); + return; + } memset(rsdp, 0, sizeof(*rsdp)); rsdp->signature = RSDP_SIGNATURE; memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6);