mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2024-11-27 01:50:20 -06:00
97922cc4cf
* lib/assert: Add LoongArch assert support Added LoongArch break 3 assert instruction. Signed-off-by: Chao Li <lichao@loongson.cn> * lib/barrier: Add barrier method for LoongArch Added LoongArch barriers in barrier_spin_wait and barrier_halt_wait functions. Signed-off-by: Chao Li <lichao@loognson.cn> * lib/spinlock: Add LoongArch CPU pause Because the LoongArch haven't pause instruction, using eight nops to replace the pause. Signed-off-by: Chao Li <lichao@loongson.cn> * lib/string: Make LoongArch use the string function in the file Since LoongArch GCC doesn't have built-in string functions, use the string function instance in the sting.c Signed-off-by: Chao Li <lichao@loongson.cn> * lib/unistd: Add LoongArch CPU pause Because the LoongArch haven't pause instruction, using eight nops to replace the pause. Signed-off-by: Chao Li <lichao@loongson.cn> * system/acpi: Reduce the way of search RSDP for non-x86 ARCHs Searching RSDP from legacy BIOS EDBA and reserved areas is available only on i386 and x64. Signed-off-by: Chao Li <lichao@loongson.cn> * system/cache: Add LoongArch64 cache operations support Added cache operations support for LoongArch64. Signed-off-by: Chao Li <lichao@loongson.cn> * system/cpuid: Add the compile limit Make the `cpuid` function action only on i386/x64. Signed-off-by: Chao Li <lichao@loongson.cn> * system/heap: Add heap support for LoongArch64 LoongArch64 uses the low 256MB as the low memory. Signed-off-by: Chao Li <lichao@loongson.cn> * system/memrw: Add 8-bit and 16-bit memory operations Added 8-bit and 16-bit memory access operations, which 8-bit uses `movb` and 16-bit is `movw`. Signed-off-by: Chao Li <lichao@loongson.cn> * system/memrw: Add LoongArch memory access operations Added 8/16/32/64-bit memory access operations for LoongArch64. Signed-off-by: Chao Li <lichao@loongson.cn> * system: Add Loongson PCI vendor ID and Loongson 7A chipset EHCI workaround 1. Added Loongson PCI vendor ID. 2. Added Loongson 7A chipset ECHI workaround. Signed-off-by: Chao Li <lichao@loongson.cn> * system/io: Add LoongArch64 IO port operations Added IO port operations for LoongArch64. Signed-off-by: Chao Li <lichao@loongson.cn> * system/reloc64: Add LoongArch64 relocations support Added R_LARCH_RELATIVE and R_LARCH_NONE relocations support for LoongArch64. Signed-off-by: Chao Li <lichao@loongson.cn> * system/serial: Add Loongson CPU serial port support Add the serial port address perfix of Loongson CPU and obtain serial port clock method. Signed-off-by: Chao Li <lichao@loongson.cn> * system/smbus: Rename smbus.c to i2c_x86.c Renamed the smbus.c to i2c_x86.c in i386 and x64 platforms. Signed-off-by: Chao Li <lichao@loongson.cn> * system/smp: Add LoongArch SMP support Added LoongArch multi-core support and a way of map to node numbers if the NUMA is enabled. Signed-off-by: Chao Li <lichao@loongson.cn> * system/timers: Add LoongArch supports In LoongArch, there is a stable counter that is independent of other clocks, it like the TSC in x64. Using it to count the ticks per millisecond. Signed-off-by: Chao Li <lichao@loongson.cn> * system/tsc: Add LoongArch support Usually the frequency of stable counter is not same to CPU frequency, so using the performance counter for the delay operations. Signed-off-by: Chao Li <lichao@loongson.cn> * system/usbhcd: Add LoongArch MMIO perfix Added LoongArch64 MMIO address perfix, use for address the PCI memory space. Signed-off-by: Chao Li <lichao@loongson.cn> * system/usbhcd: Add Loongson 7A2000 chipset OHCI BAR offset fix If the BAR address is not fixed for the Loongson 7A2000 OHCI controller, some prots will not be usable, This change currently only affects the LoongArch platform. Signed-off-by: Chao Li <lichao@loongson.cn> * system: Add the way to IO access via MMIO Usually, it is access the IO like PCI IO via MMIO on non-X86 ARCHs, so a method to access IO via MMIO is added. Signed-off-by: Chao Li <lichao@loongson.cn> * system: Add the way to access PCI memory space via MMIO Some uniformly address ARCHs access the PCI memory depended the MMIO, so the method to access PCI memory via MMIO is added. Signed-off-by: Chao Li <lichao@loongson.cn> * app: Add LoongArch version support Reduced the version field by two characters to support ARCH name abbreviations with more than three characters, and added "la64" ARCH version display. Singed-off-by: Chao Li <lichao@loongson.cn> * test/block_move: Add block move test via ASM for LoongArch Add block move test inline assembly instance for LoongArch. Signed-off-by: Chao Li <lichao@loongson.cn> * test/mov_inv_fixed: Add LoongArch ASM version word write operation Add LoongArch ASM version word write cycle if it uses the HAND_OPTIMISED. Signed-off-by: Chao Li <lichao@loongson.cn> * boot: Adjust the AP stack size for LoongArch LoongArch exception will store all of the GP, FP and CSR on stack, it need more stack size, make LoongArch AP using 2KB stack size. Signed-off-by: Chao Li <lichao@loongson.cn> * boot/efisetup: Add LoongArch CPU halt instruction Add "idle 0" for LoongArch Signed-off-by: Chao Li <lichao@loongson.cn> * boot/efi: Limiting the ms_abi using scope Make the ms_abi only work on i386 and x64. Signed-off-by: Chao Li <lichao@loongson.cn> * system/imc/loongson: Add Loongson LoongArch IMC support Added the Loongson LoongArch CPU IMC instance, support read out the IMC sequence, currently only supports reading MC0. Signed-off-by: Chao Li <lichao@loongson.cn> * app/loongarch: Add intrrupt handler for LoongArch Added the LoongArch IRQ handler support. Signed-off-by: Chao Li <lichao@loongson.cn> * system/loongarch: Add LoongArch ARCH specific files Added LoongArch ARCH specific files: cpuid.c, cpuinfo.c, hwctrl.c, memctrl.c, temperature.c, vmem.c, registers.h They use the same pubilc API for i386 and x64 platforms. Signed-off-by: Chao Li <lichao@loongson.cn> * boot: Add LoongArch startup and header Added the header.S and startup64.S for LoongArch, CPU works on: 1. Page mode. 2. Load and store is cacheable. 3. Instructions is cacheable. 4. DMWn 0 and 1 is used. 5. To access non-cacheable areas, use the perfix 0x8000000000000000. Signed-off Chao Li <lichao@loongson.cn> * build64/la64: Add LoongArch64 build files Add infrastructure files to build memtest86 plus for LoongArch64 platform. Signed-off-by: Chao Li <lichao@loongson.cn> * workflows: Add LoongArch64 CI supports Adjust workflow logci, remvoe 32 and 64 wordsize, replace with "i386, x86_64 and la64", add LoongArch64 build CI check. Signed-off-by: Chao Li <lichao@loongson.cn> --------- Signed-off-by: Chao Li <lichao@loongson.cn> Signed-off-by: Chao Li <lichao@loognson.cn>
341 lines
12 KiB
C
341 lines
12 KiB
C
// 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)) // Root System Description Table
|
|
|
|
#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) // Extended System Description Table
|
|
|
|
#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) // Multiple APIC Description Table
|
|
|
|
#define FADTSignature ('F' | ('A' << 8) | ('C' << 16) | ('P' << 24)) // Fixed ACPI Description Table
|
|
|
|
#define HPETSignature ('H' | ('P' << 8) | ('E' << 16) | ('T' << 24)) // High Precision Event Timer
|
|
|
|
#define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24)) // Error Injection Table
|
|
#define ERSTSignature ('E' | ('R' << 8) | ('S' << 16) | ('T' << 24)) // Error Record Serialization Table
|
|
#define CPEPSignature ('C' | ('P' << 8) | ('E' << 16) | ('P' << 24)) // Corrected Platform Error Polling Table
|
|
#define HESTSignature ('H' | ('E' << 8) | ('S' << 16) | ('T' << 24)) // Hardware Error Source Table
|
|
|
|
#define SLITSignature ('S' | ('L' << 8) | ('I' << 16) | ('T' << 24)) // System Locality Information Table (NUMA)
|
|
#define SRATSignature ('S' | ('R' << 8) | ('A' << 16) | ('T' << 24)) // System Resource Affinity Table (NUMA)
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Types
|
|
//------------------------------------------------------------------------------
|
|
|
|
typedef struct __attribute__ ((packed)) {
|
|
uint8_t address_space;
|
|
uint8_t bit_width;
|
|
uint8_t bit_offset;
|
|
uint8_t access_size;
|
|
uint64_t address;
|
|
} acpi_gen_addr_struct;
|
|
|
|
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;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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 = "";
|
|
|
|
acpi_t acpi_config = {0, 0, 0, 0, 0, /*0,*/ 0, 0, 0, false};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private Functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
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;
|
|
}
|
|
#endif
|
|
|
|
#if (ARCH_BITS == 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;
|
|
#if (ARCH_BITS == 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 defined(__i386__) || defined(__x86_64__)
|
|
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";
|
|
}
|
|
#endif
|
|
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 *)acpi_config.rsdp_addr;
|
|
|
|
// Found the RSDP, now get either the RSDT or XSDT
|
|
// and scan it for a pointer to the table we're looking for
|
|
rsdt_header_t *rt;
|
|
|
|
if (acpi_config.ver_maj < rp->revision) {
|
|
acpi_config.ver_maj = rp->revision;
|
|
}
|
|
|
|
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 table we're looking for.
|
|
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 table we're looking for.
|
|
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;
|
|
}
|
|
|
|
static bool parse_fadt(uintptr_t fadt_addr)
|
|
{
|
|
// FADT is a very big & complex table and we only need a few pieces of data.
|
|
// We use byte offset instead of a complete struct.
|
|
|
|
// FADT Header is identical to RSDP Header
|
|
rsdt_header_t *fadt = (rsdt_header_t *)fadt_addr;
|
|
|
|
// Validate FADT
|
|
if (fadt == NULL || acpi_checksum(fadt, fadt->length) != 0) {
|
|
return false;
|
|
}
|
|
|
|
// Get ACPI Version
|
|
acpi_config.ver_maj = fadt->revision;
|
|
|
|
if (fadt->length > FADT_MINOR_REV_OFFSET) {
|
|
acpi_config.ver_min = *(uint8_t *)(fadt_addr+FADT_MINOR_REV_OFFSET) & 0xF;
|
|
}
|
|
|
|
// Get Old PM Base Address (32-bit IO)
|
|
acpi_config.pm_addr = *(uint32_t *)(fadt_addr+FADT_PM_TMR_BLK_OFFSET);
|
|
acpi_config.pm_is_io = true;
|
|
|
|
#if (ARCH_BITS == 64)
|
|
acpi_gen_addr_struct *rt;
|
|
|
|
// Get APIC Timer Address
|
|
if (fadt->length > FADT_X_PM_TMR_BLK_OFFSET) {
|
|
rt = (acpi_gen_addr_struct *)map_region(fadt_addr+FADT_X_PM_TMR_BLK_OFFSET, sizeof(acpi_gen_addr_struct), true);
|
|
|
|
acpi_config.pm_is_io = (rt->address_space == 1) ? true : false;
|
|
|
|
if (rt->address != 0) {
|
|
acpi_config.pm_addr = rt->address;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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)
|
|
{
|
|
acpi_config.rsdp_addr = find_rsdp();
|
|
|
|
if (acpi_config.rsdp_addr == 0) {
|
|
return;
|
|
}
|
|
|
|
acpi_config.madt_addr = find_acpi_table(MADTSignature);
|
|
|
|
acpi_config.fadt_addr = find_acpi_table(FADTSignature);
|
|
|
|
if (acpi_config.fadt_addr) {
|
|
parse_fadt(acpi_config.fadt_addr);
|
|
}
|
|
|
|
acpi_config.hpet_addr = find_acpi_table(HPETSignature);
|
|
|
|
acpi_config.srat_addr = find_acpi_table(SRATSignature);
|
|
|
|
//acpi_config.slit_addr = find_acpi_table(SLITSignature);
|
|
}
|