#------------------------------------------------------------------------------ | |
# | |
# Start for Loongson LoongArch processor | |
# | |
# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR> | |
# | |
# SPDX-License-Identifier: BSD-2-Clause-Patent | |
# | |
# @par Glossary: | |
# - CSR - CPU Status Register | |
# - EBASE - Exception Base Address | |
#------------------------------------------------------------------------------ | |
#ifndef __ASSEMBLY__ | |
#define __ASSEMBLY__ | |
#endif | |
#include <Library/BaseMemoryLib.h> | |
#include <Register/LoongArch64/Csr.h> | |
#include <Protocol/DebugSupport.h> | |
#define BOOTCORE_ID 0 | |
// | |
// For coding convenience, define the maximum valid | |
// LoongArch exception. | |
// Since UEFI V2.11, it will be present in DebugSupport.h. | |
// | |
#define MAX_LOONGARCH_EXCEPTION 64 | |
ASM_GLOBAL ASM_PFX(_ModuleEntryPoint) | |
ASM_PFX(_ModuleEntryPoint): | |
/* Disable global interrupt */ | |
bl DisableInterrupts | |
/* Disable all local interrupt */ | |
li.w $a0, 0x1FFF | |
bl DisableLocalInterrupts | |
/* Read physical cpu number id */ | |
bl GetApicId | |
li.d $t0, BOOTCORE_ID //0 | |
bne $a0, $t0, SlaveMain | |
/* Set BSP stack */ | |
li.d $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize) # stack base | |
move $sp, $t0 | |
addi.d $sp, $sp, -0x8 | |
/* Load the exception vector base address */ | |
li.d $s0, FixedPcdGet64(PcdLoongArchExceptionVectorBaseAddress) | |
/* Construct SEC and PEI step exception environment */ | |
la.pcrel $a1, ExceptionEntryStart | |
la.pcrel $t0, ExceptionEntryEnd | |
sub.d $a2, $t0, $a1 | |
li.w $t0, (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512 | |
bgeu $a2, $t0, DeadLoop | |
move $a0, $s0 | |
bl CopyMem | |
/* Configure BSP reset ebase */ | |
move $a0, $s0 | |
bl SetExceptionBaseAddress | |
CallEntry: | |
/* Call C function make sure parameter true */ | |
li.d $a0, FixedPcdGet64(PcdOvmfFdBaseAddress) # FW base | |
addi.d $a1, $sp, 0x8 | |
bl SecCoreStartupWithStack | |
# End of _ModuleEntryPoint | |
ASM_PFX(ClearMailBox): | |
/* Clear mailbox */ | |
li.d $t1, LOONGARCH_IOCSR_MBUF3 | |
iocsrwr.d $zero, $t1 | |
li.d $t1, LOONGARCH_IOCSR_MBUF2 | |
iocsrwr.d $zero, $t1 | |
li.d $t1, LOONGARCH_IOCSR_MBUF1 | |
iocsrwr.d $zero, $t1 | |
li.d $t1, LOONGARCH_IOCSR_MBUF0 | |
iocsrwr.d $zero, $t1 | |
jirl $zero, $ra, 0 | |
# End of ClearMailBox | |
ASM_PFX(EnableIPI): | |
/* Enable IPI interrupt */ | |
li.w $t1, BIT12 | |
csrxchg $t1, $t1, LOONGARCH_CSR_ECFG | |
li.w $t2, 0xFFFFFFFFU | |
li.d $t1, LOONGARCH_IOCSR_IPI_EN | |
iocsrwr.w $t2, $t1 | |
jirl $zero, $ra, 0 | |
# End of EeableIPI | |
#/** | |
# Get APIC ID for every CPU. | |
# | |
# @param NULL | |
# @return APICID | |
# | |
# UINTN | |
# EFI_API | |
# GetApicId ( | |
# VOID | |
# ) | |
#**/ | |
ASM_PFX(GetApicId): | |
csrrd $a0, LOONGARCH_CSR_CPUNUM | |
andi $a0, $a0, 0x3ff | |
jirl $zero, $ra, 0 | |
# End of GetApicId | |
ASM_PFX(ApInitStack): | |
li.d $t1, SIZE_1KB | |
csrrd $t0, LOONGARCH_CSR_TMID | |
mul.d $t1, $t0, $t1 | |
li.d $t2, FixedPcdGet32(PcdCpuMaxLogicalProcessorNumber) | |
bgeu $t0, $t2, DeadLoop | |
li.d $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize) - SIZE_64KB | |
sub.d $sp, $t0, $t1 | |
addi.d $sp, $sp, -0x8 | |
jirl $zero, $ra, 0 | |
# End of ApInitStack | |
ASM_PFX(SlaveMain): | |
/* Set AP exception handle in flash */ | |
la.pcrel $a0, ApException | |
bl SetExceptionBaseAddress | |
/* Clean up local mail box and open INT */ | |
bl ClearMailBox | |
bl EnableIPI | |
bl EnableInterrupts | |
WaitForWake: | |
/* Wait for wakeup */ | |
bl CpuSleep | |
b WaitForWake | |
# End of SlaveMain | |
.align 12 | |
ASM_PFX(ApException): | |
csrrd $t0, LOONGARCH_CSR_ESTAT | |
srli.d $t0, $t0, 12 | |
andi $t0, $t0, 0x1 | |
beqz $t0, DeadLoop | |
li.d $t0, LOONGARCH_IOCSR_IPI_STATUS | |
iocsrrd.w $t1, $t0 | |
li.d $t0, LOONGARCH_IOCSR_IPI_CLEAR | |
iocsrwr.w $t1, $t0 | |
/* Read mail buf and jump to specified entry */ | |
li.d $t1, LOONGARCH_IOCSR_MBUF0 | |
iocsrrd.d $t0, $t1 | |
beqz $t0, OutOfException | |
csrwr $t0, LOONGARCH_CSR_ERA | |
li.d $t0, LOONGARCH_IOCSR_MBUF3 | |
iocsrrd.d $a1, $t0 | |
bl ClearMailBox | |
beqz $a1, NoParameterCall | |
// | |
// If the parameters are not NULL, then calling happened in FW ENV. | |
// Set the EBASE to be the same as BSP. | |
// | |
li.d $a0, FixedPcdGet64(PcdLoongArchExceptionVectorBaseAddress) | |
bl SetExceptionBaseAddress | |
bl ApInitStack | |
bl GetApicId | |
b OutOfException | |
NoParameterCall: | |
li.w $t0, BIT2 // IE | |
csrxchg $zero, $t0, LOONGARCH_CSR_PRMD // Clean PIE | |
OutOfException: | |
ertn | |
# End of ApException | |
ASM_PFX(DeadLoop): | |
b DeadLoop | |
# End of DeadLoop | |
.end |