genode/repos/base-hw/src/include/hw/spec/x86_64/acpi.h
Sebastian Sumpf d417d26ce8 hw: fix calculation of CPU count on x86_64
On x86 the CPU count is determined through ACPI's MADT by counting the
local APICs reported there. Some platforms report more APICs
than there are actual CPUs. These might be physically disabled CPUs.
Therefore, a check if the LAPIC is actually physically enabled in
hardware fixes this issue.

Thanks to Alex Boettcher

fixes #3376
2019-05-29 10:20:52 +02:00

123 lines
3.1 KiB
C++

/*
* \brief ACPI structures and parsing
* \author Alexander Boettcher
* \date 2018-04-23
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__LIB__HW__SPEC__X86_64__ACPI_H_
#define _SRC__LIB__HW__SPEC__X86_64__ACPI_H_
#include <base/fixed_stdint.h>
namespace Hw {
struct Acpi_generic;
struct Apic_madt;
template <typename FUNC>
void for_each_rsdt_entry(Hw::Acpi_generic &, FUNC);
template <typename FUNC>
void for_each_xsdt_entry(Hw::Acpi_generic &, FUNC);
template <typename FUNC>
void for_each_apic_struct(Acpi_generic &, FUNC);
}
/* ACPI spec 5.2.6 */
struct Hw::Acpi_generic
{
Genode::uint8_t signature[4];
Genode::uint32_t size;
Genode::uint8_t rev;
Genode::uint8_t checksum;
Genode::uint8_t oemid[6];
Genode::uint8_t oemtabid[8];
Genode::uint32_t oemrev;
Genode::uint8_t creator[4];
Genode::uint32_t creator_rev;
} __attribute__((packed));
struct Hw::Apic_madt
{
enum { LAPIC = 0, IO_APIC = 1 };
Genode::uint8_t type;
Genode::uint8_t length;
Apic_madt *next() const { return reinterpret_cast<Apic_madt *>((Genode::uint8_t *)this + length); }
struct Ioapic : Genode::Mmio {
struct Id : Register <0x02, 8> { };
struct Paddr : Register <0x04, 32> { };
struct Gsi_base : Register <0x08, 32> { };
Ioapic(Apic_madt const * a) : Mmio(reinterpret_cast<Genode::addr_t>(a)) { }
};
struct Lapic : Genode::Mmio {
struct Flags : Register <0x04, 32> { enum { VALID = 1 }; };
Lapic(Apic_madt const * a) : Mmio(reinterpret_cast<Genode::addr_t>(a)) { }
bool valid() { return read<Flags>() & Flags::VALID; };
};
} __attribute__((packed));
template <typename FUNC>
void Hw::for_each_rsdt_entry(Hw::Acpi_generic &rsdt, FUNC fn)
{
if (Genode::memcmp(rsdt.signature, "RSDT", 4))
return;
typedef Genode::uint32_t entry_t;
unsigned const table_size = rsdt.size;
unsigned const entry_count = (table_size - sizeof(rsdt)) / sizeof(entry_t);
entry_t * entries = reinterpret_cast<entry_t *>(&rsdt + 1);
for (unsigned i = 0; i < entry_count; i++)
fn(entries[i]);
}
template <typename FUNC>
void Hw::for_each_xsdt_entry(Hw::Acpi_generic &xsdt, FUNC fn)
{
if (Genode::memcmp(xsdt.signature, "XSDT", 4))
return;
typedef Genode::uint64_t entry_t;
unsigned const table_size = xsdt.size;
unsigned const entry_count = (table_size - sizeof(xsdt)) / sizeof(entry_t);
entry_t * entries = reinterpret_cast<entry_t *>(&xsdt + 1);
for (unsigned i = 0; i < entry_count; i++)
fn(entries[i]);
}
template <typename FUNC>
void Hw::for_each_apic_struct(Hw::Acpi_generic &apic_madt, FUNC fn)
{
if (Genode::memcmp(apic_madt.signature, "APIC", 4))
return;
Apic_madt const * const first = reinterpret_cast<Apic_madt *>(&apic_madt.creator_rev + 3);
Apic_madt const * const last = reinterpret_cast<Apic_madt *>(reinterpret_cast<Genode::uint8_t *>(apic_madt.signature) + apic_madt.size);
for (Apic_madt const * e = first; e < last ; e = e->next())
fn(e);
}
#endif /* _SRC__LIB__HW__SPEC__X86_64__ACPI_H_ */