X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Facpi.c;h=ea7b17160b4eb46c6c8bbeafe7423cd0c8133324;hb=ceb8ed4ef2e45cc5cc2525aeebd255838f656b69;hp=5818d4cf19a77b7f1586ee3da731bf6ba621574b;hpb=fe54a531bf14ef20f4da5d7af4a0d0fa11f45723;p=seabios.git diff --git a/src/acpi.c b/src/acpi.c index 5818d4c..ea7b171 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -1,18 +1,17 @@ // Support for generating ACPI tables (on emulators) // -// Copyright (C) 2008,2009 Kevin O'Connor +// Copyright (C) 2008-2010 Kevin O'Connor // Copyright (C) 2006 Fabrice Bellard // // This file may be distributed under the terms of the GNU LGPLv3 license. #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 #include "paravirt.h" -#include "dev-i440fx.h" // piix4_fadt_init /****************************************************/ /* ACPI tables init */ @@ -213,6 +212,20 @@ build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev) h->checksum -= checksum(h, len); } +#define PIIX4_ACPI_ENABLE 0xf1 +#define PIIX4_ACPI_DISABLE 0xf0 +#define PIIX4_GPE0_BLK 0xafe0 +#define PIIX4_GPE0_BLK_LEN 4 + +static void piix4_fadt_init(struct pci_device *pci, void *arg) +{ + struct fadt_descriptor_rev1 *fadt = arg; + fadt->acpi_enable = PIIX4_ACPI_ENABLE; + fadt->acpi_disable = PIIX4_ACPI_DISABLE; + fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK); + fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN; +} + static const struct pci_device_id fadt_init_tbl[] = { /* PIIX4 Power Management device (for ACPI) */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, @@ -221,8 +234,8 @@ static const struct pci_device_id fadt_init_tbl[] = { PCI_DEVICE_END }; -static void* -build_fadt(int bdf) +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)); @@ -247,7 +260,7 @@ build_fadt(int bdf) fadt->dsdt = cpu_to_le32((u32)dsdt); fadt->model = 1; fadt->reserved1 = 0; - int pm_sci_int = pci_config_readb(bdf, PCI_INTERRUPT_LINE); + int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE); fadt->sci_int = cpu_to_le16(pm_sci_int); fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD); fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE); @@ -258,9 +271,9 @@ build_fadt(int bdf) fadt->pm_tmr_len = 4; fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported - pci_init_device(fadt_init_tbl, bdf, fadt); - /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC */ - fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6)); + pci_init_device(fadt_init_tbl, pci, fadt); + /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */ + fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7)); build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1); @@ -329,64 +342,121 @@ build_madt(void) return madt; } +// Encode a hex value +static inline char getHex(u32 val) { + val &= 0x0f; + return (val <= 9) ? ('0' + val) : ('A' + val - 10); +} + +// Encode a length in an SSDT. +static u8 * +encodeLen(u8 *ssdt_ptr, int length, int bytes) +{ + switch (bytes) { + default: + case 4: ssdt_ptr[3] = ((length >> 20) & 0xff); + case 3: ssdt_ptr[2] = ((length >> 12) & 0xff); + case 2: ssdt_ptr[1] = ((length >> 4) & 0xff); + ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f); + break; + case 1: ssdt_ptr[0] = length & 0x3f; + } + 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 + #define SSDT_SIGNATURE 0x54445353 // SSDT static void* build_ssdt(void) { int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs; - // calculate the length of processor block and scope block - // excluding PkgLength - int cpu_length = 13 * acpi_cpus + 4; - - int length = sizeof(struct acpi_table_header) + 3 + cpu_length; - u8 *ssdt = malloc_high(length); + // length = ScopeOp + procs + NTYF method + CPON package + int length = ((1+3+4) + + (acpi_cpus * sizeof(ssdt_proc)) + + (1+2+5+(12*acpi_cpus)) + + (6+2+1+(1*acpi_cpus))); + u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length); if (! ssdt) { warn_noalloc(); return NULL; } + u8 *ssdt_ptr = ssdt + sizeof(struct acpi_table_header); - u8 *ssdt_ptr = ssdt; - ssdt_ptr[9] = 0; // checksum; - ssdt_ptr += sizeof(struct acpi_table_header); - - // build processor scope header + // build Scope(_SB_) header *(ssdt_ptr++) = 0x10; // ScopeOp - if (cpu_length <= 0x3e) { - /* Handle 1-4 CPUs with one byte encoding */ - *(ssdt_ptr++) = cpu_length + 1; - } else { - /* Handle 5-314 CPUs with two byte encoding */ - *(ssdt_ptr++) = 0x40 | ((cpu_length + 2) & 0xf); - *(ssdt_ptr++) = (cpu_length + 2) >> 4; - } - *(ssdt_ptr++) = '_'; // Name - *(ssdt_ptr++) = 'P'; - *(ssdt_ptr++) = 'R'; + ssdt_ptr = encodeLen(ssdt_ptr, length-1, 3); + *(ssdt_ptr++) = '_'; + *(ssdt_ptr++) = 'S'; + *(ssdt_ptr++) = 'B'; *(ssdt_ptr++) = '_'; - // build object for each processor + // build Processor object for each processor int i; for (i=0; i> 4) < 0xa ? (i >> 4) + '0' : (i >> 4) + 'A' - 0xa; - else - *(ssdt_ptr++) = 'U'; - *(ssdt_ptr++) = (i & 0xf) < 0xa ? (i & 0xf) + '0' : (i & 0xf) + 'A' - 0xa; + memcpy(ssdt_ptr, ssdt_proc, sizeof(ssdt_proc)); + ssdt_ptr[SD_OFFSET_CPUHEX] = getHex(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); + } + + // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}" + *(ssdt_ptr++) = 0x14; // MethodOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*acpi_cpus), 2); + *(ssdt_ptr++) = 'N'; + *(ssdt_ptr++) = 'T'; + *(ssdt_ptr++) = 'F'; + *(ssdt_ptr++) = 'Y'; + *(ssdt_ptr++) = 0x02; + for (i=0; i> 4); + *(ssdt_ptr++) = getHex(i); + *(ssdt_ptr++) = 0x69; // Arg1Op } + // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })" + *(ssdt_ptr++) = 0x08; // NameOp + *(ssdt_ptr++) = 'C'; + *(ssdt_ptr++) = 'P'; + *(ssdt_ptr++) = 'O'; + *(ssdt_ptr++) = 'N'; + *(ssdt_ptr++) = 0x12; // PackageOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2); + *(ssdt_ptr++) = acpi_cpus; + for (i=0; i