From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qv1-f51.google.com (mail-qv1-f51.google.com [209.85.219.51]) by mx.groups.io with SMTP id smtpd.web10.1424.1684952204910000197 for ; Wed, 24 May 2023 11:16:45 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="signature has expired" header.i=@ventanamicro.com header.s=google header.b=Kl+iIsxt; spf=pass (domain: ventanamicro.com, ip: 209.85.219.51, mailfrom: tphan@ventanamicro.com) Received: by mail-qv1-f51.google.com with SMTP id 6a1803df08f44-62385a3106dso318626d6.2 for ; Wed, 24 May 2023 11:16:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ventanamicro.com; s=google; t=1684952204; x=1687544204; h=mime-version:content-language:accept-language:in-reply-to :references:message-id:date:thread-index:thread-topic:subject:cc:to :from:from:to:cc:subject:date:message-id:reply-to; bh=/eSrfgqC+prSvsu/Ymv/FdN5knH7gkzCPQD6sVI2xO4=; b=Kl+iIsxtAjUAFXI9hEZVPL5UewXEpk/qD7ZPSR0tUgOe2xgFa5/ZCv/2zyjaeheckD /RE4JdwI9VsgZR7gGPC9WQEYE1X8HWkvYcbI4lrTqCnsvZnmIvTXWm1ZzDSKQ0Md4gAY mSGsCHLa3PQ5jc/mA5ui+zARNMj5J0xUWvMpIs2/3UaxkTkGTo1tBZ551wEQSa8IGOS5 L91+mkIEjm4+unoA6+WpWScaQPq+UZrqOh8D21Q7jY6qkXbkxxFQziU5gRLj3EBQ6d3j 3DnaIkhKE/fk4di1ELO7t6PGTMQlalnQupdNPnRMtGDxcBCa55IR+DDX4AlUqDIBarJl XjMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684952204; x=1687544204; h=mime-version:content-language:accept-language:in-reply-to :references:message-id:date:thread-index:thread-topic:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/eSrfgqC+prSvsu/Ymv/FdN5knH7gkzCPQD6sVI2xO4=; b=HKRsQiMyQRHfffRSJXXbgsg/bd68KHPTgShu0jRnBF7/hCl83186ZpSIbkdgZdqbEF J5bxVR0ybeKzhKsL1iIjC85JF5Zsj4qPQm9UHrorh80NA+LxTp3q1YM/udTexdpBJloi 9ri9R+CohDG+aZqggKeT/RvdmJRFfRmD0gtN41DjlmYK+fQv3OgggAHmgre7q8B1nJIg rf9AhQ+LaJ5FhblrcblSMOIA+xs7VHEQSa9iZ6C1bZZvukhasd9fqVtbub/jj24VRVoY N8+g2h+JWJ341kXChUUXWRcSqkCj4ESWFUaHVJEUtN8CU/McawfLvmLiiJ4RzAj6fdeW l+BA== X-Gm-Message-State: AC+VfDx+ZxAkd5x3bAxO6sp0COciXaPYagvz7JmAy1vWR3MHNG0XoFjp 32NuNKCotHrPAxfvmB1y3IMHN0aqxd5IAJWdMUI= X-Google-Smtp-Source: ACHHUZ5ZfkiAfmQjJ+Kmumi67ZrauCSYnrsv59gK8BB7y+5cwnx+HcTIt6smtV04dUW7+mLYdoPzVQ== X-Received: by 2002:ad4:5ced:0:b0:5c8:403a:22f8 with SMTP id iv13-20020ad45ced000000b005c8403a22f8mr29298750qvb.5.1684952203749; Wed, 24 May 2023 11:16:43 -0700 (PDT) Return-Path: Received: from MN2PR13MB3022.namprd13.prod.outlook.com ([2603:1036:302:405e::5]) by smtp.gmail.com with ESMTPSA id cz10-20020a056214088a00b0062120b054easm3730598qvb.20.2023.05.24.11.16.43 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 24 May 2023 11:16:43 -0700 (PDT) From: "Tuan Phan" To: "Ni, Ray" , "devel@edk2.groups.io" , "lichao@loongson.cn" , Ard Biesheuvel CC: "Kinney, Michael D" , "Gao, Liming" , "Liu, Zhiguang" , "sunilvl@ventanamicro.com" , "git@danielschaefer.me" , "Warkentin, Andrei" Subject: Re: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support MMU with SV39/48/57 mode Thread-Topic: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support MMU with SV39/48/57 mode Thread-Index: AQHZbwMga4CTCPv2R0CJThklTy+FM69o692AgACA1QCAAIyRiA== X-MS-Exchange-MessageSentRepresentingType: 1 Date: Wed, 24 May 2023 18:16:26 +0000 Message-ID: References: <20230414185815.2994-1-tphan@ventanamicro.com> <20230414185815.2994-4-tphan@ventanamicro.com> In-Reply-To: Accept-Language: en-US X-MS-Has-Attach: X-MS-Exchange-Organization-SCL: -1 X-MS-TNEF-Correlator: X-MS-Exchange-Organization-RecordReviewCfmType: 0 MIME-Version: 1.0 Content-Language: en-US Content-Type: multipart/alternative; boundary="_000_MN2PR13MB30225A5769E6AF33496072E0A7419MN2PR13MB3022namp_" --_000_MN2PR13MB30225A5769E6AF33496072E0A7419MN2PR13MB3022namp_ Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: quoted-printable Agree it makes more sense to put the MMU library into UefiCpuPkg. From: Ni, Ray Date: Wednesday, May 24, 2023 at 2:52 AM To: devel@edk2.groups.io , lichao@loongson.cn , tphan@ventanamicro.com , Ard Biesheu= vel Cc: Kinney, Michael D , Gao, Liming , Liu, Zhiguang , sunilvl@ventanamic= ro.com , git@danielschaefer.me , Warkentin, Andrei Subject: RE: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support MMU wi= th SV39/48/57 mode X86 version is in UefiCpuPkg. So be consistent, I would prefer the LoongArch64 version be in UefiCpuPkg a= s well. I know that ARM has similar code (I didn=1B$B!G=1B(Bt check in detail, +@Ar= d Biesheuvel). The trending is to abstract the memory attribute implementation behind Memo= ryAttribute PPI/Protocol for using by other modules. Thanks, Ray From: devel@edk2.groups.io On Behalf Of Chao Li Sent: Wednesday, May 24, 2023 10:11 AM To: devel@edk2.groups.io; tphan@ventanamicro.com Cc: Kinney, Michael D ; Gao, Liming ; Liu, Zhiguang ; sunilvl@ventanamic= ro.com; git@danielschaefer.me; Warkentin, Andrei ; Ni, Ray Subject: Re: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support MMU wi= th SV39/48/57 mode Dear all, I'm also porting MMU library of LoongArch64 to EDK2, I added it in to UefiC= puPkg 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 CpuPageTableL= ib to UefiCpuPkg, this library are similar to MMU libraries. I have a quest= ion, should the MMU library be in the MdePkg or UefiCpuPkg? Thanks, Chao =1B$B:_=1B(B 2023/4/15 02:58, Tuan Phan =1B$B --- 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/Libr= ary/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/Libr= ary/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) !=3D (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)) =3D=3D 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 =3D SetValidPte (Entry); + Entry &=3D ~(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 =3D 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 =3D ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT); + ASSERT (~(Ppn & ~PTE_PPN_MASK)); + Entry &=3D ~PTE_PPN_MASK; + return Entry | Ppn; +} + +STATIC +VOID +FreePageTablesRecursive ( + IN UINTN *TranslationTable, + IN UINTN Level + ) +{ + UINTN Index; + + if (Level < mMaxRootTableLevel - 1) { + for (Index =3D 0; Index < mTableEntryCount; Index++) { + if (IsTableEntry (TranslationTable[Index])) { + FreePageTablesRecursive ( + (UINTN *)(GetPpnfromPte ((TranslationTabl= e[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) =3D=3D 0); + + BlockShift =3D (mMaxRootTableLevel - Level - 1) * mBitPerLevel + RISCV_M= MU_PAGE_SHIFT; + BlockMask =3D 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 =3D BlockEnd) { + BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockMask) + 1); + Entry =3D &PageTable[(RegionStart >> BlockShift) & (mTableEntryCoun= t - 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 =3D=3D 0) || + (((RegionStart | BlockEnd) & BlockMask) !=3D 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 =3D AllocatePages (1); + if (TranslationTable =3D=3D 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 popul= ate + // the new table with the attributes of the block entry it repla= ces. + // + Status =3D UpdateRegionMappingRecursive ( + RegionStart & ~BlockMask, + (RegionStart | BlockMask)= + 1, + *Entry & PTE_ATTRIBUTES_M= ASK, + PTE_ATTRIBUTES_MASK, + TranslationTable, + Level + 1, + FALSE + ); + if (EFI_ERROR (Status)) { + // + // The range we passed to UpdateRegionMappingRecursive () is b= lock + // aligned, so it is guaranteed that no further pages were all= ocated + // by it, and so we only have to free the page we allocated he= re. + // + FreePages (TranslationTable, 1); + return Status; + } + } + + NextTableIsLive =3D FALSE; + } else { + TranslationTable =3D (UINTN *)(GetPpnfromPte (*Entry, Level) << RI= SCV_MMU_PAGE_SHIFT); + NextTableIsLive =3D TableIsLive; + } + + // + // Recurse to the next level + // + Status =3D 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 subhier= archy + // has not been wired into the live page tables yet. (This is no= t + // possible for existing table entries, since we cannot revert t= he + // modifications we made to the subhierarchy it represents.) + // + FreePageTablesRecursive (TranslationTable, Level + 1); + } + + return Status; + } + + if (!IsTableEntry (*Entry)) { + EntryValue =3D SetPpnToPte (0, (UINTN)TranslationTable, Level); + EntryValue =3D SetTableEntry (EntryValue); + ReplaceTableEntry ( + Entry, + EntryValue, + RegionStart, + TableIsLive + ); + } + } else { + EntryValue =3D (*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 |=3D RISCV_PG_A; + } + + if (AttributeSetMask & RISCV_PG_W) { + EntryValue |=3D RISCV_PG_D; + } + + EntryValue =3D SetPpnToPte (EntryValue, RegionStart, Level); + EntryValue =3D 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) !=3D 0) { + return EFI_INVALID_PARAMETER; + } + + return UpdateRegionMappingRecursive ( + RegionStart, + RegionStart + RegionLength, + AttributeSetMask, + AttributeClearMask, + RootTable, + 0, + TableIsLive + ); +} + +STATIC +UINTN +GcdAttributeToPageAttribute ( + IN UINTN GcdAttributes + ) +{ + UINTN RiscVAttributes =3D RISCV_PG_R | RISCV_PG_W | RISCV_PG_X; + + // Determine protection attributes + if (GcdAttributes & EFI_MEMORY_RO) { + RiscVAttributes &=3D ~(RISCV_PG_W); + } + + // Process eXecute Never attribute + if (GcdAttributes & EFI_MEMORY_XP) { + RiscVAttributes &=3D ~RISCV_PG_X; + } + + return RiscVAttributes; +} + +EFI_STATUS +EFIAPI +RiscVSetMemoryAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINTN Length, + IN UINTN Attributes + ) +{ + UINTN PageAttributesSet =3D 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 =3D 3; + mBitPerLevel =3D 9; + mTableEntryCount =3D 512; + break; + case SATP_MODE_SV48: + mMaxRootTableLevel =3D 4; + mBitPerLevel =3D 9; + mTableEntryCount =3D 512; + break; + case SATP_MODE_SV57: + mMaxRootTableLevel =3D 5; + mBitPerLevel =3D 9; + mTableEntryCount =3D 512; + break; + default: + return EFI_INVALID_PARAMETER; + } + + // Allocate pages for translation table + TranslationTable =3D AllocatePages (1); + if (TranslationTable =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN)); + + NumberOfDescriptors =3D 0; + MemoryMap =3D NULL; + Status =3D gDS->GetMemorySpaceMap ( + &NumberOfDescriptors, + &MemoryMap + ); + ASSERT_EFI_ERROR (Status); + + for (Index =3D 0; Index < NumberOfDescriptors; Index++) { + if (MemoryMap[Index].GcdMemoryType =3D=3D EfiGcdMemoryTypeMemoryMapped= Io) { + // 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 =3D=3D EfiGcdMemoryTypeSyste= mMemory) { + // 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 =3D (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT; + ASSERT (!(Ppn & ~(SATP64_PPN))); + + SatpReg =3D Ppn; + SatpReg |=3D (SatpMode << + SATP64_MODE_SHIFT) & SATP64_MODE; + RiscVSetSupervisorAddressTranslationRegister (SatpReg); + /* Check if HW support the setup satp mode */ + if (SatpReg !=3D 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 =3D EFI_SUCCESS; + INTN ModeSupport[] =3D { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MOD= E_SV39 }; + INTN Idx; + + /* Try to setup MMU with highest mode as possible */ + for (Idx =3D 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) { + Status =3D RiscVMmuSetSatpMode (ModeSupport[Idx]); + if (Status =3D=3D 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/Li= brary/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 =3D 0x0001001b + BASE_NAME =3D BaseRiscVMmuLib + FILE_GUID =3D d3bc42ee-c9eb-4339-ba11-06747083d3ae + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D 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/RiscVV= irt.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/BaseRiscV64CpuExceptionHandler= Lib/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/BaseResetSystemL= ib.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 << 6= 0); - 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) = =3D=3D (SATP_MODE_OFF << SATP64_MODE_SHIFT)); BuildMemoryTypeInformationHob (); diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c b/UefiCpuPkg/CpuDxeRiscV64/C= puDxe.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", __f= unc__)); - return EFI_SUCCESS; + return RiscVSetMemoryAttributes (BaseAddress, Length, Attributes); } /** @@ -340,6 +339,12 @@ InitializeCpu ( // DisableInterrupts (); + // + // Enable MMU + // + Status =3D RiscVConfigureMmu (); + ASSERT_EFI_ERROR (Status); + // // Install Boot protocol // diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h b/UefiCpuPkg/CpuDxeRiscV64/C= puDxe.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/CpuDxe= RiscV64/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 --_000_MN2PR13MB30225A5769E6AF33496072E0A7419MN2PR13MB3022namp_ Content-Type: text/html; charset="iso-2022-jp" Content-Transfer-Encoding: quoted-printable

Agree it makes more= sense to put the MMU library into UefiCpuPkg.

 

From: Ni, Ray <ray.ni@= intel.com>
Date: Wednesday, May 24, 2023 at 2:52 AM
To: devel@edk2.groups.io <devel@edk2.groups.io>, lichao@loongs= on.cn <lichao@loongson.cn>, tphan@ventanamicro.com <tphan@ventanam= icro.com>, Ard Biesheuvel <ardb@kernel.org>
Cc: Kinney, Michael D <michael.d.kinney@intel.com>, Gao, Limin= g <gaoliming@byosoft.com.cn>, Liu, Zhiguang <zhiguang.liu@intel.co= m>, sunilvl@ventanamicro.com <sunilvl@ventanamicro.com>, git@danie= lschaefer.me <git@danielschaefer.me>, Warkentin, Andrei <andrei.warkentin@intel.com>
Subject: RE: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support= MMU with SV39/48/57 mode

X86 version is in U= efiCpuPkg.

So be consistent, I= would prefer the LoongArch64 version be in UefiCpuPkg as well.<= /span>

I know that ARM has= similar code (I didn=1B$B!G=1B(Bt check in detail, +@Ard Biesheuvel).

 

The trending is to = abstract the memory attribute implementation behind MemoryAttribute PPI/Pro= tocol for using by other modules.

 

 

Thanks,
Ray

 

From:= devel@edk2.groups.io <devel@edk2.group= s.io> On Behalf Of Chao Li
Sent: Wednesday, May 24, 2023 10:11 AM
To: devel@edk2.groups.io; tphan@ventanamicro.com
Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Limin= g <gaoliming@byosoft.com.cn>; Liu, Zhiguang <zhiguang.liu@intel.co= m>; sunilvl@ventanamicro.com; git@danielschaefer.me; Warkentin, Andrei &= lt;andrei.warkentin@intel.com>; Ni, Ray <ray.ni@intel.com>
Subject: Re: [edk2-devel] [PATCH v2 3/6] UefiCpuPkg: RISC-V: Support= MMU with SV39/48/57 mode

 

Dear all,

I'm also porting MMU library of LoongAr= ch64 to EDK2, I added it in to UefiCpuPkg and make it possible to use the s= ame 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 questio= n, should the MMU library be in the MdePkg or UefiCpuPkg?=

 

Thanks,
Chao

= =1B$B:_=1B(B 2023/4/15 02:58, Tuan = Phan =1B$B:

During CpuDxe initialization, MMU will be setup with the highest<=
/o:p>
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     &nbs=
p;     |   1 +
 OvmfPkg/RiscVVirt/Sec/Memory.c      &nb=
sp;         |  18 +-
 UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c      =
       |   9 +-
 UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h      =
       |   2 +
 UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf    | &=
nbsp; 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 Rese=
rved.<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.&l=
t;BR>
+*  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Res=
erved.<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        &nb=
sp;  BIT0
+#define RISCV_PG_R        &nb=
sp;  BIT1
+#define RISCV_PG_W        &nb=
sp;  BIT2
+#define RISCV_PG_X        &nb=
sp;  BIT3
+#define RISCV_PG_G        &nb=
sp;  BIT5
+#define RISCV_PG_A        &nb=
sp;  BIT6
+#define RISCV_PG_D        &nb=
sp;  BIT7
+#define PTE_ATTRIBUTES_MASK  0xE
+
+#define PTE_PPN_MASK        &=
nbsp; 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_M=
ODE) !=3D (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)) =3D=3D 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  =3D SetValidPte (Entry);
+  Entry &=3D ~(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 =3D 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 =3D ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_=
PPN_SHIFT);
+  ASSERT (~(Ppn & ~PTE_PPN_MASK));
+  Entry &=3D ~PTE_PPN_MASK;
+  return Entry | Ppn;
+}
+
+STATIC
+VOID
+FreePageTablesRecursive (
+  IN  UINTN  *TranslationTable,
+  IN  UINTN  Level
+  )
+{
+  UINTN  Index;
+
+  if (Level < mMaxRootTableLevel - 1) {
+    for (Index =3D 0; Index < mTableEntryCount; Ind=
ex++) {
+      if (IsTableEntry (TranslationTable[Ind=
ex])) {
+        FreePageTablesRecursive (<=
o:p>
+           &nb=
sp;            =
         (UINTN *)(GetPpnfromPte ((=
TranslationTable[Index]), Level) <<
+           &nb=
sp;            =
            &nb=
sp;      RISCV_MMU_PAGE_SHIFT),
+           &nb=
sp;            =
         Level + 1
+           &nb=
sp;            =
         );
+      }
+    }
+  }
+
+  FreePages (TranslationTable, 1);
+}
+
+STATIC
+EFI_STATUS
+UpdateRegionMappingRecursive (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionEnd,
+  IN  UINTN    AttributeSetMask,<=
/pre>
+  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) =3D=3D=
 0);
+
+  BlockShift =3D (mMaxRootTableLevel - Level - 1) * mBitPerLevel=
 + RISCV_MMU_PAGE_SHIFT;
+  BlockMask  =3D MAX_ADDRESS >> (64 - BlockShift);
+
+  DEBUG (
+         (
+          DEBUG_VERBOSE,=
+          "%a(%d): =
%llx - %llx set %lx clr %lx\n",
+          __func__,=
+          Level,
+          RegionStart,
+          RegionEnd,
+          AttributeSetMa=
sk,
+          AttributeClear=
Mask
+         )
+         );
+
+  for ( ; RegionStart < RegionEnd; RegionStart =3D BlockEnd) =
{
+    BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockM=
ask) + 1);
+    Entry    =3D &PageTable[(Region=
Start >> BlockShift) & (mTableEntryCount - 1)];
+
+    //
+    // If RegionStart or BlockEnd is not aligned to th=
e block size at this
+    // level, we will have to create a table mapping i=
n order to map less
+    // than a block, and recurse to create the block o=
r page entries at
+    // the next level. No block mappings are allowed a=
t all at level 0,
+    // so in that case, we have to recurse uncondition=
ally.
+    //
+    if ((Level =3D=3D 0) ||
+        (((RegionStart | BlockEnd)=
 & BlockMask) !=3D 0) || IsTableEntry (*Entry))
+    {
+      ASSERT (Level < mMaxRootTableLevel =
- 1);
+      if (!IsTableEntry (*Entry)) {
+        //
+        // No table entry exists y=
et, so we need to allocate a page table
+        // for the next level.
+        //
+        TranslationTable =3D Alloc=
atePages (1);
+        if (TranslationTable =3D=
=3D NULL) {
+          return EFI_OUT=
_OF_RESOURCES;
+        }
+
+        ZeroMem (TranslationTable,=
 EFI_PAGE_SIZE);
+
+        if (IsBlockEntry (*Entry))=
 {
+          //<=
/pre>
+          // We are spli=
tting an existing block entry, so we have to populate
+          // the new tab=
le with the attributes of the block entry it replaces.
+          //<=
/pre>
+          Status =3D Upd=
ateRegionMappingRecursive (
+           &nb=
sp;            =
            &nb=
sp;            Regio=
nStart & ~BlockMask,
+            &n=
bsp;            =
;            &n=
bsp;           (Regi=
onStart | BlockMask) + 1,
+           &nb=
sp;            =
            &nb=
sp;            *Entr=
y & PTE_ATTRIBUTES_MASK,
+           &nb=
sp;            =
            &nb=
sp;            PTE_A=
TTRIBUTES_MASK,
+           &nb=
sp;            =
             &n=
bsp;           Trans=
lationTable,
+           &nb=
sp;            =
            &nb=
sp;            Level=
 + 1,
+           &nb=
sp;            =
            &nb=
sp;            FALSE=
+           &nb=
sp;            =
            &nb=
sp;            );
+          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.<=
/pre>
+            //=
+            Fr=
eePages (TranslationTable, 1);
+            re=
turn Status;
+          }
+        }
+
+        NextTableIsLive =3D FALSE;=
+      } else {
+        TranslationTable =3D (UINT=
N *)(GetPpnfromPte (*Entry, Level) << RISCV_MMU_PAGE_SHIFT);
+        NextTableIsLive  =3D =
TableIsLive;
+      }
+
+      //
+      // Recurse to the next level
+      //
+      Status =3D UpdateRegionMappingRecursiv=
e (
+           &nb=
sp;            =
            &nb=
sp;        RegionStart,
+           &nb=
sp;            =
            &nb=
sp;        BlockEnd,
+           &nb=
sp;            =
            &nb=
sp;        AttributeSetMask,<=
/pre>
+           &nb=
sp;            =
            &nb=
sp;        AttributeClearMask,
+           &nb=
sp;            =
            &nb=
sp;        TranslationTable,<=
/pre>
+           &nb=
sp;            =
            &nb=
sp;        Level + 1,
+           &nb=
sp;            =
            &nb=
sp;        NextTableIsLive
+           &nb=
sp;            =
            &nb=
sp;        );
+      if (EFI_ERROR (Status)) {
+        if (!IsTableEntry (*Entry)=
) {
+          //<=
/pre>
+          // We are crea=
ting a new table entry, so on failure, we can free all
+          // allocations=
 we made recursively, given that the whole subhierarchy
+          // has not bee=
n wired into the live page tables yet. (This is not
+          // possible fo=
r existing table entries, since we cannot revert the
+          // modificatio=
ns we made to the subhierarchy it represents.)
+          //<=
/pre>
+          FreePageTables=
Recursive (TranslationTable, Level + 1);
+        }
+
+        return Status;<=
/pre>
+      }
+
+      if (!IsTableEntry (*Entry)) {
+        EntryValue =3D SetPpnToPte=
 (0, (UINTN)TranslationTable, Level);
+        EntryValue =3D SetTableEnt=
ry (EntryValue);
+        ReplaceTableEntry (
+           &nb=
sp;            =
   Entry,
+           &nb=
sp;            =
   EntryValue,
+           &nb=
sp;            =
   RegionStart,
+           &nb=
sp;            =
   TableIsLive
+           &nb=
sp;            =
   );
+      }
+    } else {
+      EntryValue =3D (*Entry & ~Attribut=
eClearMask) | AttributeSetMask;
+      //
+      // We don't have page fault exception =
handler when a virtual page is accessed and
+      // the A bit is clear, or is written a=
nd the D bit is clear.
+      // So just set A for read and D for wr=
ite permission.
+      //
+      if (AttributeSetMask & RISCV_PG_R)=
 {
+        EntryValue |=3D RISCV_PG_A=
;
+      }
+
+      if (AttributeSetMask & RISCV_PG_W)=
 {
+        EntryValue |=3D RISCV_PG_D=
;
+      }
+
+      EntryValue =3D SetPpnToPte (EntryValue=
, RegionStart, Level);
+      EntryValue =3D SetValidPte (EntryValue=
);
+      ReplaceTableEntry (Entry, EntryValue, =
RegionStart, TableIsLive);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+UpdateRegionMapping (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionLength,
+  IN  UINTN    AttributeSetMask,<=
/pre>
+  IN  UINTN    AttributeClearMask,
+  IN  UINTN    *RootTable,
+  IN  BOOLEAN  TableIsLive
+  )
+{
+  if (((RegionStart | RegionLength) & EFI_PAGE_MASK) !=3D 0)=
 {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return UpdateRegionMappingRecursive (
+           &nb=
sp;            =
            &nb=
sp;  RegionStart,
+           &nb=
sp;            =
            &nb=
sp;  RegionStart + RegionLength,
+           &nb=
sp;            =
            &nb=
sp;  AttributeSetMask,
+           &nb=
sp;            =
            &nb=
sp;  AttributeClearMask,
+            &n=
bsp;            =
;            &n=
bsp; RootTable,
+           &nb=
sp;            =
            &nb=
sp;  0,
+           &nb=
sp;            =
            &nb=
sp;  TableIsLive
+           &nb=
sp;            =
            &nb=
sp;  );
+}
+
+STATIC
+UINTN
+GcdAttributeToPageAttribute (
+  IN UINTN  GcdAttributes
+  )
+{
+  UINTN  RiscVAttributes =3D RISCV_PG_R | RISCV_PG_W | RISC=
V_PG_X;
+
+  // Determine protection attributes
+  if (GcdAttributes & EFI_MEMORY_RO) {
+    RiscVAttributes &=3D ~(RISCV_PG_W);=
+  }
+
+  // Process eXecute Never attribute
+  if (GcdAttributes & EFI_MEMORY_XP) {
+    RiscVAttributes &=3D ~RISCV_PG_X;
+  }
+
+  return RiscVAttributes;
+}
+
+EFI_STATUS
+EFIAPI
+RiscVSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN          =
;       Length,
+  IN UINTN         =
        Attributes
+  )
+{
+  UINTN  PageAttributesSet =3D GcdAttributeToPageAttribute =
(Attributes);
+
+  if (!RiscVMmuEnabled ()) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG (
+         (
+          DEBUG_VERBOSE,=
+          "%a: Set =
%llX page attribute 0x%X\n",
+          __func__,=
+          BaseAddress,
+          PageAttributes=
Set
+         )
+         );
+
+  return UpdateRegionMapping (
+           &nb=
sp;            =
      BaseAddress,
+           &nb=
sp;             =
;     Length,
+           &nb=
sp;            =
      PageAttributesSet,
+           &nb=
sp;            =
      PTE_ATTRIBUTES_MASK,
+           &nb=
sp;            =
      (UINTN *)RiscVGetRootTranslateTable (),=
+           &nb=
sp;            =
      TRUE
+           &nb=
sp;             =
;     );
+}
+
+STATIC
+EFI_STATUS
+RiscVMmuSetSatpMode  (
+  UINTN  SatpMode
+  )
+{
+  VOID         &nbs=
p;            &=
nbsp;      *TranslationTable;
+  UINTN         &nb=
sp;            =
      SatpReg;
+  UINTN         &nb=
sp;            =
      Ppn;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemoryMap;
+  UINTN         &nb=
sp;            =
      NumberOfDescriptors;
+  UINTN         &nb=
sp;            =
      Index;
+  EFI_STATUS        &nbs=
p;            &=
nbsp; Status;
+
+  switch (SatpMode) {
+    case SATP_MODE_OFF:
+      return EFI_SUCCESS;
+    case SATP_MODE_SV39:
+      mMaxRootTableLevel =3D 3;
+      mBitPerLevel    &n=
bsp;  =3D 9;
+      mTableEntryCount   =3D 512;<=
o:p>
+      break;
+    case SATP_MODE_SV48:
+      mMaxRootTableLevel =3D 4;
+      mBitPerLevel    &n=
bsp;  =3D 9;
+      mTableEntryCount   =3D 512;<=
o:p>
+      break;
+    case SATP_MODE_SV57:
+      mMaxRootTableLevel =3D 5;
+      mBitPerLevel    &n=
bsp;  =3D 9;
+      mTableEntryCount   =3D 512;<=
o:p>
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  // Allocate pages for translation table
+  TranslationTable =3D AllocatePages (1);
+  if (TranslationTable =3D=3D NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN));=
+
+  NumberOfDescriptors =3D 0;
+  MemoryMap         =
;  =3D NULL;
+  Status         &n=
bsp;    =3D gDS->GetMemorySpaceMap (
+           &nb=
sp;            =
            &nb=
sp;           &Number=
OfDescriptors,
+            &n=
bsp;            =
;            &n=
bsp;          &Memory=
Map
+           &nb=
sp;            =
            &nb=
sp;           );
+  ASSERT_EFI_ERROR (Status);
+
+  for (Index =3D 0; Index < NumberOfDescriptors; Index++) {
+    if (MemoryMap[Index].GcdMemoryType =3D=3D EfiGcdMe=
moryTypeMemoryMappedIo) {
+      // Default Read/Write attribute for me=
mory mapped IO
+      UpdateRegionMapping (
+           &nb=
sp;            =
   MemoryMap[Index].BaseAddress,
+           &nb=
sp;            =
   MemoryMap[Index].Length,
+           &nb=
sp;            =
   RISCV_PG_R | RISCV_PG_W,
+           &nb=
sp;            =
   PTE_ATTRIBUTES_MASK,
+           &nb=
sp;            =
   TranslationTable,
+           &nb=
sp;            =
   FALSE
+           &nb=
sp;            =
   );
+    } else if (MemoryMap[Index].GcdMemoryType =3D=3D E=
fiGcdMemoryTypeSystemMemory) {
+      // Default Read/Write/Execute attribut=
e for system memory
+      UpdateRegionMapping (
+           &nb=
sp;            =
   MemoryMap[Index].BaseAddress,
+           &nb=
sp;            =
   MemoryMap[Index].Length,
+           &nb=
sp;            =
   RISCV_PG_R | RISCV_PG_W | RISCV_PG_X,
+           &nb=
sp;            =
   PTE_ATTRIBUTES_MASK,
+           &nb=
sp;            =
   TranslationTable,
+           &nb=
sp;            =
   FALSE
+           &nb=
sp;            =
   );
+    }
+  }
+
+  FreePool ((VOID *)MemoryMap);
+
+  if (GetInterruptState ()) {
+    DisableInterrupts ();
+  }
+
+  Ppn =3D (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT;=
+  ASSERT (!(Ppn & ~(SATP64_PPN)));
+
+  SatpReg  =3D Ppn;
+  SatpReg |=3D (SatpMode <<
+           &nb=
sp;  SATP64_MODE_SHIFT) & SATP64_MODE;
+  RiscVSetSupervisorAddressTranslationRegister (SatpReg);
+  /* Check if HW support the setup satp mode */
+  if (SatpReg !=3D RiscVGetSupervisorAddressTranslationRegister =
()) {
+    DEBUG (
+           (
+            DE=
BUG_VERBOSE,
+            &q=
uot;%a: HW does not support SATP mode:%d\n",
+            __=
func__,
+            Sa=
tpMode
+           )
+           );<=
/o:p>
+    FreePageTablesRecursive (TranslationTable, 0);
+    return EFI_DEVICE_ERROR;
+  }
+
+  RiscVLocalTlbFlushAll ();
+
+  if (GetInterruptState ()) {
+    EnableInterrupts ();
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+RiscVConfigureMmu (
+  VOID
+  )
+{
+  EFI_STATUS  Status =3D EFI_SUCCESS;
+  INTN        ModeSupport[] =
=3D { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MODE_SV39 };
+  INTN        Idx;=
+
+  /* Try to setup MMU with highest mode as possible */
+  for (Idx =3D 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) {
+    Status =3D RiscVMmuSetSatpMode (ModeSupport[Idx]);=
+    if (Status =3D=3D EFI_DEVICE_ERROR) {
+      continue;
+    } else if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DEBUG (
+           (
+            DE=
BUG_INFO,
+            &q=
uot;%a: SATP mode %d successfully configured\n",
+            __=
func__,
+            Mo=
deSupport[Idx]
+           )
+           );<=
/o:p>
+    break;
+  }
+
+  return Status;
+}
diff --git a/MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf b/MdeP=
kg/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 Res=
erved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION         =
=3D 0x0001001b
+  BASE_NAME         =
;  =3D BaseRiscVMmuLib
+  FILE_GUID         =
;  =3D d3bc42ee-c9eb-4339-ba11-06747083d3ae
+  MODULE_TYPE         =
=3D BASE
+  VERSION_STRING      =3D 1.0
+  LIBRARY_CLASS       =3D RiscVMmu=
Lib
+
+[Sources]
+  BaseRiscVMmuLib.c
+  RiscVMmuCore.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
diff --git a/MdePkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S b/MdePkg/Li=
brary/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 Res=
erved.<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/R=
iscVVirt.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/BaseRiscV64CpuE=
xceptionHandlerLib/BaseRiscV64CpuExceptionHandlerLib.inf
   RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLi=
b.inf
+  RiscVMmuLib|MdePkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf=
   PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/Platform=
BootManagerLib/PlatformBootManagerLib.inf
   ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/B=
aseResetSystemLib.inf
 
diff --git a/OvmfPkg/RiscVVirt/Sec/Memory.c b/OvmfPkg/RiscVVirt/Sec/Me=
mory.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_MOD=
E_OFF << 60);
-  DEBUG ((DEBUG_INFO, "%a: Set Supervisor address mode to b=
are-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) =3D=3D (SATP_MODE_OFF << SATP64_MODE_SHIFT));
 
   BuildMemoryTypeInformationHob ();
 
diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c b/UefiCpuPkg/CpuDxeRisc=
V64/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 suppor=
ted yet\n", __func__));
-  return EFI_SUCCESS;
+  return RiscVSetMemoryAttributes (BaseAddress, Length, Attribut=
es);
 }
 
 /**
@@ -340,6 +339,12 @@ InitializeCpu (
   //
   DisableInterrupts ();
 
+  //
+  // Enable MMU
+  //
+  Status =3D RiscVConfigureMmu ();
+  ASSERT_EFI_ERROR (Status);
+
   //
   // Install Boot protocol
   //
diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h b/UefiCpuPkg/CpuDxeRisc=
V64/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 c=
oherent
diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf b/UefiCpuPkg/C=
puDxeRiscV64/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

<= /p>

--_000_MN2PR13MB30225A5769E6AF33496072E0A7419MN2PR13MB3022namp_--