From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) by mx.groups.io with SMTP id smtpd.web11.15588.1689330267418774058 for ; Fri, 14 Jul 2023 03:24:27 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="signature has expired" header.i=@ventanamicro.com header.s=google header.b=jL7BR7oy; spf=pass (domain: ventanamicro.com, ip: 209.85.210.181, mailfrom: sunilvl@ventanamicro.com) Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-666ecf9a081so1680332b3a.2 for ; Fri, 14 Jul 2023 03:24:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ventanamicro.com; s=google; t=1689330266; x=1691922266; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=1rb6UHi/DinTwwfbwPTMCGQMJcMPFTQjfaiKUnh270o=; b=jL7BR7oypxyTcxJExwgyC4QojC1xBmFY5Et51k++Y5xeTWoIR2CjJCDoVjC5IDMB9y IM0G4GGP5UA/MASJs8F7k6NM2NrsgSwlsVI7KNeNnkfgUSwFTXrPiaSjkMpRsEnWLpKo dCep67Mx80HO6qzlR9LCNNdes2ELzbKmn/WKQBm/L7BjIBwdL6z5KOr89yZkkcgOObnn QwMhHqbcfpprlVke1PLafRYBEKIvFldrEpMWzMizxE2Ab2tJuJTLBI/NZKU9WPUIYw11 EAw8ExIsrfADhSYFbsjGK85lftkGv112c6vzfHzBQ82ubLMjvWvtz5qZwUhYHKXH1olZ fi6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689330266; x=1691922266; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=1rb6UHi/DinTwwfbwPTMCGQMJcMPFTQjfaiKUnh270o=; b=M7IoqxXzk7GZ1NwLqnwSE+gRH1nnsQGGxzd25ZmfUEAfoYccyJsA6REkXnhYBeCqTi 71CfgHfGuRhas3Zg9fsGOpIXKqBg16wmdSIInAd4ct6pxewpR93BTErgs6W4r2+uWHhu 2AMbNHPgCVHDQeuEQhUdsQpUgU7Z2g36qAJ3rTRNJc0hcZjhErrKJJkGULjyPCJHA4Ft JGWRPPIccQ97kqxpdatR7hrCN6IPbpgkoI8ezOtJfYyMa4UMwmRh49vEGwDssxSGP0NV eZPobM+3DCWjYYlbxgX+dYdong/7rC2qtxxWJDHXQk2B1jV99XQYvq9et8SfXb4w86PS F1pQ== X-Gm-Message-State: ABy/qLZoQh416vPTGXJWZWJd8jnjyJ/h/wiaS0Cf4gdaPYy01JhAxClE /2KgexcpW4N6HCBnhNajlmqHyQ== X-Google-Smtp-Source: APBJJlF3o2kjaVemE78j+aJuJujdoQiSPA8LkMeVWNMHfWWsakGFzU/WJlX0R51mz/KJ14aAQqo4MA== X-Received: by 2002:a05:6a00:198f:b0:664:9579:d31c with SMTP id d15-20020a056a00198f00b006649579d31cmr5090271pfl.8.1689330266329; Fri, 14 Jul 2023 03:24:26 -0700 (PDT) Return-Path: Received: from sunil-laptop ([106.51.190.25]) by smtp.gmail.com with ESMTPSA id c19-20020aa78e13000000b0062bc045bf4fsm7142856pfr.19.2023.07.14.03.24.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 14 Jul 2023 03:24:25 -0700 (PDT) Date: Fri, 14 Jul 2023 15:54:19 +0530 From: "Sunil V L" To: Tuan Phan 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 Subject: Re: [PATCH v4 7/7] UefiCpuPkg: RISC-V: Support MMU with SV39/48/57 mode Message-ID: References: <20230623183934.23905-1-tphan@ventanamicro.com> <20230623183934.23905-8-tphan@ventanamicro.com> MIME-Version: 1.0 In-Reply-To: <20230623183934.23905-8-tphan@ventanamicro.com> Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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? 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/BaseRiscV64CpuExceptionHandlerLib/BaseRiscV64CpuExceptionHandlerLib.inf > RiscVSbiLib|MdePkg/Library/BaseRiscVSbiLib/BaseRiscVSbiLib.inf > + RiscVMmuLib|UefiCpuPkg/Library/BaseRiscVMmuLib/BaseRiscVMmuLib.inf > PlatformBootManagerLib|OvmfPkg/RiscVVirt/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf > ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/BaseResetSystemLib.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 = 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) != (SATP_MODE_OFF << SATP64_MODE_SHIFT)); > +} > + > +STATIC > +UINTN > +RiscVGetRootTranslateTable ( > + VOID > + ) > +{ > + return (RiscVGetSupervisorAddressTranslationRegister () & SATP64_PPN) << > + RISCV_MMU_PAGE_SHIFT; > +} > + > +STATIC > +BOOLEAN > +IsValidPte ( > + IN UINTN Entry > + ) > +{ > + if (!(Entry & RISCV_PG_V) || > + (((Entry & (RISCV_PG_R | RISCV_PG_W)) == RISCV_PG_W))) > + { > + return FALSE; > + } > + > + return TRUE; > +} > + > +STATIC > +UINTN > +SetValidPte ( > + IN UINTN Entry > + ) > +{ > + /* Set Valid and Global mapping bits */ > + return Entry | RISCV_PG_G | RISCV_PG_V; > +} > + > +STATIC > +BOOLEAN > +IsBlockEntry ( > + IN UINTN Entry > + ) > +{ > + return IsValidPte (Entry) && > + (Entry & (RISCV_PG_X | RISCV_PG_R)); > +} > + > +STATIC > +BOOLEAN > +IsTableEntry ( > + IN UINTN Entry > + ) > +{ > + return IsValidPte (Entry) && > + !IsBlockEntry (Entry); > +} > + > +STATIC > +UINTN > +SetTableEntry ( > + IN UINTN Entry > + ) > +{ > + Entry = SetValidPte (Entry); > + Entry &= ~(RISCV_PG_X | RISCV_PG_W | RISCV_PG_R); > + > + return Entry; > +} > + > +STATIC > +VOID > +ReplaceTableEntry ( > + IN UINTN *Entry, > + IN UINTN Value, > + IN UINTN RegionStart, > + IN BOOLEAN IsLiveBlockMapping > + ) > +{ > + *Entry = Value; > + > + if (IsLiveBlockMapping && RiscVMmuEnabled ()) { > + RiscVLocalTlbFlush (RegionStart); > + } > +} > + > +STATIC > +UINTN > +GetPpnfromPte ( > + UINTN Entry, > + UINTN Level > + ) > +{ > + return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT); > +} > + > +STATIC > +UINTN > +SetPpnToPte ( > + UINTN Entry, > + UINTN Address, > + UINTN Level > + ) > +{ > + UINTN Ppn; > + > + Ppn = ((Address >> RISCV_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT); > + ASSERT (~(Ppn & ~PTE_PPN_MASK)); > + Entry &= ~PTE_PPN_MASK; > + return Entry | Ppn; > +} > + > +STATIC > +VOID > +FreePageTablesRecursive ( > + IN UINTN *TranslationTable, > + IN UINTN Level > + ) > +{ > + UINTN Index; > + > + if (Level < mMaxRootTableLevel - 1) { > + for (Index = 0; Index < mTableEntryCount; Index++) { > + if (IsTableEntry (TranslationTable[Index])) { > + FreePageTablesRecursive ( > + (UINTN *)(GetPpnfromPte ((TranslationTable[Index]), Level) << > + RISCV_MMU_PAGE_SHIFT), > + Level + 1 > + ); > + } > + } > + } > + > + FreePages (TranslationTable, 1); > +} > + > +STATIC > +EFI_STATUS > +UpdateRegionMappingRecursive ( > + IN UINTN RegionStart, > + IN UINTN RegionEnd, > + IN UINTN AttributeSetMask, > + IN UINTN AttributeClearMask, > + IN UINTN *PageTable, > + IN UINTN Level, > + IN BOOLEAN TableIsLive > + ) > +{ > + EFI_STATUS Status; > + UINTN BlockShift; > + UINTN BlockMask; > + UINTN BlockEnd; > + UINTN *Entry; > + UINTN EntryValue; > + UINTN *TranslationTable; > + BOOLEAN NextTableIsLive; > + > + ASSERT (Level < mMaxRootTableLevel); > + ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0); > + > + BlockShift = (mMaxRootTableLevel - Level - 1) * mBitPerLevel + RISCV_MMU_PAGE_SHIFT; > + BlockMask = MAX_ADDRESS >> (64 - BlockShift); > + > + DEBUG ( > + ( > + DEBUG_VERBOSE, > + "%a(%d): %llx - %llx set %lx clr %lx\n", > + __func__, > + Level, > + RegionStart, > + RegionEnd, > + AttributeSetMask, > + AttributeClearMask > + ) > + ); > + > + for ( ; RegionStart < RegionEnd; RegionStart = BlockEnd) { > + BlockEnd = MIN (RegionEnd, (RegionStart | BlockMask) + 1); > + Entry = &PageTable[(RegionStart >> BlockShift) & (mTableEntryCount - 1)]; > + > + // > + // If RegionStart or BlockEnd is not aligned to the block size at this > + // level, we will have to create a table mapping in order to map less > + // than a block, and recurse to create the block or page entries at > + // the next level. No block mappings are allowed at all at level 0, > + // so in that case, we have to recurse unconditionally. > + // > + if ((Level == 0) || > + (((RegionStart | BlockEnd) & BlockMask) != 0) || IsTableEntry (*Entry)) > + { > + ASSERT (Level < mMaxRootTableLevel - 1); > + if (!IsTableEntry (*Entry)) { > + // > + // No table entry exists yet, so we need to allocate a page table > + // for the next level. > + // > + TranslationTable = AllocatePages (1); > + if (TranslationTable == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + ZeroMem (TranslationTable, EFI_PAGE_SIZE); > + > + if (IsBlockEntry (*Entry)) { > + // > + // We are splitting an existing block entry, so we have to populate > + // the new table with the attributes of the block entry it replaces. > + // > + Status = UpdateRegionMappingRecursive ( > + RegionStart & ~BlockMask, > + (RegionStart | BlockMask) + 1, > + *Entry & PTE_ATTRIBUTES_MASK, > + PTE_ATTRIBUTES_MASK, > + TranslationTable, > + Level + 1, > + FALSE > + ); > + if (EFI_ERROR (Status)) { > + // > + // The range we passed to UpdateRegionMappingRecursive () is block > + // aligned, so it is guaranteed that no further pages were allocated > + // by it, and so we only have to free the page we allocated here. > + // > + FreePages (TranslationTable, 1); > + return Status; > + } > + } > + > + NextTableIsLive = FALSE; > + } else { > + TranslationTable = (UINTN *)(GetPpnfromPte (*Entry, Level) << RISCV_MMU_PAGE_SHIFT); > + NextTableIsLive = TableIsLive; > + } > + > + // > + // Recurse to the next level > + // > + Status = UpdateRegionMappingRecursive ( > + RegionStart, > + BlockEnd, > + AttributeSetMask, > + AttributeClearMask, > + TranslationTable, > + Level + 1, > + NextTableIsLive > + ); > + if (EFI_ERROR (Status)) { > + if (!IsTableEntry (*Entry)) { > + // > + // We are creating a new table entry, so on failure, we can free all > + // allocations we made recursively, given that the whole subhierarchy > + // has not been wired into the live page tables yet. (This is not > + // possible for existing table entries, since we cannot revert the > + // modifications we made to the subhierarchy it represents.) > + // > + FreePageTablesRecursive (TranslationTable, Level + 1); > + } > + > + return Status; > + } > + > + if (!IsTableEntry (*Entry)) { > + EntryValue = SetPpnToPte (0, (UINTN)TranslationTable, Level); > + EntryValue = SetTableEntry (EntryValue); > + ReplaceTableEntry ( > + Entry, > + EntryValue, > + RegionStart, > + TableIsLive > + ); > + } > + } else { > + EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask; > + // > + // We don't have page fault exception handler when a virtual page is accessed and > + // the A bit is clear, or is written and the D bit is clear. > + // So just set A for read and D for write permission. > + // > + if (AttributeSetMask & RISCV_PG_R) { > + EntryValue |= RISCV_PG_A; > + } > + > + if (AttributeSetMask & RISCV_PG_W) { > + EntryValue |= RISCV_PG_D; > + } > + > + EntryValue = SetPpnToPte (EntryValue, RegionStart, Level); > + EntryValue = SetValidPte (EntryValue); > + ReplaceTableEntry (Entry, EntryValue, RegionStart, TableIsLive); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +UpdateRegionMapping ( > + IN UINTN RegionStart, > + IN UINTN RegionLength, > + IN UINTN AttributeSetMask, > + IN UINTN AttributeClearMask, > + IN UINTN *RootTable, > + IN BOOLEAN TableIsLive > + ) > +{ > + if (((RegionStart | RegionLength) & EFI_PAGE_MASK) != 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + return UpdateRegionMappingRecursive ( > + RegionStart, > + RegionStart + RegionLength, > + AttributeSetMask, > + AttributeClearMask, > + RootTable, > + 0, > + TableIsLive > + ); > +} > + > +STATIC > +UINTN > +GcdAttributeToPageAttribute ( > + IN UINTN GcdAttributes > + ) > +{ > + UINTN RiscVAttributes = RISCV_PG_R | RISCV_PG_W | RISCV_PG_X; > + > + // Determine protection attributes > + if (GcdAttributes & EFI_MEMORY_RO) { > + RiscVAttributes &= ~(RISCV_PG_W); > + } > + > + // Process eXecute Never attribute > + if (GcdAttributes & EFI_MEMORY_XP) { > + RiscVAttributes &= ~RISCV_PG_X; > + } > + > + return RiscVAttributes; > +} > + > +EFI_STATUS > +EFIAPI > +RiscVSetMemoryAttributes ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINTN Length, > + IN UINTN Attributes > + ) > +{ > + UINTN PageAttributesSet = GcdAttributeToPageAttribute (Attributes); > + > + if (!RiscVMmuEnabled ()) { > + return EFI_SUCCESS; > + } > + > + DEBUG ( > + ( > + DEBUG_VERBOSE, > + "%a: Set %llX page attribute 0x%X\n", > + __func__, > + BaseAddress, > + PageAttributesSet > + ) > + ); > + > + return UpdateRegionMapping ( > + BaseAddress, > + Length, > + PageAttributesSet, > + PTE_ATTRIBUTES_MASK, > + (UINTN *)RiscVGetRootTranslateTable (), > + TRUE > + ); > +} > + > +STATIC > +EFI_STATUS > +RiscVMmuSetSatpMode ( > + UINTN SatpMode > + ) > +{ > + VOID *TranslationTable; > + UINTN SatpReg; > + UINTN Ppn; > + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemoryMap; > + UINTN NumberOfDescriptors; > + UINTN Index; > + EFI_STATUS Status; > + > + switch (SatpMode) { > + case SATP_MODE_OFF: > + return EFI_SUCCESS; > + case SATP_MODE_SV39: > + mMaxRootTableLevel = 3; > + mBitPerLevel = 9; > + mTableEntryCount = 512; > + break; > + case SATP_MODE_SV48: > + mMaxRootTableLevel = 4; > + mBitPerLevel = 9; > + mTableEntryCount = 512; > + break; > + case SATP_MODE_SV57: > + mMaxRootTableLevel = 5; > + mBitPerLevel = 9; > + mTableEntryCount = 512; > + break; > + default: > + return EFI_INVALID_PARAMETER; > + } > + > + // Allocate pages for translation table > + TranslationTable = AllocatePages (1); > + if (TranslationTable == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + ZeroMem (TranslationTable, mTableEntryCount * sizeof (UINTN)); > + > + NumberOfDescriptors = 0; > + MemoryMap = NULL; > + Status = gDS->GetMemorySpaceMap ( > + &NumberOfDescriptors, > + &MemoryMap > + ); > + ASSERT_EFI_ERROR (Status); > + > + for (Index = 0; Index < NumberOfDescriptors; Index++) { > + if (MemoryMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { > + // Default Read/Write attribute for memory mapped IO > + UpdateRegionMapping ( > + MemoryMap[Index].BaseAddress, > + MemoryMap[Index].Length, > + RISCV_PG_R | RISCV_PG_W, > + PTE_ATTRIBUTES_MASK, > + TranslationTable, > + FALSE > + ); > + } else if (MemoryMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { > + // Default Read/Write/Execute attribute for system memory > + UpdateRegionMapping ( > + MemoryMap[Index].BaseAddress, > + MemoryMap[Index].Length, > + RISCV_PG_R | RISCV_PG_W | RISCV_PG_X, > + PTE_ATTRIBUTES_MASK, > + TranslationTable, > + FALSE > + ); > + } > + } > + > + FreePool ((VOID *)MemoryMap); > + > + if (GetInterruptState ()) { > + DisableInterrupts (); > + } > + > + Ppn = (UINTN)TranslationTable >> RISCV_MMU_PAGE_SHIFT; > + ASSERT (!(Ppn & ~(SATP64_PPN))); > + > + SatpReg = Ppn; > + SatpReg |= (SatpMode << > + SATP64_MODE_SHIFT) & SATP64_MODE; > + RiscVSetSupervisorAddressTranslationRegister (SatpReg); > + /* Check if HW support the setup satp mode */ > + if (SatpReg != RiscVGetSupervisorAddressTranslationRegister ()) { > + DEBUG ( > + ( > + DEBUG_VERBOSE, > + "%a: HW does not support SATP mode:%d\n", > + __func__, > + SatpMode > + ) > + ); > + FreePageTablesRecursive (TranslationTable, 0); > + return EFI_DEVICE_ERROR; > + } > + > + RiscVLocalTlbFlushAll (); > + > + if (GetInterruptState ()) { > + EnableInterrupts (); > + } > + > + return Status; > +} > + > +EFI_STATUS > +EFIAPI > +RiscVConfigureMmu ( > + VOID > + ) > +{ > + EFI_STATUS Status = EFI_SUCCESS; > + INTN ModeSupport[] = { SATP_MODE_SV57, SATP_MODE_SV48, SATP_MODE_SV39 }; > + INTN Idx; > + > + /* Try to setup MMU with highest mode as possible */ > + for (Idx = 0; Idx < ARRAY_SIZE (ModeSupport); Idx++) { > + Status = RiscVMmuSetSatpMode (ModeSupport[Idx]); > + if (Status == EFI_DEVICE_ERROR) { > + continue; > + } else if (EFI_ERROR (Status)) { > + return Status; > + } > + > + DEBUG ( > + ( > + DEBUG_INFO, > + "%a: SATP mode %d successfully configured\n", > + __func__, > + ModeSupport[Idx] > + ) > + ); > + break; > + } > + > + return Status; > +} > diff --git a/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 = 0x0001001b > + BASE_NAME = BaseRiscVMmuLib > + FILE_GUID = d3bc42ee-c9eb-4339-ba11-06747083d3ae > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = RiscVMmuLib > + > +[Sources] > + BaseRiscVMmuLib.c > + RiscVMmuCore.S > + > +[Packages] > + MdePkg/MdePkg.dec > + 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 >