From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ed1-f44.google.com (mail-ed1-f44.google.com [209.85.208.44]) by mx.groups.io with SMTP id smtpd.web11.4050.1689361829838530229 for ; Fri, 14 Jul 2023 12:10:30 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="signature has expired" header.i=@ventanamicro.com header.s=google header.b=Etxbc+ao; spf=pass (domain: ventanamicro.com, ip: 209.85.208.44, mailfrom: tphan@ventanamicro.com) Received: by mail-ed1-f44.google.com with SMTP id 4fb4d7f45d1cf-51a52a7d859so7270475a12.0 for ; Fri, 14 Jul 2023 12:10:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ventanamicro.com; s=google; t=1689361828; x=1691953828; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=BttGwxDiOd30dHKwum0JTENcZCmsGmQnro1E4AppTIw=; b=Etxbc+aorXGSvjnfmZ7Wm7h0l2XV5afCilgtyPkxOYh2VvQHOadBWVbGL5Uw50p4Fa HQwIj56CY7AA5pRDHIaWVDIy1q7VLpncryjUl1Vpfq63f8rOJsZtOLCRb9ax1P1xGTx9 yE3nivVpyj8vyCiIUlU8UGgORuASOQ3RAkV/wKtBJkaWJZ6TCnhyYAeal2sa840LEmCX 8gPmOfBzXy68KTDKpJ+Vn6zAIlXF2EmqCLXj1ygCR0prlF8DO9r0xIJPZvx5S6s+b0em EehaCwfjIUuyJqDZ4Z5woePnP3cOUD1jA30R5RKqQqRRUncqBd9/SbP+EygRI46Dlpem /M6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689361828; x=1691953828; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=BttGwxDiOd30dHKwum0JTENcZCmsGmQnro1E4AppTIw=; b=Nmwx1A/6CH0cQL/26kFNQDcIJOeaNYiD634kkmeVXkKw02gIfg9rb9k51hH2kquppL qRedzSFD+FrknAvHOnAXvnZvNCRtf0G+ug8ZdcjkGfLlYqS+z5GdlbaycOsAs/vkDaOx aYpheZotFtxzwe3n2LTZ548DRcdyQtq/TrtJV4wZZz4ltZbO4JssCdxQVhS9iv+BiTDs gk6HrXKhgoma6yd2xb4KV9NrSjD4PqwC0a8oRlMpWiMhU6LhyRamGMkdWXTV2G2X1I/g Nc0SwL6QDds3iQUhiOs4DGm71TLhirUe9V//nC1P4W8En6Vo5o1r04U6x0LHGTVY+ZPB 0ThQ== X-Gm-Message-State: ABy/qLYPRaGI6TST60MiNIsDCeWR43+0jHhB3GFPyeRF99J8BsU/IaQE 7Iy7ND7rWmcF1JGBBrBHV5VT2QbEpx3wJJ5hb4iBZQ== X-Google-Smtp-Source: APBJJlEQkEBTd7JY4yCV1g9053e0jCNg/kVWozuwQ3QACJppsaOu5ILMD5AfFWpMdfGKNHtoH6KGu9VtIWW55ob8cmQ= X-Received: by 2002:a05:6402:74c:b0:521:60f3:77b6 with SMTP id p12-20020a056402074c00b0052160f377b6mr2905935edy.19.1689361827951; Fri, 14 Jul 2023 12:10:27 -0700 (PDT) MIME-Version: 1.0 References: <20230623183934.23905-1-tphan@ventanamicro.com> <20230623183934.23905-8-tphan@ventanamicro.com> In-Reply-To: From: "Tuan Phan" Date: Fri, 14 Jul 2023 12:10:16 -0700 Message-ID: Subject: Re: [PATCH v4 7/7] UefiCpuPkg: RISC-V: Support MMU with SV39/48/57 mode To: Sunil V L Cc: devel@edk2.groups.io, michael.d.kinney@intel.com, gaoliming@byosoft.com.cn, zhiguang.liu@intel.com, git@danielschaefer.me, andrei.warkentin@intel.com, ardb+tianocore@kernel.org Content-Type: multipart/alternative; boundary="000000000000a70c8906007733f3" --000000000000a70c8906007733f3 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Jul 14, 2023 at 3:24=E2=80=AFAM Sunil V L wrote: > On Fri, Jun 23, 2023 at 11:39:34AM -0700, Tuan Phan wrote: > > During CpuDxe initialization, MMU will be setup with the highest > > mode that HW supports. > > > > Reviewed-by: Andrei Warkentin > > Signed-off-by: Tuan Phan > > --- > Hi Tuan, > > CI tests are failing for these changes primarily due to code formatting > errors. Can you please fix them and send the next version? > Hi Sunil, I sent the next version. It passed CI at this pull request: https://github.com/tianocore/edk2/pull/4569 > > Thanks, > Sunil > > OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc | 1 + > > UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c | 9 +- > > UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h | 2 + > > UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf | 2 + > > UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h | 39 ++ > > .../Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c | 569 ++++++++++++++++++ > > .../BaseRiscVMmuLib/BaseRiscVMmuLib.inf | 26 + > > .../Library/BaseRiscVMmuLib/RiscVMmuCore.S | 31 + > > 8 files changed, 677 insertions(+), 2 deletions(-) > > create mode 100644 UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h > > create mode 100644 UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.= c > > create mode 100644 > UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > > create mode 100644 UefiCpuPkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S > > > > diff --git a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > > index 731f54f73f81..bc204ba5fe52 100644 > > --- a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > > +++ b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc > > @@ -83,6 +83,7 @@ > > # RISC-V Architectural Libraries > > > CpuExceptionHandlerLib|UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandlerL= ib/BaseRiscV64CpuExceptionHandlerLib.inf > > RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLib.inf > > + RiscVMmuLib|UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > > > PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/PlatformBootManagerLib/P= latformBootManagerLib.inf > > > ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/BaseResetSystemLi= b.inf > > > > 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 =3D 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..6d52085df0d5 100644 > > --- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf > > +++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf > > @@ -37,6 +37,8 @@ > > TimerLib > > PeCoffGetEntryPointLib > > RiscVSbiLib > > + RiscVMmuLib > > + CacheMaintenanceLib > > > > [Sources] > > CpuDxe.c > > diff --git a/UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h > b/UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h > > new file mode 100644 > > index 000000000000..f71d6a4a1e7b > > --- /dev/null > > +++ b/UefiCpuPkg/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/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c > b/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c > > new file mode 100644 > > index 000000000000..e6841b793bfc > > --- /dev/null > > +++ b/UefiCpuPkg/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 ((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) =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, > > + AttributeSetMask, > > + AttributeClearMask > > + ) > > + ); > > + > > + for ( ; RegionStart < RegionEnd; RegionStart =3D BlockEnd) { > > + BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockMask) + 1); > > + Entry =3D &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 a= t > > + // 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) || IsTableEntr= y > (*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 > populate > > + // the new table with the attributes of the block entry it > replaces. > > + // > > + Status =3D 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 allocate= d > here. > > + // > > + FreePages (TranslationTable, 1); > > + return Status; > > + } > > + } > > + > > + NextTableIsLive =3D FALSE; > > + } else { > > + TranslationTable =3D (UINTN *)(GetPpnfromPte (*Entry, Level) <= < > RISCV_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 > subhierarchy > > + // has not been wired into the live page tables yet. (This i= s > 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 =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 pag= e > 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 > 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 =3D=3D > 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 =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_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 ( > > + ( > > + DEBUG_INFO, > > + "%a: SATP mode %d successfully configured\n", > > + __func__, > > + ModeSupport[Idx] > > + ) > > + ); > > + break; > > + } > > + > > + return Status; > > +} > > diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > b/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > > new file mode 100644 > > index 000000000000..2819c871b2a2 > > --- /dev/null > > +++ b/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > > @@ -0,0 +1,26 @@ > > +## @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 > > + UefiCpuPkg/UefiCpuPkg.dec > > + > > +[LibraryClasses] > > + BaseLib > > diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S > b/UefiCpuPkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S > > new file mode 100644 > > index 000000000000..42eec4cbdf83 > > --- /dev/null > > +++ b/UefiCpuPkg/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 > > -- > > 2.25.1 > > > --000000000000a70c8906007733f3 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Fri, Jul 14, 2023 at 3:24=E2=80=AF= AM Sunil V L <sunilvl@ventan= amicro.com> wrote:
On Fri, Jun 23, 2023 a= t 11:39:34AM -0700, Tuan Phan wrote:
> During CpuDxe initialization, MMU will be setup with the highest
> mode that HW supports.
>
> Reviewed-by: Andrei Warkentin <andrei.warkentin@intel.com>
> Signed-off-by: Tuan Phan <tphan@ventanamicro.com>
> ---
Hi Tuan,

CI tests are failing for these changes primarily due to code formatting
errors. Can you please fix them and send the next version?

Hi Sunil,
I sent the next version. It passed= CI at this pull request: https://github.com/tianocore/edk2/pull/4569
=C2=A0

Thanks,
Sunil
>=C2=A0 OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0|=C2=A0 =C2=A01 +
>=C2=A0 UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0|=C2=A0 =C2=A09 +-
>=C2=A0 UefiCpuPkg/CpuDxeRiscV64/CpuDxe.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0|=C2=A0 =C2=A02 +
>=C2=A0 UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf=C2=A0 =C2=A0 |=C2=A0 = =C2=A02 +
>=C2=A0 UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h=C2=A0 |=C2=A0 39 ++=
>=C2=A0 .../Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c | 569 ++++++++++++= ++++++
>=C2=A0 .../BaseRiscVMmuLib/BaseRiscVMmuLib.inf=C2=A0 =C2=A0 =C2=A0 =C2= =A0|=C2=A0 26 +
>=C2=A0 .../Library/BaseRiscVMmuLib/RiscVMmuCore.S=C2=A0 =C2=A0 |=C2=A0 = 31 +
>=C2=A0 8 files changed, 677 insertions(+), 2 deletions(-)
>=C2=A0 create mode 100644 UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h<= br> >=C2=A0 create mode 100644 UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVM= muLib.c
>=C2=A0 create mode 100644 UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVM= muLib.inf
>=C2=A0 create mode 100644 UefiCpuPkg/Library/BaseRiscVMmuLib/RiscVMmuCo= re.S
>
> diff --git a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc b/OvmfPkg/RiscVVirt/R= iscVVirt.dsc.inc
> index 731f54f73f81..bc204ba5fe52 100644
> --- a/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc
> +++ b/OvmfPkg/RiscVVirt/RiscVVirt.dsc.inc
> @@ -83,6 +83,7 @@
>=C2=A0 =C2=A0 # RISC-V Architectural Libraries
>=C2=A0 =C2=A0 CpuExceptionHandlerLib|UefiCpuPkg/Library/BaseRiscV64CpuE= xceptionHandlerLib/BaseRiscV64CpuExceptionHandlerLib.inf
>=C2=A0 =C2=A0 RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLi= b.inf
> +=C2=A0 RiscVMmuLib|UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib= .inf
>=C2=A0 =C2=A0 PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/Platform= BootManagerLib/PlatformBootManagerLib.inf
>=C2=A0 =C2=A0 ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/B= aseResetSystemLib.inf
>=C2=A0
> 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 (
>=C2=A0 =C2=A0 IN UINT64=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0Attributes
>=C2=A0 =C2=A0 )
>=C2=A0 {
> -=C2=A0 DEBUG ((DEBUG_INFO, "%a: Set memory attributes not suppor= ted yet\n", __func__));
> -=C2=A0 return EFI_SUCCESS;
> +=C2=A0 return RiscVSetMemoryAttributes (BaseAddress, Length, Attribut= es);
>=C2=A0 }
>=C2=A0
>=C2=A0 /**
> @@ -340,6 +339,12 @@ InitializeCpu (
>=C2=A0 =C2=A0 //
>=C2=A0 =C2=A0 DisableInterrupts ();
>=C2=A0
> +=C2=A0 //
> +=C2=A0 // Enable MMU
> +=C2=A0 //
> +=C2=A0 Status =3D RiscVConfigureMmu ();
> +=C2=A0 ASSERT_EFI_ERROR (Status);
> +
>=C2=A0 =C2=A0 //
>=C2=A0 =C2=A0 // Install Boot protocol
>=C2=A0 =C2=A0 //
> 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 @@
>=C2=A0 #include <Protocol/Cpu.h>
>=C2=A0 #include <Protocol/RiscVBootProtocol.h>
>=C2=A0 #include <Library/BaseRiscVSbiLib.h>
> +#include <Library/BaseRiscVMmuLib.h>
>=C2=A0 #include <Library/BaseLib.h>
>=C2=A0 #include <Library/CpuExceptionHandlerLib.h>
>=C2=A0 #include <Library/DebugLib.h>
>=C2=A0 #include <Library/UefiBootServicesTableLib.h>
>=C2=A0 #include <Library/UefiDriverEntryPoint.h>
> +#include <Register/RiscV64/RiscVEncoding.h>
>=C2=A0
>=C2=A0 /**
>=C2=A0 =C2=A0 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..6d52085df0d5 100644
> --- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
> +++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
> @@ -37,6 +37,8 @@
>=C2=A0 =C2=A0 TimerLib
>=C2=A0 =C2=A0 PeCoffGetEntryPointLib
>=C2=A0 =C2=A0 RiscVSbiLib
> +=C2=A0 RiscVMmuLib
> +=C2=A0 CacheMaintenanceLib
>=C2=A0
>=C2=A0 [Sources]
>=C2=A0 =C2=A0 CpuDxe.c
> diff --git a/UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h b/UefiCpuPkg= /Include/Library/BaseRiscVMmuLib.h
> new file mode 100644
> index 000000000000..f71d6a4a1e7b
> --- /dev/null
> +++ b/UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h
> @@ -0,0 +1,39 @@
> +/** @file
> +
> +=C2=A0 Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.<= ;BR>
> +=C2=A0 Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Rese= rved.<BR>
> +
> +=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef BASE_RISCV_MMU_LIB_H_
> +#define BASE_RISCV_MMU_LIB_H_
> +
> +VOID
> +EFIAPI
> +RiscVLocalTlbFlushAll (
> +=C2=A0 VOID
> +=C2=A0 );
> +
> +VOID
> +EFIAPI
> +RiscVLocalTlbFlush (
> +=C2=A0 UINTN=C2=A0 VirtAddr
> +=C2=A0 );
> +
> +EFI_STATUS
> +EFIAPI
> +RiscVSetMemoryAttributes (
> +=C2=A0 IN EFI_PHYSICAL_ADDRESS=C2=A0 BaseAddress,
> +=C2=A0 IN UINT64=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 Length,
> +=C2=A0 IN UINT64=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 Attributes
> +=C2=A0 );
> +
> +EFI_STATUS
> +EFIAPI
> +RiscVConfigureMmu (
> +=C2=A0 VOID
> +=C2=A0 );
> +
> +#endif /* BASE_RISCV_MMU_LIB_H_ */
> diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c b/Ue= fiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c
> new file mode 100644
> index 000000000000..e6841b793bfc
> --- /dev/null
> +++ b/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c
> @@ -0,0 +1,569 @@
> +/** @file
> +*=C2=A0 MMU implementation for RISC-V
> +*
> +*=C2=A0 Copyright (c) 2011-2020, ARM Limited. All rights reserved. > +*=C2=A0 Copyright (c) 2016, Linaro Limited. All rights reserved.
> +*=C2=A0 Copyright (c) 2017, Intel Corporation. All rights reserved.&l= t;BR>
> +*=C2=A0 Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Res= erved.<BR>
> +*
> +*=C2=A0 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=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT0
> +#define RISCV_PG_R=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT1
> +#define RISCV_PG_W=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT2
> +#define RISCV_PG_X=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT3
> +#define RISCV_PG_G=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT5
> +#define RISCV_PG_A=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT6
> +#define RISCV_PG_D=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIT7
> +#define PTE_ATTRIBUTES_MASK=C2=A0 0xE
> +
> +#define PTE_PPN_MASK=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x3FFFFFFFFFFC= 00ULL
> +#define PTE_PPN_SHIFT=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A010
> +#define RISCV_MMU_PAGE_SHIFT=C2=A0 12
> +
> +STATIC UINTN=C2=A0 mMaxRootTableLevel;
> +STATIC UINTN=C2=A0 mBitPerLevel;
> +STATIC UINTN=C2=A0 mTableEntryCount;
> +
> +STATIC
> +BOOLEAN
> +RiscVMmuEnabled (
> +=C2=A0 VOID
> +=C2=A0 )
> +{
> +=C2=A0 return ((RiscVGetSupervisorAddressTranslationRegister () &=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0SATP64_MODE) !=3D (SATP_MODE= _OFF << SATP64_MODE_SHIFT));
> +}
> +
> +STATIC
> +UINTN
> +RiscVGetRootTranslateTable (
> +=C2=A0 VOID
> +=C2=A0 )
> +{
> +=C2=A0 return (RiscVGetSupervisorAddressTranslationRegister () & = SATP64_PPN) <<
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RISCV_MMU_PAGE_SHIFT;
> +}
> +
> +STATIC
> +BOOLEAN
> +IsValidPte (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 Entry
> +=C2=A0 )
> +{
> +=C2=A0 if (!(Entry & RISCV_PG_V) ||
> +=C2=A0 =C2=A0 =C2=A0 (((Entry & (RISCV_PG_R | RISCV_PG_W)) =3D=3D= RISCV_PG_W)))
> +=C2=A0 {
> +=C2=A0 =C2=A0 return FALSE;
> +=C2=A0 }
> +
> +=C2=A0 return TRUE;
> +}
> +
> +STATIC
> +UINTN
> +SetValidPte (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 Entry
> +=C2=A0 )
> +{
> +=C2=A0 /* Set Valid and Global mapping bits */
> +=C2=A0 return Entry | RISCV_PG_G | RISCV_PG_V;
> +}
> +
> +STATIC
> +BOOLEAN
> +IsBlockEntry (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 Entry
> +=C2=A0 )
> +{
> +=C2=A0 return IsValidPte (Entry) &&
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(Entry & (RISCV_PG_X | RISCV_PG= _R));
> +}
> +
> +STATIC
> +BOOLEAN
> +IsTableEntry (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 Entry
> +=C2=A0 )
> +{
> +=C2=A0 return IsValidPte (Entry) &&
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0!IsBlockEntry (Entry);
> +}
> +
> +STATIC
> +UINTN
> +SetTableEntry (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 Entry
> +=C2=A0 )
> +{
> +=C2=A0 Entry=C2=A0 =3D SetValidPte (Entry);
> +=C2=A0 Entry &=3D ~(RISCV_PG_X | RISCV_PG_W | RISCV_PG_R);
> +
> +=C2=A0 return Entry;
> +}
> +
> +STATIC
> +VOID
> +ReplaceTableEntry (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 *Entry,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 Value,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 RegionStart,
> +=C2=A0 IN=C2=A0 BOOLEAN=C2=A0 IsLiveBlockMapping
> +=C2=A0 )
> +{
> +=C2=A0 *Entry =3D Value;
> +
> +=C2=A0 if (IsLiveBlockMapping && RiscVMmuEnabled ()) {
> +=C2=A0 =C2=A0 RiscVLocalTlbFlush (RegionStart);
> +=C2=A0 }
> +}
> +
> +STATIC
> +UINTN
> +GetPpnfromPte (
> +=C2=A0 UINTN=C2=A0 Entry,
> +=C2=A0 UINTN=C2=A0 Level
> +=C2=A0 )
> +{
> +=C2=A0 return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT); > +}
> +
> +STATIC
> +UINTN
> +SetPpnToPte (
> +=C2=A0 UINTN=C2=A0 Entry,
> +=C2=A0 UINTN=C2=A0 Address,
> +=C2=A0 UINTN=C2=A0 Level
> +=C2=A0 )
> +{
> +=C2=A0 UINTN=C2=A0 Ppn;
> +
> +=C2=A0 Ppn =3D ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_= PPN_SHIFT);
> +=C2=A0 ASSERT (~(Ppn & ~PTE_PPN_MASK));
> +=C2=A0 Entry &=3D ~PTE_PPN_MASK;
> +=C2=A0 return Entry | Ppn;
> +}
> +
> +STATIC
> +VOID
> +FreePageTablesRecursive (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 *TranslationTable,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 Level
> +=C2=A0 )
> +{
> +=C2=A0 UINTN=C2=A0 Index;
> +
> +=C2=A0 if (Level < mMaxRootTableLevel - 1) {
> +=C2=A0 =C2=A0 for (Index =3D 0; Index < mTableEntryCount; Index++)= {
> +=C2=A0 =C2=A0 =C2=A0 if (IsTableEntry (TranslationTable[Index])) { > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 FreePageTablesRecursive (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (UINTN *)(GetPpnfromPte ((Translat= ionTable[Index]), Level) <<
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= RISCV_MMU_PAGE_SHIFT),
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Level + 1
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
> +=C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 }
> +=C2=A0 }
> +
> +=C2=A0 FreePages (TranslationTable, 1);
> +}
> +
> +STATIC
> +EFI_STATUS
> +UpdateRegionMappingRecursive (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 RegionStart,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 RegionEnd,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 AttributeSetMask,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 AttributeClearMask,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 *PageTable,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 Level,
> +=C2=A0 IN=C2=A0 BOOLEAN=C2=A0 TableIsLive
> +=C2=A0 )
> +{
> +=C2=A0 EFI_STATUS=C2=A0 Status;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0BlockShift;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0BlockMask;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0BlockEnd;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0*Entry;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0EntryValue;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0*TranslationTable;
> +=C2=A0 BOOLEAN=C2=A0 =C2=A0 =C2=A0NextTableIsLive;
> +
> +=C2=A0 ASSERT (Level < mMaxRootTableLevel);
> +=C2=A0 ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) =3D=3D= 0);
> +
> +=C2=A0 BlockShift =3D (mMaxRootTableLevel - Level - 1) * mBitPerLevel= + RISCV_MMU_PAGE_SHIFT;
> +=C2=A0 BlockMask=C2=A0 =3D MAX_ADDRESS >> (64 - BlockShift); > +
> +=C2=A0 DEBUG (
> +=C2=A0 =C2=A0 (
> +=C2=A0 =C2=A0 =C2=A0DEBUG_VERBOSE,
> +=C2=A0 =C2=A0 =C2=A0"%a(%d): %llx - %llx set %lx clr %lx\n"= ,
> +=C2=A0 =C2=A0 =C2=A0__func__,
> +=C2=A0 =C2=A0 =C2=A0Level,
> +=C2=A0 =C2=A0 =C2=A0RegionStart,
> +=C2=A0 =C2=A0 =C2=A0RegionEnd,
> +=C2=A0 =C2=A0 =C2=A0AttributeSetMask,
> +=C2=A0 =C2=A0 =C2=A0AttributeClearMask
> +=C2=A0 =C2=A0 )
> +=C2=A0 =C2=A0 );
> +
> +=C2=A0 for ( ; RegionStart < RegionEnd; RegionStart =3D BlockEnd) = {
> +=C2=A0 =C2=A0 BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockMask) = + 1);
> +=C2=A0 =C2=A0 Entry=C2=A0 =C2=A0 =3D &PageTable[(RegionStart >= > BlockShift) & (mTableEntryCount - 1)];
> +
> +=C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 // If RegionStart or BlockEnd is not aligned to the blo= ck size at this
> +=C2=A0 =C2=A0 // level, we will have to create a table mapping in ord= er to map less
> +=C2=A0 =C2=A0 // than a block, and recurse to create the block or pag= e entries at
> +=C2=A0 =C2=A0 // the next level. No block mappings are allowed at all= at level 0,
> +=C2=A0 =C2=A0 // so in that case, we have to recurse unconditionally.=
> +=C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 if ((Level =3D=3D 0) ||
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 (((RegionStart | BlockEnd) & BlockMas= k) !=3D 0) || IsTableEntry (*Entry))
> +=C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 ASSERT (Level < mMaxRootTableLevel - 1);
> +=C2=A0 =C2=A0 =C2=A0 if (!IsTableEntry (*Entry)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 // No table entry exists yet, so we need = to allocate a page table
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 // for the next level.
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 TranslationTable =3D AllocatePages (1); > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (TranslationTable =3D=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return EFI_OUT_OF_RESOURCES;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 ZeroMem (TranslationTable, EFI_PAGE_SIZE)= ;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (IsBlockEntry (*Entry)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // We are splitting an existing bl= ock entry, so we have to populate
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // the new table with the attribut= es of the block entry it replaces.
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Status =3D UpdateRegionMappingRecu= rsive (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0RegionStart & ~BlockMask,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0(RegionStart | BlockMask) + 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0*Entry & PTE_ATTRIBUTES_MASK,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0PTE_ATTRIBUTES_MASK,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0TranslationTable,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0Level + 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0FALSE
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (EFI_ERROR (Status)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // The range we passed to U= pdateRegionMappingRecursive () is block
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // aligned, so it is guaran= teed that no further pages were allocated
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // by it, and so we only ha= ve to free the page we allocated here.
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FreePages (TranslationTable= , 1);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return Status;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 NextTableIsLive =3D FALSE;
> +=C2=A0 =C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 TranslationTable =3D (UINTN *)(GetPpnfrom= Pte (*Entry, Level) << RISCV_MMU_PAGE_SHIFT);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 NextTableIsLive=C2=A0 =3D TableIsLive; > +=C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 // Recurse to the next level
> +=C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 Status =3D UpdateRegionMappingRecursive (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RegionS= tart,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BlockEn= d,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Attribu= teSetMask,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Attribu= teClearMask,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Transla= tionTable,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Level += 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0NextTab= leIsLive
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0);
> +=C2=A0 =C2=A0 =C2=A0 if (EFI_ERROR (Status)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!IsTableEntry (*Entry)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // We are creating a new table ent= ry, so on failure, we can free all
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // allocations we made recursively= , given that the whole subhierarchy
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // has not been wired into the liv= e page tables yet. (This is not
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // possible for existing table ent= ries, since we cannot revert the
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // modifications we made to the su= bhierarchy it represents.)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FreePageTablesRecursive (Translati= onTable, Level + 1);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return Status;
> +=C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 if (!IsTableEntry (*Entry)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 EntryValue =3D SetPpnToPte (0, (UINTN)Tra= nslationTable, Level);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 EntryValue =3D SetTableEntry (EntryValue)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 ReplaceTableEntry (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Entry,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 EntryValue,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 RegionStart,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 TableIsLive
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
> +=C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 EntryValue =3D (*Entry & ~AttributeClearMask= ) | AttributeSetMask;
> +=C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 // We don't have page fault exception handle= r when a virtual page is accessed and
> +=C2=A0 =C2=A0 =C2=A0 // the A bit is clear, or is written and the D b= it is clear.
> +=C2=A0 =C2=A0 =C2=A0 // So just set A for read and D for write permis= sion.
> +=C2=A0 =C2=A0 =C2=A0 //
> +=C2=A0 =C2=A0 =C2=A0 if (AttributeSetMask & RISCV_PG_R) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 EntryValue |=3D RISCV_PG_A;
> +=C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 if (AttributeSetMask & RISCV_PG_W) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 EntryValue |=3D RISCV_PG_D;
> +=C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 EntryValue =3D SetPpnToPte (EntryValue, RegionSt= art, Level);
> +=C2=A0 =C2=A0 =C2=A0 EntryValue =3D SetValidPte (EntryValue);
> +=C2=A0 =C2=A0 =C2=A0 ReplaceTableEntry (Entry, EntryValue, RegionStar= t, TableIsLive);
> +=C2=A0 =C2=A0 }
> +=C2=A0 }
> +
> +=C2=A0 return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +UpdateRegionMapping (
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 RegionStart,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 RegionLength,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 AttributeSetMask,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 AttributeClearMask,
> +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 *RootTable,
> +=C2=A0 IN=C2=A0 BOOLEAN=C2=A0 TableIsLive
> +=C2=A0 )
> +{
> +=C2=A0 if (((RegionStart | RegionLength) & EFI_PAGE_MASK) !=3D 0)= {
> +=C2=A0 =C2=A0 return EFI_INVALID_PARAMETER;
> +=C2=A0 }
> +
> +=C2=A0 return UpdateRegionMappingRecursive (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RegionStart,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RegionStart + RegionLength,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0AttributeSetMask,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0AttributeClearMask,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RootTable,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TableIsLive
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0);
> +}
> +
> +STATIC
> +UINTN
> +GcdAttributeToPageAttribute (
> +=C2=A0 IN UINTN=C2=A0 GcdAttributes
> +=C2=A0 )
> +{
> +=C2=A0 UINTN=C2=A0 RiscVAttributes =3D RISCV_PG_R | RISCV_PG_W | RISC= V_PG_X;
> +
> +=C2=A0 // Determine protection attributes
> +=C2=A0 if (GcdAttributes & EFI_MEMORY_RO) {
> +=C2=A0 =C2=A0 RiscVAttributes &=3D ~(RISCV_PG_W);
> +=C2=A0 }
> +
> +=C2=A0 // Process eXecute Never attribute
> +=C2=A0 if (GcdAttributes & EFI_MEMORY_XP) {
> +=C2=A0 =C2=A0 RiscVAttributes &=3D ~RISCV_PG_X;
> +=C2=A0 }
> +
> +=C2=A0 return RiscVAttributes;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +RiscVSetMemoryAttributes (
> +=C2=A0 IN EFI_PHYSICAL_ADDRESS=C2=A0 BaseAddress,
> +=C2=A0 IN UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0Length,
> +=C2=A0 IN UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0Attributes
> +=C2=A0 )
> +{
> +=C2=A0 UINTN=C2=A0 PageAttributesSet =3D GcdAttributeToPageAttribute = (Attributes);
> +
> +=C2=A0 if (!RiscVMmuEnabled ()) {
> +=C2=A0 =C2=A0 return EFI_SUCCESS;
> +=C2=A0 }
> +
> +=C2=A0 DEBUG (
> +=C2=A0 =C2=A0 (
> +=C2=A0 =C2=A0 =C2=A0DEBUG_VERBOSE,
> +=C2=A0 =C2=A0 =C2=A0"%a: Set %llX page attribute 0x%X\n", > +=C2=A0 =C2=A0 =C2=A0__func__,
> +=C2=A0 =C2=A0 =C2=A0BaseAddress,
> +=C2=A0 =C2=A0 =C2=A0PageAttributesSet
> +=C2=A0 =C2=A0 )
> +=C2=A0 =C2=A0 );
> +
> +=C2=A0 return UpdateRegionMapping (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BaseAddress,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Length,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0PageAttributesSet,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0PTE_ATTRIBUTES_MASK,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(UINTN *)RiscVGetRootTransla= teTable (),
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TRUE
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0);
> +}
> +
> +STATIC
> +EFI_STATUS
> +RiscVMmuSetSatpMode=C2=A0 (
> +=C2=A0 UINTN=C2=A0 SatpMode
> +=C2=A0 )
> +{
> +=C2=A0 VOID=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*TranslationTable;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SatpReg;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Ppn;
> +=C2=A0 EFI_GCD_MEMORY_SPACE_DESCRIPTOR=C2=A0 *MemoryMap;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 NumberOfDescriptors;
> +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Index;
> +=C2=A0 EFI_STATUS=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Status;
> +
> +=C2=A0 switch (SatpMode) {
> +=C2=A0 =C2=A0 case SATP_MODE_OFF:
> +=C2=A0 =C2=A0 =C2=A0 return EFI_SUCCESS;
> +=C2=A0 =C2=A0 case SATP_MODE_SV39:
> +=C2=A0 =C2=A0 =C2=A0 mMaxRootTableLevel =3D 3;
> +=C2=A0 =C2=A0 =C2=A0 mBitPerLevel=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D 9; > +=C2=A0 =C2=A0 =C2=A0 mTableEntryCount=C2=A0 =C2=A0=3D 512;
> +=C2=A0 =C2=A0 =C2=A0 break;
> +=C2=A0 =C2=A0 case SATP_MODE_SV48:
> +=C2=A0 =C2=A0 =C2=A0 mMaxRootTableLevel =3D 4;
> +=C2=A0 =C2=A0 =C2=A0 mBitPerLevel=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D 9; > +=C2=A0 =C2=A0 =C2=A0 mTableEntryCount=C2=A0 =C2=A0=3D 512;
> +=C2=A0 =C2=A0 =C2=A0 break;
> +=C2=A0 =C2=A0 case SATP_MODE_SV57:
> +=C2=A0 =C2=A0 =C2=A0 mMaxRootTableLevel =3D 5;
> +=C2=A0 =C2=A0 =C2=A0 mBitPerLevel=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D 9; > +=C2=A0 =C2=A0 =C2=A0 mTableEntryCount=C2=A0 =C2=A0=3D 512;
> +=C2=A0 =C2=A0 =C2=A0 break;
> +=C2=A0 =C2=A0 default:
> +=C2=A0 =C2=A0 =C2=A0 return EFI_INVALID_PARAMETER;
> +=C2=A0 }
> +
> +=C2=A0 // Allocate pages for translation table
> +=C2=A0 TranslationTable =3D AllocatePages (1);
> +=C2=A0 if (TranslationTable =3D=3D NULL) {
> +=C2=A0 =C2=A0 return EFI_OUT_OF_RESOURCES;
> +=C2=A0 }
> +
> +=C2=A0 ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN));=
> +
> +=C2=A0 NumberOfDescriptors =3D 0;
> +=C2=A0 MemoryMap=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D NULL; > +=C2=A0 Status=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D gDS= ->GetMemorySpaceMap (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&NumberOfDescriptors,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&MemoryMap
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0);
> +=C2=A0 ASSERT_EFI_ERROR (Status);
> +
> +=C2=A0 for (Index =3D 0; Index < NumberOfDescriptors; Index++) { > +=C2=A0 =C2=A0 if (MemoryMap[Index].GcdMemoryType =3D=3D EfiGcdMemoryT= ypeMemoryMappedIo) {
> +=C2=A0 =C2=A0 =C2=A0 // Default Read/Write attribute for memory mappe= d IO
> +=C2=A0 =C2=A0 =C2=A0 UpdateRegionMapping (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 MemoryMap[Index].BaseAddress,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 MemoryMap[Index].Length,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 RISCV_PG_R | RISCV_PG_W,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 PTE_ATTRIBUTES_MASK,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 TranslationTable,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 FALSE
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 );
> +=C2=A0 =C2=A0 } else if (MemoryMap[Index].GcdMemoryType =3D=3D EfiGcd= MemoryTypeSystemMemory) {
> +=C2=A0 =C2=A0 =C2=A0 // Default Read/Write/Execute attribute for syst= em memory
> +=C2=A0 =C2=A0 =C2=A0 UpdateRegionMapping (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 MemoryMap[Index].BaseAddress,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 MemoryMap[Index].Length,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 RISCV_PG_R | RISCV_PG_W | RISCV_PG_X,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 PTE_ATTRIBUTES_MASK,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 TranslationTable,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 FALSE
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 );
> +=C2=A0 =C2=A0 }
> +=C2=A0 }
> +
> +=C2=A0 FreePool ((VOID *)MemoryMap);
> +
> +=C2=A0 if (GetInterruptState ()) {
> +=C2=A0 =C2=A0 DisableInterrupts ();
> +=C2=A0 }
> +
> +=C2=A0 Ppn =3D (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT;=
> +=C2=A0 ASSERT (!(Ppn & ~(SATP64_PPN)));
> +
> +=C2=A0 SatpReg=C2=A0 =3D Ppn;
> +=C2=A0 SatpReg |=3D (SatpMode <<
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SATP64_MODE_SHIFT) &= amp; SATP64_MODE;
> +=C2=A0 RiscVSetSupervisorAddressTranslationRegister (SatpReg);
> +=C2=A0 /* Check if HW support the setup satp mode */
> +=C2=A0 if (SatpReg !=3D RiscVGetSupervisorAddressTranslationRegister = ()) {
> +=C2=A0 =C2=A0 DEBUG (
> +=C2=A0 =C2=A0 =C2=A0 (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0DEBUG_VERBOSE,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0"%a: HW does not support SATP mode:%d= \n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0__func__,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0SatpMode
> +=C2=A0 =C2=A0 =C2=A0 )
> +=C2=A0 =C2=A0 =C2=A0 );
> +=C2=A0 =C2=A0 FreePageTablesRecursive (TranslationTable, 0);
> +=C2=A0 =C2=A0 return EFI_DEVICE_ERROR;
> +=C2=A0 }
> +
> +=C2=A0 RiscVLocalTlbFlushAll ();
> +
> +=C2=A0 if (GetInterruptState ()) {
> +=C2=A0 =C2=A0 EnableInterrupts ();
> +=C2=A0 }
> +
> +=C2=A0 return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +RiscVConfigureMmu (
> +=C2=A0 VOID
> +=C2=A0 )
> +{
> +=C2=A0 EFI_STATUS=C2=A0 Status=C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D EFI_SUC= CESS;
> +=C2=A0 INTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 ModeSupport[] =3D { SATP_MODE_= SV57, SATP_MODE_SV48, SATP_MODE_SV39 };
> +=C2=A0 INTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 Idx;
> +
> +=C2=A0 /* Try to setup MMU with highest mode as possible */
> +=C2=A0 for (Idx =3D 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) { > +=C2=A0 =C2=A0 Status =3D RiscVMmuSetSatpMode (ModeSupport[Idx]);
> +=C2=A0 =C2=A0 if (Status =3D=3D EFI_DEVICE_ERROR) {
> +=C2=A0 =C2=A0 =C2=A0 continue;
> +=C2=A0 =C2=A0 } else if (EFI_ERROR (Status)) {
> +=C2=A0 =C2=A0 =C2=A0 return Status;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 DEBUG (
> +=C2=A0 =C2=A0 =C2=A0 (
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0DEBUG_INFO,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0"%a: SATP mode %d successfully config= ured\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0__func__,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0ModeSupport[Idx]
> +=C2=A0 =C2=A0 =C2=A0 )
> +=C2=A0 =C2=A0 =C2=A0 );
> +=C2=A0 =C2=A0 break;
> +=C2=A0 }
> +
> +=C2=A0 return Status;
> +}
> diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf b/= UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf
> new file mode 100644
> index 000000000000..2819c871b2a2
> --- /dev/null
> +++ b/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf
> @@ -0,0 +1,26 @@
> +## @file
> +#
> +#=C2=A0 Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Res= erved.<BR>
> +#
> +#=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +=C2=A0 INF_VERSION=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D 0x0001001b > +=C2=A0 BASE_NAME=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D BaseRisc= VMmuLib
> +=C2=A0 FILE_GUID=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D d3bc42ee= -c9eb-4339-ba11-06747083d3ae
> +=C2=A0 MODULE_TYPE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D BASE
> +=C2=A0 VERSION_STRING=C2=A0 =C2=A0 =C2=A0 =3D 1.0
> +=C2=A0 LIBRARY_CLASS=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D RiscVMmuLib
> +
> +[Sources]
> +=C2=A0 BaseRiscVMmuLib.c
> +=C2=A0 RiscVMmuCore.S
> +
> +[Packages]
> +=C2=A0 MdePkg/MdePkg.dec
> +=C2=A0 UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> +=C2=A0 BaseLib
> diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S b/UefiC= puPkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S
> new file mode 100644
> index 000000000000..42eec4cbdf83
> --- /dev/null
> +++ b/UefiCpuPkg/Library/BaseRiscVMmuLib/RiscVMmuCore.S
> @@ -0,0 +1,31 @@
> +/** @file
> +*
> +*=C2=A0 Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Res= erved.<BR>
> +*
> +*=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent
> +*
> +**/
> +
> +#include <Base.h>
> +#include <Register/RiscV64/RiscVImpl.h>
> +
> +.text
> +=C2=A0 .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 (
> +=C2=A0 RiscVLocalTlbFlush
> +=C2=A0 )
> +sfence.vma a0
> +ret
> --
> 2.25.1
>
--000000000000a70c8906007733f3--