Maximilian Stein has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/41953 )

Change subject: arch-x86: Add ACPI support for MADT
......................................................................

arch-x86: Add ACPI support for MADT

This extends the ACPI implementation to support the MADT. This table
contains information about the interrupt system (Local APIC, IO-APIC)
and partially replaces the Intel MP tables.
The change is particularly needed to support other OSes than Linux that
do not support Intel MP.

Change-Id: I132226f46f4d54e2e0b964e2986004e3e5f5f347
Signed-off-by: Maximilian Stein <m...@steiny.biz>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/41953
Reviewed-by: Gabe Black <gabe.bl...@gmail.com>
Maintainer: Gabe Black <gabe.bl...@gmail.com>
Tested-by: kokoro <noreply+kok...@google.com>
---
M src/arch/x86/bios/ACPI.py
M src/arch/x86/bios/acpi.cc
M src/arch/x86/bios/acpi.hh
3 files changed, 336 insertions(+), 0 deletions(-)

Approvals:
  Gabe Black: Looks good to me, approved; Looks good to me, approved
  kokoro: Regressions pass



diff --git a/src/arch/x86/bios/ACPI.py b/src/arch/x86/bios/ACPI.py
index 19edac4..5dfcb4d 100644
--- a/src/arch/x86/bios/ACPI.py
+++ b/src/arch/x86/bios/ACPI.py
@@ -67,6 +67,66 @@

entries = VectorParam.X86ACPISysDescTable([], 'system description tables')

+
+class X86ACPIMadtRecord(SimObject):
+    type = 'X86ACPIMadtRecord'
+    cxx_class = 'X86ISA::ACPI::MADT::Record'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+    abstract = True
+
+class X86ACPIMadt(X86ACPISysDescTable):
+    type = 'X86ACPIMadt'
+    cxx_class = 'X86ISA::ACPI::MADT::MADT'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+
+    local_apic_address = Param.UInt32(0, 'Address of the local apic')
+    flags = Param.UInt32(0, 'Flags')
+    records = VectorParam.X86ACPIMadtRecord([], 'Records in this MADT')
+
+class X86ACPIMadtLAPIC(X86ACPIMadtRecord):
+    type = 'X86ACPIMadtLAPIC'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+    cxx_class = 'X86ISA::ACPI::MADT::LAPIC'
+
+    acpi_processor_id = Param.UInt8(0, 'ACPI Processor ID')
+    apic_id = Param.UInt8(0, 'APIC ID')
+    flags = Param.UInt32(0, 'Flags')
+
+class X86ACPIMadtIOAPIC(X86ACPIMadtRecord):
+    type = 'X86ACPIMadtIOAPIC'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+    cxx_class = 'X86ISA::ACPI::MADT::IOAPIC'
+
+    id = Param.UInt8(0, 'I/O APIC ID')
+    address = Param.Addr(0, 'I/O APIC Address')
+    int_base = Param.UInt32(0, 'Global Interrupt Base')
+
+class X86ACPIMadtIntSourceOverride(X86ACPIMadtRecord):
+    type = 'X86ACPIMadtIntSourceOverride'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+    cxx_class = 'X86ISA::ACPI::MADT::IntSourceOverride'
+
+    bus_source = Param.UInt8(0, 'Bus Source')
+    irq_source = Param.UInt8(0, 'IRQ Source')
+    sys_int = Param.UInt32(0, 'Global System Interrupt')
+    flags = Param.UInt16(0, 'Flags')
+
+class X86ACPIMadtNMI(X86ACPIMadtRecord):
+    type = 'X86ACPIMadtNMI'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+    cxx_class = 'X86ISA::ACPI::MADT::NMI'
+
+    acpi_processor_id = Param.UInt8(0, 'ACPI Processor ID')
+    flags = Param.UInt16(0, 'Flags')
+    lint_no = Param.UInt8(0, 'LINT# (0 or 1)')
+
+class X86ACPIMadtLAPICOverride(X86ACPIMadtRecord):
+    type = 'X86ACPIMadtLAPICOverride'
+    cxx_header = 'arch/x86/bios/acpi.hh'
+    cxx_class = 'X86ISA::ACPI::MADT::LAPICOverride'
+
+    address = Param.Addr(0, '64-bit Physical Address of Local APIC')
+
 # Root System Description Pointer Structure
 class X86ACPIRSDP(SimObject):
     type = 'X86ACPIRSDP'
diff --git a/src/arch/x86/bios/acpi.cc b/src/arch/x86/bios/acpi.cc
index 91c8e47..53b6e4d 100644
--- a/src/arch/x86/bios/acpi.cc
+++ b/src/arch/x86/bios/acpi.cc
@@ -195,6 +195,119 @@
     entries = p.entries;
 }

+
+//// MADT
+MADT::MADT::MADT(const Params& p) :
+    SysDescTable(p, "APIC", 4),
+    records(p.records)
+{}
+
+Addr
+MADT::MADT::writeBuf(PortProxy& phys_proxy, Allocator& alloc,
+        std::vector<uint8_t>& 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));
+
+    Mem* header = reinterpret_cast<Mem*>(mem.data());
+    header->localAPICAddress = params().local_apic_address;
+    header->flags = params().flags;
+
+    for (const auto& record : records) {
+        auto entry = record->prepare();
+        mem.insert(mem.end(), entry.begin(), entry.end());
+    }
+
+    DPRINTF(ACPI, "MADT: writing %d records (size: %d)\n",
+            records.size(), mem.size());
+
+    return SysDescTable::writeBuf(phys_proxy, alloc, mem);
+}
+
+void
+MADT::Record::prepareBuf(std::vector<uint8_t>& mem) const
+{
+    assert(mem.size() >= sizeof(Mem));
+    DPRINTF(ACPI, "MADT: writing record type %d (size: %d)\n",
+            type, mem.size());
+
+    Mem* header = reinterpret_cast<Mem*>(mem.data());
+    header->type = type;
+    header->length = mem.size();
+}
+
+void
+MADT::LAPIC::prepareBuf(std::vector<uint8_t>& mem) const
+{
+    assert(mem.empty());
+    mem.resize(sizeof(Mem));
+
+    Mem* data = reinterpret_cast<Mem*>(mem.data());
+    data->acpiProcessorId = params().acpi_processor_id;
+    data->apicId = params().apic_id;
+    data->flags = params().flags;
+
+    Record::prepareBuf(mem);
+}
+
+void
+MADT::IOAPIC::prepareBuf(std::vector<uint8_t>& mem) const
+{
+    assert(mem.empty());
+    mem.resize(sizeof(Mem));
+
+    Mem* data = reinterpret_cast<Mem*>(mem.data());
+    data->ioApicId = params().id;
+    data->ioApicAddress = params().address;
+    data->intBase = params().int_base;
+
+    Record::prepareBuf(mem);
+}
+
+void
+MADT::IntSourceOverride::prepareBuf(std::vector<uint8_t>& mem) const
+{
+    assert(mem.empty());
+    mem.resize(sizeof(Mem));
+
+    Mem* data = reinterpret_cast<Mem*>(mem.data());
+    data->busSource = params().bus_source;
+    data->irqSource = params().irq_source;
+    data->globalSystemInterrupt = params().sys_int;
+    data->flags = params().flags;
+
+    Record::prepareBuf(mem);
+}
+
+void
+MADT::NMI::prepareBuf(std::vector<uint8_t>& mem) const
+{
+    assert(mem.empty());
+    mem.resize(sizeof(Mem));
+
+    Mem* data = reinterpret_cast<Mem*>(mem.data());
+    data->acpiProcessorId = params().acpi_processor_id;
+    // The "flags" field is not properly aligned.
+    memcpy(&data->flags, &params().flags, sizeof(data->flags));
+    data->lintNo = params().lint_no;
+
+    Record::prepareBuf(mem);
+}
+
+void
+MADT::LAPICOverride::prepareBuf(std::vector<uint8_t>& mem) const
+{
+    assert(mem.empty());
+    mem.resize(sizeof(Mem));
+
+    Mem* data = reinterpret_cast<Mem*>(mem.data());
+    data->localAPICAddress = params().address;
+
+    Record::prepareBuf(mem);
+}
+
 } // namespace ACPI

 } // namespace X86ISA
diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh
index 64f75ea..1c9f8e0 100644
--- a/src/arch/x86/bios/acpi.hh
+++ b/src/arch/x86/bios/acpi.hh
@@ -46,6 +46,13 @@
 #include "base/compiler.hh"
 #include "base/types.hh"
 #include "debug/ACPI.hh"
+#include "params/X86ACPIMadt.hh"
+#include "params/X86ACPIMadtIOAPIC.hh"
+#include "params/X86ACPIMadtIntSourceOverride.hh"
+#include "params/X86ACPIMadtLAPIC.hh"
+#include "params/X86ACPIMadtLAPICOverride.hh"
+#include "params/X86ACPIMadtNMI.hh"
+#include "params/X86ACPIMadtRecord.hh"
 #include "params/X86ACPIRSDP.hh"
 #include "params/X86ACPIRSDT.hh"
 #include "params/X86ACPISysDescTable.hh"
@@ -193,6 +200,162 @@
     XSDT(const Params &p);
 };

+namespace MADT
+{
+class Record : public SimObject
+{
+  protected:
+    PARAMS(X86ACPIMadtRecord);
+
+    struct M5_ATTR_PACKED Mem
+    {
+        uint8_t type = 0;
+        uint8_t length = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    uint8_t type;
+
+    virtual void prepareBuf(std::vector<uint8_t>& mem) const = 0;
+
+  public:
+    Record(const Params& p, uint8_t _type) : SimObject(p), type(_type) {}
+
+    std::vector<uint8_t>
+    prepare() const
+    {
+        std::vector<uint8_t> mem;
+        prepareBuf(mem);
+        return mem;
+    }
+};
+
+class LAPIC : public Record
+{
+  protected:
+    PARAMS(X86ACPIMadtLAPIC);
+
+    struct M5_ATTR_PACKED Mem : public Record::Mem
+    {
+        uint8_t acpiProcessorId = 0;
+        uint8_t apicId = 0;
+        uint32_t flags = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    void prepareBuf(std::vector<uint8_t>& mem) const override;
+
+  public:
+    LAPIC(const Params& p) : Record(p, 0) {}
+};
+
+class IOAPIC : public Record
+{
+  protected:
+    PARAMS(X86ACPIMadtIOAPIC);
+
+    struct M5_ATTR_PACKED Mem : public Record::Mem
+    {
+        uint8_t ioApicId = 0;
+        uint8_t _reserved = 0;
+        uint32_t ioApicAddress = 0;
+        uint32_t intBase = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    void prepareBuf(std::vector<uint8_t>& mem) const override;
+
+  public:
+    IOAPIC(const Params& p) : Record(p, 1) {}
+};
+
+class IntSourceOverride : public Record
+{
+  protected:
+    PARAMS(X86ACPIMadtIntSourceOverride);
+
+    struct M5_ATTR_PACKED Mem : public Record::Mem
+    {
+        uint8_t busSource = 0;
+        uint8_t irqSource = 0;
+        uint32_t globalSystemInterrupt = 0;
+        uint16_t flags = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    void prepareBuf(std::vector<uint8_t>& mem) const override;
+
+  public:
+    IntSourceOverride(const Params& p) : Record(p, 2) {}
+};
+
+class NMI : public Record
+{
+  protected:
+    PARAMS(X86ACPIMadtNMI);
+
+    struct M5_ATTR_PACKED Mem : public Record::Mem
+    {
+        uint8_t acpiProcessorId = 0;
+        uint16_t flags = 0;
+        uint8_t lintNo = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    void prepareBuf(std::vector<uint8_t>& mem) const override;
+
+  public:
+    NMI(const Params& p) : Record(p, 3) {}
+};
+
+class LAPICOverride : public Record
+{
+  protected:
+    PARAMS(X86ACPIMadtLAPICOverride);
+
+    struct M5_ATTR_PACKED Mem : public Record::Mem
+    {
+        uint16_t _reserved = 0;
+        uint64_t localAPICAddress = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    void prepareBuf(std::vector<uint8_t>& mem) const override;
+
+  public:
+    LAPICOverride(const Params& p) : Record(p, 5) {}
+};
+
+class MADT : public SysDescTable
+{
+  protected:
+    PARAMS(X86ACPIMadt);
+
+    struct M5_ATTR_PACKED Mem : public SysDescTable::Mem
+    {
+        uint32_t localAPICAddress = 0;
+        uint32_t flags = 0;
+    };
+    static_assert(std::is_trivially_copyable<Mem>::value,
+            "Type not suitable for memcpy.");
+
+    std::vector<Record *> records;
+
+    Addr writeBuf(PortProxy& phys_proxy, Allocator& alloc,
+            std::vector<uint8_t>& mem) const override;
+
+  public:
+    MADT(const Params &p);
+};
+
+} // namespace MADT
+
 } // namespace ACPI

 } // namespace X86ISA

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/41953
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: I132226f46f4d54e2e0b964e2986004e3e5f5f347
Gerrit-Change-Number: 41953
Gerrit-PatchSet: 15
Gerrit-Owner: Maximilian Stein <m...@steiny.biz>
Gerrit-Reviewer: Gabe Black <gabe.bl...@gmail.com>
Gerrit-Reviewer: Maximilian Stein <m...@steiny.biz>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-CC: Jason Lowe-Power <power...@gmail.com>
Gerrit-MessageType: merged
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to