From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) by mx.groups.io with SMTP id smtpd.web10.6046.1687545678270701684 for ; Fri, 23 Jun 2023 11:41:18 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="signature has expired" header.i=@ventanamicro.com header.s=google header.b=DghAcD1a; spf=pass (domain: ventanamicro.com, ip: 209.85.210.172, mailfrom: tphan@ventanamicro.com) Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-66869feb7d1so600932b3a.3 for ; Fri, 23 Jun 2023 11:41:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ventanamicro.com; s=google; t=1687545677; x=1690137677; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=3Ye3ggnDXvXjrgoFHeIHUzjaPAZsl+KLVmU37HR2YFc=; b=DghAcD1aDDiEXDxRkGIjNcB5a2LHqWFZ89kmYDk0adEagMsKxxexkigF3YKF5urllg WeKtTS3T83kP7FJ3L5kCwaNWx3mcOk7rjcFkr+/E1BRgVAPULZ4aDiWEI4YJjycJNOwL 0lRq45Xv8j4lLapNZaiiYjj8w6EsaEymA4G2GQAnGF/FHGDCMDj2pFO8RuhsQ0uQlVVB trjnsj8IqxBfFkuYW1tumEZTXCjTNQqyByt6SAmFXoThR2f0TmhTi/aguslD+rbUCBOy cpFcVmQ2ivocV7g6/HrSDy+il4f8mYuLPTdIM4+3XA8DdFe0JDNXAux0R1pS+Kcln4uD 9Ctg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687545677; x=1690137677; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3Ye3ggnDXvXjrgoFHeIHUzjaPAZsl+KLVmU37HR2YFc=; b=kCSLJ+zG61MLd7Ug/oeJ+Fn52aJJO1yxumNnGV5aBt88QPX9rZX6qtAbDELKi9Q5PN NQ0BGdQ9ZWsJxzsKzFSBh3NOnnQW4MTLgYH3YQy3ajipGDFk7THLYMa6k4FbVEVK9zVP LpXzF8vqvxEXWZlb7Rf41fG62+5AQp/z6AN6lhYQIx6TgX9DR0e9mhdulaxs97RpShfi DVqQRt9B1/ePL/vzvQsm+TuD+XhyoFd+KpD60731kNTBS8fQUByIOhuGuahgy17TN9/p mHL/2sPKfx0lhKhkp3PGQ35BW+wb5OryEfBbnD34VJz+KhjudWmYylAzgqGQ1YklmJ1E LnyQ== X-Gm-Message-State: AC+VfDx4GOnDad3301f3N+NIz3jvEaetXpLw2O4DWUqn7Qlnck3LZOGo 32oA20mMOgc/j42ALSBcOgl3Jg/VLjTQNW5oLrRI4w== X-Google-Smtp-Source: ACHHUZ52mhk9IHyyDo9kqav1KgcbPtG6I9eIV5e2Jt+wmE3JdCqatFknhz4RteGj5yRXMP0190cQow== X-Received: by 2002:a05:6a00:1483:b0:65b:351a:e70a with SMTP id v3-20020a056a00148300b0065b351ae70amr22605401pfu.29.1687545676902; Fri, 23 Jun 2023 11:41:16 -0700 (PDT) Return-Path: Received: from localhost.localdomain (c-174-50-177-95.hsd1.ca.comcast.net. [174.50.177.95]) by smtp.gmail.com with ESMTPSA id v2-20020aa78502000000b006667b36e904sm6354184pfn.113.2023.06.23.11.41.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Jun 2023 11:41:16 -0700 (PDT) From: "Tuan Phan" To: devel@edk2.groups.io Cc: michael.d.kinney@intel.com, gaoliming@byosoft.com.cn, zhiguang.liu@intel.com, sunilvl@ventanamicro.com, git@danielschaefer.me, andrei.warkentin@intel.com, ardb+tianocore@kernel.org, Tuan Phan Subject: [PATCH v4 7/7] UefiCpuPkg: RISC-V: Support MMU with SV39/48/57 mode Date: Fri, 23 Jun 2023 11:39:34 -0700 Message-Id: <20230623183934.23905-8-tphan@ventanamicro.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230623183934.23905-1-tphan@ventanamicro.com> References: <20230623183934.23905-1-tphan@ventanamicro.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable During CpuDxe initialization, MMU will be setup with the highest mode that HW supports. Reviewed-by: Andrei Warkentin Signed-off-by: Tuan Phan --- 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/RiscVV= irt.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=0D CpuExceptionHandlerLib|UefiCpuPkg/Library/BaseRiscV64CpuExceptionHandler= Lib/BaseRiscV64CpuExceptionHandlerLib.inf=0D RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLib.inf=0D + RiscVMmuLib|UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf=0D PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/PlatformBootManagerLib/= PlatformBootManagerLib.inf=0D ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/BaseResetSystemL= ib.inf=0D =0D 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=0D )=0D {=0D - DEBUG ((DEBUG_INFO, "%a: Set memory attributes not supported yet\n", __f= unc__));=0D - return EFI_SUCCESS;=0D + return RiscVSetMemoryAttributes (BaseAddress, Length, Attributes);=0D }=0D =0D /**=0D @@ -340,6 +339,12 @@ InitializeCpu ( //=0D DisableInterrupts ();=0D =0D + //=0D + // Enable MMU=0D + //=0D + Status =3D RiscVConfigureMmu ();=0D + ASSERT_EFI_ERROR (Status);=0D +=0D //=0D // Install Boot protocol=0D //=0D 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 =0D #include =0D #include =0D +#include =0D #include =0D #include =0D #include =0D #include =0D #include =0D +#include =0D =0D /**=0D Flush CPU data cache. If the instruction cache is fully coherent=0D diff --git a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf b/UefiCpuPkg/CpuDxe= RiscV64/CpuDxeRiscV64.inf index e8fa25446aef..6d52085df0d5 100644 --- a/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf +++ b/UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf @@ -37,6 +37,8 @@ TimerLib=0D PeCoffGetEntryPointLib=0D RiscVSbiLib=0D + RiscVMmuLib + CacheMaintenanceLib =0D [Sources]=0D CpuDxe.c=0D diff --git a/UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h b/UefiCpuPkg/Incl= ude/Library/BaseRiscVMmuLib.h new file mode 100644 index 000000000000..f71d6a4a1e7b --- /dev/null +++ b/UefiCpuPkg/Include/Library/BaseRiscVMmuLib.h @@ -0,0 +1,39 @@ +/** @file=0D +=0D + Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.
=0D + Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
= =0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef BASE_RISCV_MMU_LIB_H_=0D +#define BASE_RISCV_MMU_LIB_H_=0D +=0D +VOID=0D +EFIAPI=0D +RiscVLocalTlbFlushAll (=0D + VOID=0D + );=0D +=0D +VOID=0D +EFIAPI=0D +RiscVLocalTlbFlush (=0D + UINTN VirtAddr=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +RiscVSetMemoryAttributes (=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 Attributes=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +RiscVConfigureMmu (=0D + VOID=0D + );=0D +=0D +#endif /* BASE_RISCV_MMU_LIB_H_ */=0D diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c b/UefiCpu= Pkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c new file mode 100644 index 000000000000..e6841b793bfc --- /dev/null +++ b/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.c @@ -0,0 +1,569 @@ +/** @file=0D +* MMU implementation for RISC-V=0D +*=0D +* Copyright (c) 2011-2020, ARM Limited. All rights reserved.=0D +* Copyright (c) 2016, Linaro Limited. All rights reserved.=0D +* Copyright (c) 2017, Intel Corporation. All rights reserved.
=0D +* Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
= =0D +*=0D +* SPDX-License-Identifier: BSD-2-Clause-Patent=0D +*=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define RISCV_PG_V BIT0=0D +#define RISCV_PG_R BIT1=0D +#define RISCV_PG_W BIT2=0D +#define RISCV_PG_X BIT3=0D +#define RISCV_PG_G BIT5=0D +#define RISCV_PG_A BIT6=0D +#define RISCV_PG_D BIT7=0D +#define PTE_ATTRIBUTES_MASK 0xE=0D +=0D +#define PTE_PPN_MASK 0x3FFFFFFFFFFC00ULL=0D +#define PTE_PPN_SHIFT 10=0D +#define RISCV_MMU_PAGE_SHIFT 12=0D +=0D +STATIC UINTN mMaxRootTableLevel;=0D +STATIC UINTN mBitPerLevel;=0D +STATIC UINTN mTableEntryCount;=0D +=0D +STATIC=0D +BOOLEAN=0D +RiscVMmuEnabled (=0D + VOID=0D + )=0D +{=0D + return ((RiscVGetSupervisorAddressTranslationRegister () &=0D + SATP64_MODE) !=3D (SATP_MODE_OFF << SATP64_MODE_SHIFT));=0D +}=0D +=0D +STATIC=0D +UINTN=0D +RiscVGetRootTranslateTable (=0D + VOID=0D + )=0D +{=0D + return (RiscVGetSupervisorAddressTranslationRegister () & SATP64_PPN) <<= =0D + RISCV_MMU_PAGE_SHIFT;=0D +}=0D +=0D +STATIC=0D +BOOLEAN=0D +IsValidPte (=0D + IN UINTN Entry=0D + )=0D +{=0D + if (!(Entry & RISCV_PG_V) ||=0D + (((Entry & (RISCV_PG_R | RISCV_PG_W)) =3D=3D RISCV_PG_W)))=0D + {=0D + return FALSE;=0D + }=0D +=0D + return TRUE;=0D +}=0D +=0D +STATIC=0D +UINTN=0D +SetValidPte (=0D + IN UINTN Entry=0D + )=0D +{=0D + /* Set Valid and Global mapping bits */=0D + return Entry | RISCV_PG_G | RISCV_PG_V;=0D +}=0D +=0D +STATIC=0D +BOOLEAN=0D +IsBlockEntry (=0D + IN UINTN Entry=0D + )=0D +{=0D + return IsValidPte (Entry) &&=0D + (Entry & (RISCV_PG_X | RISCV_PG_R));=0D +}=0D +=0D +STATIC=0D +BOOLEAN=0D +IsTableEntry (=0D + IN UINTN Entry=0D + )=0D +{=0D + return IsValidPte (Entry) &&=0D + !IsBlockEntry (Entry);=0D +}=0D +=0D +STATIC=0D +UINTN=0D +SetTableEntry (=0D + IN UINTN Entry=0D + )=0D +{=0D + Entry =3D SetValidPte (Entry);=0D + Entry &=3D ~(RISCV_PG_X | RISCV_PG_W | RISCV_PG_R);=0D +=0D + return Entry;=0D +}=0D +=0D +STATIC=0D +VOID=0D +ReplaceTableEntry (=0D + IN UINTN *Entry,=0D + IN UINTN Value,=0D + IN UINTN RegionStart,=0D + IN BOOLEAN IsLiveBlockMapping=0D + )=0D +{=0D + *Entry =3D Value;=0D +=0D + if (IsLiveBlockMapping && RiscVMmuEnabled ()) {=0D + RiscVLocalTlbFlush (RegionStart);=0D + }=0D +}=0D +=0D +STATIC=0D +UINTN=0D +GetPpnfromPte (=0D + UINTN Entry,=0D + UINTN Level=0D + )=0D +{=0D + return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT);=0D +}=0D +=0D +STATIC=0D +UINTN=0D +SetPpnToPte (=0D + UINTN Entry,=0D + UINTN Address,=0D + UINTN Level=0D + )=0D +{=0D + UINTN Ppn;=0D +=0D + Ppn =3D ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT);=0D + ASSERT (~(Ppn & ~PTE_PPN_MASK));=0D + Entry &=3D ~PTE_PPN_MASK;=0D + return Entry | Ppn;=0D +}=0D +=0D +STATIC=0D +VOID=0D +FreePageTablesRecursive (=0D + IN UINTN *TranslationTable,=0D + IN UINTN Level=0D + )=0D +{=0D + UINTN Index;=0D +=0D + if (Level < mMaxRootTableLevel - 1) {=0D + for (Index =3D 0; Index < mTableEntryCount; Index++) {=0D + if (IsTableEntry (TranslationTable[Index])) {=0D + FreePageTablesRecursive (=0D + (UINTN *)(GetPpnfromPte ((TranslationTable[Index]), Level) <<=0D + RISCV_MMU_PAGE_SHIFT),=0D + Level + 1=0D + );=0D + }=0D + }=0D + }=0D +=0D + FreePages (TranslationTable, 1);=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +UpdateRegionMappingRecursive (=0D + IN UINTN RegionStart,=0D + IN UINTN RegionEnd,=0D + IN UINTN AttributeSetMask,=0D + IN UINTN AttributeClearMask,=0D + IN UINTN *PageTable,=0D + IN UINTN Level,=0D + IN BOOLEAN TableIsLive=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN BlockShift;=0D + UINTN BlockMask;=0D + UINTN BlockEnd;=0D + UINTN *Entry;=0D + UINTN EntryValue;=0D + UINTN *TranslationTable;=0D + BOOLEAN NextTableIsLive;=0D +=0D + ASSERT (Level < mMaxRootTableLevel);=0D + ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) =3D=3D 0);=0D +=0D + BlockShift =3D (mMaxRootTableLevel - Level - 1) * mBitPerLevel + RISCV_M= MU_PAGE_SHIFT;=0D + BlockMask =3D MAX_ADDRESS >> (64 - BlockShift);=0D +=0D + DEBUG (=0D + (=0D + DEBUG_VERBOSE,=0D + "%a(%d): %llx - %llx set %lx clr %lx\n",=0D + __func__,=0D + Level,=0D + RegionStart,=0D + RegionEnd,=0D + AttributeSetMask,=0D + AttributeClearMask=0D + )=0D + );=0D +=0D + for ( ; RegionStart < RegionEnd; RegionStart =3D BlockEnd) {=0D + BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockMask) + 1);=0D + Entry =3D &PageTable[(RegionStart >> BlockShift) & (mTableEntryCoun= t - 1)];=0D +=0D + //=0D + // If RegionStart or BlockEnd is not aligned to the block size at this= =0D + // level, we will have to create a table mapping in order to map less= =0D + // than a block, and recurse to create the block or page entries at=0D + // the next level. No block mappings are allowed at all at level 0,=0D + // so in that case, we have to recurse unconditionally.=0D + //=0D + if ((Level =3D=3D 0) ||=0D + (((RegionStart | BlockEnd) & BlockMask) !=3D 0) || IsTableEntry (*= Entry))=0D + {=0D + ASSERT (Level < mMaxRootTableLevel - 1);=0D + if (!IsTableEntry (*Entry)) {=0D + //=0D + // No table entry exists yet, so we need to allocate a page table= =0D + // for the next level.=0D + //=0D + TranslationTable =3D AllocatePages (1);=0D + if (TranslationTable =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + ZeroMem (TranslationTable, EFI_PAGE_SIZE);=0D +=0D + if (IsBlockEntry (*Entry)) {=0D + //=0D + // We are splitting an existing block entry, so we have to popul= ate=0D + // the new table with the attributes of the block entry it repla= ces.=0D + //=0D + Status =3D UpdateRegionMappingRecursive (=0D + RegionStart & ~BlockMask,=0D + (RegionStart | BlockMask) + 1,=0D + *Entry & PTE_ATTRIBUTES_MASK,=0D + PTE_ATTRIBUTES_MASK,=0D + TranslationTable,=0D + Level + 1,=0D + FALSE=0D + );=0D + if (EFI_ERROR (Status)) {=0D + //=0D + // The range we passed to UpdateRegionMappingRecursive () is b= lock=0D + // aligned, so it is guaranteed that no further pages were all= ocated=0D + // by it, and so we only have to free the page we allocated he= re.=0D + //=0D + FreePages (TranslationTable, 1);=0D + return Status;=0D + }=0D + }=0D +=0D + NextTableIsLive =3D FALSE;=0D + } else {=0D + TranslationTable =3D (UINTN *)(GetPpnfromPte (*Entry, Level) << RI= SCV_MMU_PAGE_SHIFT);=0D + NextTableIsLive =3D TableIsLive;=0D + }=0D +=0D + //=0D + // Recurse to the next level=0D + //=0D + Status =3D UpdateRegionMappingRecursive (=0D + RegionStart,=0D + BlockEnd,=0D + AttributeSetMask,=0D + AttributeClearMask,=0D + TranslationTable,=0D + Level + 1,=0D + NextTableIsLive=0D + );=0D + if (EFI_ERROR (Status)) {=0D + if (!IsTableEntry (*Entry)) {=0D + //=0D + // We are creating a new table entry, so on failure, we can free= all=0D + // allocations we made recursively, given that the whole subhier= archy=0D + // has not been wired into the live page tables yet. (This is no= t=0D + // possible for existing table entries, since we cannot revert t= he=0D + // modifications we made to the subhierarchy it represents.)=0D + //=0D + FreePageTablesRecursive (TranslationTable, Level + 1);=0D + }=0D +=0D + return Status;=0D + }=0D +=0D + if (!IsTableEntry (*Entry)) {=0D + EntryValue =3D SetPpnToPte (0, (UINTN)TranslationTable, Level);=0D + EntryValue =3D SetTableEntry (EntryValue);=0D + ReplaceTableEntry (=0D + Entry,=0D + EntryValue,=0D + RegionStart,=0D + TableIsLive=0D + );=0D + }=0D + } else {=0D + EntryValue =3D (*Entry & ~AttributeClearMask) | AttributeSetMask;=0D + //=0D + // We don't have page fault exception handler when a virtual page is= accessed and=0D + // the A bit is clear, or is written and the D bit is clear.=0D + // So just set A for read and D for write permission.=0D + //=0D + if (AttributeSetMask & RISCV_PG_R) {=0D + EntryValue |=3D RISCV_PG_A;=0D + }=0D +=0D + if (AttributeSetMask & RISCV_PG_W) {=0D + EntryValue |=3D RISCV_PG_D;=0D + }=0D +=0D + EntryValue =3D SetPpnToPte (EntryValue, RegionStart, Level);=0D + EntryValue =3D SetValidPte (EntryValue);=0D + ReplaceTableEntry (Entry, EntryValue, RegionStart, TableIsLive);=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +UpdateRegionMapping (=0D + IN UINTN RegionStart,=0D + IN UINTN RegionLength,=0D + IN UINTN AttributeSetMask,=0D + IN UINTN AttributeClearMask,=0D + IN UINTN *RootTable,=0D + IN BOOLEAN TableIsLive=0D + )=0D +{=0D + if (((RegionStart | RegionLength) & EFI_PAGE_MASK) !=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + return UpdateRegionMappingRecursive (=0D + RegionStart,=0D + RegionStart + RegionLength,=0D + AttributeSetMask,=0D + AttributeClearMask,=0D + RootTable,=0D + 0,=0D + TableIsLive=0D + );=0D +}=0D +=0D +STATIC=0D +UINTN=0D +GcdAttributeToPageAttribute (=0D + IN UINTN GcdAttributes=0D + )=0D +{=0D + UINTN RiscVAttributes =3D RISCV_PG_R | RISCV_PG_W | RISCV_PG_X;=0D +=0D + // Determine protection attributes=0D + if (GcdAttributes & EFI_MEMORY_RO) {=0D + RiscVAttributes &=3D ~(RISCV_PG_W);=0D + }=0D +=0D + // Process eXecute Never attribute=0D + if (GcdAttributes & EFI_MEMORY_XP) {=0D + RiscVAttributes &=3D ~RISCV_PG_X;=0D + }=0D +=0D + return RiscVAttributes;=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +RiscVSetMemoryAttributes (=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINTN Length,=0D + IN UINTN Attributes=0D + )=0D +{=0D + UINTN PageAttributesSet =3D GcdAttributeToPageAttribute (Attributes);=0D +=0D + if (!RiscVMmuEnabled ()) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + DEBUG (=0D + (=0D + DEBUG_VERBOSE,=0D + "%a: Set %llX page attribute 0x%X\n",=0D + __func__,=0D + BaseAddress,=0D + PageAttributesSet=0D + )=0D + );=0D +=0D + return UpdateRegionMapping (=0D + BaseAddress,=0D + Length,=0D + PageAttributesSet,=0D + PTE_ATTRIBUTES_MASK,=0D + (UINTN *)RiscVGetRootTranslateTable (),=0D + TRUE=0D + );=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +RiscVMmuSetSatpMode (=0D + UINTN SatpMode=0D + )=0D +{=0D + VOID *TranslationTable;=0D + UINTN SatpReg;=0D + UINTN Ppn;=0D + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemoryMap;=0D + UINTN NumberOfDescriptors;=0D + UINTN Index;=0D + EFI_STATUS Status;=0D +=0D + switch (SatpMode) {=0D + case SATP_MODE_OFF:=0D + return EFI_SUCCESS;=0D + case SATP_MODE_SV39:=0D + mMaxRootTableLevel =3D 3;=0D + mBitPerLevel =3D 9;=0D + mTableEntryCount =3D 512;=0D + break;=0D + case SATP_MODE_SV48:=0D + mMaxRootTableLevel =3D 4;=0D + mBitPerLevel =3D 9;=0D + mTableEntryCount =3D 512;=0D + break;=0D + case SATP_MODE_SV57:=0D + mMaxRootTableLevel =3D 5;=0D + mBitPerLevel =3D 9;=0D + mTableEntryCount =3D 512;=0D + break;=0D + default:=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Allocate pages for translation table=0D + TranslationTable =3D AllocatePages (1);=0D + if (TranslationTable =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN));=0D +=0D + NumberOfDescriptors =3D 0;=0D + MemoryMap =3D NULL;=0D + Status =3D gDS->GetMemorySpaceMap (=0D + &NumberOfDescriptors,=0D + &MemoryMap=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + for (Index =3D 0; Index < NumberOfDescriptors; Index++) {=0D + if (MemoryMap[Index].GcdMemoryType =3D=3D EfiGcdMemoryTypeMemoryMapped= Io) {=0D + // Default Read/Write attribute for memory mapped IO=0D + UpdateRegionMapping (=0D + MemoryMap[Index].BaseAddress,=0D + MemoryMap[Index].Length,=0D + RISCV_PG_R | RISCV_PG_W,=0D + PTE_ATTRIBUTES_MASK,=0D + TranslationTable,=0D + FALSE=0D + );=0D + } else if (MemoryMap[Index].GcdMemoryType =3D=3D EfiGcdMemoryTypeSyste= mMemory) {=0D + // Default Read/Write/Execute attribute for system memory=0D + UpdateRegionMapping (=0D + MemoryMap[Index].BaseAddress,=0D + MemoryMap[Index].Length,=0D + RISCV_PG_R | RISCV_PG_W | RISCV_PG_X,=0D + PTE_ATTRIBUTES_MASK,=0D + TranslationTable,=0D + FALSE=0D + );=0D + }=0D + }=0D +=0D + FreePool ((VOID *)MemoryMap);=0D +=0D + if (GetInterruptState ()) {=0D + DisableInterrupts ();=0D + }=0D +=0D + Ppn =3D (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT;=0D + ASSERT (!(Ppn & ~(SATP64_PPN)));=0D +=0D + SatpReg =3D Ppn;=0D + SatpReg |=3D (SatpMode <<=0D + SATP64_MODE_SHIFT) & SATP64_MODE;=0D + RiscVSetSupervisorAddressTranslationRegister (SatpReg);=0D + /* Check if HW support the setup satp mode */=0D + if (SatpReg !=3D RiscVGetSupervisorAddressTranslationRegister ()) {=0D + DEBUG (=0D + (=0D + DEBUG_VERBOSE,=0D + "%a: HW does not support SATP mode:%d\n",=0D + __func__,=0D + SatpMode=0D + )=0D + );=0D + FreePageTablesRecursive (TranslationTable, 0);=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + RiscVLocalTlbFlushAll ();=0D +=0D + if (GetInterruptState ()) {=0D + EnableInterrupts ();=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +RiscVConfigureMmu (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status =3D EFI_SUCCESS;=0D + INTN ModeSupport[] =3D { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MOD= E_SV39 };=0D + INTN Idx;=0D +=0D + /* Try to setup MMU with highest mode as possible */=0D + for (Idx =3D 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) {=0D + Status =3D RiscVMmuSetSatpMode (ModeSupport[Idx]);=0D + if (Status =3D=3D EFI_DEVICE_ERROR) {=0D + continue;=0D + } else if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + DEBUG (=0D + (=0D + DEBUG_INFO,=0D + "%a: SATP mode %d successfully configured\n",=0D + __func__,=0D + ModeSupport[Idx]=0D + )=0D + );=0D + break;=0D + }=0D +=0D + return Status;=0D +}=0D diff --git a/UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf b/UefiC= puPkg/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=0D +*=0D +* Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.
= =0D +*=0D +* SPDX-License-Identifier: BSD-2-Clause-Patent=0D +*=0D +**/=0D +=0D +#include =0D +#include =0D +=0D +.text=0D + .align 3=0D +=0D +//=0D +// Local tlb flush all.=0D +//=0D +//=0D +ASM_FUNC (RiscVLocalTlbFlushAll)=0D +sfence.vma=0D +ret=0D +=0D +//=0D +// Local tlb flush at a virtual address=0D +// @retval a0 : virtual address.=0D +//=0D +ASM_FUNC (=0D + RiscVLocalTlbFlush=0D + )=0D +sfence.vma a0=0D +ret=0D --=20 2.25.1