From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web11.2666.1684894246572406058 for ; Tue, 23 May 2023 19:10:47 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lichao@loongson.cn) Received: from loongson.cn (unknown [10.40.24.149]) by gateway (Coremail) with SMTP id _____8Dxd_Ejcm1kDEYAAA--.761S3; Wed, 24 May 2023 10:10:43 +0800 (CST) Received: from [10.40.24.149] (unknown [10.40.24.149]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Bx670jcm1kHYpyAA--.59648S3; Wed, 24 May 2023 10:10:43 +0800 (CST) Message-ID: Date: Wed, 24 May 2023 10:10:43 +0800 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.10.0 Subject: Re: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support MMU with SV39/48/57 mode To: devel@edk2.groups.io, tphan@ventanamicro.com Cc: michael.d.kinney@intel.com, gaoliming@byosoft.com.cn, zhiguang.liu@intel.com, sunilvl@ventanamicro.com, git@danielschaefer.me, andrei.warkentin@intel.com, "Ni, Ray" References: <20230414185815.2994-1-tphan@ventanamicro.com> <20230414185815.2994-4-tphan@ventanamicro.com> From: "Chao Li" In-Reply-To: <20230414185815.2994-4-tphan@ventanamicro.com> X-CM-TRANSID: AQAAf8Bx670jcm1kHYpyAA--.59648S3 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQABCGRsrP8NYwABs8 X-Coremail-Antispam: 1Uk129KBjvAXoWfXFWfKFy7CFWxtw4kXw47urg_yoW8ZF4xuo W7tF4kGw4rGw15ZryfCrn7Ww4IgF4ktws3XFn8Xa4jg3Z8Cw4q9w48Jan8K3ySk34xJFWD Gr95X3yxArWfWrn7n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf J3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnRJUUUvjb4IE77IF4wAFF20E14v26r1j 6r4UM7CY07I20VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1Y6r17M28lY4 IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l 84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVWxJVW8Jr 1l84ACjcxK6I8E87Iv6xkF7I0E14v26r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG 8wAqjxCEc2xF0cIa020Ex4CE44I27wAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aV AFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcVAKI48JMx8GjcxK6IxK0xII j40E5I8CrwCYjI0SjxkI62AI1cAE67vIY487MxAIw28IcxkI7VAKI48JMxC20s026xCaFV Cjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_JrI_JrWlx2IqxVCjr7xvwVAFwI0_JrI_JrWl x4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1j6r 1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVWUJVW8JwCI42IY6xAIw20EY4v20xvaj40_Jr0_ JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVWUJVW8JbIYCT nIWIevJa73UjIFyTuYvjxUzPfHUUUUU Content-Type: multipart/alternative; boundary="------------cpZvKmnKPh3gVNHwvlbUY0R9" --------------cpZvKmnKPh3gVNHwvlbUY0R9 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Dear all, I'm also porting MMU library of LoongArch64 to EDK2, I added it in to UefiCpuPkg and make it possible to use the same headers for both the no-IA32 and no-X64 platforms, and I also saw that IA32 and X64 added the CpuPageTableLib to UefiCpuPkg, this library are similar to MMU libraries. I have a question, should the MMU library be in the MdePkg or UefiCpuPkg? Thanks, Chao 在 2023/4/15 02:58, Tuan Phan 写道: > During CpuDxe initialization, MMU will be setup with the highest > mode that HW supports. > > Signed-off-by: Tuan Phan > --- > MdePkg/Include/Library/BaseRiscVMmuLib.h | 39 ++ > .../Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c | 569 ++++++++++++++++++ > .../BaseRiscVMmuLib/BaseRiscVMmuLib.inf | 25 + > MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S | 31 + > OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc | 1 + > OvmfPkg/RiscVVirt/Sec/Memory.c | 18 +- > UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c | 9 +- > UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h | 2 + > UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf | 2 + > 9 files changed, 678 insertions(+), 18 deletions(-) > create mode 100644 MdePkg/Include/Library/BaseRiscVMmuLib.h > create mode 100644 MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c > create mode 100644 MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > create mode 100644 MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S > > diff --git a/MdePkg/Include/Library/BaseRiscVMmuLib.h b/MdePkg/Include/Library/BaseRiscVMmuLib.h > new file mode 100644 > index 000000000000..f71d6a4a1e7b > --- /dev/null > +++ b/MdePkg/Include/Library/BaseRiscVMmuLib.h > @@ -0,0 +1,39 @@ > +/** @file > + > + Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.
> + Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef BASE_RISCV_MMU_LIB_H_ > +#define BASE_RISCV_MMU_LIB_H_ > + > +VOID > +EFIAPI > +RiscVLocalTlbFlushAll ( > + VOID > + ); > + > +VOID > +EFIAPI > +RiscVLocalTlbFlush ( > + UINTN VirtAddr > + ); > + > +EFI_STATUS > +EFIAPI > +RiscVSetMemoryAttributes ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes > + ); > + > +EFI_STATUS > +EFIAPI > +RiscVConfigureMmu ( > + VOID > + ); > + > +#endif /* BASE_RISCV_MMU_LIB_H_ */ > diff --git a/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c > new file mode 100644 > index 000000000000..230f34261d8b > --- /dev/null > +++ b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c > @@ -0,0 +1,569 @@ > +/** @file > +* MMU implementation for RISC-V > +* > +* Copyright (c) 2011-2020, ARM Limited. All rights reserved. > +* Copyright (c) 2016, Linaro Limited. All rights reserved. > +* Copyright (c) 2017, Intel Corporation. All rights reserved.
> +* Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
> +* > +* SPDX-License-Identifier: BSD-2-Clause-Patent > +* > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define RISCV_PG_V BIT0 > +#define RISCV_PG_R BIT1 > +#define RISCV_PG_W BIT2 > +#define RISCV_PG_X BIT3 > +#define RISCV_PG_G BIT5 > +#define RISCV_PG_A BIT6 > +#define RISCV_PG_D BIT7 > +#define PTE_ATTRIBUTES_MASK 0xE > + > +#define PTE_PPN_MASK 0x3FFFFFFFFFFC00ULL > +#define PTE_PPN_SHIFT 10 > +#define RISCV_MMU_PAGE_SHIFT 12 > + > +STATIC UINTN mMaxRootTableLevel; > +STATIC UINTN mBitPerLevel; > +STATIC UINTN mTableEntryCount; > + > +STATIC > +BOOLEAN > +RiscVMmuEnabled ( > + VOID > + ) > +{ > + return ((RiscVGetSupervisorAddressTranslationRegister () & > + SATP64_MODE) != (SATP_MODE_OFF << SATP64_MODE_SHIFT)); > +} > + > +STATIC > +UINTN > +RiscVGetRootTranslateTable ( > + VOID > + ) > +{ > + return (RiscVGetSupervisorAddressTranslationRegister () & SATP64_PPN) << > + RISCV_MMU_PAGE_SHIFT; > +} > + > +STATIC > +BOOLEAN > +IsValidPte ( > + IN UINTN Entry > + ) > +{ > + if (!(Entry & RISCV_PG_V) || > + (((Entry & (RISCV_PG_R | RISCV_PG_W)) == RISCV_PG_W))) > + { > + return FALSE; > + } > + > + return TRUE; > +} > + > +STATIC > +UINTN > +SetValidPte ( > + IN UINTN Entry > + ) > +{ > + /* Set Valid and Global mapping bits */ > + return Entry | RISCV_PG_G | RISCV_PG_V; > +} > + > +STATIC > +BOOLEAN > +IsBlockEntry ( > + IN UINTN Entry > + ) > +{ > + return IsValidPte (Entry) && > + (Entry & (RISCV_PG_X | RISCV_PG_R)); > +} > + > +STATIC > +BOOLEAN > +IsTableEntry ( > + IN UINTN Entry > + ) > +{ > + return IsValidPte (Entry) && > + !IsBlockEntry (Entry); > +} > + > +STATIC > +UINTN > +SetTableEntry ( > + IN UINTN Entry > + ) > +{ > + Entry = SetValidPte (Entry); > + Entry &= ~(RISCV_PG_X | RISCV_PG_W | RISCV_PG_R); > + > + return Entry; > +} > + > +STATIC > +VOID > +ReplaceTableEntry ( > + IN UINTN *Entry, > + IN UINTN Value, > + IN UINTN RegionStart, > + IN BOOLEAN IsLiveBlockMapping > + ) > +{ > + *Entry = Value; > + > + if (IsLiveBlockMapping && RiscVMmuEnabled ()) { > + RiscVLocalTlbFlush (RegionStart); > + } > +} > + > +STATIC > +UINTN > +GetPpnfromPte ( > + UINTN Entry, > + UINTN Level > + ) > +{ > + return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT); > +} > + > +STATIC > +UINTN > +SetPpnToPte ( > + UINTN Entry, > + UINTN Address, > + UINTN Level > + ) > +{ > + UINTN Ppn; > + > + Ppn = ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT); > + ASSERT (~(Ppn & ~PTE_PPN_MASK)); > + Entry &= ~PTE_PPN_MASK; > + return Entry | Ppn; > +} > + > +STATIC > +VOID > +FreePageTablesRecursive ( > + IN UINTN *TranslationTable, > + IN UINTN Level > + ) > +{ > + UINTN Index; > + > + if (Level < mMaxRootTableLevel - 1) { > + for (Index = 0; Index < mTableEntryCount; Index++) { > + if (IsTableEntry (TranslationTable[Index])) { > + FreePageTablesRecursive ( > + (UINTN *)(GetPpnfromPte ((TranslationTable[Index]), Level) << > + RISCV_MMU_PAGE_SHIFT), > + Level + 1 > + ); > + } > + } > + } > + > + FreePages (TranslationTable, 1); > +} > + > +STATIC > +EFI_STATUS > +UpdateRegionMappingRecursive ( > + IN UINTN RegionStart, > + IN UINTN RegionEnd, > + IN UINTN AttributeSetMask, > + IN UINTN AttributeClearMask, > + IN UINTN *PageTable, > + IN UINTN Level, > + IN BOOLEAN TableIsLive > + ) > +{ > + EFI_STATUS Status; > + UINTN BlockShift; > + UINTN BlockMask; > + UINTN BlockEnd; > + UINTN *Entry; > + UINTN EntryValue; > + UINTN *TranslationTable; > + BOOLEAN NextTableIsLive; > + > + ASSERT (Level < mMaxRootTableLevel); > + ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0); > + > + BlockShift = (mMaxRootTableLevel - Level - 1) * mBitPerLevel + RISCV_MMU_PAGE_SHIFT; > + BlockMask = MAX_ADDRESS >> (64 - BlockShift); > + > + DEBUG ( > + ( > + DEBUG_VERBOSE, > + "%a(%d): %llx - %llx set %lx clr %lx\n", > + __func__, > + Level, > + RegionStart, > + RegionEnd, > + AttributeSetMask, > + AttributeClearMask > + ) > + ); > + > + for ( ; RegionStart < RegionEnd; RegionStart = BlockEnd) { > + BlockEnd = MIN (RegionEnd, (RegionStart | BlockMask) + 1); > + Entry = &PageTable[(RegionStart >> BlockShift) & (mTableEntryCount - 1)]; > + > + // > + // If RegionStart or BlockEnd is not aligned to the block size at this > + // level, we will have to create a table mapping in order to map less > + // than a block, and recurse to create the block or page entries at > + // the next level. No block mappings are allowed at all at level 0, > + // so in that case, we have to recurse unconditionally. > + // > + if ((Level == 0) || > + (((RegionStart | BlockEnd) & BlockMask) != 0) || IsTableEntry (*Entry)) > + { > + ASSERT (Level < mMaxRootTableLevel - 1); > + if (!IsTableEntry (*Entry)) { > + // > + // No table entry exists yet, so we need to allocate a page table > + // for the next level. > + // > + TranslationTable = AllocatePages (1); > + if (TranslationTable == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + ZeroMem (TranslationTable, EFI_PAGE_SIZE); > + > + if (IsBlockEntry (*Entry)) { > + // > + // We are splitting an existing block entry, so we have to populate > + // the new table with the attributes of the block entry it replaces. > + // > + Status = UpdateRegionMappingRecursive ( > + RegionStart & ~BlockMask, > + (RegionStart | BlockMask) + 1, > + *Entry & PTE_ATTRIBUTES_MASK, > + PTE_ATTRIBUTES_MASK, > + TranslationTable, > + Level + 1, > + FALSE > + ); > + if (EFI_ERROR (Status)) { > + // > + // The range we passed to UpdateRegionMappingRecursive () is block > + // aligned, so it is guaranteed that no further pages were allocated > + // by it, and so we only have to free the page we allocated here. > + // > + FreePages (TranslationTable, 1); > + return Status; > + } > + } > + > + NextTableIsLive = FALSE; > + } else { > + TranslationTable = (UINTN *)(GetPpnfromPte (*Entry, Level) << RISCV_MMU_PAGE_SHIFT); > + NextTableIsLive = TableIsLive; > + } > + > + // > + // Recurse to the next level > + // > + Status = UpdateRegionMappingRecursive ( > + RegionStart, > + BlockEnd, > + AttributeSetMask, > + AttributeClearMask, > + TranslationTable, > + Level + 1, > + NextTableIsLive > + ); > + if (EFI_ERROR (Status)) { > + if (!IsTableEntry (*Entry)) { > + // > + // We are creating a new table entry, so on failure, we can free all > + // allocations we made recursively, given that the whole subhierarchy > + // has not been wired into the live page tables yet. (This is not > + // possible for existing table entries, since we cannot revert the > + // modifications we made to the subhierarchy it represents.) > + // > + FreePageTablesRecursive (TranslationTable, Level + 1); > + } > + > + return Status; > + } > + > + if (!IsTableEntry (*Entry)) { > + EntryValue = SetPpnToPte (0, (UINTN)TranslationTable, Level); > + EntryValue = SetTableEntry (EntryValue); > + ReplaceTableEntry ( > + Entry, > + EntryValue, > + RegionStart, > + TableIsLive > + ); > + } > + } else { > + EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask; > + // > + // We don't have page fault exception handler when a virtual page is accessed and > + // the A bit is clear, or is written and the D bit is clear. > + // So just set A for read and D for write permission. > + // > + if (AttributeSetMask & RISCV_PG_R) { > + EntryValue |= RISCV_PG_A; > + } > + > + if (AttributeSetMask & RISCV_PG_W) { > + EntryValue |= RISCV_PG_D; > + } > + > + EntryValue = SetPpnToPte (EntryValue, RegionStart, Level); > + EntryValue = SetValidPte (EntryValue); > + ReplaceTableEntry (Entry, EntryValue, RegionStart, TableIsLive); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +UpdateRegionMapping ( > + IN UINTN RegionStart, > + IN UINTN RegionLength, > + IN UINTN AttributeSetMask, > + IN UINTN AttributeClearMask, > + IN UINTN *RootTable, > + IN BOOLEAN TableIsLive > + ) > +{ > + if (((RegionStart | RegionLength) & EFI_PAGE_MASK) != 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + return UpdateRegionMappingRecursive ( > + RegionStart, > + RegionStart + RegionLength, > + AttributeSetMask, > + AttributeClearMask, > + RootTable, > + 0, > + TableIsLive > + ); > +} > + > +STATIC > +UINTN > +GcdAttributeToPageAttribute ( > + IN UINTN GcdAttributes > + ) > +{ > + UINTN RiscVAttributes = RISCV_PG_R | RISCV_PG_W | RISCV_PG_X; > + > + // Determine protection attributes > + if (GcdAttributes & EFI_MEMORY_RO) { > + RiscVAttributes &= ~(RISCV_PG_W); > + } > + > + // Process eXecute Never attribute > + if (GcdAttributes & EFI_MEMORY_XP) { > + RiscVAttributes &= ~RISCV_PG_X; > + } > + > + return RiscVAttributes; > +} > + > +EFI_STATUS > +EFIAPI > +RiscVSetMemoryAttributes ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINTN Length, > + IN UINTN Attributes > + ) > +{ > + UINTN PageAttributesSet = GcdAttributeToPageAttribute (Attributes); > + > + if (!RiscVMmuEnabled ()) { > + return EFI_SUCCESS; > + } > + > + DEBUG ( > + ( > + DEBUG_VERBOSE, > + "%a: Set %llX page attribute 0x%X\n", > + __func__, > + BaseAddress, > + PageAttributesSet > + ) > + ); > + > + return UpdateRegionMapping ( > + BaseAddress, > + Length, > + PageAttributesSet, > + PTE_ATTRIBUTES_MASK, > + (UINTN *)RiscVGetRootTranslateTable (), > + TRUE > + ); > +} > + > +STATIC > +EFI_STATUS > +RiscVMmuSetSatpMode ( > + UINTN SatpMode > + ) > +{ > + VOID *TranslationTable; > + UINTN SatpReg; > + UINTN Ppn; > + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemoryMap; > + UINTN NumberOfDescriptors; > + UINTN Index; > + EFI_STATUS Status; > + > + switch (SatpMode) { > + case SATP_MODE_OFF: > + return EFI_SUCCESS; > + case SATP_MODE_SV39: > + mMaxRootTableLevel = 3; > + mBitPerLevel = 9; > + mTableEntryCount = 512; > + break; > + case SATP_MODE_SV48: > + mMaxRootTableLevel = 4; > + mBitPerLevel = 9; > + mTableEntryCount = 512; > + break; > + case SATP_MODE_SV57: > + mMaxRootTableLevel = 5; > + mBitPerLevel = 9; > + mTableEntryCount = 512; > + break; > + default: > + return EFI_INVALID_PARAMETER; > + } > + > + // Allocate pages for translation table > + TranslationTable = AllocatePages (1); > + if (TranslationTable == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN)); > + > + NumberOfDescriptors = 0; > + MemoryMap = NULL; > + Status = gDS->GetMemorySpaceMap ( > + &NumberOfDescriptors, > + &MemoryMap > + ); > + ASSERT_EFI_ERROR (Status); > + > + for (Index = 0; Index < NumberOfDescriptors; Index++) { > + if (MemoryMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { > + // Default Read/Write attribute for memory mapped IO > + UpdateRegionMapping ( > + MemoryMap[Index].BaseAddress, > + MemoryMap[Index].Length, > + RISCV_PG_R | RISCV_PG_W, > + PTE_ATTRIBUTES_MASK, > + TranslationTable, > + FALSE > + ); > + } else if (MemoryMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { > + // Default Read/Write/Execute attribute for system memory > + UpdateRegionMapping ( > + MemoryMap[Index].BaseAddress, > + MemoryMap[Index].Length, > + RISCV_PG_R | RISCV_PG_W | RISCV_PG_X, > + PTE_ATTRIBUTES_MASK, > + TranslationTable, > + FALSE > + ); > + } > + } > + > + FreePool ((VOID *)MemoryMap); > + > + if (GetInterruptState ()) { > + DisableInterrupts (); > + } > + > + Ppn = (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT; > + ASSERT (!(Ppn & ~(SATP64_PPN))); > + > + SatpReg = Ppn; > + SatpReg |= (SatpMode << > + SATP64_MODE_SHIFT) & SATP64_MODE; > + RiscVSetSupervisorAddressTranslationRegister (SatpReg); > + /* Check if HW support the setup satp mode */ > + if (SatpReg != RiscVGetSupervisorAddressTranslationRegister ()) { > + DEBUG ( > + ( > + DEBUG_VERBOSE, > + "%a: HW does not support SATP mode:%d\n", > + __func__, > + SatpMode > + ) > + ); > + FreePageTablesRecursive (TranslationTable, 0); > + return EFI_DEVICE_ERROR; > + } > + > + RiscVLocalTlbFlushAll (); > + > + if (GetInterruptState ()) { > + EnableInterrupts (); > + } > + > + return Status; > +} > + > +EFI_STATUS > +EFIAPI > +RiscVConfigureMmu ( > + VOID > + ) > +{ > + EFI_STATUS Status = EFI_SUCCESS; > + INTN ModeSupport[] = { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MODE_SV39 }; > + INTN Idx; > + > + /* Try to setup MMU with highest mode as possible */ > + for (Idx = 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) { > + Status = RiscVMmuSetSatpMode (ModeSupport[Idx]); > + if (Status == EFI_DEVICE_ERROR) { > + continue; > + } else if (EFI_ERROR (Status)) { > + return Status; > + } > + > + DEBUG ( > + ( > + DEBUG_INFO, > + "%a: SATP mode %d successfully configured\n", > + __func__, > + ModeSupport[Idx] > + ) > + ); > + break; > + } > + > + return Status; > +} > diff --git a/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > new file mode 100644 > index 000000000000..8ee0127c2144 > --- /dev/null > +++ b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > @@ -0,0 +1,25 @@ > +## @file > +# > +# Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x0001001b > + BASE_NAME = BaseRiscVMmuLib > + FILE_GUID = d3bc42ee-c9eb-4339-ba11-06747083d3ae > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = RiscVMmuLib > + > +[Sources] > + BaseRiscVMmuLib.c > + RiscVMmuCore.S > + > +[Packages] > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + BaseLib > diff --git a/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S b/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S > new file mode 100644 > index 000000000000..42eec4cbdf83 > --- /dev/null > +++ b/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S > @@ -0,0 +1,31 @@ > +/** @file > +* > +* Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
> +* > +* SPDX-License-Identifier: BSD-2-Clause-Patent > +* > +**/ > + > +#include > +#include > + > +.text > + .align 3 > + > +// > +// Local tlb flush all. > +// > +// > +ASM_FUNC (RiscVLocalTlbFlushAll) > +sfence.vma > +ret > + > +// > +// Local tlb flush at a virtual address > +// @retval a0 : virtual address. > +// > +ASM_FUNC ( > + RiscVLocalTlbFlush > + ) > +sfence.vma a0 > +ret > diff --git a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > index 731f54f73f81..083a182655d3 100644 > --- a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > +++ b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > @@ -83,6 +83,7 @@ > # RISC-V Architectural Libraries > CpuExceptionHandlerLib|UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/BaseRiscV64CpuExceptionHandlerLib.inf > RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLib.inf > + RiscVMmuLib|MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf > ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/BaseResetSystemLib.inf > > diff --git a/OvmfPkg/RiscVVirt/Sec/Memory.c b/OvmfPkg/RiscVVirt/Sec/Memory.c > index 0e2690c73687..69041f6404a4 100644 > --- a/OvmfPkg/RiscVVirt/Sec/Memory.c > +++ b/OvmfPkg/RiscVVirt/Sec/Memory.c > @@ -85,21 +85,6 @@ AddMemoryRangeHob ( > AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase)); > } > > -/** > - Configure MMU > -**/ > -STATIC > -VOID > -InitMmu ( > - ) > -{ > - // > - // Set supervisor translation mode to Bare mode > - // > - RiscVSetSupervisorAddressTranslationRegister ((UINT64)SATP_MODE_OFF << 60); > - DEBUG ((DEBUG_INFO, "%a: Set Supervisor address mode to bare-metal mode.\n", __func__)); > -} > - > /** > Publish system RAM and reserve memory regions. > > @@ -327,7 +312,8 @@ MemoryPeimInitialization ( > > AddReservedMemoryMap (FdtPointer); > > - InitMmu (); > + /* Make sure SEC is booting with bare mode*/ > + ASSERT ((RiscVGetSupervisorAddressTranslationRegister () & SATP64_MODE) == (SATP_MODE_OFF << SATP64_MODE_SHIFT)); > > BuildMemoryTypeInformationHob (); > > diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c > index 25fe3f54c325..2af3b6223450 100644 > --- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c > +++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c > @@ -296,8 +296,7 @@ CpuSetMemoryAttributes ( > IN UINT64 Attributes > ) > { > - DEBUG ((DEBUG_INFO, "%a: Set memory attributes not supported yet\n", __func__)); > - return EFI_SUCCESS; > + return RiscVSetMemoryAttributes (BaseAddress, Length, Attributes); > } > > /** > @@ -340,6 +339,12 @@ InitializeCpu ( > // > DisableInterrupts (); > > + // > + // Enable MMU > + // > + Status = RiscVConfigureMmu (); > + ASSERT_EFI_ERROR (Status); > + > // > // Install Boot protocol > // > diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h > index 49f4e119665a..68e6d038b66e 100644 > --- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h > +++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h > @@ -15,11 +15,13 @@ > #include > #include > #include > +#include > #include > #include > #include > #include > #include > +#include > > /** > Flush CPU data cache. If the instruction cache is fully coherent > diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf > index e8fa25446aef..9d9a5ef8f247 100644 > --- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf > +++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf > @@ -37,6 +37,8 @@ > TimerLib > PeCoffGetEntryPointLib > RiscVSbiLib > + RiscVMmuLib > + CacheMaintenanceLib > > [Sources] > CpuDxe.c --------------cpZvKmnKPh3gVNHwvlbUY0R9 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit

Dear all,

I'm also porting MMU library of LoongArch64 to EDK2, I added it in to UefiCpuPkg and make it possible to use the same headers for both the no-IA32 and no-X64 platforms, and I also saw that IA32 and X64 added the CpuPageTableLib to UefiCpuPkg, this library are similar to MMU libraries. I have a question, should the MMU library be in the MdePkg or UefiCpuPkg?


Thanks,
Chao
在 2023/4/15 02:58, Tuan Phan 写道:
During CpuDxe initialization, MMU will be setup with the highest
mode that HW supports.

Signed-off-by: Tuan Phan <tphan@ventanamicro.com>
---
 MdePkg/Include/Library/BaseRiscVMmuLib.h      |  39 ++
 .../Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c | 569 ++++++++++++++++++
 .../BaseRiscVMmuLib/BaseRiscVMmuLib.inf       |  25 +
 MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S |  31 +
 OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc           |   1 +
 OvmfPkg/RiscVVirt/Sec/Memory.c                |  18 +-
 UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c             |   9 +-
 UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h             |   2 +
 UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf    |   2 +
 9 files changed, 678 insertions(+), 18 deletions(-)
 create mode 100644 MdePkg/Include/Library/BaseRiscVMmuLib.h
 create mode 100644 MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c
 create mode 100644 MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf
 create mode 100644 MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S

diff --git a/MdePkg/Include/Library/BaseRiscVMmuLib.h b/MdePkg/Include/Library/BaseRiscVMmuLib.h
new file mode 100644
index 000000000000..f71d6a4a1e7b
--- /dev/null
+++ b/MdePkg/Include/Library/BaseRiscVMmuLib.h
@@ -0,0 +1,39 @@
+/** @file
+
+  Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BASE_RISCV_MMU_LIB_H_
+#define BASE_RISCV_MMU_LIB_H_
+
+VOID
+EFIAPI
+RiscVLocalTlbFlushAll (
+  VOID
+  );
+
+VOID
+EFIAPI
+RiscVLocalTlbFlush (
+  UINTN  VirtAddr
+  );
+
+EFI_STATUS
+EFIAPI
+RiscVSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+RiscVConfigureMmu (
+  VOID
+  );
+
+#endif /* BASE_RISCV_MMU_LIB_H_ */
diff --git a/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c
new file mode 100644
index 000000000000..230f34261d8b
--- /dev/null
+++ b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c
@@ -0,0 +1,569 @@
+/** @file
+*  MMU implementation for RISC-V
+*
+*  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
+*  Copyright (c) 2016, Linaro Limited. All rights reserved.
+*  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+*  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseRiscVMmuLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Register/RiscV64/RiscVEncoding.h>
+
+#define RISCV_PG_V           BIT0
+#define RISCV_PG_R           BIT1
+#define RISCV_PG_W           BIT2
+#define RISCV_PG_X           BIT3
+#define RISCV_PG_G           BIT5
+#define RISCV_PG_A           BIT6
+#define RISCV_PG_D           BIT7
+#define PTE_ATTRIBUTES_MASK  0xE
+
+#define PTE_PPN_MASK          0x3FFFFFFFFFFC00ULL
+#define PTE_PPN_SHIFT         10
+#define RISCV_MMU_PAGE_SHIFT  12
+
+STATIC UINTN  mMaxRootTableLevel;
+STATIC UINTN  mBitPerLevel;
+STATIC UINTN  mTableEntryCount;
+
+STATIC
+BOOLEAN
+RiscVMmuEnabled (
+  VOID
+  )
+{
+  return ((RiscVGetSupervisorAddressTranslationRegister () &
+           SATP64_MODE) != (SATP_MODE_OFF << SATP64_MODE_SHIFT));
+}
+
+STATIC
+UINTN
+RiscVGetRootTranslateTable (
+  VOID
+  )
+{
+  return (RiscVGetSupervisorAddressTranslationRegister () & SATP64_PPN) <<
+         RISCV_MMU_PAGE_SHIFT;
+}
+
+STATIC
+BOOLEAN
+IsValidPte (
+  IN  UINTN  Entry
+  )
+{
+  if (!(Entry & RISCV_PG_V) ||
+      (((Entry & (RISCV_PG_R | RISCV_PG_W)) == RISCV_PG_W)))
+  {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+STATIC
+UINTN
+SetValidPte (
+  IN  UINTN  Entry
+  )
+{
+  /* Set Valid and Global mapping bits */
+  return Entry | RISCV_PG_G | RISCV_PG_V;
+}
+
+STATIC
+BOOLEAN
+IsBlockEntry (
+  IN  UINTN  Entry
+  )
+{
+  return IsValidPte (Entry) &&
+         (Entry & (RISCV_PG_X | RISCV_PG_R));
+}
+
+STATIC
+BOOLEAN
+IsTableEntry (
+  IN  UINTN  Entry
+  )
+{
+  return IsValidPte (Entry) &&
+         !IsBlockEntry (Entry);
+}
+
+STATIC
+UINTN
+SetTableEntry (
+  IN  UINTN  Entry
+  )
+{
+  Entry  = SetValidPte (Entry);
+  Entry &= ~(RISCV_PG_X | RISCV_PG_W | RISCV_PG_R);
+
+  return Entry;
+}
+
+STATIC
+VOID
+ReplaceTableEntry (
+  IN  UINTN    *Entry,
+  IN  UINTN    Value,
+  IN  UINTN    RegionStart,
+  IN  BOOLEAN  IsLiveBlockMapping
+  )
+{
+  *Entry = Value;
+
+  if (IsLiveBlockMapping && RiscVMmuEnabled ()) {
+    RiscVLocalTlbFlush (RegionStart);
+  }
+}
+
+STATIC
+UINTN
+GetPpnfromPte (
+  UINTN  Entry,
+  UINTN  Level
+  )
+{
+  return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT);
+}
+
+STATIC
+UINTN
+SetPpnToPte (
+  UINTN  Entry,
+  UINTN  Address,
+  UINTN  Level
+  )
+{
+  UINTN  Ppn;
+
+  Ppn = ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT);
+  ASSERT (~(Ppn & ~PTE_PPN_MASK));
+  Entry &= ~PTE_PPN_MASK;
+  return Entry | Ppn;
+}
+
+STATIC
+VOID
+FreePageTablesRecursive (
+  IN  UINTN  *TranslationTable,
+  IN  UINTN  Level
+  )
+{
+  UINTN  Index;
+
+  if (Level < mMaxRootTableLevel - 1) {
+    for (Index = 0; Index < mTableEntryCount; Index++) {
+      if (IsTableEntry (TranslationTable[Index])) {
+        FreePageTablesRecursive (
+                                 (UINTN *)(GetPpnfromPte ((TranslationTable[Index]), Level) <<
+                                           RISCV_MMU_PAGE_SHIFT),
+                                 Level + 1
+                                 );
+      }
+    }
+  }
+
+  FreePages (TranslationTable, 1);
+}
+
+STATIC
+EFI_STATUS
+UpdateRegionMappingRecursive (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionEnd,
+  IN  UINTN    AttributeSetMask,
+  IN  UINTN    AttributeClearMask,
+  IN  UINTN    *PageTable,
+  IN  UINTN    Level,
+  IN  BOOLEAN  TableIsLive
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlockShift;
+  UINTN       BlockMask;
+  UINTN       BlockEnd;
+  UINTN       *Entry;
+  UINTN       EntryValue;
+  UINTN       *TranslationTable;
+  BOOLEAN     NextTableIsLive;
+
+  ASSERT (Level < mMaxRootTableLevel);
+  ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0);
+
+  BlockShift = (mMaxRootTableLevel - Level - 1) * mBitPerLevel + RISCV_MMU_PAGE_SHIFT;
+  BlockMask  = MAX_ADDRESS >> (64 - BlockShift);
+
+  DEBUG (
+         (
+          DEBUG_VERBOSE,
+          "%a(%d): %llx - %llx set %lx clr %lx\n",
+          __func__,
+          Level,
+          RegionStart,
+          RegionEnd,
+          AttributeSetMask,
+          AttributeClearMask
+         )
+         );
+
+  for ( ; RegionStart < RegionEnd; RegionStart = BlockEnd) {
+    BlockEnd = MIN (RegionEnd, (RegionStart | BlockMask) + 1);
+    Entry    = &PageTable[(RegionStart >> BlockShift) & (mTableEntryCount - 1)];
+
+    //
+    // If RegionStart or BlockEnd is not aligned to the block size at this
+    // level, we will have to create a table mapping in order to map less
+    // than a block, and recurse to create the block or page entries at
+    // the next level. No block mappings are allowed at all at level 0,
+    // so in that case, we have to recurse unconditionally.
+    //
+    if ((Level == 0) ||
+        (((RegionStart | BlockEnd) & BlockMask) != 0) || IsTableEntry (*Entry))
+    {
+      ASSERT (Level < mMaxRootTableLevel - 1);
+      if (!IsTableEntry (*Entry)) {
+        //
+        // No table entry exists yet, so we need to allocate a page table
+        // for the next level.
+        //
+        TranslationTable = AllocatePages (1);
+        if (TranslationTable == NULL) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        ZeroMem (TranslationTable, EFI_PAGE_SIZE);
+
+        if (IsBlockEntry (*Entry)) {
+          //
+          // We are splitting an existing block entry, so we have to populate
+          // the new table with the attributes of the block entry it replaces.
+          //
+          Status = UpdateRegionMappingRecursive (
+                                                 RegionStart & ~BlockMask,
+                                                 (RegionStart | BlockMask) + 1,
+                                                 *Entry & PTE_ATTRIBUTES_MASK,
+                                                 PTE_ATTRIBUTES_MASK,
+                                                 TranslationTable,
+                                                 Level + 1,
+                                                 FALSE
+                                                 );
+          if (EFI_ERROR (Status)) {
+            //
+            // The range we passed to UpdateRegionMappingRecursive () is block
+            // aligned, so it is guaranteed that no further pages were allocated
+            // by it, and so we only have to free the page we allocated here.
+            //
+            FreePages (TranslationTable, 1);
+            return Status;
+          }
+        }
+
+        NextTableIsLive = FALSE;
+      } else {
+        TranslationTable = (UINTN *)(GetPpnfromPte (*Entry, Level) << RISCV_MMU_PAGE_SHIFT);
+        NextTableIsLive  = TableIsLive;
+      }
+
+      //
+      // Recurse to the next level
+      //
+      Status = UpdateRegionMappingRecursive (
+                                             RegionStart,
+                                             BlockEnd,
+                                             AttributeSetMask,
+                                             AttributeClearMask,
+                                             TranslationTable,
+                                             Level + 1,
+                                             NextTableIsLive
+                                             );
+      if (EFI_ERROR (Status)) {
+        if (!IsTableEntry (*Entry)) {
+          //
+          // We are creating a new table entry, so on failure, we can free all
+          // allocations we made recursively, given that the whole subhierarchy
+          // has not been wired into the live page tables yet. (This is not
+          // possible for existing table entries, since we cannot revert the
+          // modifications we made to the subhierarchy it represents.)
+          //
+          FreePageTablesRecursive (TranslationTable, Level + 1);
+        }
+
+        return Status;
+      }
+
+      if (!IsTableEntry (*Entry)) {
+        EntryValue = SetPpnToPte (0, (UINTN)TranslationTable, Level);
+        EntryValue = SetTableEntry (EntryValue);
+        ReplaceTableEntry (
+                           Entry,
+                           EntryValue,
+                           RegionStart,
+                           TableIsLive
+                           );
+      }
+    } else {
+      EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask;
+      //
+      // We don't have page fault exception handler when a virtual page is accessed and
+      // the A bit is clear, or is written and the D bit is clear.
+      // So just set A for read and D for write permission.
+      //
+      if (AttributeSetMask & RISCV_PG_R) {
+        EntryValue |= RISCV_PG_A;
+      }
+
+      if (AttributeSetMask & RISCV_PG_W) {
+        EntryValue |= RISCV_PG_D;
+      }
+
+      EntryValue = SetPpnToPte (EntryValue, RegionStart, Level);
+      EntryValue = SetValidPte (EntryValue);
+      ReplaceTableEntry (Entry, EntryValue, RegionStart, TableIsLive);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+UpdateRegionMapping (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionLength,
+  IN  UINTN    AttributeSetMask,
+  IN  UINTN    AttributeClearMask,
+  IN  UINTN    *RootTable,
+  IN  BOOLEAN  TableIsLive
+  )
+{
+  if (((RegionStart | RegionLength) & EFI_PAGE_MASK) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return UpdateRegionMappingRecursive (
+                                       RegionStart,
+                                       RegionStart + RegionLength,
+                                       AttributeSetMask,
+                                       AttributeClearMask,
+                                       RootTable,
+                                       0,
+                                       TableIsLive
+                                       );
+}
+
+STATIC
+UINTN
+GcdAttributeToPageAttribute (
+  IN UINTN  GcdAttributes
+  )
+{
+  UINTN  RiscVAttributes = RISCV_PG_R | RISCV_PG_W | RISCV_PG_X;
+
+  // Determine protection attributes
+  if (GcdAttributes & EFI_MEMORY_RO) {
+    RiscVAttributes &= ~(RISCV_PG_W);
+  }
+
+  // Process eXecute Never attribute
+  if (GcdAttributes & EFI_MEMORY_XP) {
+    RiscVAttributes &= ~RISCV_PG_X;
+  }
+
+  return RiscVAttributes;
+}
+
+EFI_STATUS
+EFIAPI
+RiscVSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN                 Length,
+  IN UINTN                 Attributes
+  )
+{
+  UINTN  PageAttributesSet = GcdAttributeToPageAttribute (Attributes);
+
+  if (!RiscVMmuEnabled ()) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG (
+         (
+          DEBUG_VERBOSE,
+          "%a: Set %llX page attribute 0x%X\n",
+          __func__,
+          BaseAddress,
+          PageAttributesSet
+         )
+         );
+
+  return UpdateRegionMapping (
+                              BaseAddress,
+                              Length,
+                              PageAttributesSet,
+                              PTE_ATTRIBUTES_MASK,
+                              (UINTN *)RiscVGetRootTranslateTable (),
+                              TRUE
+                              );
+}
+
+STATIC
+EFI_STATUS
+RiscVMmuSetSatpMode  (
+  UINTN  SatpMode
+  )
+{
+  VOID                             *TranslationTable;
+  UINTN                            SatpReg;
+  UINTN                            Ppn;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemoryMap;
+  UINTN                            NumberOfDescriptors;
+  UINTN                            Index;
+  EFI_STATUS                       Status;
+
+  switch (SatpMode) {
+    case SATP_MODE_OFF:
+      return EFI_SUCCESS;
+    case SATP_MODE_SV39:
+      mMaxRootTableLevel = 3;
+      mBitPerLevel       = 9;
+      mTableEntryCount   = 512;
+      break;
+    case SATP_MODE_SV48:
+      mMaxRootTableLevel = 4;
+      mBitPerLevel       = 9;
+      mTableEntryCount   = 512;
+      break;
+    case SATP_MODE_SV57:
+      mMaxRootTableLevel = 5;
+      mBitPerLevel       = 9;
+      mTableEntryCount   = 512;
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  // Allocate pages for translation table
+  TranslationTable = AllocatePages (1);
+  if (TranslationTable == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN));
+
+  NumberOfDescriptors = 0;
+  MemoryMap           = NULL;
+  Status              = gDS->GetMemorySpaceMap (
+                                                &NumberOfDescriptors,
+                                                &MemoryMap
+                                                );
+  ASSERT_EFI_ERROR (Status);
+
+  for (Index = 0; Index < NumberOfDescriptors; Index++) {
+    if (MemoryMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+      // Default Read/Write attribute for memory mapped IO
+      UpdateRegionMapping (
+                           MemoryMap[Index].BaseAddress,
+                           MemoryMap[Index].Length,
+                           RISCV_PG_R | RISCV_PG_W,
+                           PTE_ATTRIBUTES_MASK,
+                           TranslationTable,
+                           FALSE
+                           );
+    } else if (MemoryMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
+      // Default Read/Write/Execute attribute for system memory
+      UpdateRegionMapping (
+                           MemoryMap[Index].BaseAddress,
+                           MemoryMap[Index].Length,
+                           RISCV_PG_R | RISCV_PG_W | RISCV_PG_X,
+                           PTE_ATTRIBUTES_MASK,
+                           TranslationTable,
+                           FALSE
+                           );
+    }
+  }
+
+  FreePool ((VOID *)MemoryMap);
+
+  if (GetInterruptState ()) {
+    DisableInterrupts ();
+  }
+
+  Ppn = (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT;
+  ASSERT (!(Ppn & ~(SATP64_PPN)));
+
+  SatpReg  = Ppn;
+  SatpReg |= (SatpMode <<
+              SATP64_MODE_SHIFT) & SATP64_MODE;
+  RiscVSetSupervisorAddressTranslationRegister (SatpReg);
+  /* Check if HW support the setup satp mode */
+  if (SatpReg != RiscVGetSupervisorAddressTranslationRegister ()) {
+    DEBUG (
+           (
+            DEBUG_VERBOSE,
+            "%a: HW does not support SATP mode:%d\n",
+            __func__,
+            SatpMode
+           )
+           );
+    FreePageTablesRecursive (TranslationTable, 0);
+    return EFI_DEVICE_ERROR;
+  }
+
+  RiscVLocalTlbFlushAll ();
+
+  if (GetInterruptState ()) {
+    EnableInterrupts ();
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+RiscVConfigureMmu (
+  VOID
+  )
+{
+  EFI_STATUS  Status = EFI_SUCCESS;
+  INTN        ModeSupport[] = { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MODE_SV39 };
+  INTN        Idx;
+
+  /* Try to setup MMU with highest mode as possible */
+  for (Idx = 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) {
+    Status = RiscVMmuSetSatpMode (ModeSupport[Idx]);
+    if (Status == EFI_DEVICE_ERROR) {
+      continue;
+    } else if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DEBUG (
+           (
+            DEBUG_INFO,
+            "%a: SATP mode %d successfully configured\n",
+            __func__,
+            ModeSupport[Idx]
+           )
+           );
+    break;
+  }
+
+  return Status;
+}
diff --git a/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf
new file mode 100644
index 000000000000..8ee0127c2144
--- /dev/null
+++ b/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf
@@ -0,0 +1,25 @@
+## @file
+#
+#  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION         = 0x0001001b
+  BASE_NAME           = BaseRiscVMmuLib
+  FILE_GUID           = d3bc42ee-c9eb-4339-ba11-06747083d3ae
+  MODULE_TYPE         = BASE
+  VERSION_STRING      = 1.0
+  LIBRARY_CLASS       = RiscVMmuLib
+
+[Sources]
+  BaseRiscVMmuLib.c
+  RiscVMmuCore.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
diff --git a/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S b/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S
new file mode 100644
index 000000000000..42eec4cbdf83
--- /dev/null
+++ b/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S
@@ -0,0 +1,31 @@
+/** @file
+*
+*  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Base.h>
+#include <Register/RiscV64/RiscVImpl.h>
+
+.text
+  .align 3
+
+//
+// Local tlb flush all.
+//
+//
+ASM_FUNC (RiscVLocalTlbFlushAll)
+sfence.vma
+ret
+
+//
+// Local tlb flush at a virtual address
+// @retval a0 : virtual address.
+//
+ASM_FUNC (
+  RiscVLocalTlbFlush
+  )
+sfence.vma a0
+ret
diff --git a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc
index 731f54f73f81..083a182655d3 100644
--- a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc
+++ b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc
@@ -83,6 +83,7 @@
   # RISC-V Architectural Libraries
   CpuExceptionHandlerLib|UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerLib/BaseRiscV64CpuExceptionHandlerLib.inf
   RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLib.inf
+  RiscVMmuLib|MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf
   PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
   ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/BaseResetSystemLib.inf
 
diff --git a/OvmfPkg/RiscVVirt/Sec/Memory.c b/OvmfPkg/RiscVVirt/Sec/Memory.c
index 0e2690c73687..69041f6404a4 100644
--- a/OvmfPkg/RiscVVirt/Sec/Memory.c
+++ b/OvmfPkg/RiscVVirt/Sec/Memory.c
@@ -85,21 +85,6 @@ AddMemoryRangeHob (
   AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
 }
 
-/**
-  Configure MMU
-**/
-STATIC
-VOID
-InitMmu (
-  )
-{
-  //
-  // Set supervisor translation mode to Bare mode
-  //
-  RiscVSetSupervisorAddressTranslationRegister ((UINT64)SATP_MODE_OFF << 60);
-  DEBUG ((DEBUG_INFO, "%a: Set Supervisor address mode to bare-metal mode.\n", __func__));
-}
-
 /**
   Publish system RAM and reserve memory regions.
 
@@ -327,7 +312,8 @@ MemoryPeimInitialization (
 
   AddReservedMemoryMap (FdtPointer);
 
-  InitMmu ();
+  /* Make sure SEC is booting with bare mode*/
+  ASSERT ((RiscVGetSupervisorAddressTranslationRegister () & SATP64_MODE) == (SATP_MODE_OFF << SATP64_MODE_SHIFT));
 
   BuildMemoryTypeInformationHob ();
 
diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c
index 25fe3f54c325..2af3b6223450 100644
--- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c
+++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c
@@ -296,8 +296,7 @@ CpuSetMemoryAttributes (
   IN UINT64                 Attributes
   )
 {
-  DEBUG ((DEBUG_INFO, "%a: Set memory attributes not supported yet\n", __func__));
-  return EFI_SUCCESS;
+  return RiscVSetMemoryAttributes (BaseAddress, Length, Attributes);
 }
 
 /**
@@ -340,6 +339,12 @@ InitializeCpu (
   //
   DisableInterrupts ();
 
+  //
+  // Enable MMU
+  //
+  Status = RiscVConfigureMmu ();
+  ASSERT_EFI_ERROR (Status);
+
   //
   // Install Boot protocol
   //
diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h
index 49f4e119665a..68e6d038b66e 100644
--- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h
+++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h
@@ -15,11 +15,13 @@
 #include <Protocol/Cpu.h>
 #include <Protocol/RiscVBootProtocol.h>
 #include <Library/BaseRiscVSbiLib.h>
+#include <Library/BaseRiscVMmuLib.h>
 #include <Library/BaseLib.h>
 #include <Library/CpuExceptionHandlerLib.h>
 #include <Library/DebugLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiDriverEntryPoint.h>
+#include <Register/RiscV64/RiscVEncoding.h>
 
 /**
   Flush CPU data cache. If the instruction cache is fully coherent
diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
index e8fa25446aef..9d9a5ef8f247 100644
--- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
+++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
@@ -37,6 +37,8 @@
   TimerLib
   PeCoffGetEntryPointLib
   RiscVSbiLib
+  RiscVMmuLib
+  CacheMaintenanceLib
 
 [Sources]
   CpuDxe.c
--------------cpZvKmnKPh3gVNHwvlbUY0R9--