}\r
}\r
\r
-UINT64\r
-PageAttributeToGcdAttribute (\r
- IN UINT64 PageAttributes\r
- )\r
-{\r
- UINT64 GcdAttributes;\r
-\r
- switch (PageAttributes & TT_ATTR_INDX_MASK) {\r
- case TT_ATTR_INDX_DEVICE_MEMORY:\r
- GcdAttributes = EFI_MEMORY_UC;\r
- break;\r
- case TT_ATTR_INDX_MEMORY_NON_CACHEABLE:\r
- GcdAttributes = EFI_MEMORY_WC;\r
- break;\r
- case TT_ATTR_INDX_MEMORY_WRITE_THROUGH:\r
- GcdAttributes = EFI_MEMORY_WT;\r
- break;\r
- case TT_ATTR_INDX_MEMORY_WRITE_BACK:\r
- GcdAttributes = EFI_MEMORY_WB;\r
- break;\r
- default:\r
- DEBUG ((DEBUG_ERROR,\r
- "PageAttributeToGcdAttribute: PageAttributes:0x%lX not supported.\n",\r
- PageAttributes));\r
- ASSERT (0);\r
- // The Global Coherency Domain (GCD) value is defined as a bit set.\r
- // Returning 0 means no attribute has been set.\r
- GcdAttributes = 0;\r
- }\r
-\r
- // Determine protection attributes\r
- if (((PageAttributes & TT_AP_MASK) == TT_AP_NO_RO) ||\r
- ((PageAttributes & TT_AP_MASK) == TT_AP_RO_RO)) {\r
- // Read only cases map to write-protect\r
- GcdAttributes |= EFI_MEMORY_RO;\r
- }\r
-\r
- // Process eXecute Never attribute\r
- if ((PageAttributes & (TT_PXN_MASK | TT_UXN_MASK)) != 0) {\r
- GcdAttributes |= EFI_MEMORY_XP;\r
- }\r
-\r
- return GcdAttributes;\r
-}\r
-\r
#define MIN_T0SZ 16\r
#define BITS_PER_LEVEL 9\r
\r
FreePages (TranslationTable, 1);\r
}\r
\r
+STATIC\r
+BOOLEAN\r
+IsBlockEntry (\r
+ IN UINT64 Entry,\r
+ IN UINTN Level\r
+ )\r
+{\r
+ if (Level == 3) {\r
+ return (Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3;\r
+ }\r
+ return (Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY;\r
+}\r
+\r
+STATIC\r
+BOOLEAN\r
+IsTableEntry (\r
+ IN UINT64 Entry,\r
+ IN UINTN Level\r
+ )\r
+{\r
+ if (Level == 3) {\r
+ //\r
+ // TT_TYPE_TABLE_ENTRY aliases TT_TYPE_BLOCK_ENTRY_LEVEL3\r
+ // so we need to take the level into account as well.\r
+ //\r
+ return FALSE;\r
+ }\r
+ return (Entry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY;\r
+}\r
+\r
STATIC\r
EFI_STATUS\r
UpdateRegionMappingRecursive (\r
// than a block, and recurse to create the block or page entries at\r
// the next level. No block mappings are allowed at all at level 0,\r
// so in that case, we have to recurse unconditionally.\r
+ // If we are changing a table entry and the AttributeClearMask is non-zero,\r
+ // we cannot replace it with a block entry without potentially losing\r
+ // attribute information, so keep the table entry in that case.\r
//\r
- if (Level == 0 || ((RegionStart | BlockEnd) & BlockMask) != 0) {\r
+ if (Level == 0 || ((RegionStart | BlockEnd) & BlockMask) != 0 ||\r
+ (IsTableEntry (*Entry, Level) && AttributeClearMask != 0)) {\r
ASSERT (Level < 3);\r
\r
- if ((*Entry & TT_TYPE_MASK) != TT_TYPE_TABLE_ENTRY) {\r
+ if (!IsTableEntry (*Entry, Level)) {\r
//\r
// No table entry exists yet, so we need to allocate a page table\r
// for the next level.\r
InvalidateDataCacheRange (TranslationTable, EFI_PAGE_SIZE);\r
}\r
\r
- if ((*Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) {\r
+ ZeroMem (TranslationTable, EFI_PAGE_SIZE);\r
+\r
+ if (IsBlockEntry (*Entry, Level)) {\r
//\r
// We are splitting an existing block entry, so we have to populate\r
// the new table with the attributes of the block entry it replaces.\r
FreePages (TranslationTable, 1);\r
return Status;\r
}\r
- } else {\r
- ZeroMem (TranslationTable, EFI_PAGE_SIZE);\r
}\r
} else {\r
TranslationTable = (VOID *)(UINTN)(*Entry & TT_ADDRESS_MASK_BLOCK_ENTRY);\r
AttributeSetMask, AttributeClearMask, TranslationTable,\r
Level + 1);\r
if (EFI_ERROR (Status)) {\r
- if ((*Entry & TT_TYPE_MASK) != TT_TYPE_TABLE_ENTRY) {\r
+ if (!IsTableEntry (*Entry, Level)) {\r
//\r
// We are creating a new table entry, so on failure, we can free all\r
// allocations we made recursively, given that the whole subhierarchy\r
return Status;\r
}\r
\r
- if ((*Entry & TT_TYPE_MASK) != TT_TYPE_TABLE_ENTRY) {\r
+ if (!IsTableEntry (*Entry, Level)) {\r
EntryValue = (UINTN)TranslationTable | TT_TYPE_TABLE_ENTRY;\r
ReplaceTableEntry (Entry, EntryValue, RegionStart,\r
- (*Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY);\r
+ IsBlockEntry (*Entry, Level));\r
}\r
} else {\r
EntryValue = (*Entry & AttributeClearMask) | AttributeSetMask;\r
EntryValue |= (Level == 3) ? TT_TYPE_BLOCK_ENTRY_LEVEL3\r
: TT_TYPE_BLOCK_ENTRY;\r
\r
- ReplaceTableEntry (Entry, EntryValue, RegionStart, FALSE);\r
+ if (IsTableEntry (*Entry, Level)) {\r
+ //\r
+ // We are replacing a table entry with a block entry. This is only\r
+ // possible if we are keeping none of the original attributes.\r
+ // We can free the table entry's page table, and all the ones below\r
+ // it, since we are dropping the only possible reference to it.\r
+ //\r
+ ASSERT (AttributeClearMask == 0);\r
+ TranslationTable = (VOID *)(UINTN)(*Entry & TT_ADDRESS_MASK_BLOCK_ENTRY);\r
+ ReplaceTableEntry (Entry, EntryValue, RegionStart, TRUE);\r
+ FreePageTablesRecursive (TranslationTable, Level + 1);\r
+ } else {\r
+ ReplaceTableEntry (Entry, EntryValue, RegionStart, FALSE);\r
+ }\r
}\r
}\r
return EFI_SUCCESS;\r