mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2025-02-25 18:55:23 -06:00
Split ACPI Functions from SMP functions.
Add ACPI Table detection for FADT & HPET (as we need better timers)
This commit is contained in:
parent
63a07258fd
commit
221a66da1a
@ -18,6 +18,7 @@
|
|||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
#include "bootparams.h"
|
#include "bootparams.h"
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "cpuinfo.h"
|
#include "cpuinfo.h"
|
||||||
@ -218,6 +219,8 @@ static void global_init(void)
|
|||||||
|
|
||||||
quirks_init();
|
quirks_init();
|
||||||
|
|
||||||
|
acpi_init();
|
||||||
|
|
||||||
membw_init();
|
membw_init();
|
||||||
|
|
||||||
smbios_init();
|
smbios_init();
|
||||||
@ -280,6 +283,8 @@ static void global_init(void)
|
|||||||
}
|
}
|
||||||
if (rsdp_addr != 0) {
|
if (rsdp_addr != 0) {
|
||||||
trace(0, "ACPI RSDP found in %s at %0*x", rsdp_source, 2*sizeof(uintptr_t), rsdp_addr);
|
trace(0, "ACPI RSDP found in %s at %0*x", rsdp_source, 2*sizeof(uintptr_t), rsdp_addr);
|
||||||
|
trace(0, "ACPI FADT found at %0*x", 2*sizeof(uintptr_t), fadt_addr);
|
||||||
|
trace(0, "ACPI HPET found at %0*x", 2*sizeof(uintptr_t), hpet_addr);
|
||||||
}
|
}
|
||||||
if (!load_addr_ok) {
|
if (!load_addr_ok) {
|
||||||
trace(0, "Cannot relocate program. Press any key to reboot...");
|
trace(0, "Cannot relocate program. Press any key to reboot...");
|
||||||
|
@ -14,7 +14,8 @@ CFLAGS = -std=c11 -Wall -Wextra -Wshadow -m32 -march=i586 -fpic -fno-builtin \
|
|||||||
|
|
||||||
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
||||||
|
|
||||||
SYS_OBJS = system/cpuid.o \
|
SYS_OBJS = system/acpi.o \
|
||||||
|
system/cpuid.o \
|
||||||
system/cpuinfo.o \
|
system/cpuinfo.o \
|
||||||
system/cpulocal.o \
|
system/cpulocal.o \
|
||||||
system/ehci.o \
|
system/ehci.o \
|
||||||
|
@ -14,7 +14,8 @@ CFLAGS = -std=c11 -Wall -Wextra -Wshadow -m64 -march=x86-64 -mno-mmx -mno-sse -m
|
|||||||
|
|
||||||
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
||||||
|
|
||||||
SYS_OBJS = system/cpuid.o \
|
SYS_OBJS = system/acpi.o \
|
||||||
|
system/cpuid.o \
|
||||||
system/cpuinfo.o \
|
system/cpuinfo.o \
|
||||||
system/cpulocal.o \
|
system/cpulocal.o \
|
||||||
system/ehci.o \
|
system/ehci.o \
|
||||||
|
282
system/acpi.c
Normal file
282
system/acpi.c
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
|
|
||||||
|
#include "boot.h"
|
||||||
|
#include "bootparams.h"
|
||||||
|
#include "efi.h"
|
||||||
|
|
||||||
|
#include "pmem.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "unistd.h"
|
||||||
|
#include "vmem.h"
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Table signatures
|
||||||
|
|
||||||
|
#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
|
||||||
|
#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24))
|
||||||
|
|
||||||
|
#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24))
|
||||||
|
|
||||||
|
#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24))
|
||||||
|
|
||||||
|
#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24))
|
||||||
|
|
||||||
|
#define FADTSignature ('F' | ('A' << 8) | ('C' << 16) | ('P' << 24))
|
||||||
|
|
||||||
|
#define HPETSignature ('H' | ('P' << 8) | ('E' << 16) | ('T' << 24))
|
||||||
|
|
||||||
|
#define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24))
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char signature[8]; // "RSD PTR "
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_addr;
|
||||||
|
uint32_t length;
|
||||||
|
uint64_t xsdt_addr;
|
||||||
|
uint8_t xchecksum;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} rsdp_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char signature[4]; // "RSDT" or "XSDT"
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
char oem_table_id[8];
|
||||||
|
char oem_revision[4];
|
||||||
|
char creator_id[4];
|
||||||
|
char creator_revision[4];
|
||||||
|
} rsdt_header_t;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Variables
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static const efi_guid_t EFI_ACPI_1_RDSP_GUID = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
|
||||||
|
static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} };
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Variables
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *rsdp_source = "";
|
||||||
|
|
||||||
|
uintptr_t rsdp_addr = 0;
|
||||||
|
uintptr_t madt_addr = 0;
|
||||||
|
uintptr_t fadt_addr = 0;
|
||||||
|
uintptr_t hpet_addr = 0;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static rsdp_t *scan_for_rsdp(uintptr_t addr, int length)
|
||||||
|
{
|
||||||
|
uint32_t *ptr = (uint32_t *)addr;
|
||||||
|
uint32_t *end = ptr + length / sizeof(uint32_t);
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
rsdp_t *rp = (rsdp_t *)ptr;
|
||||||
|
if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && acpi_checksum(ptr, 20) == 0) {
|
||||||
|
if (rp->revision < 2 || (rp->length < 1024 && acpi_checksum(ptr, rp->length) == 0)) {
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
static rsdp_t *find_rsdp_in_efi64_system_table(efi64_system_table_t *system_table)
|
||||||
|
{
|
||||||
|
efi64_config_table_t *config_tables = (efi64_config_table_t *)map_region(system_table->config_tables,
|
||||||
|
system_table->num_config_tables * sizeof(efi64_config_table_t),
|
||||||
|
true);
|
||||||
|
if (config_tables == NULL) return NULL;
|
||||||
|
|
||||||
|
uintptr_t table_addr = 0;
|
||||||
|
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (rsdp_t *)table_addr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static rsdp_t *find_rsdp_in_efi32_system_table(efi32_system_table_t *system_table)
|
||||||
|
{
|
||||||
|
efi32_config_table_t *config_tables = (efi32_config_table_t *)map_region(system_table->config_tables,
|
||||||
|
system_table->num_config_tables * sizeof(efi32_config_table_t),
|
||||||
|
true);
|
||||||
|
if (config_tables == NULL) return NULL;
|
||||||
|
|
||||||
|
uintptr_t table_addr = 0;
|
||||||
|
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (rsdp_t *)table_addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uintptr_t find_rsdp(void)
|
||||||
|
{
|
||||||
|
const boot_params_t *boot_params = (boot_params_t *)boot_params_addr;
|
||||||
|
|
||||||
|
const efi_info_t *efi_info = &boot_params->efi_info;
|
||||||
|
|
||||||
|
// Search for the RSDP
|
||||||
|
rsdp_t *rp = NULL;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
if (efi_info->loader_signature == EFI64_LOADER_SIGNATURE) {
|
||||||
|
uintptr_t system_table_addr = (uintptr_t)efi_info->sys_tab_hi << 32 | (uintptr_t)efi_info->sys_tab;
|
||||||
|
system_table_addr = map_region(system_table_addr, sizeof(efi64_system_table_t), true);
|
||||||
|
if (system_table_addr != 0) {
|
||||||
|
rp = find_rsdp_in_efi64_system_table((efi64_system_table_t *)system_table_addr);
|
||||||
|
if (rp) rsdp_source = "EFI64 system table";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) {
|
||||||
|
uintptr_t system_table_addr = map_region(efi_info->sys_tab, sizeof(efi32_system_table_t), true);
|
||||||
|
if (system_table_addr != 0) {
|
||||||
|
rp = find_rsdp_in_efi32_system_table((efi32_system_table_t *)system_table_addr);
|
||||||
|
if (rp) rsdp_source = "EFI32 system table";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (rp == NULL) {
|
||||||
|
// Search the BIOS EBDA area.
|
||||||
|
uintptr_t address = *(uint16_t *)0x40E << 4;
|
||||||
|
if (address) {
|
||||||
|
rp = scan_for_rsdp(address, 0x400);
|
||||||
|
if (rp) rsdp_source = "BIOS EBDA";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rp == NULL) {
|
||||||
|
// Search the BIOS reserved area.
|
||||||
|
rp = scan_for_rsdp(0xE0000, 0x20000);
|
||||||
|
if (rp) rsdp_source = "BIOS reserved area";
|
||||||
|
}
|
||||||
|
if (rp == NULL) {
|
||||||
|
// RSDP not found, give up.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (uintptr_t)rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintptr_t find_acpi_table(uint32_t table_signature)
|
||||||
|
{
|
||||||
|
rsdp_t *rp = (rsdp_t *)rsdp_addr;;
|
||||||
|
|
||||||
|
// Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT.
|
||||||
|
rsdt_header_t *rt;
|
||||||
|
|
||||||
|
if (rp->revision >= 2) {
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true);
|
||||||
|
if (rt == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Validate the XSDT.
|
||||||
|
if (*(uint32_t *)rt != XSDTSignature) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, rt->length, true);
|
||||||
|
if (rt == NULL || acpi_checksum(rt, rt->length) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Scan the XSDT for a pointer to the MADT.
|
||||||
|
uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
||||||
|
uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length);
|
||||||
|
|
||||||
|
while (tab_ptr < tab_end) {
|
||||||
|
uintptr_t addr = *tab_ptr++; // read the next table entry
|
||||||
|
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
||||||
|
|
||||||
|
if (ptr && *ptr == table_signature) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, sizeof(rsdt_header_t), true);
|
||||||
|
if (rt == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Validate the RSDT.
|
||||||
|
if (*(uint32_t *)rt != RSDTSignature) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, rt->length, true);
|
||||||
|
if (rt == NULL || acpi_checksum(rt, rt->length) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Scan the RSDT for a pointer to the MADT.
|
||||||
|
uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
||||||
|
uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length);
|
||||||
|
|
||||||
|
while (tab_ptr < tab_end) {
|
||||||
|
uintptr_t addr = *tab_ptr++; // read the next table entry
|
||||||
|
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
||||||
|
|
||||||
|
if (ptr && *ptr == table_signature) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Public Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int acpi_checksum(const void *data, int length)
|
||||||
|
{
|
||||||
|
uint8_t sum = 0;
|
||||||
|
|
||||||
|
uint8_t *ptr = (uint8_t *)data;
|
||||||
|
while (length--) {
|
||||||
|
sum += *ptr++;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_init(void)
|
||||||
|
{
|
||||||
|
// Find ACPI RDST Table Address
|
||||||
|
rsdp_addr = find_rsdp();
|
||||||
|
|
||||||
|
// Find ACPI MADT Table Address
|
||||||
|
madt_addr = find_acpi_table(MADTSignature);
|
||||||
|
|
||||||
|
// Find ACPI FADT Table Address
|
||||||
|
fadt_addr = find_acpi_table(FADTSignature);
|
||||||
|
|
||||||
|
// Find ACPI HPET Table Address
|
||||||
|
hpet_addr = find_acpi_table(HPETSignature);
|
||||||
|
}
|
52
system/acpi.h
Normal file
52
system/acpi.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#ifndef _ACPI_H_
|
||||||
|
#define _ACPI_H_
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* Provides support for multi-threaded operation.
|
||||||
|
*
|
||||||
|
*//*
|
||||||
|
* Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
* Copyright (C) 2020-2022 Sam Whitaker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The search step that located the ACPI RSDP (for debug).
|
||||||
|
*/
|
||||||
|
extern const char *rsdp_source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address of the ACPI RSDP
|
||||||
|
*/
|
||||||
|
extern uintptr_t rsdp_addr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address of the ACPI MADT
|
||||||
|
*/
|
||||||
|
extern uintptr_t madt_addr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address of the ACPI FADT
|
||||||
|
*/
|
||||||
|
extern uintptr_t fadt_addr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address of the ACPI HPET
|
||||||
|
*/
|
||||||
|
extern uintptr_t hpet_addr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACPI Table Checksum Function
|
||||||
|
*/
|
||||||
|
int acpi_checksum(const void *data, int length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the SMP state and detects the number of available CPU cores.
|
||||||
|
*/
|
||||||
|
void acpi_init(void);
|
||||||
|
|
||||||
|
#endif /* _ACPI_H_ */
|
234
system/smp.c
234
system/smp.c
@ -1,11 +1,10 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
//
|
//
|
||||||
// Derived from an extract of memtest86+ smp.c:
|
// Derived from an extract of memtest86+ smp.c:
|
||||||
//
|
//
|
||||||
// MemTest86+ V5 Specific code (GPL V2.0)
|
// MemTest86+ V5 Specific code (GPL V2.0)
|
||||||
// By Samuel DEMEULEMEESTER, sdemeule@memtest.org
|
|
||||||
// http://www.canardpc.com - http://www.memtest.org
|
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// smp.c - MemTest-86 Version 3.5
|
// smp.c - MemTest-86 Version 3.5
|
||||||
//
|
//
|
||||||
@ -15,6 +14,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
#include "bootparams.h"
|
#include "bootparams.h"
|
||||||
#include "efi.h"
|
#include "efi.h"
|
||||||
@ -75,18 +75,8 @@
|
|||||||
// Table signatures
|
// Table signatures
|
||||||
|
|
||||||
#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24))
|
#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24))
|
||||||
|
|
||||||
#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
|
#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
|
||||||
|
|
||||||
#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
|
|
||||||
#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24))
|
|
||||||
|
|
||||||
#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24))
|
|
||||||
|
|
||||||
#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24))
|
|
||||||
|
|
||||||
#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24))
|
|
||||||
|
|
||||||
// MP config table entry types
|
// MP config table entry types
|
||||||
|
|
||||||
#define MP_PROCESSOR 0
|
#define MP_PROCESSOR 0
|
||||||
@ -189,30 +179,6 @@ typedef struct {
|
|||||||
uint8_t dst_apic_lint;
|
uint8_t dst_apic_lint;
|
||||||
} mp_local_interrupt_entry_t;
|
} mp_local_interrupt_entry_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char signature[8]; // "RSD PTR "
|
|
||||||
uint8_t checksum;
|
|
||||||
char oem_id[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_addr;
|
|
||||||
uint32_t length;
|
|
||||||
uint64_t xsdt_addr;
|
|
||||||
uint8_t xchecksum;
|
|
||||||
uint8_t reserved[3];
|
|
||||||
} rsdp_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char signature[4]; // "RSDT" or "XSDT"
|
|
||||||
uint32_t length;
|
|
||||||
uint8_t revision;
|
|
||||||
uint8_t checksum;
|
|
||||||
char oem_id[6];
|
|
||||||
char oem_table_id[8];
|
|
||||||
char oem_revision[4];
|
|
||||||
char creator_id[4];
|
|
||||||
char creator_revision[4];
|
|
||||||
} rsdt_header_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char signature[4]; // "APIC"
|
char signature[4]; // "APIC"
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
@ -251,9 +217,6 @@ typedef struct {
|
|||||||
// Private Variables
|
// Private Variables
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static const efi_guid_t EFI_ACPI_1_RDSP_GUID = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
|
|
||||||
static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} };
|
|
||||||
|
|
||||||
static apic_register_t *apic = NULL;
|
static apic_register_t *apic = NULL;
|
||||||
|
|
||||||
static uint8_t apic_id_to_cpu_num[MAX_APIC_IDS];
|
static uint8_t apic_id_to_cpu_num[MAX_APIC_IDS];
|
||||||
@ -270,10 +233,6 @@ static uintptr_t alloc_addr = 0;
|
|||||||
|
|
||||||
int num_available_cpus = 1; // There is always at least one CPU, the BSP
|
int num_available_cpus = 1; // There is always at least one CPU, the BSP
|
||||||
|
|
||||||
const char *rsdp_source = "";
|
|
||||||
|
|
||||||
uintptr_t rsdp_addr = 0;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private Functions
|
// Private Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -293,24 +252,13 @@ static uint32_t apic_read(int reg)
|
|||||||
return read32(&apic[reg][0]);
|
return read32(&apic[reg][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checksum(const void *data, int length)
|
|
||||||
{
|
|
||||||
uint8_t sum = 0;
|
|
||||||
|
|
||||||
uint8_t *ptr = (uint8_t *)data;
|
|
||||||
while (length--) {
|
|
||||||
sum += *ptr++;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
static floating_pointer_struct_t *scan_for_floating_ptr_struct(uintptr_t addr, int length)
|
static floating_pointer_struct_t *scan_for_floating_ptr_struct(uintptr_t addr, int length)
|
||||||
{
|
{
|
||||||
uint32_t *ptr = (uint32_t *)addr;
|
uint32_t *ptr = (uint32_t *)addr;
|
||||||
uint32_t *end = ptr + length / sizeof(uint32_t);
|
uint32_t *end = ptr + length / sizeof(uint32_t);
|
||||||
|
|
||||||
while (ptr < end) {
|
while (ptr < end) {
|
||||||
if (*ptr == FPSignature && checksum(ptr, 16) == 0) {
|
if (*ptr == FPSignature && acpi_checksum(ptr, 16) == 0) {
|
||||||
floating_pointer_struct_t *fp = (floating_pointer_struct_t *)ptr;
|
floating_pointer_struct_t *fp = (floating_pointer_struct_t *)ptr;
|
||||||
if (fp->length == 1 && (fp->spec_rev == 1 || fp->spec_rev == 4)) {
|
if (fp->length == 1 && (fp->spec_rev == 1 || fp->spec_rev == 4)) {
|
||||||
return fp;
|
return fp;
|
||||||
@ -329,7 +277,7 @@ static bool read_mp_config_table(uintptr_t addr)
|
|||||||
mpc = (mp_config_table_header_t *)map_region(addr, mpc->length, true);
|
mpc = (mp_config_table_header_t *)map_region(addr, mpc->length, true);
|
||||||
if (mpc == NULL) return false;
|
if (mpc == NULL) return false;
|
||||||
|
|
||||||
if (mpc->signature != MPCSignature || checksum(mpc, mpc->length) != 0) {
|
if (mpc->signature != MPCSignature || acpi_checksum(mpc, mpc->length) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,32 +374,17 @@ static bool find_cpus_in_floating_mp_struct(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rsdp_t *scan_for_rsdp(uintptr_t addr, int length)
|
static bool find_cpus_in_madt(void)
|
||||||
{
|
{
|
||||||
uint32_t *ptr = (uint32_t *)addr;
|
if(madt_addr == 0) return false;
|
||||||
uint32_t *end = ptr + length / sizeof(uint32_t);
|
|
||||||
|
|
||||||
while (ptr < end) {
|
madt_table_header_t *mpc = (madt_table_header_t *)map_region(madt_addr, sizeof(madt_table_header_t), true);
|
||||||
rsdp_t *rp = (rsdp_t *)ptr;
|
|
||||||
if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && checksum(ptr, 20) == 0) {
|
|
||||||
if (rp->revision < 2 || (rp->length < 1024 && checksum(ptr, rp->length) == 0)) {
|
|
||||||
return rp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_madt(uintptr_t addr)
|
|
||||||
{
|
|
||||||
madt_table_header_t *mpc = (madt_table_header_t *)map_region(addr, sizeof(madt_table_header_t), true);
|
|
||||||
if (mpc == NULL) return false;
|
if (mpc == NULL) return false;
|
||||||
|
|
||||||
mpc = (madt_table_header_t *)map_region(addr, mpc->length, true);
|
mpc = (madt_table_header_t *)map_region(madt_addr, mpc->length, true);
|
||||||
if (mpc == NULL) return false;
|
if (mpc == NULL) return false;
|
||||||
|
|
||||||
if (checksum(mpc, mpc->length) != 0) {
|
if (acpi_checksum(mpc, mpc->length) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,150 +424,6 @@ static bool parse_madt(uintptr_t addr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
static rsdp_t *find_rsdp_in_efi64_system_table(efi64_system_table_t *system_table)
|
|
||||||
{
|
|
||||||
efi64_config_table_t *config_tables = (efi64_config_table_t *)map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi64_config_table_t), true);
|
|
||||||
if (config_tables == NULL) return NULL;
|
|
||||||
|
|
||||||
uintptr_t table_addr = 0;
|
|
||||||
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (rsdp_t *)table_addr;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static rsdp_t *find_rsdp_in_efi32_system_table(efi32_system_table_t *system_table)
|
|
||||||
{
|
|
||||||
efi32_config_table_t *config_tables = (efi32_config_table_t *)map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi32_config_table_t), true);
|
|
||||||
if (config_tables == NULL) return NULL;
|
|
||||||
|
|
||||||
uintptr_t table_addr = 0;
|
|
||||||
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (rsdp_t *)table_addr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool find_cpus_in_rsdp(void)
|
|
||||||
{
|
|
||||||
const boot_params_t *boot_params = (boot_params_t *)boot_params_addr;
|
|
||||||
|
|
||||||
const efi_info_t *efi_info = &boot_params->efi_info;
|
|
||||||
|
|
||||||
// Search for the RSDP
|
|
||||||
rsdp_t *rp = NULL;
|
|
||||||
#ifdef __x86_64__
|
|
||||||
if (efi_info->loader_signature == EFI64_LOADER_SIGNATURE) {
|
|
||||||
uintptr_t system_table_addr = (uintptr_t)efi_info->sys_tab_hi << 32 | (uintptr_t)efi_info->sys_tab;
|
|
||||||
system_table_addr = map_region(system_table_addr, sizeof(efi64_system_table_t), true);
|
|
||||||
if (system_table_addr != 0) {
|
|
||||||
rp = find_rsdp_in_efi64_system_table((efi64_system_table_t *)system_table_addr);
|
|
||||||
if (rp) rsdp_source = "EFI64 system table";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) {
|
|
||||||
uintptr_t system_table_addr = map_region(efi_info->sys_tab, sizeof(efi32_system_table_t), true);
|
|
||||||
if (system_table_addr != 0) {
|
|
||||||
rp = find_rsdp_in_efi32_system_table((efi32_system_table_t *)system_table_addr);
|
|
||||||
if (rp) rsdp_source = "EFI32 system table";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (rp == NULL) {
|
|
||||||
// Search the BIOS EBDA area.
|
|
||||||
uintptr_t address = *(uint16_t *)0x40E << 4;
|
|
||||||
if (address) {
|
|
||||||
rp = scan_for_rsdp(address, 0x400);
|
|
||||||
if (rp) rsdp_source = "BIOS EBDA";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rp == NULL) {
|
|
||||||
// Search the BIOS reserved area.
|
|
||||||
rp = scan_for_rsdp(0xE0000, 0x20000);
|
|
||||||
if (rp) rsdp_source = "BIOS reserved area";
|
|
||||||
}
|
|
||||||
if (rp == NULL) {
|
|
||||||
// RSDP not found, give up.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rsdp_addr = (uintptr_t)rp;
|
|
||||||
|
|
||||||
// Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT.
|
|
||||||
rsdt_header_t *rt;
|
|
||||||
if (rp->revision >= 2) {
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true);
|
|
||||||
if (rt == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Validate the XSDT.
|
|
||||||
if (*(uint32_t *)rt != XSDTSignature) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, rt->length, true);
|
|
||||||
if (rt == NULL || checksum(rt, rt->length) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Scan the XSDT for a pointer to the MADT.
|
|
||||||
uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
|
||||||
uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length);
|
|
||||||
|
|
||||||
while (tab_ptr < tab_end) {
|
|
||||||
uintptr_t addr = *tab_ptr++; // read the next table entry
|
|
||||||
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
|
||||||
|
|
||||||
if (ptr && *ptr == MADTSignature) {
|
|
||||||
if (parse_madt(addr)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, sizeof(rsdt_header_t), true);
|
|
||||||
if (rt == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Validate the RSDT.
|
|
||||||
if (*(uint32_t *)rt != RSDTSignature) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, rt->length, true);
|
|
||||||
if (rt == NULL || checksum(rt, rt->length) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Scan the RSDT for a pointer to the MADT.
|
|
||||||
uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
|
||||||
uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length);
|
|
||||||
|
|
||||||
while (tab_ptr < tab_end) {
|
|
||||||
uintptr_t addr = *tab_ptr++; // read the next table entry
|
|
||||||
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
|
||||||
|
|
||||||
if (ptr && *ptr == MADTSignature) {
|
|
||||||
if (parse_madt(addr)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void send_ipi(int apic_id, int trigger, int level, int mode, uint8_t vector)
|
static inline void send_ipi(int apic_id, int trigger, int level, int mode, uint8_t vector)
|
||||||
{
|
{
|
||||||
apic_write(APIC_REG_ICRHI, apic_id << 24);
|
apic_write(APIC_REG_ICRHI, apic_id << 24);
|
||||||
@ -671,7 +460,8 @@ static uint32_t read_apic_esr(bool is_p5)
|
|||||||
|
|
||||||
static bool start_cpu(int cpu_num)
|
static bool start_cpu(int cpu_num)
|
||||||
{
|
{
|
||||||
// This is based on the method used in Linux 5.14. We don't support non-integrated APICs, so can simplify it a bit.
|
// This is based on the method used in Linux 5.14.
|
||||||
|
// We don't support non-integrated APICs, so can simplify it a bit.
|
||||||
|
|
||||||
int apic_id = cpu_num_to_apic_id[cpu_num];
|
int apic_id = cpu_num_to_apic_id[cpu_num];
|
||||||
|
|
||||||
@ -748,7 +538,7 @@ void smp_init(bool smp_enable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (smp_enable) {
|
if (smp_enable) {
|
||||||
(void)(find_cpus_in_rsdp() || find_cpus_in_floating_mp_struct());
|
(void)(find_cpus_in_madt() || find_cpus_in_floating_mp_struct());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,15 +38,6 @@ typedef enum __attribute__ ((packed)) {
|
|||||||
*/
|
*/
|
||||||
extern int num_available_cpus;
|
extern int num_available_cpus;
|
||||||
|
|
||||||
/**
|
|
||||||
* The search step that located the ACPI RSDP (for debug).
|
|
||||||
*/
|
|
||||||
extern const char *rsdp_source;
|
|
||||||
/**
|
|
||||||
* The address of the ACPI RSDP (for debug).
|
|
||||||
*/
|
|
||||||
extern uintptr_t rsdp_addr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the SMP state and detects the number of available CPU cores.
|
* Initialises the SMP state and detects the number of available CPU cores.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user