diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index d7da2903bd..9b16fad957 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -79,6 +79,7 @@ DebugFlag('Faults', "Trace all faults/exceptions/traps") DebugFlag('LocalApic', "Local APIC debugging") DebugFlag('Decoder', "Decoder debug output") DebugFlag('X86', "Generic X86 ISA debugging") +DebugFlag('ACPI', "ACPI debugging") python_files = ( '__init__.py', diff --git a/src/arch/x86/bios/ACPI.py b/src/arch/x86/bios/ACPI.py index 77de42f925..19edac4c8f 100644 --- a/src/arch/x86/bios/ACPI.py +++ b/src/arch/x86/bios/ACPI.py @@ -48,8 +48,8 @@ class X86ACPISysDescTable(SimObject): oem_table_id = Param.String('', 'oem table ID') oem_revision = Param.UInt32(0, 'oem revision number for the table') - creator_id = Param.String('', - 'string identifying the generator of the table') + creator_id = Param.UInt32(0, + 'ID identifying the generator of the table') creator_revision = Param.UInt32(0, 'revision number for the creator of the table') @@ -78,6 +78,7 @@ class X86ACPIRSDP(SimObject): # here. revision = Param.UInt8(2, 'revision of ACPI being used, zero indexed') - rsdt = Param.X86ACPIRSDT(NULL, 'root system description table') + rsdt = Param.X86ACPIRSDT(X86ACPIRSDT(), + 'root system description table') xsdt = Param.X86ACPIXSDT(X86ACPIXSDT(), 'extended system description table') diff --git a/src/arch/x86/bios/acpi.cc b/src/arch/x86/bios/acpi.cc index 8cdcdac3f6..91c8e47534 100644 --- a/src/arch/x86/bios/acpi.cc +++ b/src/arch/x86/bios/acpi.cc @@ -37,16 +37,34 @@ #include "arch/x86/bios/acpi.hh" +#include +#include + +#include "base/trace.hh" #include "mem/port.hh" -#include "params/X86ACPIRSDP.hh" -#include "params/X86ACPIRSDT.hh" -#include "params/X86ACPISysDescTable.hh" -#include "params/X86ACPIXSDT.hh" +#include "mem/port_proxy.hh" #include "sim/byteswap.hh" #include "sim/sim_object.hh" +namespace X86ISA +{ + +namespace ACPI +{ + +const char RSDP::signature[] = "RSD PTR "; + +static uint8_t +apic_checksum(uint8_t* ptr, std::size_t size) +{ + uint8_t sum = 0; + for (unsigned i = 0; i < size; ++i) + sum += ptr[i]; + return 0x100 - sum; +} + Addr -X86ISA::ACPI::LinearAllocator::alloc(std::size_t size, unsigned align) +LinearAllocator::alloc(std::size_t size, unsigned align) { if (align) { unsigned offset = next % align; @@ -59,24 +77,124 @@ X86ISA::ACPI::LinearAllocator::alloc(std::size_t size, unsigned align) return chunk; } -const char X86ISA::ACPI::RSDP::signature[] = "RSD PTR "; - -X86ISA::ACPI::RSDP::RSDP(const Params &p) : SimObject(p), oemID(p.oem_id), - revision(p.revision), rsdt(p.rsdt), xsdt(p.xsdt) +RSDP::RSDP(const Params &p) : + SimObject(p), + rsdt(p.rsdt), + xsdt(p.xsdt) {} -X86ISA::ACPI::SysDescTable::SysDescTable(const Params &p, - const char * _signature, uint8_t _revision) : SimObject(p), - signature(_signature), revision(_revision), - oemID(p.oem_id), oemTableID(p.oem_table_id), - oemRevision(p.oem_revision), - creatorID(p.creator_id), creatorRevision(p.creator_revision) +Addr +RSDP::write(PortProxy& phys_proxy, Allocator& alloc) const +{ + std::vector mem(sizeof(Mem)); + Addr addr = alloc.alloc(mem.size(), 16); + + Mem* data = (Mem*)mem.data(); + static_assert(sizeof(signature) - 1 == sizeof(data->signature), + "signature length mismatch"); + std::memcpy(data->signature, signature, sizeof(data->signature)); + std::strncpy(data->oemID, params().oem_id.c_str(), sizeof(data->oemID)); + data->revision = params().revision; + data->length = mem.size(); + + if (rsdt) { + data->rsdtAddress = rsdt->write(phys_proxy, alloc); + DPRINTF(ACPI, "Allocated RSDT @ %llx\n", data->rsdtAddress); + } + if (xsdt) { + data->xsdtAddress = xsdt->write(phys_proxy, alloc); + DPRINTF(ACPI, "Allocated XSDT @ %llx\n", data->xsdtAddress); + } + + // checksum calculation + data->checksum = apic_checksum(mem.data(), sizeof(MemR0)); + data->extendedChecksum = apic_checksum(mem.data(), mem.size()); + + // write the whole thing + phys_proxy.writeBlob(addr, mem.data(), mem.size()); + + return addr; +} + +Addr +SysDescTable::writeBuf(PortProxy& phys_proxy, Allocator& alloc, + std::vector &mem) const +{ + // An empty SysDescTable doesn't make any sense, so assert that somebody + // else allocated a large enough blob. + assert(mem.size() >= sizeof(Mem)); + + // Allocate a place to write this blob. + Addr addr = alloc.alloc(mem.size()); + + DPRINTF(ACPI, "Writing system description table [%llx - %llx]\n", addr, + addr + mem.size()); + + // Fill in the header. + auto& p = params(); + Mem* header = (Mem*)mem.data(); + std::strncpy(header->signature, signature, sizeof(header->signature)); + header->length = mem.size(); + header->revision = revision; + std::strncpy(header->oemID, p.oem_id.c_str(), sizeof(header->oemID)); + std::strncpy(header->oemTableID, p.oem_table_id.c_str(), + sizeof(header->oemTableID)); + header->oemRevision = p.oem_revision; + header->creatorID = p.creator_id; + header->creatorRevision = p.creator_revision; + + // Update checksum. + header->checksum = apic_checksum(mem.data(), mem.size()); + + // Write to memory. + phys_proxy.writeBlob(addr, mem.data(), mem.size()); + + return addr; +} + +//// RSDT, XSDT +template +RXSDT::RXSDT(const Params& p, const char *_signature, uint8_t _revision) : + SysDescTable(p, _signature, _revision) {} -X86ISA::ACPI::RSDT::RSDT(const Params &p) : - SysDescTable(p, "RSDT", 1), entries(p.entries) -{} +template +Addr +RXSDT::writeBuf(PortProxy& phys_proxy, Allocator& alloc, + std::vector& mem) const +{ + // Since this table ends with a variably sized array, it can't be extended + // by another table type. + assert(mem.empty()); + mem.resize(sizeof(Mem)); -X86ISA::ACPI::XSDT::XSDT(const Params &p) : - SysDescTable(p, "XSDT", 1), entries(p.entries) -{} + auto base_size = mem.size(); + mem.resize(base_size + sizeof(Ptr) * entries.size()); + + Ptr* ptr_array = reinterpret_cast(mem.data() + base_size); + DPRINTF(ACPI, "RXSDT: Writing %d entries (ptr size: %d)\n", entries.size(), + sizeof(Ptr)); + for (const auto *entry : entries) { + Addr entry_addr = entry->write(phys_proxy, alloc); + fatal_if((entry_addr & mask(sizeof(Ptr) * 8)) != entry_addr, + "RXSDT: Entry address doesn't fit in pointer type."); + DPRINTF(ACPI, "RXSDT: wrote entry @ %llx\n", entry_addr); + *ptr_array++ = entry_addr; + } + + return SysDescTable::writeBuf(phys_proxy, alloc, mem); +} + +RSDT::RSDT(const Params& p) : RXSDT(p, "RSDT", 1) +{ + entries = p.entries; +} + +XSDT::XSDT(const Params& p) : RXSDT(p, "XSDT", 1) +{ + entries = p.entries; +} + +} // namespace ACPI + +} // namespace X86ISA diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh index 6fe0f6e302..64f75ea790 100644 --- a/src/arch/x86/bios/acpi.hh +++ b/src/arch/x86/bios/acpi.hh @@ -39,18 +39,20 @@ #define __ARCH_X86_BIOS_ACPI_HH__ #include +#include +#include #include +#include "base/compiler.hh" #include "base/types.hh" +#include "debug/ACPI.hh" +#include "params/X86ACPIRSDP.hh" +#include "params/X86ACPIRSDT.hh" +#include "params/X86ACPISysDescTable.hh" +#include "params/X86ACPIXSDT.hh" #include "sim/sim_object.hh" -class Port; - -struct X86ACPIRSDPParams; - -struct X86ACPISysDescTableParams; -struct X86ACPIRSDTParams; -struct X86ACPIXSDTParams; +class PortProxy; namespace X86ISA { @@ -60,7 +62,6 @@ namespace ACPI class RSDT; class XSDT; -class SysDescTable; struct Allocator { @@ -83,56 +84,110 @@ struct LinearAllocator : public Allocator class RSDP : public SimObject { protected: - typedef X86ACPIRSDPParams Params; + PARAMS(X86ACPIRSDP); static const char signature[]; - std::string oemID; - uint8_t revision; + struct M5_ATTR_PACKED MemR0 + { + // src: https://wiki.osdev.org/RSDP + char signature[8] = {}; + uint8_t checksum = 0; + char oemID[6] = {}; + uint8_t revision = 0; + uint32_t rsdtAddress = 0; + }; + static_assert(std::is_trivially_copyable::value, + "Type not suitable for memcpy."); - RSDT * rsdt; - XSDT * xsdt; + struct M5_ATTR_PACKED Mem : public MemR0 + { + // since version 2 + uint32_t length = 0; + uint64_t xsdtAddress = 0; + uint8_t extendedChecksum = 0; + uint8_t _reserved[3] = {}; + }; + static_assert(std::is_trivially_copyable::value, + "Type not suitable for memcpy,"); + + RSDT* rsdt; + XSDT* xsdt; public: RSDP(const Params &p); + + Addr write(PortProxy& phys_proxy, Allocator& alloc) const; }; class SysDescTable : public SimObject { protected: - typedef X86ACPISysDescTableParams Params; + PARAMS(X86ACPISysDescTable); - const char * signature; + struct M5_ATTR_PACKED Mem + { + // src: https://wiki.osdev.org/RSDT + char signature[4] = {}; + uint32_t length = 0; + uint8_t revision = 0; + uint8_t checksum = 0; + char oemID[6] = {}; + char oemTableID[8] = {}; + uint32_t oemRevision = 0; + uint32_t creatorID = 0; + uint32_t creatorRevision = 0; + }; + static_assert(std::is_trivially_copyable::value, + "Type not suitable for memcpy."); + + virtual Addr writeBuf(PortProxy& phys_proxy, Allocator& alloc, + std::vector& mem) const = 0; + + const char* signature; uint8_t revision; - std::string oemID; - std::string oemTableID; - uint32_t oemRevision; - - std::string creatorID; - uint32_t creatorRevision; + SysDescTable(const Params& p, const char* _signature, uint8_t _revision) : + SimObject(p), signature(_signature), revision(_revision) + {} public: - SysDescTable(const Params &p, const char * _signature, uint8_t _revision); + Addr + write(PortProxy& phys_proxy, Allocator& alloc) const + { + std::vector mem; + return writeBuf(phys_proxy, alloc, mem); + } }; -class RSDT : public SysDescTable +template +class RXSDT : public SysDescTable { protected: - typedef X86ACPIRSDTParams Params; + using Ptr = T; std::vector entries; + Addr writeBuf(PortProxy& phys_proxy, Allocator& alloc, + std::vector& mem) const override; + + protected: + RXSDT(const Params& p, const char* _signature, uint8_t _revision); +}; + +class RSDT : public RXSDT +{ + protected: + PARAMS(X86ACPIRSDT); + public: RSDT(const Params &p); }; -class XSDT : public SysDescTable +class XSDT : public RXSDT { protected: - typedef X86ACPIXSDTParams Params; - - std::vector entries; + PARAMS(X86ACPIXSDT); public: XSDT(const Params &p); diff --git a/src/arch/x86/fs_workload.cc b/src/arch/x86/fs_workload.cc index 381ab4f636..f9818c5370 100644 --- a/src/arch/x86/fs_workload.cc +++ b/src/arch/x86/fs_workload.cc @@ -38,11 +38,13 @@ #include "arch/x86/fs_workload.hh" +#include "arch/x86/bios/acpi.hh" #include "arch/x86/bios/intelmp.hh" #include "arch/x86/bios/smbios.hh" #include "arch/x86/faults.hh" #include "base/loader/object_file.hh" #include "cpu/thread_context.hh" +#include "debug/ACPI.hh" #include "params/X86FsWorkload.hh" #include "sim/system.hh" @@ -330,6 +332,10 @@ FsWorkload::initState() // Write out the Intel MP Specification configuration table. writeOutMPTable(ebdaPos, fixed, table); ebdaPos += (fixed + table); + + // Write out ACPI tables + writeOutACPITables(ebdaPos, table); + ebdaPos += table; } void @@ -375,4 +381,17 @@ FsWorkload::writeOutMPTable(Addr fp, Addr &fpSize, Addr &tableSize, Addr table) assert(fpSize == 0x10); } +void +FsWorkload::writeOutACPITables(Addr fp, Addr &fpSize) +{ + fpSize = 0; + if (rsdp) { + ACPI::LinearAllocator alloc(fp, 0x000FFFFF); + rsdp->write(system->physProxy, alloc); + fpSize = alloc.alloc(0, 0) - fp; + DPRINTF(ACPI, "Wrote ACPI tables to memory at %llx with size %llx.\n", + fp, fpSize); + } +} + } // namespace X86ISA diff --git a/src/arch/x86/fs_workload.hh b/src/arch/x86/fs_workload.hh index f926dce32a..9e6fa80091 100644 --- a/src/arch/x86/fs_workload.hh +++ b/src/arch/x86/fs_workload.hh @@ -89,6 +89,8 @@ class FsWorkload : public KernelWorkload void writeOutMPTable(Addr fp, Addr &fpSize, Addr &tableSize, Addr table=0); + + void writeOutACPITables(Addr begin, Addr &size); }; } // namespace X86ISA