// 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 (!IsTableEntry (*Entry, Level)) {\r
InvalidateDataCacheRange (TranslationTable, EFI_PAGE_SIZE);\r
}\r
\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
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
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