From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail04.groups.io (mail04.groups.io [45.79.224.9]) by spool.mail.gandi.net (Postfix) with ESMTPS id 21E6494003C for ; Mon, 15 Apr 2024 02:11:19 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=ywOqnJpyMzyuKWGGHVM0nn3lX+mqkQDJ2slyJHAX5G4=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language:msip_labels:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Language:Content-Type; s=20240206; t=1713147078; v=1; b=PGRSthrarK3fPr5GyhGRZRdRofJql2go0+7T6t2cAAg6Bhgs0B5wPuL40cTefGxgc3c3qhiH 5F+1pUpXezUPmTnhPoLm1W7jTTo09JaZdOD0UcaioQF8RQ8i1vHsXnoDzvVXpDU/WlejG1hHlcs 9+wzS6jVkd9N7gXNiZRNYCbfiTRsiYxW6HRCxKRGCECaG7MzzBFB7iCKbleHeRooHO7uYuQeqvU Yv0KpcMpk1HlFc9b9cVdhCMvzY1YFpsG9nQCcIpWtSR+BAjD34Ih0LJMihLpp1YhKRWlt+F4jab Qv89RSOXKrCyQ4Wmkt4o6kO4xhHl46coEA8OeHepKno6g== X-Received: by 127.0.0.2 with SMTP id Vcc3YY7687511xYQKeNJMBIs; Sun, 14 Apr 2024 19:11:18 -0700 X-Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.7]) by mx.groups.io with SMTP id smtpd.web10.11670.1713147077900212231 for ; Sun, 14 Apr 2024 19:11:17 -0700 X-CSE-ConnectionGUID: Q6ClatipS5Sgvqwj8jUYdQ== X-CSE-MsgGUID: 9kwtoy+iTG2c6uQCgXEBhg== X-IronPort-AV: E=McAfee;i="6600,9927,11044"; a="33908237" X-IronPort-AV: E=Sophos;i="6.07,202,1708416000"; d="scan'208,217";a="33908237" X-Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Apr 2024 19:11:17 -0700 X-CSE-ConnectionGUID: +B1x9UCnRJy5+3EZ85ENug== X-CSE-MsgGUID: zCM2Uu03Sx2dNcSd36fFZg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.07,202,1708416000"; d="scan'208,217";a="26567215" X-Received: from orsmsx603.amr.corp.intel.com ([10.22.229.16]) by orviesa005.jf.intel.com with ESMTP/TLS/AES256-GCM-SHA384; 14 Apr 2024 19:11:17 -0700 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX603.amr.corp.intel.com (10.22.229.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Sun, 14 Apr 2024 19:11:16 -0700 X-Received: from orsedg603.ED.cps.intel.com (10.7.248.4) by orsmsx610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35 via Frontend Transport; Sun, 14 Apr 2024 19:11:16 -0700 X-Received: from NAM04-MW2-obe.outbound.protection.outlook.com (104.47.73.169) by edgegateway.intel.com (134.134.137.100) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Sun, 14 Apr 2024 19:11:16 -0700 X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com (2603:10b6:208:470::14) by SJ2PR11MB7454.namprd11.prod.outlook.com (2603:10b6:a03:4cc::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.29; Mon, 15 Apr 2024 02:11:14 +0000 X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::8774:81a7:c5b7:5c2c]) by MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::8774:81a7:c5b7:5c2c%7]) with mapi id 15.20.7452.049; Mon, 15 Apr 2024 02:11:14 +0000 From: "Ni, Ray" To: Chao Li , "devel@edk2.groups.io" CC: "Kumar, Rahul R" , Gerd Hoffmann , Baoqi Zhang , Dongyan Qian , Xianglai Li , Bibo Mao Subject: Re: [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Thread-Topic: [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Thread-Index: AQHajKvpssP7CmLkDE+IFeTyRS7GOLFomvZ5 Date: Mon, 15 Apr 2024 02:11:14 +0000 Message-ID: References: <20240412073254.3486364-1-lichao@loongson.cn> <20240412073435.3488309-1-lichao@loongson.cn> In-Reply-To: <20240412073435.3488309-1-lichao@loongson.cn> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: msip_labels: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: MN6PR11MB8244:EE_|SJ2PR11MB7454:EE_ x-ms-office365-filtering-correlation-id: 7f4fd54e-98d9-4871-62da-08dc5cf153c6 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: iQkOD4YnVfp1t5fKc/2Tz8pYiC6fpOMwYqitP2rvzYEAe3vKbZSWqh0d8PGRiURC5BRxlyR0+kK/AB65L1ZWs9tcdzZ+i1sm1DOP5WeZoBrGdIHd2iwMlzapmnTkyK1jqp9+0qflCicWmmxDUa1hxGM3ksFMH94NDPPZb8yW7NbrM90SvVt+qN04mmKIRNn7Jy0SSdnagKjtIjfwLNTnLIuJj+BzEU4vWo0Jf7KtV5mFOHIjbDbzq/5Ub7LrNem+MgpYpucbwSjbYFzkBb+Ebs3t/qrNU1/P+ZGml7X6F3mLrTJattrnbmitc2oAfcvxKnMhF+AUEoYRvENCVxuLDBpZXBJZE9qrVt26ZPX0UirwE2h96OuSjXy3AgTGqPTg3FQyArg6xLSxMtelhKURNkJn44FMTWK4c1neuH/5r7XvKQP41DjWTLxQT7ZFKO6O4/Ik2EISCoxoY6WDrdpjJiP8lYrvIQ1/KYb1sEQ7omAXMcNhubOVjSy+kpRilBN5q/5p7RQYe+d0EbDCGyS3iy+ANe/IYO944nA0r3W5/1iRpM6lFRRnF7J0vW6C0jSThjMzEyWTO9XpXgOQjNx6ufRdh2Y+9Ep6PRd1NUhIqSWrt77+afR7e+j38Uceg0KtNe/MbAEavIa2LTlF9Lw8oieFMiQ2Di3MNphaNGMNfUY= x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?XnZJzHMQknP/cZ/LRAO981GqPBxzALSqiYtiji3vznLUz+ev3gaA3zxSzw4U?= =?us-ascii?Q?tP3pITKU6H02vsmSvLA65aU/w4pm6iQFBijVnfxkejKXF9kAsKX7uhIPX8s+?= =?us-ascii?Q?3gq2RcNkjIYATgA22jdb+bV7Npsr5tOHftrmBjS4icUejUClPdEn3+tTcHhB?= =?us-ascii?Q?oNHL27qTy4hovybdoXlNUsz868I1RV1Di4sPIq4iR/pEhitKqJnEVL8HlHba?= =?us-ascii?Q?Wf/6ykbZPHl2E0J5bZH1zphJOgdmmhaZynr0Tz3Thh7FIoSrNaQ/RdO1P2Y0?= =?us-ascii?Q?J68IEHzoisybQBfD1+AMFESNsuBJLBiFqwvG8ReUe0v0EvgWpT5Qrms+ZlBw?= =?us-ascii?Q?noounpzRLZK1FcyjgDZZvEjDdgHk0pNxA3nEd7hnoToIr6mNtHMZK9aBeTWt?= =?us-ascii?Q?BRpoKSIDYrBnRqEc286mSLAezpX5LS9UYD9qk9FCS+v1MfwGpQLSt83Vfn9f?= =?us-ascii?Q?Eb8QRPlGf1kDe2iwGMRBtjeiQe70/mVTYoMU8/PEnue9xIjhwULWbSifOwcA?= =?us-ascii?Q?KCrGquvlJt3ZOaFPGNwzfF1QzYhH+Np5b9IycW+4wzU5FyWDLMAt9t6ffWoX?= =?us-ascii?Q?srGkl5S3dfptnpP6rqbOO1NKR2XRvL1cAKWLhiEn+8r7NjYYI8z3jt9HK1hB?= =?us-ascii?Q?/rNRRM4bYBdwwalFro5hoV2jcNtVcTbTQ2WPES28k1FkJuY5W/06rqi9xu7A?= =?us-ascii?Q?pKozF4cvnkqiXQf6aveyuQoc4eop30bjcWTkhCSSR0kgSLZrun7zu2k7siHx?= =?us-ascii?Q?f+frE8ZptpN5DbyxtnktX0t9wmO2Iw6Exmg4TMCzqFwCpNMJlwF9FQUEa8fC?= =?us-ascii?Q?bvJrEUTYsw4Gima/SL8K3WupIF9pPqFOPUngB2CZgoaSghbfBh7YmMTc48lh?= =?us-ascii?Q?eRPXOJpgyjBGGyaTUx97l1mFV9U1iOVrdZan8M1pHQEmhdey+TGGMv4vZtLh?= =?us-ascii?Q?xfHoUHUi2fAAPAeHbn+MV4jIgcE8YuYFSNTxmBYw86xNsovoPr38kU7Nz+ap?= =?us-ascii?Q?RwrW7fNG+I+BR7WnQxcNGWX1JX5qxdKFFhJXomVHRYfSLikWXWC+z6uzcg5X?= =?us-ascii?Q?YwpVo6cqE6MFYI/bdlvJ67Ledt/WJarTScMdZ1+YYUeeNeAGR1qS+Z5/QlIF?= =?us-ascii?Q?TJbUk0kH8HpIh2E9ulAD1kWBfR6aFshZ5JBg+EX4XXgL5JTp7H+4Vl5VWsbE?= =?us-ascii?Q?rJcJyXI4vrxZYQ/qGolHfDORiYJGqu4DF0oKLK0hYvdHUWCQmuOkZnP4w7TO?= =?us-ascii?Q?TEJ7Eha8wUznbKPW9bTZ1ym5OiDEAnN+31ROQAfRv6BH31OKP68Q8uL9wTmt?= =?us-ascii?Q?i3zf/p/TynWNe+N13rQDsuk7j3aR4kJYlCAUr/k2Xr03ojGVYCY4khqE6aD6?= =?us-ascii?Q?J+9XR0DSTkGjbEHKMb78yGNLKm4t5Cws1PUNyyTsLLYQDoj/O0OmBG+Rs2vI?= =?us-ascii?Q?rriLlKFMULbLLYGthEv3H3sZpF3/wp9jlIqSPuClbyTqloKCSCVvdutXbLK+?= =?us-ascii?Q?dkdc6CzhxjB/SJhN/UVAiiraeHqF6+S5hcmkXEmq0swvhGmBH7V0hrKnnMj2?= =?us-ascii?Q?xqnTTtcQC1sVZP8DDLE=3D?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: MN6PR11MB8244.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7f4fd54e-98d9-4871-62da-08dc5cf153c6 X-MS-Exchange-CrossTenant-originalarrivaltime: 15 Apr 2024 02:11:14.2104 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: nn1p6PVMGr1C1uv4s/G9YqPkO4mo9LagsNa5tUYTzTKuwc8ZiCOnHJdPx7GtSCeghpTm5UEphoxfU2VnMezurg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR11MB7454 X-OriginatorOrg: intel.com Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Sun, 14 Apr 2024 19:11:18 -0700 Resent-From: ray.ni@intel.com Reply-To: devel@edk2.groups.io,ray.ni@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: VfveP9dsQQ40AMmw3w9GmaU6x7686176AA= Content-Language: en-US Content-Type: multipart/alternative; boundary="_000_MN6PR11MB82442ADA15DB9FA5F526851A8C092MN6PR11MB8244namp_" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=PGRSthra; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 45.79.224.9 as permitted sender) smtp.mailfrom=bounce@groups.io --_000_MN6PR11MB82442ADA15DB9FA5F526851A8C092MN6PR11MB8244namp_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Acked-by: Ray Ni Thanks, Ray ________________________________ From: Chao Li Sent: Friday, April 12, 2024 15:34 To: devel@edk2.groups.io Cc: Ni, Ray ; Kumar, Rahul R ; G= erd Hoffmann ; Baoqi Zhang ; Don= gyan Qian ; Xianglai Li ; = Bibo Mao Subject: [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Add a new base library named CpuMmuLib and add a LoongArch64 instance with in the library. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4734 Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann Signed-off-by: Chao Li Co-authored-by: Baoqi Zhang Co-authored-by: Dongyan Qian Co-authored-by: Xianglai Li Co-authored-by: Bibo Mao Acked-by: Gerd Hoffmann --- UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf | 39 + UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni | 14 + .../Library/CpuMmuLib/LoongArch64/CpuMmu.c | 785 ++++++++++++++++++ .../Library/CpuMmuLib/LoongArch64/Page.h | 33 + .../LoongArch64/TlbExceptionHandle.S | 51 ++ .../LoongArch64/TlbExceptionHandle.h | 36 + .../CpuMmuLib/LoongArch64/TlbInvalid.S | 24 + .../CpuMmuLib/LoongArch64/TlbInvalid.h | 24 + UefiCpuPkg/UefiCpuPkg.dsc | 3 + 9 files changed, 1009 insertions(+) create mode 100644 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf create mode 100644 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHa= ndle.S create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHa= ndle.h create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h diff --git a/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf b/UefiCpuPkg/Librar= y/CpuMmuLib/CpuMmuLib.inf new file mode 100644 index 0000000000..5eecfb4838 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf @@ -0,0 +1,39 @@ +## @file +# CPU Memory Manager Unit library instance. +# +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights = reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 1.29 + BASE_NAME =3D CpuMmuLib + MODULE_UNI_FILE =3D CpuMmuLib.uni + FILE_GUID =3D DA8F0232-FB14-42F0-922C-63104D2C70BE + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D CpuMmuLib + +# +# VALID_ARCHITECTURES =3D LOONGARCH64 +# + +[Sources.LoongArch64] + LoongArch64/TlbInvalid.S | GCC + LoongArch64/TlbExceptionHandle.S | GCC + LoongArch64/CpuMmu.c + LoongArch64/Page.h + LoongArch64/TlbInvalid.h + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + DebugLib + MemoryAllocationLib + +[Pcd.LoongArch64] + gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress ##= CONSUMES diff --git a/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni b/UefiCpuPkg/Librar= y/CpuMmuLib/CpuMmuLib.uni new file mode 100644 index 0000000000..2408f2f90b --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni @@ -0,0 +1,14 @@ +// /** @file +// CPU Memory Manager Unit library instance. +// +// CPU Memory Manager Unit library instance. +// +// Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manage= r Unit library instance." + +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manage= r Unit library instance." diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c b/UefiCpuPkg= /Library/CpuMmuLib/LoongArch64/CpuMmu.c new file mode 100644 index 0000000000..6d77a1221f --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c @@ -0,0 +1,785 @@ +/** @file + + CPU Memory Map Unit Handler Library common functions. + + 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.
+ Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TlbInvalid.h" +#include "TlbExceptionHandle.h" +#include "Page.h" + +/** + Check to see if mmu successfully initializes. + + @param VOID. + + @retval TRUE Initialization has been completed. + FALSE Initialization did not complete. +**/ +STATIC +BOOLEAN +MmuIsInit ( + VOID + ) +{ + if (CsrRead (LOONGARCH_CSR_PGDL) !=3D 0) { + return TRUE; + } + + return FALSE; +} + +/** + Check to see if mmu is enabled. + + @param VOID. + + @retval TRUE MMU has been enabled. + FALSE MMU did not enabled. +**/ +STATIC +BOOLEAN +MmuIsEnabled ( + VOID + ) +{ + if ((CsrRead (LOONGARCH_CSR_CRMD) & BIT4) !=3D 0) { + return TRUE; + } + + return FALSE; +} + +/** + Determine if an entry is valid pte. + + @param Entry The entry value. + + @retval TRUE The entry is a valid pte. + @retval FALSE The entry is not a valid pte. + +**/ +STATIC +BOOLEAN +IsValidPte ( + IN UINTN Entry + ) +{ + if (Entry !=3D INVALID_PAGE) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Determine if an entry is huge page. + + @param Entry The entry value. + + @retval TRUE The entry is a huge page. + @retval FALSE The entry is not a valid huge page. + +**/ +STATIC +BOOLEAN +IsValidHugePage ( + IN UINTN Entry + ) +{ + if ((Entry & (PAGE_HGLOBAL | PAGE_HUGE)) =3D=3D (PAGE_HGLOBAL | PAGE_HUG= E)) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Set an entry to be a valid pte. + + @param Entry The entry value. + + @return The entry value. + +**/ +STATIC +UINTN +SetValidPte ( + IN UINTN Entry + ) +{ + /* Set Valid and Global mapping bits */ + return Entry | PAGE_GLOBAL | PAGE_VALID; +} + +/** + Parse max page table level. + + @param[in] PageWalkCfg Page table configure value. + + @return 5 MAX page level is 5 + 4 MAX page level is 4 + 3 MAX page level is 3 + 0 Invalid +**/ +STATIC +UINTN +ParseMaxPageTableLevel ( + IN UINT64 PageWalkCfg + ) +{ + UINT32 Pwctl0; + UINT32 Pwctl1; + + Pwctl0 =3D PageWalkCfg & MAX_UINT32; + Pwctl1 =3D (PageWalkCfg >> 32) & MAX_UINT32; + + if (((Pwctl1 >> 18) & 0x3F) !=3D 0x0) { + return LEVEL5; + } else if (((Pwctl1 >> 6) & 0x3F) !=3D 0x0) { + return LEVEL4; + } else if (((Pwctl0 >> 25) & 0x3F) !=3D 0x0) { + return LEVEL3; + } + + return 0; +} + +/** + Parse page table bit width. + + Assume that the bit width of the page table that each level is the same = to PTwidth. + + @param[in] PageWalkCfg Page table configure value. + + @return page table bit width + +**/ +STATIC +UINTN +ParsePageTableBitWidth ( + IN UINT64 PageWalkCfg + ) +{ + // + // PTwidth + // + return ((PageWalkCfg >> 5) & 0x1F); +} + +/** + Determine if an entry is a HUGE PTE or 4K PTE. + + @param Entry The entry value. + @param Level The current page table level. + @param PageWalkCfg Page table configure value. + + @retval TRUE The entry is a block pte. + @retval FALSE The entry is not a block pte. + +**/ +STATIC +BOOLEAN +IsBlockEntry ( + IN UINTN Entry, + IN UINTN Level, + IN UINT64 PageWalkCfg + ) +{ + if (Level =3D=3D (ParseMaxPageTableLevel (PageWalkCfg) - 1)) { + return ((Entry & PAGE_VALID) =3D=3D PAGE_VALID); + } + + return IsValidHugePage (Entry); +} + +/** + Determine if an entry is a table pte. + + @param Entry The entry value. + @param Level The current page table level. + @param PageWalkCfg Page table configure value. + + @retval TRUE The entry is a table pte. + @retval FALSE The entry is not a table pte. + +**/ +STATIC +BOOLEAN +IsTableEntry ( + IN UINTN Entry, + IN UINTN Level, + IN UINT64 PageWalkCfg + ) +{ + if (Level =3D=3D (ParseMaxPageTableLevel (PageWalkCfg) - 1)) { + // + // The last level is PAGE rather than Table. + // + return FALSE; + } + + // + // Is DIR4 or DIR3 or DIR2 a Huge Page ? + // + return (!IsValidHugePage (Entry)) && (IsValidPte (Entry)); +} + +/** + Replace an existing entry with new value. + + @param Entry The entry pointer. + @param Value The new entry value. + @param RegionStart The start of region that new value affects. + @param IsLiveBlockMapping TRUE if this is live update, FALSE otherwise= . + +**/ +STATIC +VOID +ReplaceTableEntry ( + IN UINTN *Entry, + IN UINTN Value, + IN UINTN RegionStart, + IN BOOLEAN IsLiveBlockMapping + ) +{ + *Entry =3D Value; + + if (IsLiveBlockMapping && MmuIsInit ()) { + InvalidTlb (RegionStart); + } +} + +/** + Get an ppn value from an entry. + + @param Entry The entry value. + + @return The ppn value. + +**/ +STATIC +UINTN +GetPpnfromPte ( + IN UINTN Entry + ) +{ + return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT); +} + +/** + Set an ppn value to a entry. + + @param Entry The entry value. + @param Address The address. + + @return The new entry value. + +**/ +STATIC +UINTN +SetPpnToPte ( + UINTN Entry, + UINTN Address + ) +{ + UINTN Ppn; + + Ppn =3D ((Address >> LOONGARCH_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT); + ASSERT (~(Ppn & ~PTE_PPN_MASK)); + Entry &=3D ~PTE_PPN_MASK; + return Entry | Ppn; +} + +/** + Free resources of translation table recursively. + + @param TranslationTable The pointer of table. + @param PageWalkCfg Page table configure value. + @param Level The current level. + +**/ +STATIC +VOID +FreePageTablesRecursive ( + IN UINTN *TranslationTable, + IN UINT64 PageWalkCfg, + IN UINTN Level + ) +{ + UINTN Index; + UINTN TableEntryNum; + + TableEntryNum =3D (1 << ParsePageTableBitWidth (PageWalkCfg)); + + if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1)) { + for (Index =3D 0; Index < TableEntryNum; Index++) { + if (IsTableEntry (TranslationTable[Index], Level, PageWalkCfg)) { + FreePageTablesRecursive ( + (UINTN *)(GetPpnfromPte ((TranslationTable[Index])) << + LOONGARCH_MMU_PAGE_SHIFT), + PageWalkCfg, + Level + 1 + ); + } + } + } + + FreePages (TranslationTable, 1); +} + +/** + Update region mapping recursively. + + @param RegionStart The start address of the region. + @param RegionEnd The end address of the region. + @param AttributeSetMask The attribute mask to be set. + @param AttributeClearMask The attribute mask to be clear. + @param PageTable The pointer of current page table. + @param Level The current level. + @param PageWalkCfg Page table configure value. + @param TableIsLive TRUE if this is live update, FALSE otherwi= se. + + @retval EFI_OUT_OF_RESOURCES Not enough resource. + @retval EFI_SUCCESS The operation succesfully. + +**/ +STATIC +EFI_STATUS +UpdateRegionMappingRecursive ( + IN UINTN RegionStart, + IN UINTN RegionEnd, + IN UINTN AttributeSetMask, + IN UINTN AttributeClearMask, + IN UINTN *PageTable, + IN UINTN Level, + IN UINT64 PageWalkCfg, + IN BOOLEAN TableIsLive + ) +{ + EFI_STATUS Status; + UINTN BlockShift; + UINTN BlockMask; + UINTN BlockEnd; + UINTN *Entry; + UINTN EntryValue; + UINTN *TranslationTable; + UINTN TableEntryNum; + UINTN TableBitWidth; + BOOLEAN NextTableIsLive; + + ASSERT (Level < ParseMaxPageTableLevel (PageWalkCfg)); + ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) =3D=3D 0); + + TableBitWidth =3D ParsePageTableBitWidth (PageWalkCfg); + BlockShift =3D (ParseMaxPageTableLevel (PageWalkCfg) - Level - 1) * T= ableBitWidth + LOONGARCH_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 + ) + ); + + TableEntryNum =3D (1 << TableBitWidth); + for ( ; RegionStart < RegionEnd; RegionStart =3D BlockEnd) { + BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockMask) + 1); + Entry =3D &PageTable[(RegionStart >> BlockShift) & (TableEntryNum -= 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 2, + // so in that case, we have to recurse unconditionally. + // + if ((Level < 2) || + (((RegionStart | BlockEnd) & BlockMask) !=3D 0) || IsTableEntry (*= Entry, Level, PageWalkCfg)) + { + ASSERT (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1)); + if (!IsTableEntry (*Entry, Level, PageWalkCfg)) { + // + // 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, Level, PageWalkCfg)) { + // + // We are splitting an existing block entry, so we have to popul= ate + // the new table with the attributes of the block entry it repla= ces. + // + Status =3D UpdateRegionMappingRecursive ( + RegionStart & ~BlockMask, + (RegionStart | BlockMask) + 1, + *Entry & PTE_ATTRIBUTES_MASK, + PTE_ATTRIBUTES_MASK, + TranslationTable, + Level + 1, + PageWalkCfg, + FALSE + ); + if (EFI_ERROR (Status)) { + // + // The range we passed to UpdateRegionMappingRecursive () is b= lock + // aligned, so it is guaranteed that no further pages were all= ocated + // by it, and so we only have to free the page we allocated he= re. + // + FreePages (TranslationTable, 1); + return Status; + } + } + + NextTableIsLive =3D FALSE; + } else { + TranslationTable =3D (UINTN *)(GetPpnfromPte (*Entry) << LOONGARCH= _MMU_PAGE_SHIFT); + NextTableIsLive =3D TableIsLive; + } + + // + // Recurse to the next level + // + Status =3D UpdateRegionMappingRecursive ( + RegionStart, + BlockEnd, + AttributeSetMask, + AttributeClearMask, + TranslationTable, + Level + 1, + PageWalkCfg, + NextTableIsLive + ); + if (EFI_ERROR (Status)) { + if (!IsTableEntry (*Entry, Level, PageWalkCfg)) { + // + // We are creating a new table entry, so on failure, we can free= all + // allocations we made recursively, given that the whole subhier= archy + // has not been wired into the live page tables yet. (This is no= t + // possible for existing table entries, since we cannot revert t= he + // modifications we made to the subhierarchy it represents.) + // + FreePageTablesRecursive (TranslationTable, PageWalkCfg, Level + = 1); + } + + return Status; + } + + if (!IsTableEntry (*Entry, Level, PageWalkCfg)) { + EntryValue =3D SetPpnToPte (0, (UINTN)TranslationTable); + ReplaceTableEntry ( + Entry, + EntryValue, + RegionStart, + TableIsLive + ); + } + } else { + EntryValue =3D (*Entry & ~AttributeClearMask) | AttributeSetMask; + + EntryValue =3D SetPpnToPte (EntryValue, RegionStart); + EntryValue =3D SetValidPte (EntryValue); + + if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1)) { + EntryValue |=3D (PAGE_HGLOBAL | PAGE_HUGE | PAGE_VALID); + } else { + EntryValue |=3D PAGE_GLOBAL | PAGE_VALID; + } + + ReplaceTableEntry (Entry, EntryValue, RegionStart, TableIsLive); + } + } + + return EFI_SUCCESS; +} + +/** + Update region mapping at root table. + + @param RegionStart The start address of the region. + @param RegionLength The length of the region. + @param PageWalkCfg Page table configure value. + @param AttributeSetMask The attribute mask to be set. + @param AttributeClearMask The attribute mask to be clear. + @param RootTable The pointer of root table. + @param TableIsLive TRUE if this is live update, FALSE otherwi= se. + + @retval EFI_INVALID_PARAMETER The RegionStart or RegionLength was not va= lid. + @retval EFI_OUT_OF_RESOURCES Not enough resource. + @retval EFI_SUCCESS The operation succesfully. + +**/ +EFI_STATUS +UpdateRegionMapping ( + IN UINTN RegionStart, + IN UINTN RegionLength, + IN UINT64 PageWalkCfg, + 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, + PageWalkCfg, + TableIsLive + ); +} + +/** + Convert EFI Attributes to Loongarch Attributes. + + @param[in] EfiAttributes Efi Attributes. + + @retval Corresponding architecture attributes. +**/ +UINT64 +EFIAPI +EfiAttributeConverse ( + IN UINT64 EfiAttributes + ) +{ + UINT64 LoongArchAttributes; + + LoongArchAttributes =3D PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE_GLOB= AL; + + switch (EfiAttributes & EFI_CACHE_ATTRIBUTE_MASK) { + case EFI_MEMORY_UC: + LoongArchAttributes |=3D CACHE_SUC; + break; + case EFI_MEMORY_WC: + LoongArchAttributes |=3D CACHE_WUC; + break; + case EFI_MEMORY_WT: + case EFI_MEMORY_WB: + LoongArchAttributes |=3D CACHE_CC; + break; + case EFI_MEMORY_WP: + LoongArchAttributes &=3D ~PAGE_DIRTY; + break; + default: + LoongArchAttributes |=3D CACHE_CC; + break; + } + + // Write protection attributes + switch (EfiAttributes & EFI_MEMORY_ACCESS_MASK) { + case EFI_MEMORY_RP: + LoongArchAttributes |=3D PAGE_NO_READ; + break; + case EFI_MEMORY_XP: + LoongArchAttributes |=3D PAGE_NO_EXEC; + break; + case EFI_MEMORY_RO: + LoongArchAttributes &=3D ~PAGE_DIRTY; + break; + default: + break; + } + + return LoongArchAttributes; +} + +/** + TLB refill handler configure. + + @param VOID. + + @retval EFI_SUCCESS TLB refill handler configure successfully. + EFI_UNSUPPORTED Size not aligned. +**/ +EFI_STATUS +TlbRefillHandlerConfigure ( + VOID + ) +{ + UINTN Length; + UINTN TlbReEntry; + UINTN TlbReEntryOffset; + UINTN Remaining; + + // + // Set TLB exception handler + // + /// + /// TLB Re-entry address at the end of exception vector, a vector is up = to 512 bytes, + /// so the starting address is: total exception vector size + total inte= rrupt vector size + base. + /// The total size of TLB handler and exception vector size and interrup= t vector size should not + /// be lager than 64KB. + /// + Length =3D (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillS= tart; + TlbReEntryOffset =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT)= * 512; + Remaining =3D TlbReEntryOffset % SIZE_4KB; + if (Remaining !=3D 0x0) { + TlbReEntryOffset +=3D (SIZE_4KB - Remaining); + } + + TlbReEntry =3D PcdGet64 (PcdLoongArchExceptionVectorBaseAddress) + TlbRe= EntryOffset; + if ((TlbReEntryOffset + Length) > SIZE_64KB) { + return EFI_UNSUPPORTED; + } + + // + // Ensure that TLB refill exception base address alignment is equals to = 4KB and is valid. + // + if (TlbReEntry & (SIZE_4KB - 1)) { + return EFI_UNSUPPORTED; + } + + CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length); + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Le= ngth); + + // + // Set the address of TLB refill exception handler + // + SetTlbRebaseAddress ((UINTN)TlbReEntry); + + return EFI_SUCCESS; +} + +/** + Maps the memory region in the page table to the specified attributes. + + @param[in, out] PageTable The pointer to the page table to update, = or pointer to NULL + if a new page table is to be created. + @param[in] PageWalkCfg The page walk controller configure. + @param[in] BaseAddress The base address of the memory region to = set the Attributes. + @param[in] Length The length of the memory region to set th= e Attributes. + @param[in] Attributes The bitmask of attributes to set, which r= efer to UEFI SPEC + 7.2.3(EFI_BOOT_SERVICES.GetMemoryMap()). + @param[in] AttributeMask Mask of memory attributes to take into ac= count. + + @retval EFI_SUCCESS The Attributes was set successfully or Le= ngth is 0. + @retval EFI_INVALID_PARAMETER PageTable is NULL, PageWalkCfg is invalid= . + @retval EFI_UNSUPPORTED *PageTable is NULL. +**/ +EFI_STATUS +EFIAPI +MemoryRegionMap ( + IN OUT UINTN *PageTable OPTIONAL, + IN UINT64 PageWalkCfg, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN UINT64 AttributeMask + ) +{ + EFI_STATUS Status; + UINT64 LoongArchAttributes; + BOOLEAN Initialization; + BOOLEAN CreateNew; + UINTN PageTableBitWidth; + UINTN MaxLevel; + UINTN PgdSize; + + if ((PageTable =3D=3D NULL) || (PageWalkCfg =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + PageTableBitWidth =3D ParsePageTableBitWidth (PageWalkCfg); + MaxLevel =3D ParseMaxPageTableLevel (PageWalkCfg); + + if ((!PageTableBitWidth && !MaxLevel) || (PageTableBitWidth > 0x1F) || (= MaxLevel > LEVEL5)) { + return EFI_INVALID_PARAMETER; + } + + Initialization =3D FALSE; + CreateNew =3D FALSE; + + // + // *PageTable is NULL, create a new and return. + // + if (*PageTable =3D=3D 0) { + CreateNew =3D TRUE; + // + // If the MMU has not been configured yet, configure it later. + // + if (!MmuIsInit ()) { + Initialization =3D TRUE; + } + } + + if (Length =3D=3D 0) { + return EFI_SUCCESS; + } + + if (Initialization =3D=3D TRUE) { + Status =3D TlbRefillHandlerConfigure (); + ASSERT_EFI_ERROR (Status); + } + + if (CreateNew =3D=3D TRUE) { + // + // Create a new page table. + // + PgdSize =3D (1 << PageTableBitWidth) * sizeof (UINTN); + *PageTable =3D (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PgdSize)); + ZeroMem ((VOID *)*PageTable, PgdSize); + + if ((VOID *)*PageTable =3D=3D NULL) { + return EFI_UNSUPPORTED; + } + } + + LoongArchAttributes =3D EfiAttributeConverse (Attributes); + + // + // Update the page table attributes. + // + // If the MMU has been configured and *PageTable =3D=3D CSR_PGDL, the pa= ge table in use will update. + // + // If *PageTable !=3D CSR_PGDL, only the page table structure in memory = is update, but some TLB + // region may be invalidated during the mapping process. So at this time= the caller must ensure + // that the execution environment must be safe. It is recommended to use= the DA mode! + // + Status =3D UpdateRegionMapping ( + BaseAddress, + Length, + PageWalkCfg, + LoongArchAttributes, + PTE_ATTRIBUTES_MASK, + (UINTN *)(*PageTable), + (MmuIsEnabled () && !CreateNew) + ); + + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h b/UefiCpuPkg/L= ibrary/CpuMmuLib/LoongArch64/Page.h new file mode 100644 index 0000000000..b115245d68 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h @@ -0,0 +1,33 @@ +/** @file + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PAGE_H_ +#define PAGE_H_ + +#define INVALID_PAGE 0 + +#define LEVEL5 5 +#define LEVEL4 4 +#define LEVEL3 3 +#define LEVEL2 2 +#define LEVEL1 1 + +#define PTE_ATTRIBUTES_MASK 0x600000000000007EULL + +#define PTE_PPN_MASK 0xFFFFFFFFF000ULL +#define PTE_PPN_SHIFT EFI_PAGE_SHIFT +#define LOONGARCH_MMU_PAGE_SHIFT EFI_PAGE_SHIFT + +// +// For coding convenience, define the maximum valid +// LoongArch exception. +// Since UEFI V2.11, it will be present in DebugSupport.h. +// +#define MAX_LOONGARCH_EXCEPTION 64 + +#endif // PAGE_H_ diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S = b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S new file mode 100644 index 0000000000..4395b574f5 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S @@ -0,0 +1,51 @@ +#-------------------------------------------------------------------------= ----- +# +# TLB refill exception handler +# +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#-------------------------------------------------------------------------= ---- + +#include + +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart) +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd) + +# +# Refill the page table. +# @param VOID +# @retval VOID +# +ASM_PFX(HandleTlbRefillStart): + csrwr $t0, LOONGARCH_CSR_TLBRSAVE + csrrd $t0, LOONGARCH_CSR_PWCTL1 + srli.d $t0, $t0, 18 + andi $t0, $t0, 0x3F + bnez $t0, Level5 + csrrd $t0, LOONGARCH_CSR_PWCTL1 + srli.d $t0, $t0, 6 + andi $t0, $t0, 0x3F + bnez $t0, Level4 + csrrd $t0, LOONGARCH_CSR_PGD + b Level3 +Level5: + csrrd $t0, LOONGARCH_CSR_PGD + lddir $t0, $t0, 4 #Put pud BaseAddress into T0 + lddir $t0, $t0, 3 #Put pud BaseAddress into T0 + b Level3 +Level4: + csrrd $t0, LOONGARCH_CSR_PGD + lddir $t0, $t0, 3 #Put pud BaseAddress into T0 +Level3: + lddir $t0, $t0, 2 #Put pmd BaseAddress into T0 + lddir $t0, $t0, 1 #Put pte BaseAddress into T0 + ldpte $t0, 0 + ldpte $t0, 1 + tlbfill // refill hi, lo0, lo1 + csrrd $t0, LOONGARCH_CSR_TLBRSAVE + ertn +ASM_PFX(HandleTlbRefillEnd): + + .end diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h = b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h new file mode 100644 index 0000000000..c164db567d --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h @@ -0,0 +1,36 @@ +/** @file + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef TLB_EXCEPTION_HANDLE_H_ +#define TLB_EXCEPTION_HANDLE_H_ + +/** + TLB refill handler start. + + @param none + + @retval none +**/ +VOID +HandleTlbRefillStart ( + VOID + ); + +/** + TLB refill handler end. + + @param none + + @retval none +**/ +VOID +HandleTlbRefillEnd ( + VOID + ); + +#endif // TLB_EXCEPTION_HANDLE_H_ diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S b/UefiCp= uPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S new file mode 100644 index 0000000000..676aada240 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S @@ -0,0 +1,24 @@ +#-------------------------------------------------------------------------= ----- +# +# Invalid TLB operation function +# +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#-------------------------------------------------------------------------= ---- + +#include + +ASM_GLOBAL ASM_PFX(InvalidTlb) + +# +# Invalid corresponding TLB entries are based on the address given +# @param a0 The address corresponding to the invalid page table entry +# @retval none +# +ASM_PFX(InvalidTlb): + invtlb INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0 + jirl $zero, $ra, 0 + + .end diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h b/UefiCp= uPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h new file mode 100644 index 0000000000..5063e6662b --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h @@ -0,0 +1,24 @@ +/** @file + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef INVALID_TLB_H_ +#define INVALID_TLB_H_ + +/** + Invalid corresponding TLB entries are based on the address given + + @param Address The address corresponding to the invalid page table entry + + @retval none +**/ +VOID +InvalidTlb ( + UINTN Address + ); + +#endif // INVALID_TLB_H_ diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 2eebd45125..e92ceb6466 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -211,5 +211,8 @@ [Components.RISCV64] UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf UefiCpuPkg/CpuMmio2Dxe/CpuMmio2Dxe.inf +[Components.LOONGARCH64] + UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf + [BuildOptions] *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES -- 2.27.0 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#117741): https://edk2.groups.io/g/devel/message/117741 Mute This Topic: https://groups.io/mt/105478500/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --_000_MN6PR11MB82442ADA15DB9FA5F526851A8C092MN6PR11MB8244namp_ Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable
Acked-by: Ray Ni <ray.ni@intel.com>

Thanks,
Ray

From: Chao Li <lichao@lo= ongson.cn>
Sent: Friday, April 12, 2024 15:34
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kum= ar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Baoqi Zhang <= zhangbaoqi@loongson.cn>; Dongyan Qian <qiandongyan@loongson.cn>; X= ianglai Li <lixianglai@loongson.cn>; Bibo Mao <maobibo@loongson.cn= >
Subject: [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg
 
Add a new base library named CpuMmuLib and add a L= oongArch64 instance
with in the library.

BZ: https= ://bugzilla.tianocore.org/show_bug.cgi?id=3D4734

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian <qiandongyan@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf    |  = 39 +
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni    |  = 14 +
 .../Library/CpuMmuLib/LoongArch64/CpuMmu.c    | 785 ++= ++++++++++++++++
 .../Library/CpuMmuLib/LoongArch64/Page.h     = ; |  33 +
 .../LoongArch64/TlbExceptionHandle.S     &nb= sp;    |  51 ++
 .../LoongArch64/TlbExceptionHandle.h     &nb= sp;    |  36 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.S     &= nbsp;  |  24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.h     &= nbsp;  |  24 +
 UefiCpuPkg/UefiCpuPkg.dsc       &n= bsp;            = ; |   3 +
 9 files changed, 1009 insertions(+)
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c<= br>  create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h  create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExcept= ionHandle.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExcept= ionHandle.h
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvali= d.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvali= d.h

diff --git a/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf b/UefiCpuPkg/Librar= y/CpuMmuLib/CpuMmuLib.inf
new file mode 100644
index 0000000000..5eecfb4838
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
@@ -0,0 +1,39 @@
+## @file
+#  CPU Memory Manager Unit library instance.
+#
+#  Copyright (c) 2024 Loongson Technology Corporation Limited. All ri= ghts reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION         &n= bsp;          =3D 1.29
+  BASE_NAME         &nbs= p;            =3D Cp= uMmuLib
+  MODULE_UNI_FILE        &nbs= p;       =3D CpuMmuLib.uni
+  FILE_GUID         &nbs= p;            =3D DA= 8F0232-FB14-42F0-922C-63104D2C70BE
+  MODULE_TYPE         &n= bsp;          =3D BASE
+  VERSION_STRING         = ;        =3D 1.0
+  LIBRARY_CLASS         =          =3D CpuMmuLib
+
+#
+#  VALID_ARCHITECTURES        = ;   =3D LOONGARCH64
+#
+
+[Sources.LoongArch64]
+  LoongArch64/TlbInvalid.S       &= nbsp; | GCC
+  LoongArch64/TlbExceptionHandle.S | GCC
+  LoongArch64/CpuMmu.c
+  LoongArch64/Page.h
+  LoongArch64/TlbInvalid.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
+
+[Pcd.LoongArch64]
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress&nb= sp;     ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni b/UefiCpuPkg/Librar= y/CpuMmuLib/CpuMmuLib.uni
new file mode 100644
index 0000000000..2408f2f90b
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CPU Memory Manager Unit library instance.
+//
+// CPU Memory Manager Unit library instance.
+//
+// Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT        = ;     #language en-US "CPU Memory Manager Unit lib= rary instance."
+
+#string STR_MODULE_DESCRIPTION       &n= bsp;  #language en-US "CPU Memory Manager Unit library instance.&= quot;
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c b/UefiCpuPkg= /Library/CpuMmuLib/LoongArch64/CpuMmu.c
new file mode 100644
index 0000000000..6d77a1221f
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c
@@ -0,0 +1,785 @@
+/** @file
+
+  CPU Memory Map Unit Handler Library common functions.
+
+  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
+  Copyright (c) 2016, Linaro Limited. All rights reserved.
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR&g= t;
+  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.= <BR>
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rig= hts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/DebugSupport.h>
+#include <Register/LoongArch64/Csr.h>
+#include "TlbInvalid.h"
+#include "TlbExceptionHandle.h"
+#include "Page.h"
+
+/**
+  Check to see if mmu successfully initializes.
+
+  @param  VOID.
+
+  @retval  TRUE  Initialization has been completed.
+           FALSE Initial= ization did not complete.
+**/
+STATIC
+BOOLEAN
+MmuIsInit (
+  VOID
+  )
+{
+  if (CsrRead (LOONGARCH_CSR_PGDL) !=3D 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Check to see if mmu is enabled.
+
+  @param  VOID.
+
+  @retval  TRUE  MMU has been enabled.
+           FALSE MMU did= not enabled.
+**/
+STATIC
+BOOLEAN
+MmuIsEnabled (
+  VOID
+  )
+{
+  if ((CsrRead (LOONGARCH_CSR_CRMD) & BIT4) !=3D 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Determine if an entry is valid pte.
+
+  @param    Entry   The entry value.
+
+  @retval   TRUE    The entry is a valid pte= .
+  @retval   FALSE   The entry is not a valid pte.=
+
+**/
+STATIC
+BOOLEAN
+IsValidPte (
+  IN  UINTN  Entry
+  )
+{
+  if (Entry !=3D INVALID_PAGE) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Determine if an entry is huge page.
+
+  @param    Entry   The entry value.
+
+  @retval   TRUE    The entry is a huge page= .
+  @retval   FALSE   The entry is not a valid huge= page.
+
+**/
+STATIC
+BOOLEAN
+IsValidHugePage (
+  IN  UINTN  Entry
+  )
+{
+  if ((Entry & (PAGE_HGLOBAL | PAGE_HUGE)) =3D=3D (PAGE_HGLOBAL |= PAGE_HUGE)) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Set an entry to be a valid pte.
+
+  @param  Entry   The entry value.
+
+  @return         The entry v= alue.
+
+**/
+STATIC
+UINTN
+SetValidPte (
+  IN  UINTN  Entry
+  )
+{
+  /* Set Valid and Global mapping bits */
+  return Entry | PAGE_GLOBAL | PAGE_VALID;
+}
+
+/**
+  Parse max page table level.
+
+  @param[in]  PageWalkCfg  Page table configure value.
+
+  @return         5 &nbs= p; MAX page level is 5
+            &n= bsp;     4   MAX page level is 4
+            &n= bsp;     3   MAX page level is 3
+            &n= bsp;     0   Invalid
+**/
+STATIC
+UINTN
+ParseMaxPageTableLevel (
+  IN  UINT64  PageWalkCfg
+  )
+{
+  UINT32  Pwctl0;
+  UINT32  Pwctl1;
+
+  Pwctl0 =3D PageWalkCfg & MAX_UINT32;
+  Pwctl1 =3D (PageWalkCfg >> 32) & MAX_UINT32;
+
+  if (((Pwctl1 >> 18) & 0x3F) !=3D 0x0) {
+    return LEVEL5;
+  } else if (((Pwctl1 >> 6) & 0x3F) !=3D 0x0) {
+    return LEVEL4;
+  } else if (((Pwctl0 >> 25) & 0x3F) !=3D 0x0) {
+    return LEVEL3;
+  }
+
+  return 0;
+}
+
+/**
+  Parse page table bit width.
+
+  Assume that the bit width of the page table that each level is the = same to PTwidth.
+
+  @param[in]  PageWalkCfg  Page table configure value.
+
+  @return         page table = bit width
+
+**/
+STATIC
+UINTN
+ParsePageTableBitWidth (
+  IN  UINT64  PageWalkCfg
+  )
+{
+  //
+  // PTwidth
+  //
+  return ((PageWalkCfg >> 5) & 0x1F);
+}
+
+/**
+  Determine if an entry is a HUGE PTE or 4K PTE.
+
+  @param    Entry      &= nbsp; The entry value.
+  @param    Level      &= nbsp; The current page table level.
+  @param    PageWalkCfg  Page table configure val= ue.
+
+  @retval   TRUE    The entry is a block pte= .
+  @retval   FALSE   The entry is not a block pte.=
+
+**/
+STATIC
+BOOLEAN
+IsBlockEntry (
+  IN  UINTN   Entry,
+  IN  UINTN   Level,
+  IN  UINT64  PageWalkCfg
+  )
+{
+  if (Level =3D=3D (ParseMaxPageTableLevel (PageWalkCfg) - 1)) {
+    return ((Entry & PAGE_VALID) =3D=3D PAGE_VALID); +  }
+
+  return IsValidHugePage (Entry);
+}
+
+/**
+  Determine if an entry is a table pte.
+
+  @param    Entry      &= nbsp; The entry value.
+  @param    Level      &= nbsp; The current page table level.
+  @param    PageWalkCfg  Page table configure val= ue.
+
+  @retval   TRUE    The entry is a table pte= .
+  @retval   FALSE   The entry is not a table pte.=
+
+**/
+STATIC
+BOOLEAN
+IsTableEntry (
+  IN  UINTN   Entry,
+  IN  UINTN   Level,
+  IN  UINT64  PageWalkCfg
+  )
+{
+  if (Level =3D=3D (ParseMaxPageTableLevel (PageWalkCfg) - 1)) {
+    //
+    // The last level is PAGE rather than Table.
+    //
+    return FALSE;
+  }
+
+  //
+  // Is DIR4 or DIR3 or DIR2 a Huge Page ?
+  //
+  return (!IsValidHugePage (Entry)) && (IsValidPte (Entry));<= br> +}
+
+/**
+  Replace an existing entry with new value.
+
+  @param  Entry        &= nbsp;      The entry pointer.
+  @param  Value        &= nbsp;      The new entry value.
+  @param  RegionStart       &= nbsp; The start of region that new value affects.
+  @param  IsLiveBlockMapping  TRUE if this is live update, = FALSE otherwise.
+
+**/
+STATIC
+VOID
+ReplaceTableEntry (
+  IN  UINTN    *Entry,
+  IN  UINTN    Value,
+  IN  UINTN    RegionStart,
+  IN  BOOLEAN  IsLiveBlockMapping
+  )
+{
+  *Entry =3D Value;
+
+  if (IsLiveBlockMapping && MmuIsInit ()) {
+    InvalidTlb (RegionStart);
+  }
+}
+
+/**
+  Get an ppn value from an entry.
+
+  @param  Entry   The entry value.
+
+  @return         The ppn val= ue.
+
+**/
+STATIC
+UINTN
+GetPpnfromPte (
+  IN UINTN  Entry
+  )
+{
+  return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT);
+}
+
+/**
+  Set an ppn value to a entry.
+
+  @param  Entry   The entry value.
+  @param  Address The address.
+
+  @return The new entry value.
+
+**/
+STATIC
+UINTN
+SetPpnToPte (
+  UINTN  Entry,
+  UINTN  Address
+  )
+{
+  UINTN  Ppn;
+
+  Ppn =3D ((Address >> LOONGARCH_MMU_PAGE_SHIFT) << PTE_P= PN_SHIFT);
+  ASSERT (~(Ppn & ~PTE_PPN_MASK));
+  Entry &=3D ~PTE_PPN_MASK;
+  return Entry | Ppn;
+}
+
+/**
+  Free resources of translation table recursively.
+
+  @param  TranslationTable  The pointer of table.
+  @param  PageWalkCfg       Page t= able configure value.
+  @param  Level        &= nbsp;    The current level.
+
+**/
+STATIC
+VOID
+FreePageTablesRecursive (
+  IN  UINTN   *TranslationTable,
+  IN  UINT64  PageWalkCfg,
+  IN  UINTN   Level
+  )
+{
+  UINTN  Index;
+  UINTN  TableEntryNum;
+
+  TableEntryNum =3D (1 << ParsePageTableBitWidth (PageWalkCfg))= ;
+
+  if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1)) {
+    for (Index =3D 0; Index < TableEntryNum; Index++) {<= br> +      if (IsTableEntry (TranslationTable[Index], = Level, PageWalkCfg)) {
+        FreePageTablesRecursive (
+          (UINTN *)(GetPpnfro= mPte ((TranslationTable[Index])) <<
+            &n= bsp;       LOONGARCH_MMU_PAGE_SHIFT),
+          PageWalkCfg,
+          Level + 1
+          );
+      }
+    }
+  }
+
+  FreePages (TranslationTable, 1);
+}
+
+/**
+  Update region mapping recursively.
+
+  @param  RegionStart       &= nbsp;   The start address of the region.
+  @param  RegionEnd       &nb= sp;     The end address of the region.
+  @param  AttributeSetMask      The att= ribute mask to be set.
+  @param  AttributeClearMask    The attribute mas= k to be clear.
+  @param  PageTable       &nb= sp;     The pointer of current page table.
+  @param  Level        &= nbsp;        The current level.
+  @param  PageWalkCfg       &= nbsp;   Page table configure value.
+  @param  TableIsLive       &= nbsp;   TRUE if this is live update, FALSE otherwise.
+
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource.
+  @retval EFI_SUCCESS        =    The operation succesfully.
+
+**/
+STATIC
+EFI_STATUS
+UpdateRegionMappingRecursive (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionEnd,
+  IN  UINTN    AttributeSetMask,
+  IN  UINTN    AttributeClearMask,
+  IN  UINTN    *PageTable,
+  IN  UINTN    Level,
+  IN  UINT64   PageWalkCfg,
+  IN  BOOLEAN  TableIsLive
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlockShift;
+  UINTN       BlockMask;
+  UINTN       BlockEnd;
+  UINTN       *Entry;
+  UINTN       EntryValue;
+  UINTN       *TranslationTable;
+  UINTN       TableEntryNum;
+  UINTN       TableBitWidth;
+  BOOLEAN     NextTableIsLive;
+
+  ASSERT (Level < ParseMaxPageTableLevel (PageWalkCfg));
+  ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) =3D=3D 0);<= br> +
+  TableBitWidth =3D ParsePageTableBitWidth (PageWalkCfg);
+  BlockShift    =3D (ParseMaxPageTableLevel (PageWalkC= fg) - Level - 1) * TableBitWidth + LOONGARCH_MMU_PAGE_SHIFT;
+  BlockMask     =3D MAX_ADDRESS >> (64 - Bl= ockShift);
+
+  DEBUG (
+    (
+     DEBUG_VERBOSE,
+     "%a(%d): %llx - %llx set %lx clr %lx\n"= ,
+     __func__,
+     Level,
+     RegionStart,
+     RegionEnd,
+     AttributeSetMask,
+     AttributeClearMask
+    )
+    );
+
+  TableEntryNum =3D (1 << TableBitWidth);
+  for ( ; RegionStart < RegionEnd; RegionStart =3D BlockEnd) {
+    BlockEnd =3D MIN (RegionEnd, (RegionStart | BlockMask) = + 1);
+    Entry    =3D &PageTable[(RegionStart= >> BlockShift) & (TableEntryNum - 1)];
+
+    //
+    // If RegionStart or BlockEnd is not aligned to the blo= ck size at this
+    // level, we will have to create a table mapping in ord= er to map less
+    // than a block, and recurse to create the block or pag= e entries at
+    // the next level. No block mappings are allowed at all= at level 2,
+    // so in that case, we have to recurse unconditionally.=
+    //
+    if ((Level < 2) ||
+        (((RegionStart | BlockEnd) &= ; BlockMask) !=3D 0) || IsTableEntry (*Entry, Level, PageWalkCfg))
+    {
+      ASSERT (Level < (ParseMaxPageTableLevel = (PageWalkCfg) - 1));
+      if (!IsTableEntry (*Entry, Level, PageWalkC= fg)) {
+        //
+        // No table entry exists yet, s= o we need to allocate a page table
+        // for the next level.
+        //
+        TranslationTable =3D AllocatePa= ges (1);
+        if (TranslationTable =3D=3D NUL= L) {
+          return EFI_OUT_OF_R= ESOURCES;
+        }
+
+        ZeroMem (TranslationTable, EFI_= PAGE_SIZE);
+
+        if (IsBlockEntry (*Entry, Level= , PageWalkCfg)) {
+          //
+          // We are splitting= an existing block entry, so we have to populate
+          // the new table wi= th the attributes of the block entry it replaces.
+          //
+          Status =3D UpdateRe= gionMappingRecursive (
+            &n= bsp;        RegionStart & ~BlockMask= ,
+            &n= bsp;        (RegionStart | BlockMask) + = 1,
+            &n= bsp;        *Entry & PTE_ATTRIBUTES_= MASK,
+            &n= bsp;        PTE_ATTRIBUTES_MASK,
+            &n= bsp;        TranslationTable,
+            &n= bsp;        Level + 1,
+            &n= bsp;        PageWalkCfg,
+            &n= bsp;        FALSE
+            &n= bsp;        );
+          if (EFI_ERROR (Stat= us)) {
+            //
+            // The = range we passed to UpdateRegionMappingRecursive () is block
+            // alig= ned, so it is guaranteed that no further pages were allocated
+            // by i= t, and so we only have to free the page we allocated here.
+            //
+            FreePag= es (TranslationTable, 1);
+            return = Status;
+          }
+        }
+
+        NextTableIsLive =3D FALSE;
+      } else {
+        TranslationTable =3D (UINTN *)(= GetPpnfromPte (*Entry) << LOONGARCH_MMU_PAGE_SHIFT);
+        NextTableIsLive  =3D Table= IsLive;
+      }
+
+      //
+      // Recurse to the next level
+      //
+      Status =3D UpdateRegionMappingRecursive ( +            &n= bsp;    RegionStart,
+            &n= bsp;    BlockEnd,
+            &n= bsp;    AttributeSetMask,
+            &n= bsp;    AttributeClearMask,
+            &n= bsp;    TranslationTable,
+            &n= bsp;    Level + 1,
+            &n= bsp;    PageWalkCfg,
+            &n= bsp;    NextTableIsLive
+            &n= bsp;    );
+      if (EFI_ERROR (Status)) {
+        if (!IsTableEntry (*Entry, Leve= l, PageWalkCfg)) {
+          //
+          // We are creating = a new table entry, so on failure, we can free all
+          // allocations we m= ade recursively, given that the whole subhierarchy
+          // has not been wir= ed into the live page tables yet. (This is not
+          // possible for exi= sting table entries, since we cannot revert the
+          // modifications we= made to the subhierarchy it represents.)
+          //
+          FreePageTablesRecur= sive (TranslationTable, PageWalkCfg, Level + 1);
+        }
+
+        return Status;
+      }
+
+      if (!IsTableEntry (*Entry, Level, PageWalkC= fg)) {
+        EntryValue =3D SetPpnToPte (0, = (UINTN)TranslationTable);
+        ReplaceTableEntry (
+          Entry,
+          EntryValue,
+          RegionStart,
+          TableIsLive
+          );
+      }
+    } else {
+      EntryValue =3D (*Entry & ~AttributeClea= rMask) | AttributeSetMask;
+
+      EntryValue =3D SetPpnToPte (EntryValue, Reg= ionStart);
+      EntryValue =3D SetValidPte (EntryValue); +
+      if (Level < (ParseMaxPageTableLevel (Pag= eWalkCfg) - 1)) {
+        EntryValue |=3D (PAGE_HGLOBAL |= PAGE_HUGE | PAGE_VALID);
+      } else {
+        EntryValue |=3D PAGE_GLOBAL | P= AGE_VALID;
+      }
+
+      ReplaceTableEntry (Entry, EntryValue, Regio= nStart, TableIsLive);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update region mapping at root table.
+
+  @param  RegionStart       &= nbsp;   The start address of the region.
+  @param  RegionLength       =    The length of the region.
+  @param  PageWalkCfg       &= nbsp;   Page table configure value.
+  @param  AttributeSetMask      The att= ribute mask to be set.
+  @param  AttributeClearMask    The attribute mas= k to be clear.
+  @param  RootTable       &nb= sp;     The pointer of root table.
+  @param  TableIsLive       &= nbsp;   TRUE if this is live update, FALSE otherwise.
+
+  @retval EFI_INVALID_PARAMETER The RegionStart or RegionLength was n= ot valid.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource.
+  @retval EFI_SUCCESS        =    The operation succesfully.
+
+**/
+EFI_STATUS
+UpdateRegionMapping (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionLength,
+  IN  UINT64   PageWalkCfg,
+  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,<= br> +           RegionStart += RegionLength,
+           AttributeSetM= ask,
+           AttributeClea= rMask,
+           RootTable, +           0,
+           PageWalkCfg,<= br> +           TableIsLive +           );
+}
+
+/**
+  Convert EFI Attributes to Loongarch Attributes.
+
+  @param[in]  EfiAttributes     Efi Attribut= es.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINT64
+EFIAPI
+EfiAttributeConverse (
+  IN UINT64  EfiAttributes
+  )
+{
+  UINT64  LoongArchAttributes;
+
+  LoongArchAttributes =3D PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE= _GLOBAL;
+
+  switch (EfiAttributes & EFI_CACHE_ATTRIBUTE_MASK) {
+    case EFI_MEMORY_UC:
+      LoongArchAttributes |=3D CACHE_SUC;
+      break;
+    case EFI_MEMORY_WC:
+      LoongArchAttributes |=3D CACHE_WUC;
+      break;
+    case EFI_MEMORY_WT:
+    case EFI_MEMORY_WB:
+      LoongArchAttributes |=3D CACHE_CC;
+      break;
+    case EFI_MEMORY_WP:
+      LoongArchAttributes &=3D ~PAGE_DIRTY; +      break;
+    default:
+      LoongArchAttributes |=3D CACHE_CC;
+      break;
+  }
+
+  // Write protection attributes
+  switch (EfiAttributes & EFI_MEMORY_ACCESS_MASK) {
+    case EFI_MEMORY_RP:
+      LoongArchAttributes |=3D PAGE_NO_READ;
+      break;
+    case EFI_MEMORY_XP:
+      LoongArchAttributes |=3D PAGE_NO_EXEC;
+      break;
+    case EFI_MEMORY_RO:
+      LoongArchAttributes &=3D ~PAGE_DIRTY; +      break;
+    default:
+      break;
+  }
+
+  return LoongArchAttributes;
+}
+
+/**
+  TLB refill handler configure.
+
+  @param  VOID.
+
+  @retval  EFI_SUCCESS      TLB refill = handler configure successfully.
+           EFI_UNSUPPORT= ED  Size not aligned.
+**/
+EFI_STATUS
+TlbRefillHandlerConfigure (
+  VOID
+  )
+{
+  UINTN  Length;
+  UINTN  TlbReEntry;
+  UINTN  TlbReEntryOffset;
+  UINTN  Remaining;
+
+  //
+  // Set TLB exception handler
+  //
+  ///
+  /// TLB Re-entry address at the end of exception vector, a vector i= s up to 512 bytes,
+  /// so the starting address is: total exception vector size + total= interrupt vector size + base.
+  /// The total size of TLB handler and exception vector size and int= errupt vector size should not
+  /// be lager than 64KB.
+  ///
+  Length           = =3D (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
+  TlbReEntryOffset =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTER= RUPT) * 512;
+  Remaining        =3D TlbReEntryO= ffset % SIZE_4KB;
+  if (Remaining !=3D 0x0) {
+    TlbReEntryOffset +=3D (SIZE_4KB - Remaining);
+  }
+
+  TlbReEntry =3D PcdGet64 (PcdLoongArchExceptionVectorBaseAddress) + = TlbReEntryOffset;
+  if ((TlbReEntryOffset + Length) > SIZE_64KB) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Ensure that TLB refill exception base address alignment is equal= s to 4KB and is valid.
+  //
+  if (TlbReEntry & (SIZE_4KB - 1)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStar= t, Length);
+
+  //
+  // Set the address of TLB refill exception handler
+  //
+  SetTlbRebaseAddress ((UINTN)TlbReEntry);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Maps the memory region in the page table to the specified attribute= s.
+
+  @param[in, out] PageTable      The pointer= to the page table to update, or pointer to NULL
+            &n= bsp;            = ;        if a new page table is to be cr= eated.
+  @param[in]      PageWalkCfg  &nb= sp; The page walk controller configure.
+  @param[in]      BaseAddress  &nb= sp; The base address of the memory region to set the Attributes.
+  @param[in]      Length   &n= bsp;     The length of the memory region to set the Att= ributes.
+  @param[in]      Attributes  &nbs= p;  The bitmask of attributes to set, which refer to UEFI SPEC
+            &n= bsp;            = ;        7.2.3(EFI_BOOT_SERVICES.GetMemo= ryMap()).
+  @param[in]      AttributeMask  Mask o= f memory attributes to take into account.
+
+  @retval EFI_SUCCESS        =     The Attributes was set successfully or Length is 0.
+  @retval EFI_INVALID_PARAMETER  PageTable is NULL, PageWalkCfg = is invalid.
+  @retval EFI_UNSUPPORTED        *= PageTable is NULL.
+**/
+EFI_STATUS
+EFIAPI
+MemoryRegionMap (
+  IN OUT UINTN         &= nbsp;       *PageTable  OPTIONAL,
+  IN     UINT64     &nbs= p;          PageWalkCfg,
+  IN     EFI_PHYSICAL_ADDRESS  BaseAddress,<= br> +  IN     UINT64     &nbs= p;          Length,
+  IN     UINT64     &nbs= p;          Attributes,
+  IN     UINT64     &nbs= p;          AttributeMask
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      LoongArchAttributes;
+  BOOLEAN     Initialization;
+  BOOLEAN     CreateNew;
+  UINTN       PageTableBitWidth;
+  UINTN       MaxLevel;
+  UINTN       PgdSize;
+
+  if ((PageTable =3D=3D NULL) || (PageWalkCfg =3D=3D 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PageTableBitWidth =3D ParsePageTableBitWidth (PageWalkCfg);
+  MaxLevel          =3D = ParseMaxPageTableLevel (PageWalkCfg);
+
+  if ((!PageTableBitWidth && !MaxLevel) || (PageTableBitWidth= > 0x1F) || (MaxLevel > LEVEL5)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Initialization =3D FALSE;
+  CreateNew      =3D FALSE;
+
+  //
+  // *PageTable is NULL, create a new and return.
+  //
+  if (*PageTable =3D=3D 0) {
+    CreateNew =3D TRUE;
+    //
+    // If the MMU has not been configured yet, configure it= later.
+    //
+    if (!MmuIsInit ()) {
+      Initialization =3D TRUE;
+    }
+  }
+
+  if (Length =3D=3D 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (Initialization =3D=3D TRUE) {
+    Status =3D TlbRefillHandlerConfigure ();
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (CreateNew =3D=3D TRUE) {
+    //
+    // Create a new page table.
+    //
+    PgdSize    =3D  (1 << PageTab= leBitWidth) * sizeof (UINTN);
+    *PageTable =3D (UINTN)AllocatePages (EFI_SIZE_TO_PAGES = (PgdSize));
+    ZeroMem ((VOID *)*PageTable, PgdSize);
+
+    if ((VOID *)*PageTable =3D=3D NULL) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  LoongArchAttributes =3D EfiAttributeConverse (Attributes);
+
+  //
+  // Update the page table attributes.
+  //
+  // If the MMU has been configured and *PageTable =3D=3D CSR_PGDL, t= he page table in use will update.
+  //
+  // If *PageTable !=3D CSR_PGDL, only the page table structure in me= mory is update, but some TLB
+  // region may be invalidated during the mapping process. So at this= time the caller must ensure
+  // that the execution environment must be safe. It is recommended t= o use the DA mode!
+  //
+  Status =3D UpdateRegionMapping (
+             B= aseAddress,
+             L= ength,
+             P= ageWalkCfg,
+             L= oongArchAttributes,
+             P= TE_ATTRIBUTES_MASK,
+             (= UINTN *)(*PageTable),
+             (= MmuIsEnabled () && !CreateNew)
+             )= ;
+
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h b/UefiCpuPkg/L= ibrary/CpuMmuLib/LoongArch64/Page.h
new file mode 100644
index 0000000000..b115245d68
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h
@@ -0,0 +1,33 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rig= hts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#define INVALID_PAGE  0
+
+#define LEVEL5  5
+#define LEVEL4  4
+#define LEVEL3  3
+#define LEVEL2  2
+#define LEVEL1  1
+
+#define PTE_ATTRIBUTES_MASK  0x600000000000007EULL
+
+#define PTE_PPN_MASK         =      0xFFFFFFFFF000ULL
+#define PTE_PPN_SHIFT         = ;    EFI_PAGE_SHIFT
+#define LOONGARCH_MMU_PAGE_SHIFT  EFI_PAGE_SHIFT
+
+//
+// For coding convenience, define the maximum valid
+// LoongArch exception.
+// Since UEFI V2.11, it will be present in DebugSupport.h.
+//
+#define MAX_LOONGARCH_EXCEPTION  64
+
+#endif // PAGE_H_
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S = b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S
new file mode 100644
index 0000000000..4395b574f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S
@@ -0,0 +1,51 @@
+#-------------------------------------------------------------------------= -----
+#
+# TLB refill exception handler
+#
+# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-------------------------------------------------------------------------= ----
+
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
+ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
+
+#
+#  Refill the page table.
+#  @param  VOID
+#  @retval  VOID
+#
+ASM_PFX(HandleTlbRefillStart):
+  csrwr   $t0, LOONGARCH_CSR_TLBRSAVE
+  csrrd   $t0, LOONGARCH_CSR_PWCTL1
+  srli.d  $t0, $t0, 18
+  andi    $t0, $t0, 0x3F
+  bnez    $t0, Level5
+  csrrd   $t0, LOONGARCH_CSR_PWCTL1
+  srli.d  $t0, $t0, 6
+  andi    $t0, $t0, 0x3F
+  bnez    $t0, Level4
+  csrrd   $t0, LOONGARCH_CSR_PGD
+  b       Level3
+Level5:
+  csrrd   $t0, LOONGARCH_CSR_PGD
+  lddir   $t0, $t0, 4   #Put pud BaseAddress into= T0
+  lddir   $t0, $t0, 3   #Put pud BaseAddress into= T0
+  b       Level3
+Level4:
+  csrrd   $t0, LOONGARCH_CSR_PGD
+  lddir   $t0, $t0, 3   #Put pud BaseAddress into= T0
+Level3:
+  lddir   $t0, $t0, 2   #Put pmd BaseAddress into= T0
+  lddir   $t0, $t0, 1   #Put pte BaseAddress into= T0
+  ldpte   $t0, 0
+  ldpte   $t0, 1
+  tlbfill   // refill hi, lo0, lo1
+  csrrd   $t0, LOONGARCH_CSR_TLBRSAVE
+  ertn
+ASM_PFX(HandleTlbRefillEnd):
+
+    .end
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h = b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h
new file mode 100644
index 0000000000..c164db567d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h
@@ -0,0 +1,36 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rig= hts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TLB_EXCEPTION_HANDLE_H_
+#define TLB_EXCEPTION_HANDLE_H_
+
+/**
+  TLB refill handler start.
+
+  @param  none
+
+  @retval none
+**/
+VOID
+HandleTlbRefillStart (
+  VOID
+  );
+
+/**
+  TLB refill handler end.
+
+  @param  none
+
+  @retval none
+**/
+VOID
+HandleTlbRefillEnd (
+  VOID
+  );
+
+#endif // TLB_EXCEPTION_HANDLE_H_
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S b/UefiCp= uPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
new file mode 100644
index 0000000000..676aada240
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------= -----
+#
+# Invalid TLB operation function
+#
+# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights r= eserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-------------------------------------------------------------------------= ----
+
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(InvalidTlb)
+
+#
+# Invalid corresponding TLB entries are based on the address given
+# @param a0 The address corresponding to the invalid page table entry
+# @retval  none
+#
+ASM_PFX(InvalidTlb):
+    invtlb  INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
+    jirl    $zero, $ra, 0
+
+    .end
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h b/UefiCp= uPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h
new file mode 100644
index 0000000000..5063e6662b
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h
@@ -0,0 +1,24 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rig= hts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef INVALID_TLB_H_
+#define INVALID_TLB_H_
+
+/**
+  Invalid corresponding TLB entries are based on the address given +
+  @param Address The address corresponding to the invalid page table = entry
+
+  @retval  none
+**/
+VOID
+InvalidTlb (
+  UINTN  Address
+  );
+
+#endif // INVALID_TLB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 2eebd45125..e92ceb6466 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -211,5 +211,8 @@ [Components.RISCV64]
   UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
   UefiCpuPkg/CpuMmio2Dxe/CpuMmio2Dxe.inf
 
+[Components.LOONGARCH64]
+  UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
+
 [BuildOptions]
   *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.27.0

_._,_._,_

Groups.io Links:

=20 You receive all messages sent to this group. =20 =20

View/Reply Online (#117741) | =20 | Mute= This Topic | New Topic
Your Subscriptio= n | Contact Group Owner | Unsubscribe [rebecca@openfw.io]

_._,_._,_
--_000_MN6PR11MB82442ADA15DB9FA5F526851A8C092MN6PR11MB8244namp_--