Pnle->Bits.CacheDisabled = 0;\r
}\r
\r
+/**\r
+ Check if the combination for Attribute and Mask is valid for non-present entry.\r
+ 1.Mask.Present is 0 but some other attributes is provided. This case should be invalid.\r
+ 2.Map non-present range to present. In this case, all attributes should be provided.\r
+\r
+ @param[in] Attribute The attribute of the linear address range.\r
+ @param[in] Mask The mask used for attribute to check.\r
+\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 0 but some other attributes are provided.\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 1, Attribute->Bits.Present is 1 but some other attributes are not provided.\r
+ @retval RETURN_SUCCESS The combination for Attribute and Mask is valid.\r
+**/\r
+RETURN_STATUS\r
+IsAttributesAndMaskValidForNonPresentEntry (\r
+ IN IA32_MAP_ATTRIBUTE *Attribute,\r
+ IN IA32_MAP_ATTRIBUTE *Mask\r
+ )\r
+{\r
+ if ((Mask->Bits.Present == 1) && (Attribute->Bits.Present == 1)) {\r
+ //\r
+ // Creating new page table or remapping non-present range to present.\r
+ //\r
+ if ((Mask->Bits.ReadWrite == 0) || (Mask->Bits.UserSupervisor == 0) || (Mask->Bits.WriteThrough == 0) || (Mask->Bits.CacheDisabled == 0) ||\r
+ (Mask->Bits.Accessed == 0) || (Mask->Bits.Dirty == 0) || (Mask->Bits.Pat == 0) || (Mask->Bits.Global == 0) ||\r
+ (Mask->Bits.PageTableBaseAddress == 0) || (Mask->Bits.ProtectionKey == 0) || (Mask->Bits.Nx == 0))\r
+ {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+ } else if ((Mask->Bits.Present == 0) && (Mask->Uint64 > 1)) {\r
+ //\r
+ // Only change other attributes for non-present range is not permitted.\r
+ //\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
/**\r
Update page table to map [LinearAddress, LinearAddress + Length) with specified attribute in the specified level.\r
\r
when a new physical base address is set.\r
@param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.\r
\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 0 but some other attributes are provided.\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 1, Attribute->Bits.Present is 1 but some other attributes are not provided.\r
@retval RETURN_SUCCESS PageTable is created/updated successfully.\r
**/\r
RETURN_STATUS\r
UINTN Index;\r
IA32_PAGING_ENTRY *PagingEntry;\r
UINTN PagingEntryIndex;\r
+ UINTN PagingEntryIndexEnd;\r
IA32_PAGING_ENTRY *CurrentPagingEntry;\r
UINT64 RegionLength;\r
UINT64 SubLength;\r
//\r
\r
if (ParentPagingEntry->Pce.Present == 0) {\r
+ //\r
+ // [LinearAddress, LinearAddress + Length] contains non-present range.\r
+ //\r
+ Status = IsAttributesAndMaskValidForNonPresentEntry (Attribute, Mask);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
//\r
// The parent entry is CR3 or PML5E/PML4E/PDPTE/PDE.\r
// It does NOT point to an existing page directory.\r
ParentPagingEntry->Uint64 = ((UINTN)(VOID *)PagingEntry) | (ParentPagingEntry->Uint64 & (~IA32_PE_BASE_ADDRESS_MASK_40));\r
}\r
} else {\r
+ //\r
+ // If (LinearAddress + Length - 1) is not in the same ParentPagingEntry with (LinearAddress + Offset), then the remaining child PagingEntry\r
+ // starting from PagingEntryIndex of ParentPagingEntry is all covered by [LinearAddress + Offset, LinearAddress + Length - 1].\r
+ //\r
+ PagingEntryIndexEnd = (BitFieldRead64 (LinearAddress + Length - 1, BitStart + 9, 63) != BitFieldRead64 (LinearAddress + Offset, BitStart + 9, 63)) ? 511 :\r
+ (UINTN)BitFieldRead64 (LinearAddress + Length - 1, BitStart, BitStart + 9 - 1);\r
+ PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);\r
+ for (Index = PagingEntryIndex; Index <= PagingEntryIndexEnd; Index++) {\r
+ if (PagingEntry[Index].Pce.Present == 0) {\r
+ //\r
+ // [LinearAddress, LinearAddress + Length] contains non-present range.\r
+ //\r
+ Status = IsAttributesAndMaskValidForNonPresentEntry (Attribute, Mask);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
//\r
// It's a non-leaf entry\r
//\r
// Update child entries to use restrictive attribute inherited from parent.\r
// e.g.: Set PDE[0-255].ReadWrite = 0\r
//\r
- PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);\r
for (Index = 0; Index < 512; Index++) {\r
if (PagingEntry[Index].Pce.Present == 0) {\r
continue;\r
\r
@retval RETURN_UNSUPPORTED PagingMode is not supported.\r
@retval RETURN_INVALID_PARAMETER PageTable, BufferSize, Attribute or Mask is NULL.\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 0 but some other attributes are provided.\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 1, Attribute->Bits.Present is 1 but some other attributes are not provided.\r
+ @retval RETURN_INVALID_PARAMETER For non-present range, Mask->Bits.Present is 1, Attribute->Bits.Present is 0 but some other attributes are provided.\r
+ @retval RETURN_INVALID_PARAMETER For present range, Mask->Bits.Present is 1, Attribute->Bits.Present is 0 but some other attributes are provided.\r
@retval RETURN_INVALID_PARAMETER *BufferSize is not multiple of 4KB.\r
@retval RETURN_BUFFER_TOO_SMALL The buffer is too small for page table creation/updating.\r
BufferSize is updated to indicate the expected buffer size.\r
return RETURN_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // If to map [LinearAddress, LinearAddress + Length] as non-present,\r
+ // all attributes except Present should not be provided.\r
+ //\r
+ if ((Attribute->Bits.Present == 0) && (Mask->Bits.Present == 1) && (Mask->Uint64 > 1)) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
MaxLeafLevel = (IA32_PAGE_LEVEL)(UINT8)PagingMode;\r
MaxLevel = (IA32_PAGE_LEVEL)(UINT8)(PagingMode >> 8);\r
MaxLinearAddress = LShiftU64 (1, 12 + MaxLevel * 9);\r