* [Patch V7 00/22] Fix issues in CpuPageTableLib
@ 2023-03-27 2:48 duntan
2023-03-27 2:48 ` [Patch V7 20/22] UefiCpuPkg/CpuPageTableLib: Enable PAE paging duntan
2023-03-27 2:48 ` [Patch V7 21/22] UefiCpuPkg/CpuPageTableLib: Add RandomTest for " duntan
0 siblings, 2 replies; 3+ messages in thread
From: duntan @ 2023-03-27 2:48 UTC (permalink / raw)
To: devel
In the V7 atch set
In 'Add RandomTest for PAE paging', modify duplicated test case name from 'Random Test Case1' to 'Random Test Case5'.
In 'Enable PAE paging', modify the copy-right year of UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h.
Other patches are Reviewed-by Ray.
Dun Tan (20):
UefiCpuPkg/CpuPageTableLib: Remove unneeded 'if' condition
UefiCpuPkg/CpuPageTableLib: Add check for input Length
UefiCpuPkg/CpuPageTableLib:Initialize some LocalVariable at beginning
UefiCpuPkg/CpuPageTableLib: Fix the non-1:1 mapping issue
UefiCpuPkg/CpuPageTableLib:Clear PageSize bit(Bit7) for non-leaf
UefiCpuPkg/CpuPageTableLib: Fix issue when splitting leaf entry
UefiCpuPkg/MpInitLib: Add code to initialize MapMask
UefiCpuPkg/CpuPageTableLib:Add check for Mask and Attr
UefiCpuPkg/CpuPageTableLib: Add manual test to check Mask and Attr
UefiCpuPkg/CpuPageTableLib:Modify RandomBoolean() in RandomTest
UefiCpuPkg/CpuPageTableLib: Add LastMapEntry pointer
UefiCpuPkg/CpuPageTableLib:Modify RandomTest to check Mask/Attr
UefiCpuPkg/CpuPageTableLib: Enable non-1:1 mapping in random test
UefiCpuPkg/CpuPageTableLib: Add OUTPUT IsModified parameter.
UefiCpuPkg/CpuPageTableLib: Modify RandomTest to check IsModified
UefiCpuPkg/CpuPageTableLib: Add check for page table creation
UefiCpuPkg: Combine branch for non-present and leaf ParentEntry
UefiCpuPkg/CpuPageTableLib: Enable PAE paging
UefiCpuPkg/CpuPageTableLib: Add RandomTest for PAE paging
UefiCpuPkg/CpuPageTableLib: Reduce the number of random tests
Zhiguang Liu (2):
UefiCpuPkg: Fix IA32 build failure in CpuPageTableLib.inf
UefiCpuPkg: Modify UnitTest code since tested API is changed
UefiCpuPkg/Include/Library/CpuPageTableLib.h | 44 +++++++++++++++++++++++++-------------------
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c | 27 ++++++++++++++++++++++-----
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------------------------------------------------------------------------------
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c | 22 +++++++++++++++-------
UefiCpuPkg/Library/MpInitLib/X64/CreatePageTable.c | 11 +++++------
8 files changed, 784 insertions(+), 329 deletions(-)
--
2.31.1.windows.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [Patch V7 20/22] UefiCpuPkg/CpuPageTableLib: Enable PAE paging
2023-03-27 2:48 [Patch V7 00/22] Fix issues in CpuPageTableLib duntan
@ 2023-03-27 2:48 ` duntan
2023-03-27 2:48 ` [Patch V7 21/22] UefiCpuPkg/CpuPageTableLib: Add RandomTest for " duntan
1 sibling, 0 replies; 3+ messages in thread
From: duntan @ 2023-03-27 2:48 UTC (permalink / raw)
To: devel; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
Modify CpuPageTableLib code to enable PAE paging.
In PageTableMap() API:
When creating new PAE page table, after creating page table,
set all MustBeZero fields of 4 PDPTE to 0. The MustBeZero
fields are treated as RW and other attributes by the common
map logic. So they might be set to 1.
When updating exsiting PAE page table, the special steps are:
1.Prepare 4K-aligned 32bytes memory in stack for 4 temp PDPTE.
2.Copy original 4 PDPTE to the 4 temp PDPTE and set the RW,
UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0.
4.After updating the page table, set the MustBeZero fields of
4 temp PDPTE to 0.
5.Copy the temp PDPTE to original PDPTE.
In PageTableParse() API, also create 4 temp PDPTE in stack.
Copy original 4 PDPTE to the 4 temp PDPTE. Then set the RW,
UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0. Finally
use the address of temp PDPTE as the page table address.
Signed-off-by: Dun Tan <dun.tan@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h | 4 +++-
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-----
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c | 27 ++++++++++++++++++++++-----
3 files changed, 73 insertions(+), 11 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h
index 2c67ecb469..24da0ffb30 100644
--- a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h
+++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h
@@ -1,7 +1,7 @@
/** @file
Internal header for CpuPageTableLib.
- Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -20,6 +20,8 @@
#define REGION_LENGTH(l) LShiftU64 (1, (l) * 9 + 3)
+#define MAX_PAE_PDPTE_NUM 4
+
typedef enum {
Pte = 1,
Pde = 2,
diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c
index 0d576ce39a..eff02619fa 100644
--- a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c
+++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c
@@ -671,15 +671,17 @@ PageTableMap (
IA32_PAGE_LEVEL MaxLeafLevel;
IA32_MAP_ATTRIBUTE ParentAttribute;
BOOLEAN LocalIsModified;
+ UINTN Index;
+ IA32_PAGING_ENTRY *PagingEntry;
+ UINT8 BufferInStack[SIZE_4KB - 1 + MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY)];
if (Length == 0) {
return RETURN_SUCCESS;
}
- if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
+ if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
//
// 32bit paging is never supported.
- // PAE paging will be supported later.
//
return RETURN_UNSUPPORTED;
}
@@ -716,17 +718,32 @@ PageTableMap (
MaxLeafLevel = (IA32_PAGE_LEVEL)(UINT8)PagingMode;
MaxLevel = (IA32_PAGE_LEVEL)(UINT8)(PagingMode >> 8);
- MaxLinearAddress = LShiftU64 (1, 12 + MaxLevel * 9);
+ MaxLinearAddress = (PagingMode == PagingPae) ? LShiftU64 (1, 32) : LShiftU64 (1, 12 + MaxLevel * 9);
if ((LinearAddress > MaxLinearAddress) || (Length > MaxLinearAddress - LinearAddress)) {
//
- // Maximum linear address is (1 << 48) or (1 << 57)
+ // Maximum linear address is (1 << 32), (1 << 48) or (1 << 57)
//
return RETURN_INVALID_PARAMETER;
}
TopPagingEntry.Uintn = *PageTable;
if (TopPagingEntry.Uintn != 0) {
+ if (PagingMode == PagingPae) {
+ //
+ // Create 4 temporary PDPTE at a 4k-aligned address.
+ // Copy the original PDPTE content and set ReadWrite, UserSupervisor to 1, set Nx to 0.
+ //
+ TopPagingEntry.Uintn = ALIGN_VALUE ((UINTN)BufferInStack, BASE_4KB);
+ PagingEntry = (IA32_PAGING_ENTRY *)(TopPagingEntry.Uintn);
+ CopyMem (PagingEntry, (VOID *)(*PageTable), MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY));
+ for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {
+ PagingEntry[Index].Pnle.Bits.ReadWrite = 1;
+ PagingEntry[Index].Pnle.Bits.UserSupervisor = 1;
+ PagingEntry[Index].Pnle.Bits.Nx = 0;
+ }
+ }
+
TopPagingEntry.Pce.Present = 1;
TopPagingEntry.Pce.ReadWrite = 1;
TopPagingEntry.Pce.UserSupervisor = 1;
@@ -801,7 +818,33 @@ PageTableMap (
);
if (!RETURN_ERROR (Status)) {
- *PageTable = (UINTN)(TopPagingEntry.Uintn & IA32_PE_BASE_ADDRESS_MASK_40);
+ PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)(TopPagingEntry.Uintn & IA32_PE_BASE_ADDRESS_MASK_40);
+
+ if (PagingMode == PagingPae) {
+ //
+ // These MustBeZero fields are treated as RW and other attributes by the common map logic. So they might be set to 1.
+ //
+ for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {
+ PagingEntry[Index].PdptePae.Bits.MustBeZero = 0;
+ PagingEntry[Index].PdptePae.Bits.MustBeZero2 = 0;
+ PagingEntry[Index].PdptePae.Bits.MustBeZero3 = 0;
+ }
+
+ if (*PageTable != 0) {
+ //
+ // Copy temp PDPTE to original PDPTE.
+ //
+ CopyMem ((VOID *)(*PageTable), PagingEntry, MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY));
+ }
+ }
+
+ if (*PageTable == 0) {
+ //
+ // Do not assign the *PageTable when it's an existing page table.
+ // If it's an existing PAE page table, PagingEntry is the temp buffer in stack.
+ //
+ *PageTable = (UINTN)PagingEntry;
+ }
}
return Status;
diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c
index 65490751ab..37466e4e10 100644
--- a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c
+++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c
@@ -1,7 +1,7 @@
/** @file
This library implements CpuPageTableLib that are generic for IA32 family CPU.
- Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -158,6 +158,7 @@ VOID
PageTableLibParsePnle (
IN UINT64 PageTableBaseAddress,
IN UINTN Level,
+ IN UINTN MaxLevel,
IN UINT64 RegionStart,
IN IA32_MAP_ATTRIBUTE *ParentMapAttribute,
IN OUT IA32_MAP_ENTRY *Map,
@@ -171,13 +172,15 @@ PageTableLibParsePnle (
UINTN Index;
IA32_MAP_ATTRIBUTE MapAttribute;
UINT64 RegionLength;
+ UINTN PagingEntryNumber;
ASSERT (OneEntry != NULL);
- PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;
- RegionLength = REGION_LENGTH (Level);
+ PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;
+ RegionLength = REGION_LENGTH (Level);
+ PagingEntryNumber = ((MaxLevel == 3) && (Level == 3)) ? MAX_PAE_PDPTE_NUM : 512;
- for (Index = 0; Index < 512; Index++, RegionStart += RegionLength) {
+ for (Index = 0; Index < PagingEntryNumber; Index++, RegionStart += RegionLength) {
if (PagingEntry[Index].Pce.Present == 0) {
continue;
}
@@ -228,6 +231,7 @@ PageTableLibParsePnle (
PageTableLibParsePnle (
IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle),
Level - 1,
+ MaxLevel,
RegionStart,
&MapAttribute,
Map,
@@ -269,6 +273,8 @@ PageTableParse (
IA32_MAP_ENTRY *LastEntry;
IA32_MAP_ENTRY OneEntry;
UINTN MaxLevel;
+ UINTN Index;
+ IA32_PAGING_ENTRY BufferInStack[MAX_PAE_PDPTE_NUM];
if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
//
@@ -290,6 +296,17 @@ PageTableParse (
return RETURN_SUCCESS;
}
+ if (PagingMode == PagingPae) {
+ CopyMem (BufferInStack, (VOID *)PageTable, sizeof (BufferInStack));
+ for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {
+ BufferInStack[Index].Pnle.Bits.ReadWrite = 1;
+ BufferInStack[Index].Pnle.Bits.UserSupervisor = 1;
+ BufferInStack[Index].Pnle.Bits.Nx = 0;
+ }
+
+ PageTable = (UINTN)BufferInStack;
+ }
+
//
// Page table layout is as below:
//
@@ -319,7 +336,7 @@ PageTableParse (
MapCapacity = *MapCount;
*MapCount = 0;
LastEntry = NULL;
- PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, 0, &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry);
+ PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, MaxLevel, 0, &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry);
if (*MapCount > MapCapacity) {
return RETURN_BUFFER_TOO_SMALL;
--
2.31.1.windows.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [Patch V7 21/22] UefiCpuPkg/CpuPageTableLib: Add RandomTest for PAE paging
2023-03-27 2:48 [Patch V7 00/22] Fix issues in CpuPageTableLib duntan
2023-03-27 2:48 ` [Patch V7 20/22] UefiCpuPkg/CpuPageTableLib: Enable PAE paging duntan
@ 2023-03-27 2:48 ` duntan
1 sibling, 0 replies; 3+ messages in thread
From: duntan @ 2023-03-27 2:48 UTC (permalink / raw)
To: devel; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
Add RandomTest for PAE paging.
Signed-off-by: Dun Tan <dun.tan@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.c | 2 ++
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c | 3 +--
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c | 12 ++++++++----
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.c b/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.c
index 4303095579..b0be2c5a73 100644
--- a/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.c
+++ b/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.c
@@ -13,6 +13,7 @@ static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging4Level = { P
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging4Level1GB = { Paging4Level1GB, 100, 20, USE_RANDOM_ARRAY };
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging5Level = { Paging5Level, 100, 20, USE_RANDOM_ARRAY };
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging5Level1GB = { Paging5Level1GB, 100, 20, USE_RANDOM_ARRAY };
+static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPagingPae = { PagingPae, 100, 20, USE_RANDOM_ARRAY };
/**
Check if the input parameters are not supported.
@@ -884,6 +885,7 @@ UefiTestMain (
AddTestCase (RandomTestCase, "Random Test for Paging4Level1G", "Random Test Case2", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging4Level1GB);
AddTestCase (RandomTestCase, "Random Test for Paging5Level", "Random Test Case3", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging5Level);
AddTestCase (RandomTestCase, "Random Test for Paging5Level1G", "Random Test Case4", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging5Level1GB);
+ AddTestCase (RandomTestCase, "Random Test for PagingPae", "Random Test Case5", TestCaseforRandomTest, NULL, NULL, &mTestContextPagingPae);
//
// Execute the tests.
diff --git a/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c b/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c
index 2db49f7de7..f7a77d00e7 100644
--- a/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c
+++ b/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/RandomTest.c
@@ -258,10 +258,9 @@ ValidateAndRandomeModifyPageTable (
UNIT_TEST_STATUS Status;
IA32_PAGING_ENTRY *PagingEntry;
- if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
+ if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
//
// 32bit paging is never supported.
- // PAE paging will be supported later.
//
return UNIT_TEST_ERROR_TEST_FAILED;
}
diff --git a/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c b/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c
index 22f179c21f..67776255c2 100644
--- a/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c
+++ b/UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c
@@ -175,10 +175,9 @@ IsPageTableValid (
return UNIT_TEST_PASSED;
}
- if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
+ if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
//
// 32bit paging is never supported.
- // PAE paging will be supported later.
//
return UNIT_TEST_ERROR_TEST_FAILED;
}
@@ -187,7 +186,12 @@ IsPageTableValid (
MaxLevel = (UINT8)(PagingMode >> 8);
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable;
- for (Index = 0; Index < 512; Index++) {
+ for (Index = 0; Index < ((PagingMode == PagingPae) ? 4 : 512); Index++) {
+ if (PagingMode == PagingPae) {
+ UT_ASSERT_EQUAL (PagingEntry[Index].PdptePae.Bits.MustBeZero, 0);
+ UT_ASSERT_EQUAL (PagingEntry[Index].PdptePae.Bits.MustBeZero2, 0);
+ }
+
Status = IsPageTableEntryValid (&PagingEntry[Index], MaxLevel, MaxLeafLevel, Index << (9 * MaxLevel + 3));
if (Status != UNIT_TEST_PASSED) {
return Status;
@@ -264,7 +268,7 @@ GetEntryFromPageTable (
UINT64 Index;
IA32_PAGING_ENTRY *PagingEntry;
- if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
+ if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
//
// 32bit paging is never supported.
// PAE paging will be supported later.
--
2.31.1.windows.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-03-27 2:49 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-27 2:48 [Patch V7 00/22] Fix issues in CpuPageTableLib duntan
2023-03-27 2:48 ` [Patch V7 20/22] UefiCpuPkg/CpuPageTableLib: Enable PAE paging duntan
2023-03-27 2:48 ` [Patch V7 21/22] UefiCpuPkg/CpuPageTableLib: Add RandomTest for " duntan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox