Maximilian Stein has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/42824 )
Change subject: arch-x86: Implement ACPI root tables
......................................................................
arch-x86: Implement ACPI root tables
The RSDP points to the RSDT (32 bit) and/or the XSDT (64 bit), which are
both instances of the abstract System Description Table.
This commit implements the mechanism to write the three data structures
to memory based on the full system's configuration. The SysDescTable
class acts as base class for the RSDT and XSDT as well as any future
implementation of other System Description Tables.
Change-Id: I710279a72376c04f2a636ff2e96fa80228d03eaf
Signed-off-by: Maximilian Stein <[email protected]>
---
M src/arch/x86/SConscript
M src/arch/x86/bios/ACPI.py
M src/arch/x86/bios/acpi.cc
M src/arch/x86/bios/acpi.hh
M src/arch/x86/fs_workload.cc
5 files changed, 239 insertions(+), 34 deletions(-)
diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript
index f790ec1..1fcf1dc 100644
--- a/src/arch/x86/SConscript
+++ b/src/arch/x86/SConscript
@@ -81,6 +81,7 @@
"Page table walker state machine 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 77de42f..19edac4 100644
--- a/src/arch/x86/bios/ACPI.py
+++ b/src/arch/x86/bios/ACPI.py
@@ -48,8 +48,8 @@
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 @@
# 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 8cdcdac..122ad31 100644
--- a/src/arch/x86/bios/acpi.cc
+++ b/src/arch/x86/bios/acpi.cc
@@ -37,6 +37,10 @@
#include "arch/x86/bios/acpi.hh"
+#include <cassert>
+#include <cstring>
+
+#include "base/trace.hh"
#include "mem/port.hh"
#include "params/X86ACPIRSDP.hh"
#include "params/X86ACPIRSDT.hh"
@@ -45,8 +49,25 @@
#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 +80,130 @@
return chunk;
}
-const char X86ISA::ACPI::RSDP::signature[] = "RSD PTR ";
+RSDP::RSDP(const Params &p) :
+ SimObject(p),
+ rsdt(p.rsdt),
+ xsdt(p.xsdt)
+{
+ static_assert(sizeof(signature) - 1 == sizeof(d.Signature),
+ "signature length mismatch");
+ std::memcpy(d.Signature, signature, sizeof(d.Signature));
+ std::strncpy(d.OEMID, p.oem_id.c_str(), sizeof(d.OEMID));
+ d.Revision = p.revision;
+ d.Length = sizeof(d);
+}
-X86ISA::ACPI::RSDP::RSDP(const Params &p) : SimObject(p), oemID(p.oem_id),
- revision(p.revision), rsdt(p.rsdt), xsdt(p.xsdt)
+Addr
+RSDP::write(PortProxy& physProxy, Allocator& alloc) const
+{
+ std::vector<uint8_t> mem(sizeof(d));
+ Addr addr = alloc.alloc(sizeof(d), 16);
+
+ assert(mem.size() >= sizeof(d));
+ std::memcpy(mem.data(), &d, sizeof(d));
+ Mem* desc = (Mem*)mem.data();
+
+ if (rsdt) {
+ desc->RsdtAddress = rsdt->write(physProxy, alloc);
+ DPRINTF(ACPI, "Allocated RSDT @ %llx\n", desc->RsdtAddress);
+ }
+ if (xsdt) {
+ desc->XsdtAddress = xsdt->write(physProxy, alloc);
+ DPRINTF(ACPI, "Allocated XSDT @ %llx\n", desc->XsdtAddress);
+ }
+
+ // checksum calculation
+ assert(d.Length == sizeof(d));
+ desc->Checksum = apic_checksum(mem.data(), sizeof(MemR0));
+ desc->ExtendedChecksum = apic_checksum(mem.data(), d.Length);
+
+ // write the whole thing
+ physProxy.writeBlob(addr, mem.data(), mem.size());
+
+ return addr;
+}
+
+SysDescTable::Mem::Mem(const char* Signature, uint8_t Revision,
+ const Params& p) :
+ Revision(Revision)
+{
+ std::strncpy(this->Signature, Signature, sizeof(this->Signature));
+ std::strncpy(OEMID, p.oem_id.c_str(), sizeof(OEMID));
+ std::strncpy(OEMTableID, p.oem_table_id.c_str(), sizeof(OEMTableID));
+ OEMRevision = p.oem_revision;
+ CreatorID = p.creator_id;
+ CreatorRevision = p.creator_revision;
+}
+
+Addr
+SysDescTable::_write(std::vector<uint8_t>& mem,
+ PortProxy& physProxy, Allocator& alloc) const
+{
+ auto& d = data();
+ mem.resize(sizeof(d));
+ std::memcpy(mem.data(), &d, mem.size());
+ return alloc.alloc(mem.size());
+}
+
+Addr
+SysDescTable::write(PortProxy& physProxy, Allocator& alloc) const
+{
+ std::vector<uint8_t> mem;
+ auto addr = this->_write(mem, physProxy, alloc);
+
+ // checksum calculation
+ Mem* header = (Mem*)mem.data();
+ header->Length = mem.size();
+ header->Checksum = apic_checksum(mem.data(), mem.size());
+
+ // write to physical memory
+ physProxy.writeBlob(addr, mem.data(), mem.size());
+
+ return addr;
+}
+
+//// RSDT, XSDT
+template<class T>
+RXSDT<T>::RXSDT(const Params& p, const char * _signature, uint8_t
_revision) :
+ SysDescTable(p),
+ d(_signature, _revision, p)
{}
-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)
-{}
+template<class T>
+Addr
+RXSDT<T>::_write(std::vector<uint8_t>& mem,
+ PortProxy& physProxy, Allocator& alloc) const
+{
+ auto base_size = sizeof(d) - sizeof(d.ptr);
+ mem.resize(base_size + sizeof(Ptr) * entries.size());
+ assert(mem.size() >= base_size);
+ std::memcpy(mem.data(), &d, base_size);
+ auto addr = alloc.alloc(mem.size());
+ Mem* myMem = reinterpret_cast<Mem*>(mem.data());
+ DPRINTF(ACPI, "RXSDT: writing %d entries @ %llx (ptr size: %d)\n",
+ entries.size(), addr, sizeof(Ptr));
+ for (unsigned i = 0; i < entries.size(); ++i) {
+ auto entry_addr = entries[i]->write(physProxy, 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);
+ myMem->ptr[i] = entry_addr;
+ }
+ return addr;
+}
-X86ISA::ACPI::RSDT::RSDT(const Params &p) :
- SysDescTable(p, "RSDT", 1), entries(p.entries)
-{}
+RSDT::RSDT(const Params& p) :
+ RXSDT(p, "RSDT", 1)
+{
+ entries = p.entries;
+}
-X86ISA::ACPI::XSDT::XSDT(const Params &p) :
- SysDescTable(p, "XSDT", 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 e314ab8..cbd7fb7 100644
--- a/src/arch/x86/bios/acpi.hh
+++ b/src/arch/x86/bios/acpi.hh
@@ -39,9 +39,13 @@
#define __ARCH_X86_BIOS_ACPI_HH__
#include <string>
+#include <type_traits>
#include <vector>
+#include "base/compiler.hh"
#include "base/types.hh"
+#include "debug/ACPI.hh"
+#include "mem/port_proxy.hh"
#include "sim/sim_object.hh"
class Port;
@@ -87,6 +91,29 @@
static const char signature[];
+ 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<MemR0>::value);
+
+ 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<Mem>::value);
+
+ Mem d;
+
std::string oemID;
uint8_t revision;
@@ -95,6 +122,8 @@
public:
RSDP(const Params &p);
+
+ Addr write(PortProxy& physProxy, Allocator& alloc) const;
};
class SysDescTable : public SimObject
@@ -102,38 +131,76 @@
protected:
typedef X86ACPISysDescTableParams Params;
- const char * signature;
- uint8_t revision;
+ 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;
- std::string oemID;
- std::string oemTableID;
- uint32_t oemRevision;
+ Mem(char const* Signature, uint8_t Revision, const Params& p);
+ };
+ static_assert(std::is_trivially_copyable<Mem>::value);
- std::string creatorID;
- uint32_t creatorRevision;
+ virtual Addr _write(std::vector<uint8_t>& mem,
+ PortProxy& physProxy, Allocator& alloc) const;
+
+ virtual Mem const& data() const = 0;
public:
- SysDescTable(const Params &p, const char * _signature, uint8_t
_revision);
+ using SimObject::SimObject;
+
+ Addr write(PortProxy& physProxy, Allocator& alloc) const;
};
-class RSDT : public SysDescTable
+template<class T>
+class RXSDT : public SysDescTable
+{
+ protected:
+ using Ptr = T;
+ struct M5_ATTR_PACKED Mem : public SysDescTable::Mem
+ {
+ // dynamically sized array (zero-length is non-standard)
+ Ptr ptr[1] = {};
+
+ using SysDescTable::Mem::Mem;
+ };
+ static_assert(std::is_trivially_copyable<Mem>::value);
+
+ std::vector<SysDescTable *> entries;
+
+ Addr _write(std::vector<uint8_t>& mem, PortProxy& physProxy,
+ Allocator& alloc) const override;
+
+ SysDescTable::Mem const& data() const override { return d; }
+
+ private:
+ Mem d;
+
+ protected:
+ RXSDT(const Params& p, const char * _signature, uint8_t _revision);
+};
+
+class RSDT : public RXSDT<uint32_t>
{
protected:
typedef X86ACPIRSDTParams Params;
- std::vector<SysDescTable *> entries;
-
public:
RSDT(const Params &p);
};
-class XSDT : public SysDescTable
+class XSDT : public RXSDT<uint64_t>
{
protected:
typedef X86ACPIXSDTParams Params;
- std::vector<SysDescTable *> entries;
-
public:
XSDT(const Params &p);
};
diff --git a/src/arch/x86/fs_workload.cc b/src/arch/x86/fs_workload.cc
index 7499e60..187bbe6 100644
--- a/src/arch/x86/fs_workload.cc
+++ b/src/arch/x86/fs_workload.cc
@@ -38,12 +38,14 @@
#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 "arch/x86/isa_traits.hh"
#include "base/loader/object_file.hh"
#include "cpu/thread_context.hh"
+#include "debug/ACPI.hh"
#include "params/X86FsWorkload.hh"
#include "sim/system.hh"
@@ -331,6 +333,13 @@
// Write out the Intel MP Specification configuration table.
writeOutMPTable(ebdaPos, fixed, table);
ebdaPos += (fixed + table);
+
+ // Write out ACPI tables
+ if (rsdp) {
+ ACPI::LinearAllocator alloc(0x000E0000, 0x000E1000);
+ auto rsdpAddr = rsdp->write(phys_proxy, alloc);
+ DPRINTF(ACPI, "Wrote ACPI tables to memory at %llx.\n", rsdpAddr);
+ }
}
void
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/42824
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I710279a72376c04f2a636ff2e96fa80228d03eaf
Gerrit-Change-Number: 42824
Gerrit-PatchSet: 1
Gerrit-Owner: Maximilian Stein <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s