UefiCpuPkg: Add CPU exception library for LoongArch

Added LoongArch exception handler into CpuExceptionHandlerLib.

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4734

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
This commit is contained in:
Chao Li
2024-03-08 16:24:12 +08:00
committed by mergify[bot]
parent 439030bc37
commit 7750468c37
8 changed files with 1273 additions and 9 deletions

View File

@@ -0,0 +1,268 @@
/** @file ArchExceptionHandler.c
LoongArch64 CPU Exception Handler.
Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h>
#include <Register/LoongArch64/Csr.h>
#include "ExceptionCommon.h"
/**
Get Exception Type
@param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
@return LoongArch64 exception type.
**/
EFI_EXCEPTION_TYPE
EFIAPI
GetExceptionType (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
EFI_EXCEPTION_TYPE ExceptionType;
ExceptionType = (SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC);
return ExceptionType;
}
/**
Get Interrupt Type
@param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
@return LoongArch64 intrrupt type.
**/
EFI_EXCEPTION_TYPE
EFIAPI
GetInterruptType (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
EFI_EXCEPTION_TYPE InterruptType;
for (InterruptType = 0; InterruptType <= EXCEPT_LOONGARCH_INT_IPI; InterruptType++) {
if (SystemContext.SystemContextLoongArch64->ESTAT & (1 << InterruptType)) {
//
// 0 - EXCEPT_LOONGARCH_INT_SIP0
// 1 - EXCEPT_LOONGARCH_INT_SIP1
// 2 - EXCEPT_LOONGARCH_INT_IP0
// 3 - EXCEPT_LOONGARCH_INT_IP1
// 4 - EXCEPT_LOONGARCH_INT_IP2
// 5 - EXCEPT_LOONGARCH_INT_IP3
// 6 - EXCEPT_LOONGARCH_INT_IP4
// 7 - EXCEPT_LOONGARCH_INT_IP5
// 8 - EXCEPT_LOONGARCH_INT_IP6
// 9 - EXCEPT_LOONGARCH_INT_IP7
// 10 - EXCEPT_LOONGARCH_INT_PMC
// 11 - EXCEPT_LOONGARCH_INT_TIMER
// 12 - EXCEPT_LOONGARCH_INT_IPI
// Greater than EXCEPT_LOONGARCH_INI_IPI is currently invalid.
//
return InterruptType;
}
}
//
// Invalid IRQ
//
return 0xFF;
}
/**
Display CPU information.
@param ExceptionType Exception type.
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
**/
VOID
EFIAPI
DumpCpuContext (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
InternalPrintMessage (
"\n!!!! LoongArch64 Exception Type - %02x(%a) !!!!\n",
ExceptionType,
GetExceptionNameStr (ExceptionType)
);
//
// Dump TLB refill ERA and BADV
//
if (ExceptionType == (mExceptionKnownNameNum - 1)) {
InternalPrintMessage ("TLB refill ERA 0x%llx\n", (CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL)));
InternalPrintMessage ("TLB refill BADV 0x%llx\n", CsrRead (LOONGARCH_CSR_TLBRBADV));
}
//
// Dump the general registers
//
InternalPrintMessage (
"Zero - 0x%016lx, RA - 0x%016lx, TP - 0x%016lx, SP - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R0,
SystemContext.SystemContextLoongArch64->R1,
SystemContext.SystemContextLoongArch64->R2,
SystemContext.SystemContextLoongArch64->R3
);
InternalPrintMessage (
" A0 - 0x%016lx, A1 - 0x%016lx, A2 - 0x%016lx, A3 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R4,
SystemContext.SystemContextLoongArch64->R5,
SystemContext.SystemContextLoongArch64->R6,
SystemContext.SystemContextLoongArch64->R7
);
InternalPrintMessage (
" A4 - 0x%016lx, A5 - 0x%016lx, A6 - 0x%016lx, A7 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R8,
SystemContext.SystemContextLoongArch64->R9,
SystemContext.SystemContextLoongArch64->R10,
SystemContext.SystemContextLoongArch64->R11
);
InternalPrintMessage (
" T0 - 0x%016lx, T1 - 0x%016lx, T2 - 0x%016lx, T3 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R12,
SystemContext.SystemContextLoongArch64->R13,
SystemContext.SystemContextLoongArch64->R14,
SystemContext.SystemContextLoongArch64->R15
);
InternalPrintMessage (
" T4 - 0x%016lx, T5 - 0x%016lx, T6 - 0x%016lx, T7 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R16,
SystemContext.SystemContextLoongArch64->R17,
SystemContext.SystemContextLoongArch64->R18,
SystemContext.SystemContextLoongArch64->R19
);
InternalPrintMessage (
" T8 - 0x%016lx, R21 - 0x%016lx, FP - 0x%016lx, S0 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R20,
SystemContext.SystemContextLoongArch64->R21,
SystemContext.SystemContextLoongArch64->R22,
SystemContext.SystemContextLoongArch64->R23
);
InternalPrintMessage (
" S1 - 0x%016lx, S2 - 0x%016lx, S3 - 0x%016lx, S4 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R24,
SystemContext.SystemContextLoongArch64->R25,
SystemContext.SystemContextLoongArch64->R26,
SystemContext.SystemContextLoongArch64->R27
);
InternalPrintMessage (
" S5 - 0x%016lx, S6 - 0x%016lx, S7 - 0x%016lx, S8 - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->R28,
SystemContext.SystemContextLoongArch64->R29,
SystemContext.SystemContextLoongArch64->R30,
SystemContext.SystemContextLoongArch64->R31
);
InternalPrintMessage ("\n");
//
// Dump the CSR registers
//
InternalPrintMessage (
"CRMD - 0x%016lx, PRMD - 0x%016lx, EUEN - 0x%016lx, MISC - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->CRMD,
SystemContext.SystemContextLoongArch64->PRMD,
SystemContext.SystemContextLoongArch64->EUEN,
SystemContext.SystemContextLoongArch64->MISC
);
InternalPrintMessage (
"ECFG - 0x%016lx, ESTAT - 0x%016lx, ERA - 0x%016lx, BADV - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->ECFG,
SystemContext.SystemContextLoongArch64->ESTAT,
SystemContext.SystemContextLoongArch64->ERA,
SystemContext.SystemContextLoongArch64->BADV
);
InternalPrintMessage (
"BADI - 0x%016lx\n",
SystemContext.SystemContextLoongArch64->BADI
);
}
/**
Display CPU information.
@param ExceptionType Exception type.
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
**/
VOID
DumpImageAndCpuContent (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
DumpCpuContext (ExceptionType, SystemContext);
if (ExceptionType == (mExceptionKnownNameNum - 1)) {
//
// Dump TLB refill image info
//
DumpModuleImageInfo ((CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL)));
} else {
DumpModuleImageInfo (SystemContext.SystemContextLoongArch64->ERA);
}
}
/**
IPI Interrupt Handler.
@param InterruptType The type of interrupt that occurred
@param SystemContext A pointer to the system context when the interrupt occurred
**/
VOID
EFIAPI
IpiInterruptHandler (
IN EFI_EXCEPTION_TYPE InterruptType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
UINTN ResumeVector;
UINTN Parameter;
//
// Clear interrupt.
//
IoCsrWrite32 (LOONGARCH_IOCSR_IPI_CLEAR, IoCsrRead32 (LOONGARCH_IOCSR_IPI_STATUS));
//
// Get the resume vector and parameter if populated.
//
ResumeVector = IoCsrRead64 (LOONGARCH_IOCSR_MBUF0);
Parameter = IoCsrRead64 (LOONGARCH_IOCSR_MBUF3);
//
// Clean up current processor mailbox 0 and mailbox 3.
//
IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0);
IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0);
//
// If mailbox 0 is non-NULL, it means that the BSP or other cores called the IPI to wake
// up the current core and let it use the resume vector stored in mailbox 0.
//
// If both the resume vector and parameter are non-NULL, it means that the IPI was
// called in the BIOS.
//
// The situation where the resume vector is non-NULL and the parameter is NULL has been
// processed after the exception entry is pushed onto the stack.
//
if ((ResumeVector != 0) && (Parameter != 0)) {
SystemContext.SystemContextLoongArch64->ERA = ResumeVector;
//
// Set $a0 as APIC ID and $a1 as parameter value.
//
SystemContext.SystemContextLoongArch64->R4 = CsrRead (LOONGARCH_CSR_CPUNUM);
SystemContext.SystemContextLoongArch64->R5 = Parameter;
}
MemoryFence ();
}

View File

@@ -0,0 +1,366 @@
#------------------------------------------------------------------------------
#
# LoongArch64 ASM exception handler
#
# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#------------------------------------------------------------------------------
#include <Library/BaseLib.h>
#include <Library/CpuLib.h>
#include <Register/LoongArch64/Csr.h>
#define RSIZE 8 // 64 bit mode register size
#define GP_REG_CONTEXT_SIZE 32 * RSIZE // General-purpose registers size
#define FP_REG_CONTEXT_SIZE 34 * RSIZE // Floating-point registers size
#define CSR_REG_CONTEXT_SIZE 9 * RSIZE // CSR registers size
ASM_GLOBAL ASM_PFX(ExceptionEntry)
ASM_GLOBAL ASM_PFX(ExceptionEntryStart)
ASM_GLOBAL ASM_PFX(ExceptionEntryEnd)
ASM_PFX(ExceptionEntry):
move $s0, $a0
bl GetExceptionType // Exception type stored in register a0
move $a1, $s0 // SystemContxt
bl CommonExceptionHandler
PopContext:
//
// Not sure if interrupts are turned on during the exception handler, anyway disable interrupts here.
// It will be turned on when the instruction 'ertn' is executed.
//
bl DisableInterrupts
bl GetExceptionType // Get current exception type, and stored in register a0
// Check whether the FPE is changed during interrupt handler, if ture restore it.
ld.d $t1, $sp, (LOONGARCH_CSR_EUEN * RSIZE + GP_REG_CONTEXT_SIZE)
csrrd $t0, LOONGARCH_CSR_EUEN // Current EUEN
andi $t0, $t0, CSR_EUEN_FPEN
andi $t1, $t1, CSR_EUEN_FPEN
li.d $t2, EXCEPT_LOONGARCH_INT
bne $a0, $t2, PopRegs
beq $t0, $t1, PopRegs
beqz $t1, CloseFP
bl EnableFloatingPointUnits
b PopRegs
CloseFP:
bl DisableFloatingPointUnits
PopRegs:
//
// Pop CSR reigsters
//
addi.d $sp, $sp, GP_REG_CONTEXT_SIZE
ld.d $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE
csrwr $t0, LOONGARCH_CSR_CRMD
ld.d $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE
csrwr $t0, LOONGARCH_CSR_PRMD
ld.d $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE
csrwr $t0, LOONGARCH_CSR_ECFG
ld.d $t0, $sp, LOONGARCH_CSR_ERA * RSIZE
csrwr $t0, LOONGARCH_CSR_ERA
addi.d $sp, $sp, CSR_REG_CONTEXT_SIZE // Fource change the stack pointer befor pop the FP registers.
beqz $t1, PopGP // If the FPE not set, only pop the GP registers.
//
// Pop FP registers
//
fld.d $fa0, $sp, 0 * RSIZE
fld.d $fa1, $sp, 1 * RSIZE
fld.d $fa2, $sp, 2 * RSIZE
fld.d $fa3, $sp, 3 * RSIZE
fld.d $fa4, $sp, 4 * RSIZE
fld.d $fa5, $sp, 5 * RSIZE
fld.d $fa6, $sp, 6 * RSIZE
fld.d $fa7, $sp, 7 * RSIZE
fld.d $ft0, $sp, 8 * RSIZE
fld.d $ft1, $sp, 9 * RSIZE
fld.d $ft2, $sp, 10 * RSIZE
fld.d $ft3, $sp, 11 * RSIZE
fld.d $ft4, $sp, 12 * RSIZE
fld.d $ft5, $sp, 13 * RSIZE
fld.d $ft6, $sp, 14 * RSIZE
fld.d $ft7, $sp, 15 * RSIZE
fld.d $ft8, $sp, 16 * RSIZE
fld.d $ft9, $sp, 17 * RSIZE
fld.d $ft10, $sp, 18 * RSIZE
fld.d $ft11, $sp, 19 * RSIZE
fld.d $ft12, $sp, 20 * RSIZE
fld.d $ft13, $sp, 21 * RSIZE
fld.d $ft14, $sp, 22 * RSIZE
fld.d $ft15, $sp, 23 * RSIZE
fld.d $fs0, $sp, 24 * RSIZE
fld.d $fs1, $sp, 25 * RSIZE
fld.d $fs2, $sp, 26 * RSIZE
fld.d $fs3, $sp, 27 * RSIZE
fld.d $fs4, $sp, 28 * RSIZE
fld.d $fs5, $sp, 29 * RSIZE
fld.d $fs6, $sp, 30 * RSIZE
fld.d $fs7, $sp, 31 * RSIZE
ld.d $t0, $sp, 32 * RSIZE
movgr2fcsr $r0, $t0 // Pop the fcsr0 register.
//
// Pop the fcc0-fcc7 registers.
//
ld.d $t0, $sp, 33 * RSIZE
bstrpick.d $t1, $t0, 7, 0
movgr2cf $fcc0, $t1
bstrpick.d $t1, $t0, 15, 8
movgr2cf $fcc1, $t1
bstrpick.d $t1, $t0, 23, 16
movgr2cf $fcc2, $t1
bstrpick.d $t1, $t0, 31, 24
movgr2cf $fcc3, $t1
bstrpick.d $t1, $t0, 39, 32
movgr2cf $fcc4, $t1
bstrpick.d $t1, $t0, 47, 40
movgr2cf $fcc5, $t1
bstrpick.d $t1, $t0, 55, 48
movgr2cf $fcc6, $t1
bstrpick.d $t1, $t0, 63, 56
movgr2cf $fcc7, $t1
PopGP:
//
// Pop GP registers
//
addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
ld.d $ra, $sp, 1 * RSIZE
ld.d $tp, $sp, 2 * RSIZE
ld.d $a0, $sp, 4 * RSIZE
ld.d $a1, $sp, 5 * RSIZE
ld.d $a2, $sp, 6 * RSIZE
ld.d $a3, $sp, 7 * RSIZE
ld.d $a4, $sp, 8 * RSIZE
ld.d $a5, $sp, 9 * RSIZE
ld.d $a6, $sp, 10 * RSIZE
ld.d $a7, $sp, 11 * RSIZE
ld.d $t0, $sp, 12 * RSIZE
ld.d $t1, $sp, 13 * RSIZE
ld.d $t2, $sp, 14 * RSIZE
ld.d $t3, $sp, 15 * RSIZE
ld.d $t4, $sp, 16 * RSIZE
ld.d $t5, $sp, 17 * RSIZE
ld.d $t6, $sp, 18 * RSIZE
ld.d $t7, $sp, 19 * RSIZE
ld.d $t8, $sp, 20 * RSIZE
ld.d $r21, $sp, 21 * RSIZE
ld.d $fp, $sp, 22 * RSIZE
ld.d $s0, $sp, 23 * RSIZE
ld.d $s1, $sp, 24 * RSIZE
ld.d $s2, $sp, 25 * RSIZE
ld.d $s3, $sp, 26 * RSIZE
ld.d $s4, $sp, 27 * RSIZE
ld.d $s5, $sp, 28 * RSIZE
ld.d $s6, $sp, 29 * RSIZE
ld.d $s7, $sp, 30 * RSIZE
ld.d $s8, $sp, 31 * RSIZE
ld.d $sp, $sp, 3 * RSIZE
ertn // Returen from exception.
//
// End of ExceptionEntry
//
ASM_PFX(ExceptionEntryStart):
//
// Store the old stack pointer in preparation for pushing the exception context onto the new stack.
//
csrwr $sp, LOONGARCH_CSR_KS0
csrrd $sp, LOONGARCH_CSR_KS0
//
// Push GP registers
//
addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + FP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
st.d $zero, $sp, 0 * RSIZE
st.d $ra, $sp, 1 * RSIZE
st.d $tp, $sp, 2 * RSIZE
st.d $a0, $sp, 4 * RSIZE
st.d $a1, $sp, 5 * RSIZE
st.d $a2, $sp, 6 * RSIZE
st.d $a3, $sp, 7 * RSIZE
st.d $a4, $sp, 8 * RSIZE
st.d $a5, $sp, 9 * RSIZE
st.d $a6, $sp, 10 * RSIZE
st.d $a7, $sp, 11 * RSIZE
st.d $t0, $sp, 12 * RSIZE
st.d $t1, $sp, 13 * RSIZE
st.d $t2, $sp, 14 * RSIZE
st.d $t3, $sp, 15 * RSIZE
st.d $t4, $sp, 16 * RSIZE
st.d $t5, $sp, 17 * RSIZE
st.d $t6, $sp, 18 * RSIZE
st.d $t7, $sp, 19 * RSIZE
st.d $t8, $sp, 20 * RSIZE
st.d $r21, $sp, 21 * RSIZE
st.d $fp, $sp, 22 * RSIZE
st.d $s0, $sp, 23 * RSIZE
st.d $s1, $sp, 24 * RSIZE
st.d $s2, $sp, 25 * RSIZE
st.d $s3, $sp, 26 * RSIZE
st.d $s4, $sp, 27 * RSIZE
st.d $s5, $sp, 28 * RSIZE
st.d $s6, $sp, 29 * RSIZE
st.d $s7, $sp, 30 * RSIZE
st.d $s8, $sp, 31 * RSIZE
csrrd $t0, LOONGARCH_CSR_KS0 // Read the old stack pointer.
st.d $t0, $sp, 3 * RSIZE
//
// Push CSR registers
//
addi.d $sp, $sp, GP_REG_CONTEXT_SIZE
csrrd $t0, LOONGARCH_CSR_CRMD
st.d $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE
csrrd $t0, LOONGARCH_CSR_PRMD
st.d $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE
csrrd $t0, LOONGARCH_CSR_EUEN
st.d $t0, $sp, LOONGARCH_CSR_EUEN * RSIZE
csrrd $t0, LOONGARCH_CSR_MISC
st.d $t0, $sp, LOONGARCH_CSR_MISC * RSIZE
csrrd $t0, LOONGARCH_CSR_ECFG
st.d $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE
csrrd $t0, LOONGARCH_CSR_ESTAT
st.d $t0, $sp, LOONGARCH_CSR_ESTAT * RSIZE
csrrd $t0, LOONGARCH_CSR_ERA
st.d $t0, $sp, LOONGARCH_CSR_ERA * RSIZE
csrrd $t0, LOONGARCH_CSR_BADV
st.d $t0, $sp, LOONGARCH_CSR_BADV * RSIZE
csrrd $t0, LOONGARCH_CSR_BADI
st.d $t0, $sp, LOONGARCH_CSR_BADI * RSIZE
//
// Push FP registers
//
addi.d $sp, $sp, CSR_REG_CONTEXT_SIZE
csrrd $t0, LOONGARCH_CSR_EUEN
andi $t0, $t0, CSR_EUEN_FPEN
beqz $t0, PushRegDone
fst.d $fa0, $sp, 0 * RSIZE
fst.d $fa1, $sp, 1 * RSIZE
fst.d $fa2, $sp, 2 * RSIZE
fst.d $fa3, $sp, 3 * RSIZE
fst.d $fa4, $sp, 4 * RSIZE
fst.d $fa5, $sp, 5 * RSIZE
fst.d $fa6, $sp, 6 * RSIZE
fst.d $fa7, $sp, 7 * RSIZE
fst.d $ft0, $sp, 8 * RSIZE
fst.d $ft1, $sp, 9 * RSIZE
fst.d $ft2, $sp, 10 * RSIZE
fst.d $ft3, $sp, 11 * RSIZE
fst.d $ft4, $sp, 12 * RSIZE
fst.d $ft5, $sp, 13 * RSIZE
fst.d $ft6, $sp, 14 * RSIZE
fst.d $ft7, $sp, 15 * RSIZE
fst.d $ft8, $sp, 16 * RSIZE
fst.d $ft9, $sp, 17 * RSIZE
fst.d $ft10, $sp, 18 * RSIZE
fst.d $ft11, $sp, 19 * RSIZE
fst.d $ft12, $sp, 20 * RSIZE
fst.d $ft13, $sp, 21 * RSIZE
fst.d $ft14, $sp, 22 * RSIZE
fst.d $ft15, $sp, 23 * RSIZE
fst.d $fs0, $sp, 24 * RSIZE
fst.d $fs1, $sp, 25 * RSIZE
fst.d $fs2, $sp, 26 * RSIZE
fst.d $fs3, $sp, 27 * RSIZE
fst.d $fs4, $sp, 28 * RSIZE
fst.d $fs5, $sp, 29 * RSIZE
fst.d $fs6, $sp, 30 * RSIZE
fst.d $fs7, $sp, 31 * RSIZE
movfcsr2gr $t3, $r0
st.d $t3, $sp, 32 * RSIZE // Push the FCSR0 register.
//
// Push the fcc0-fcc7 registers.
//
movcf2gr $t3, $fcc0
or $t2, $t3, $zero
movcf2gr $t3, $fcc1
bstrins.d $t2, $t3, 0xf, 0x8
movcf2gr $t3, $fcc2
bstrins.d $t2, $t3, 0x17, 0x10
movcf2gr $t3, $fcc3
bstrins.d $t2, $t3, 0x1f, 0x18
movcf2gr $t3, $fcc4
bstrins.d $t2, $t3, 0x27, 0x20
movcf2gr $t3, $fcc5
bstrins.d $t2, $t3, 0x2f, 0x28
movcf2gr $t3, $fcc6
bstrins.d $t2, $t3, 0x37, 0x30
movcf2gr $t3, $fcc7
bstrins.d $t2, $t3, 0x3f, 0x38
st.d $t2, $sp, 33 * RSIZE
//
// Push exception context down
//
PushRegDone:
//
// Process IPI only when mailbox3 is NULL and mailbox0 is no-NULL.
//
li.d $t0, LOONGARCH_IOCSR_MBUF0
iocsrrd.d $a0, $t0
beqz $a0, EntryConmmonHanlder
li.d $t0, LOONGARCH_IOCSR_MBUF3
iocsrrd.d $t1, $t0
bnez $t1, EntryConmmonHanlder
csrrd $t0, LOONGARCH_CSR_ESTAT
srli.d $t0, $t0, 12
andi $t0, $t0, 0x1
beqz $t0, EntryConmmonHanlder
//
// Clean up current processor mailbox 0 and mailbox 3.
//
li.d $t0, LOONGARCH_IOCSR_MBUF0
iocsrwr.d $zero, $t0
li.d $t0, LOONGARCH_IOCSR_MBUF3
iocsrwr.d $zero, $t0
//
// Clear IPI interrupt.
//
li.d $t0, LOONGARCH_IOCSR_IPI_STATUS
iocsrrd.w $t1, $t0
li.d $t0, LOONGARCH_IOCSR_IPI_CLEAR
iocsrwr.w $t1, $t0
//
// Only kernel stage BSP calls IPI without parameters. Clean up the PIE and make sure
// global interrupts are turned off for the current processor when jumping to the kernel.
//
csrwr $a0, LOONGARCH_CSR_ERA // Update ERA
li.w $t0, BIT2 // IE
csrxchg $zero, $t0, LOONGARCH_CSR_PRMD // Clean PIE
//
// Return this exception and jump to kernel using ERA.
//
ertn
EntryConmmonHanlder:
addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
move $a0, $sp
la.abs $ra, ExceptionEntry
jirl $zero, $ra, 0
ASM_PFX(ExceptionEntryEnd):
.end