Previously, the CPU control registers were being set in a number of different ways. Now, since the APs' need this to be set in the CPU initialization code, always do it there. This removes some of the settings from the bootloader, and some unused ones from smp.s. Additionally, the control registers' flags are now enums in cpu.h and manipulated via util::bitset.
102 lines
2.5 KiB
C++
102 lines
2.5 KiB
C++
#include <cpu/cpu_id.h>
|
|
|
|
#include "console.h"
|
|
#include "error.h"
|
|
#include "hardware.h"
|
|
#include "status.h"
|
|
|
|
namespace boot {
|
|
namespace hw {
|
|
|
|
void *
|
|
find_acpi_table(uefi::system_table *st)
|
|
{
|
|
status_line status(L"Searching for ACPI table");
|
|
|
|
// Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found.
|
|
uintptr_t acpi1_table = 0;
|
|
|
|
for (size_t i = 0; i < st->number_of_table_entries; ++i) {
|
|
uefi::configuration_table *table = &st->configuration_table[i];
|
|
|
|
// If we find an ACPI 2.0 table, return it immediately
|
|
if (table->vendor_guid == uefi::vendor_guids::acpi2)
|
|
return table->vendor_table;
|
|
|
|
if (table->vendor_guid == uefi::vendor_guids::acpi1) {
|
|
// Mark a v1 table with the LSB high
|
|
acpi1_table = reinterpret_cast<uintptr_t>(table->vendor_table);
|
|
acpi1_table |= 1;
|
|
}
|
|
}
|
|
|
|
if (!acpi1_table) {
|
|
error::raise(uefi::status::not_found, L"Could not find ACPI table");
|
|
} else if (acpi1_table & 1) {
|
|
status_line::warn(L"Only found ACPI 1.0 table");
|
|
}
|
|
|
|
return reinterpret_cast<void*>(acpi1_table);
|
|
}
|
|
|
|
static uint64_t
|
|
rdmsr(uint32_t addr)
|
|
{
|
|
uint32_t low, high;
|
|
__asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr));
|
|
return (static_cast<uint64_t>(high) << 32) | low;
|
|
}
|
|
|
|
static void
|
|
wrmsr(uint32_t addr, uint64_t value)
|
|
{
|
|
uint32_t low = value & 0xffffffff;
|
|
uint32_t high = value >> 32;
|
|
__asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high));
|
|
}
|
|
|
|
void
|
|
setup_control_regs()
|
|
{
|
|
uint64_t cr4 = 0;
|
|
asm volatile ( "mov %%cr4, %0" : "=r" (cr4) );
|
|
cr4 |= 0x000080; // Enable global pages
|
|
asm volatile ( "mov %0, %%cr4" :: "r" (cr4) );
|
|
|
|
// Set up IA32_EFER
|
|
constexpr uint32_t IA32_EFER = 0xC0000080;
|
|
uint64_t efer = rdmsr(IA32_EFER);
|
|
efer |=
|
|
0x0001 | // Enable SYSCALL
|
|
0x0800 | // Enable NX bit
|
|
0;
|
|
wrmsr(IA32_EFER, efer);
|
|
}
|
|
|
|
void
|
|
check_cpu_supported()
|
|
{
|
|
status_line status {L"Checking CPU features"};
|
|
|
|
cpu::cpu_id cpu;
|
|
cpu::cpu_id::features features = cpu.validate();
|
|
bool supported = true;
|
|
|
|
#define CPU_FEATURE_OPT(...)
|
|
#define CPU_FEATURE_REQ(name, ...) \
|
|
if (!features[cpu::feature::name]) { \
|
|
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
|
supported = false; \
|
|
}
|
|
#include "cpu/features.inc"
|
|
#undef CPU_FEATURE_REQ
|
|
#undef CPU_FEATURE_OPT
|
|
|
|
if (!supported)
|
|
error::raise(uefi::status::unsupported, L"CPU not supported");
|
|
}
|
|
|
|
|
|
} // namespace hw
|
|
} // namespace boot
|