mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2025-02-25 18:55:23 -06:00
* 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>
233 lines
7.0 KiB
C
233 lines
7.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
|
// Copyright (C) 2024 Loongson Technology Corporation Limited. All rights reserved.
|
|
//
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include <stdint.h>
|
|
#include "hwctrl.h"
|
|
#include "screen.h"
|
|
#include "keyboard.h"
|
|
#include "smp.h"
|
|
#include "display.h"
|
|
|
|
#include <larchintrin.h>
|
|
|
|
#define INT_SIP0 0
|
|
#define INT_SIP1 1
|
|
#define INT_IP0 2
|
|
#define INT_IP1 3
|
|
#define INT_IP2 4
|
|
#define INT_IP3 5
|
|
#define INT_IP4 6
|
|
#define INT_IP5 7
|
|
#define INT_IP6 8
|
|
#define INT_IP7 9
|
|
#define INT_PMC 10
|
|
#define INT_TIMER 11
|
|
#define INT_IPI 12
|
|
|
|
|
|
#define EXC_INT 0
|
|
#define EXC_PIL 1
|
|
#define EXC_PIS 2
|
|
#define EXC_PIF 3
|
|
#define EXC_PME 4
|
|
#define EXC_PNR 5
|
|
#define EXC_PNX 6
|
|
#define EXC_PPI 7
|
|
#define EXC_ADE 8
|
|
#define EXC_ALE 9
|
|
#define EXC_BCE 10
|
|
#define EXC_SYS 11
|
|
#define EXC_BRK 12
|
|
#define EXC_INE 13
|
|
#define EXC_IPE 14
|
|
#define EXC_FPD 15
|
|
#define EXC_SXD 16
|
|
#define EXC_ASXD 17
|
|
#define EXC_FPE 18
|
|
|
|
#define OP_IDLE 0x06488000
|
|
#define OP_BGE 0x64000000
|
|
|
|
|
|
#ifdef __loongarch_lp64
|
|
typedef uint64_t reg_t;
|
|
#define CSR_REG_DIGITS "16"
|
|
#define GP_REG_DIGITS "16"
|
|
#define ADR_DIGITS "12"
|
|
#else
|
|
typedef uint32_t reg_t;
|
|
#define CSR_REG_DIGITS "8"
|
|
#define GP_REG_DIGITS "8"
|
|
#define ADR_DIGITS "8"
|
|
#endif
|
|
|
|
static const char *exception_code[] = {
|
|
"#INT - Interrupt(CSR.ECFG.VS=0)",
|
|
"#PIL - Page invalid exception for Load option",
|
|
"#PIS - Page invalid exception for Store operation",
|
|
"#PIF - Page invalid exception for Fetch operation",
|
|
"#PME - Page modification exception",
|
|
"#PNR - Page non-readable exception",
|
|
"#PNX - Page non-executable exception",
|
|
"#PPI - Page privilege level illegal exception",
|
|
"#ADE - Address error exception",
|
|
"#ALE - Address alignment fault exception",
|
|
"#BCE - Bound check exception",
|
|
"#SYS - System call exception",
|
|
"#BRK - Breakpoint exception",
|
|
"#INE - Instruction non-defined exception",
|
|
"#IPE - Instruction privilege error exception",
|
|
"#FPD - Floating-point instruction disable exception",
|
|
"#SXD - 128-bit vector (SIMD instructions) expansion instruction disable exception",
|
|
"#ASXD - 256-bit vector (Advanced SIMD instructions) expansion instruction disable exception",
|
|
"#FPE - Floating-Point error exception",
|
|
"#TBR - TLB refill exception"
|
|
};
|
|
|
|
|
|
struct system_context {
|
|
//
|
|
// GP
|
|
//
|
|
reg_t r0;
|
|
reg_t r1;
|
|
reg_t r2;
|
|
reg_t r3;
|
|
reg_t r4;
|
|
reg_t r5;
|
|
reg_t r6;
|
|
reg_t r7;
|
|
reg_t r8;
|
|
reg_t r9;
|
|
reg_t r10;
|
|
reg_t r11;
|
|
reg_t r12;
|
|
reg_t r13;
|
|
reg_t r14;
|
|
reg_t r15;
|
|
reg_t r16;
|
|
reg_t r17;
|
|
reg_t r18;
|
|
reg_t r19;
|
|
reg_t r20;
|
|
reg_t r21;
|
|
reg_t r22;
|
|
reg_t r23;
|
|
reg_t r24;
|
|
reg_t r25;
|
|
reg_t r26;
|
|
reg_t r27;
|
|
reg_t r28;
|
|
reg_t r29;
|
|
reg_t r30;
|
|
reg_t r31;
|
|
|
|
//
|
|
// CSR
|
|
//
|
|
reg_t crmd;
|
|
reg_t prmd;
|
|
reg_t euen;
|
|
reg_t misc;
|
|
reg_t ecfg;
|
|
reg_t estat;
|
|
reg_t era;
|
|
reg_t badv;
|
|
reg_t badi;
|
|
};
|
|
|
|
void interrupt(struct system_context *system_context)
|
|
{
|
|
uint8_t ecode;
|
|
|
|
if (system_context->estat & (1 << INT_IPI)) {
|
|
uint32_t *pc = (uint32_t *)system_context->era;
|
|
|
|
//
|
|
// Clean the mailbox 0 and 3
|
|
//
|
|
__iocsrwr_d(0x0, 0x1020);
|
|
__iocsrwr_d(0x0, 0x1038);
|
|
|
|
//
|
|
// Clean IPI
|
|
//
|
|
__iocsrwr_w(__iocsrrd_w(0x1000), 0x100c);
|
|
__dbar(0);
|
|
|
|
if ((pc[-1] & ~0x7FFF) == OP_IDLE) {
|
|
// Assume this is a barrier wakeup signal sent via IPI.
|
|
system_context->era += 4;
|
|
return;
|
|
}
|
|
|
|
// Catch the rare case that a core will fail to reach the IDLE instruction before
|
|
// its wakeup signal arrives. The barrier code contains an atomic decrement, a BLT
|
|
// instruction, and a IDLE instruction. The atomic decrement must have completed if
|
|
// another core has reached the point of sending the wakeup signals, so we should
|
|
// find the IDLE opcode either at pc[0] or at pc[1]. If we find it, adjust the ERA
|
|
// to point to the following instruction.
|
|
if ((pc[0] & ~0x7FFF) == OP_IDLE) {
|
|
system_context->era += 8;
|
|
return;
|
|
}
|
|
if ((pc[0] & ~0x3FFFFFF) == OP_BGE && (pc[1] & ~0x7FFF) == OP_IDLE) {
|
|
system_context->era += 12;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
ecode = (system_context->estat >> 16) & 0x3F;
|
|
|
|
spin_lock(error_mutex);
|
|
|
|
clear_message_area();
|
|
|
|
display_pinned_message(0, 0, "Unexpected interrupt on CPU %i", smp_my_cpu_num());
|
|
if (__csrrd_w(0x8A) & 0x1) {
|
|
display_pinned_message(2, 0, "Type: %s", exception_code[19]);
|
|
} else if (ecode < 19) {
|
|
display_pinned_message(2, 0, "Type: %s", exception_code[ecode]);
|
|
} else {
|
|
display_pinned_message(2, 0, "Type: %i", ecode);
|
|
}
|
|
display_pinned_message(3, 0, " BADV: %0" CSR_REG_DIGITS "x", (uintptr_t)system_context->badv);
|
|
display_pinned_message(4, 0, " BADI: %0" CSR_REG_DIGITS "x", (uintptr_t)system_context->badi);
|
|
display_pinned_message(5, 0, " ERA: %0" CSR_REG_DIGITS "x", (uintptr_t)system_context->era);
|
|
display_pinned_message(6, 0, " EUEN: %0" CSR_REG_DIGITS "x", (uintptr_t)system_context->euen);
|
|
display_pinned_message(7, 0, " ECFG: %0" CSR_REG_DIGITS "x", (uintptr_t)system_context->ecfg);
|
|
display_pinned_message(8, 0, "ESTAT: %0" CSR_REG_DIGITS "x", (uintptr_t)system_context->estat);
|
|
|
|
display_pinned_message(3, 25, "RA: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r1);
|
|
display_pinned_message(4, 25, "SP: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r3);
|
|
display_pinned_message(5, 25, "A0: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r4);
|
|
display_pinned_message(6, 25, "A1: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r5);
|
|
display_pinned_message(7, 25, "A2: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r6);
|
|
display_pinned_message(8, 25, "A3: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r7);
|
|
display_pinned_message(9, 25, "A4: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r8);
|
|
display_pinned_message(10, 25, "A5: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r9);
|
|
display_pinned_message(11, 25, "T0: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r12);
|
|
display_pinned_message(12, 25, "T1: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r13);
|
|
display_pinned_message(13, 25, "T2: %0" GP_REG_DIGITS "x", (uintptr_t)system_context->r14);
|
|
|
|
display_pinned_message(0, 50, "Stack:");
|
|
for (int i = 0; i < 12; i++) {
|
|
uintptr_t addr = system_context->r3 + sizeof(reg_t)*(11 - i);
|
|
reg_t data = *(reg_t *)addr;
|
|
display_pinned_message(1 + i, 50, "%0" ADR_DIGITS "x %0" GP_REG_DIGITS "x", addr, (uintptr_t)data);
|
|
}
|
|
|
|
clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1);
|
|
prints(ROW_FOOTER, 0, "Press any key to reboot...");
|
|
|
|
while (get_key() == 0) { }
|
|
reboot();
|
|
}
|