26#define RISCV_PG_V BIT0
27#define RISCV_PG_R BIT1
28#define RISCV_PG_W BIT2
29#define RISCV_PG_X BIT3
30#define RISCV_PG_G BIT5
31#define RISCV_PG_A BIT6
32#define RISCV_PG_D BIT7
33#define PTE_ATTRIBUTES_MASK 0xE
35#define PTE_PPN_MASK 0x3FFFFFFFFFFC00ULL
36#define PTE_PPN_SHIFT 10
37#define RISCV_MMU_PAGE_SHIFT 12
39#define RISCV_CPU_FEATURE_PBMT_BITMASK BIT2
40#define PTE_PBMT_NC BIT61
41#define PTE_PBMT_IO BIT62
42#define PTE_PBMT_MASK (PTE_PBMT_NC | PTE_PBMT_IO)
44STATIC UINTN mModeSupport[] = { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MODE_SV39, SATP_MODE_OFF };
62 return ((RiscVGetSupervisorAddressTranslationRegister () &
63 SATP64_MODE) != (SATP_MODE_OFF << SATP64_MODE_SHIFT));
78 return (RiscVGetSupervisorAddressTranslationRegister () & SATP64_PPN) <<
97 if (((Entry & RISCV_PG_V) == 0) ||
98 (((Entry & (RISCV_PG_R | RISCV_PG_W)) == RISCV_PG_W)))
121 return Entry | RISCV_PG_G | RISCV_PG_V;
140 (Entry & (RISCV_PG_X | RISCV_PG_R));
177 Entry &= ~(UINT64)(RISCV_PG_X | RISCV_PG_W | RISCV_PG_R);
196 IN UINT64 RegionStart,
197 IN BOOLEAN IsLiveBlockMapping
221 return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT);
242 Ppn = ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT);
243 ASSERT (~(Ppn & ~PTE_PPN_MASK));
244 Entry &= ~PTE_PPN_MASK;
258 IN UINT64 *TranslationTable,
264 if (Level < mMaxRootTableLevel - 1) {
265 for (Index = 0; Index < mTableEntryCount; Index++) {
269 RISCV_MMU_PAGE_SHIFT),
297 IN UINT64 RegionStart,
299 IN UINT64 AttributeSetMask,
300 IN UINT64 AttributeClearMask,
301 IN UINT64 *PageTable,
303 IN BOOLEAN TableIsLive
312 UINT64 *TranslationTable;
313 BOOLEAN NextTableIsLive;
315 ASSERT (Level < mMaxRootTableLevel);
316 ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0);
318 BlockShift = (mMaxRootTableLevel - Level - 1) * mBitPerLevel + RISCV_MMU_PAGE_SHIFT;
323 "%a(%d): %LX - %LX set %LX clr %LX\n",
332 for ( ; RegionStart < RegionEnd; RegionStart = BlockEnd) {
333 BlockEnd =
MIN (RegionEnd, (RegionStart | BlockMask) + 1);
334 Entry = &PageTable[(RegionStart >> BlockShift) & (mTableEntryCount - 1)];
344 (((RegionStart | BlockEnd) & BlockMask) != 0) ||
IsTableEntry (*Entry))
346 ASSERT (Level < mMaxRootTableLevel - 1);
353 if (TranslationTable ==
NULL) {
354 return EFI_OUT_OF_RESOURCES;
357 ZeroMem (TranslationTable, EFI_PAGE_SIZE);
365 RegionStart & ~BlockMask,
366 (RegionStart | BlockMask) + 1,
367 *Entry & PTE_ATTRIBUTES_MASK,
373 if (EFI_ERROR (Status)) {
384 NextTableIsLive =
FALSE;
386 TranslationTable = (UINT64 *)(
GetPpnfromPte (*Entry) << RISCV_MMU_PAGE_SHIFT);
387 NextTableIsLive = TableIsLive;
402 if (EFI_ERROR (Status)) {
418 EntryValue =
SetPpnToPte (0, (UINT64)TranslationTable);
428 EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask;
434 if ((AttributeSetMask & RISCV_PG_R) != 0) {
435 EntryValue |= RISCV_PG_A;
438 if ((AttributeSetMask & RISCV_PG_W) != 0) {
439 EntryValue |= RISCV_PG_D;
442 EntryValue =
SetPpnToPte (EntryValue, RegionStart);
469 IN UINT64 RegionStart,
470 IN UINT64 RegionLength,
471 IN UINT64 AttributeSetMask,
472 IN UINT64 AttributeClearMask,
473 IN UINT64 *RootTable,
474 IN BOOLEAN TableIsLive
477 if (((RegionStart | RegionLength) & EFI_PAGE_MASK) != 0) {
478 return EFI_INVALID_PARAMETER;
483 RegionStart + RegionLength,
505 IN UINT64 GcdAttributes,
506 OUT UINT64 *RiscVAttributes
509 UINT64 CacheTypeMask;
510 BOOLEAN PmbtExtEnabled;
512 if (RiscVAttributes ==
NULL) {
513 return EFI_INVALID_PARAMETER;
516 *RiscVAttributes = RISCV_PG_R | RISCV_PG_W | RISCV_PG_X;
518 PmbtExtEnabled =
FALSE;
519 if ((
PcdGet64 (PcdRiscVFeatureOverride) & RISCV_CPU_FEATURE_PBMT_BITMASK) != 0) {
520 PmbtExtEnabled =
TRUE;
524 if ((GcdAttributes & EFI_MEMORY_RO) != 0) {
525 *RiscVAttributes &= ~(UINT64)(RISCV_PG_W);
529 if ((GcdAttributes & EFI_MEMORY_XP) != 0) {
530 *RiscVAttributes &= ~(UINT64)RISCV_PG_X;
533 CacheTypeMask = GcdAttributes & EFI_CACHE_ATTRIBUTE_MASK;
534 if ((CacheTypeMask != 0) &&
535 (((CacheTypeMask - 1) & CacheTypeMask) != 0))
539 "%a: More than one bit set in cache type mask (0x%LX)\n",
543 return EFI_INVALID_PARAMETER;
546 switch (CacheTypeMask) {
548 if (PmbtExtEnabled) {
549 *RiscVAttributes |= PTE_PBMT_IO;
554 if (PmbtExtEnabled) {
555 *RiscVAttributes |= PTE_PBMT_NC;
559 "%a: EFI_MEMORY_WC set but Pmbt extension not available\n",
593 UINT64 PageAttributesSet;
594 UINT64 PageAttributesClear;
598 if (EFI_ERROR (Status)) {
606 PageAttributesClear = PTE_ATTRIBUTES_MASK;
607 if ((
PcdGet64 (PcdRiscVFeatureOverride) & RISCV_CPU_FEATURE_PBMT_BITMASK) != 0) {
608 PageAttributesClear |= PTE_PBMT_MASK;
613 "%a: %LX: set attributes 0x%LX, clear attributes 0x%LX\n",
647 VOID *TranslationTable;
651 UINTN NumberOfDescriptors;
655 if (SatpMode >
PcdGet32 (PcdCpuRiscVMmuMaxSatpMode)) {
656 return EFI_DEVICE_ERROR;
663 mMaxRootTableLevel = 3;
665 mTableEntryCount = 512;
668 mMaxRootTableLevel = 4;
670 mTableEntryCount = 512;
673 mMaxRootTableLevel = 5;
675 mTableEntryCount = 512;
678 return EFI_INVALID_PARAMETER;
683 if (TranslationTable ==
NULL) {
684 return EFI_OUT_OF_RESOURCES;
687 ZeroMem (TranslationTable, mTableEntryCount *
sizeof (UINT64));
689 NumberOfDescriptors = 0;
691 Status =
gDS->GetMemorySpaceMap (
692 &NumberOfDescriptors,
697 for (Index = 0; Index < NumberOfDescriptors; Index++) {
701 MemoryMap[Index].BaseAddress,
702 MemoryMap[Index].Length,
703 RISCV_PG_R | RISCV_PG_W,
711 MemoryMap[Index].BaseAddress,
712 MemoryMap[Index].Length,
713 RISCV_PG_R | RISCV_PG_W | RISCV_PG_X,
727 Ppn = (UINT64)TranslationTable >> RISCV_MMU_PAGE_SHIFT;
728 ASSERT (!(Ppn & ~(SATP64_PPN)));
731 SatpReg |= (SatpMode <<
732 SATP64_MODE_SHIFT) & SATP64_MODE;
733 RiscVSetSupervisorAddressTranslationRegister (SatpReg);
735 if (SatpReg != RiscVGetSupervisorAddressTranslationRegister ()) {
738 "%a: HW does not support SATP mode:%d\n",
743 return EFI_DEVICE_ERROR;
774 for (Idx = 0; Idx <
ARRAY_SIZE (mModeSupport); Idx++) {
776 if (Status == EFI_DEVICE_ERROR) {
778 }
else if (EFI_ERROR (Status)) {
784 "%a: SATP mode %d successfully configured\n",
BOOLEAN EFIAPI GetInterruptState(VOID)
VOID EFIAPI EnableInterrupts(VOID)
VOID EFIAPI DisableInterrupts(VOID)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
STATIC BOOLEAN RiscVMmuEnabled(VOID)
STATIC UINT64 SetValidPte(IN UINT64 Entry)
EFI_STATUS EFIAPI RiscVSetMemoryAttributes(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes)
STATIC BOOLEAN IsValidPte(IN UINT64 Entry)
STATIC UINT64 GetPpnfromPte(IN UINT64 Entry)
STATIC VOID FreePageTablesRecursive(IN UINT64 *TranslationTable, IN UINTN Level)
STATIC EFI_STATUS UpdateRegionMapping(IN UINT64 RegionStart, IN UINT64 RegionLength, IN UINT64 AttributeSetMask, IN UINT64 AttributeClearMask, IN UINT64 *RootTable, IN BOOLEAN TableIsLive)
STATIC VOID ReplaceTableEntry(IN UINT64 *Entry, IN UINT64 Value, IN UINT64 RegionStart, IN BOOLEAN IsLiveBlockMapping)
STATIC UINT64 SetPpnToPte(UINT64 Entry, UINT64 Address)
STATIC EFI_STATUS GcdAttributeToPageAttribute(IN UINT64 GcdAttributes, OUT UINT64 *RiscVAttributes)
STATIC BOOLEAN IsTableEntry(IN UINT64 Entry)
STATIC EFI_STATUS UpdateRegionMappingRecursive(IN UINT64 RegionStart, IN UINT64 RegionEnd, IN UINT64 AttributeSetMask, IN UINT64 AttributeClearMask, IN UINT64 *PageTable, IN UINTN Level, IN BOOLEAN TableIsLive)
STATIC EFI_STATUS RiscVMmuSetSatpMode(UINTN SatpMode)
STATIC BOOLEAN IsBlockEntry(IN UINT64 Entry)
STATIC UINT64 SetTableEntry(IN UINT64 Entry)
STATIC UINT64 RiscVGetRootTranslateTable(VOID)
EFI_STATUS EFIAPI RiscVConfigureMmu(VOID)
VOID EFIAPI RiscVLocalTlbFlush(UINTN VirtAddr)
VOID EFIAPI RiscVLocalTlbFlushAll(VOID)
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define ARRAY_SIZE(Array)
#define ASSERT_EFI_ERROR(StatusParameter)
#define DEBUG(Expression)
#define PcdGet64(TokenName)
#define PcdGet32(TokenName)
@ EfiGcdMemoryTypeSystemMemory
@ EfiGcdMemoryTypeMemoryMappedIo
VOID *EFIAPI AllocatePages(IN UINTN Pages)
UINT64 EFI_PHYSICAL_ADDRESS