Skip to content

Commit efaa102

Browse files
CrystalLee-77mergify[bot]
authored andcommitted
UefiCpuPkg: Produce EFI memory attributes protocol
Produce the protocol introduced in UEFI v2.10 that permits the caller to manage mapping permissions in the page tables. Cc: Felix Polyudov <[email protected]> Cc: David Hsieh <[email protected]> Cc: James Wang <[email protected]> Signed-off-by: Crystal Lee <[email protected]>
1 parent aaf0846 commit efaa102

File tree

4 files changed

+313
-0
lines changed

4 files changed

+313
-0
lines changed

UefiCpuPkg/CpuDxe/CpuDxe.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,11 @@ InitializeCpu (
10331033
);
10341034
ASSERT_EFI_ERROR (Status);
10351035

1036+
//
1037+
// Install EFI memory attribute Protocol
1038+
//
1039+
InstallEfiMemoryAttributeProtocol (mCpuHandle);
1040+
10361041
//
10371042
// Refresh GCD memory space map according to MTRR value.
10381043
//

UefiCpuPkg/CpuDxe/CpuDxe.inf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575

7676
[Protocols]
7777
gEfiCpuArchProtocolGuid ## PRODUCES
78+
gEfiMemoryAttributeProtocolGuid ## PRODUCES
7879
gEfiMpServiceProtocolGuid ## PRODUCES
7980
gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
8081

UefiCpuPkg/CpuDxe/CpuPageTable.c

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,3 +1437,298 @@ InitializePageTableLib (
14371437

14381438
return;
14391439
}
1440+
1441+
/**
1442+
This function set given attributes of the memory region specified by
1443+
BaseAddress and Length.
1444+
The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
1445+
1446+
@param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
1447+
@param BaseAddress The physical address that is the start address of
1448+
a memory region.
1449+
@param Length The size in bytes of the memory region.
1450+
@param Attributes The bit mask of attributes to set for the memory
1451+
region.
1452+
1453+
@retval EFI_SUCCESS The attributes were set for the memory region.
1454+
@retval EFI_INVALID_PARAMETER Length is zero.
1455+
Attributes specified an illegal combination of
1456+
attributes that cannot be set together.
1457+
@retval EFI_UNSUPPORTED The processor does not support one or more
1458+
bytes of the memory resource range specified
1459+
by BaseAddress and Length.
1460+
The bit mask of attributes is not supported for
1461+
the memory resource range specified by
1462+
BaseAddress and Length.
1463+
@retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due to lack of
1464+
system resources.
1465+
@retval EFI_ACCESS_DENIED Attributes for the requested memory region are
1466+
controlled by system firmware and cannot be updated
1467+
via the protocol.
1468+
**/
1469+
EFI_STATUS
1470+
EFIAPI
1471+
EfiSetMemoryAttributes (
1472+
IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
1473+
IN EFI_PHYSICAL_ADDRESS BaseAddress,
1474+
IN UINT64 Length,
1475+
IN UINT64 Attributes
1476+
)
1477+
{
1478+
RETURN_STATUS Status;
1479+
BOOLEAN IsModified;
1480+
BOOLEAN IsSplitted;
1481+
1482+
DEBUG ((DEBUG_VERBOSE, "%a: 0x%lx - 0x%lx (0x%lx)\n", __func__, BaseAddress, Length, Attributes));
1483+
1484+
if (Attributes == 0) {
1485+
DEBUG ((DEBUG_ERROR, "%a: Error - Attributes == 0\n", __func__));
1486+
return EFI_INVALID_PARAMETER;
1487+
}
1488+
1489+
if ((Attributes & ~EFI_MEMORY_ACCESS_MASK) != 0) {
1490+
DEBUG ((DEBUG_ERROR, "%a: Error - Attributes(0x%lx) invalid\n", __func__, Attributes));
1491+
return EFI_INVALID_PARAMETER;
1492+
}
1493+
1494+
if (Length == 0) {
1495+
DEBUG ((DEBUG_ERROR, "%a: Length is 0!\n", __func__));
1496+
return RETURN_INVALID_PARAMETER;
1497+
}
1498+
1499+
Status = ConvertMemoryPageAttributes (NULL, BaseAddress, Length, Attributes, PageActionSet, NULL, &IsSplitted, &IsModified);
1500+
if (!EFI_ERROR (Status)) {
1501+
if (IsModified) {
1502+
//
1503+
// Flush TLB as last step.
1504+
//
1505+
// Note: Since APs will always init CR3 register in HLT loop mode or do
1506+
// TLB flush in MWAIT loop mode, there's no need to flush TLB for them
1507+
// here.
1508+
//
1509+
CpuFlushTlb ();
1510+
}
1511+
} else {
1512+
DEBUG ((DEBUG_ERROR, "%a: Failed in ConvertMemoryPageAttributes (%r)\n", __func__, Status));
1513+
}
1514+
1515+
return Status;
1516+
}
1517+
1518+
/**
1519+
This function clears given attributes of the memory region specified by
1520+
BaseAddress and Length.
1521+
The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
1522+
@param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
1523+
@param BaseAddress The physical address that is the start address of
1524+
a memory region.
1525+
@param Length The size in bytes of the memory region.
1526+
@param Attributes The bit mask of attributes to clear for the memory
1527+
region.
1528+
1529+
@retval EFI_SUCCESS The attributes were cleared for the memory region.
1530+
@retval EFI_INVALID_PARAMETER Length is zero.
1531+
Attributes specified an illegal combination of
1532+
attributes that cannot be cleared together.
1533+
@retval EFI_UNSUPPORTED The processor does not support one or more
1534+
bytes of the memory resource range specified
1535+
by BaseAddress and Length.
1536+
The bit mask of attributes is not supported for
1537+
the memory resource range specified by
1538+
BaseAddress and Length.
1539+
@retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due to lack of
1540+
system resources.
1541+
@retval EFI_ACCESS_DENIED Attributes for the requested memory region are
1542+
controlled by system firmware and cannot be updated
1543+
via the protocol.
1544+
**/
1545+
EFI_STATUS
1546+
EFIAPI
1547+
EfiClearMemoryAttributes (
1548+
IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
1549+
IN EFI_PHYSICAL_ADDRESS BaseAddress,
1550+
IN UINT64 Length,
1551+
IN UINT64 Attributes
1552+
)
1553+
{
1554+
RETURN_STATUS Status;
1555+
BOOLEAN IsModified;
1556+
BOOLEAN IsSplitted;
1557+
1558+
DEBUG ((DEBUG_VERBOSE, "%a: 0x%lx - 0x%lx (0x%lx)\n", __func__, BaseAddress, Length, Attributes));
1559+
1560+
if (Attributes == 0) {
1561+
DEBUG ((DEBUG_ERROR, "%a: Error - Attributes == 0\n", __func__));
1562+
return EFI_INVALID_PARAMETER;
1563+
}
1564+
1565+
if ((Attributes & ~EFI_MEMORY_ACCESS_MASK) != 0) {
1566+
DEBUG ((DEBUG_ERROR, "%a: Error - Attributes(0x%lx) invalid\n", __func__, Attributes));
1567+
return EFI_INVALID_PARAMETER;
1568+
}
1569+
1570+
if (Length == 0) {
1571+
DEBUG ((DEBUG_ERROR, "%a: Length is 0!\n", __func__));
1572+
return RETURN_INVALID_PARAMETER;
1573+
}
1574+
1575+
Status = ConvertMemoryPageAttributes (NULL, BaseAddress, Length, Attributes, PageActionClear, NULL, &IsSplitted, &IsModified);
1576+
if (!EFI_ERROR (Status)) {
1577+
if (IsModified) {
1578+
//
1579+
// Flush TLB as last step.
1580+
//
1581+
// Note: Since APs will always init CR3 register in HLT loop mode or do
1582+
// TLB flush in MWAIT loop mode, there's no need to flush TLB for them
1583+
// here.
1584+
//
1585+
CpuFlushTlb ();
1586+
}
1587+
} else {
1588+
DEBUG ((DEBUG_ERROR, "%a: Failed in ConvertMemoryPageAttributes (%r)\n", __func__, Status));
1589+
}
1590+
1591+
return Status;
1592+
}
1593+
1594+
/**
1595+
This function retrieves the attributes of the memory region specified by
1596+
BaseAddress and Length. If different attributes are got from different part
1597+
of the memory region, EFI_NO_MAPPING will be returned.
1598+
1599+
@param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
1600+
@param BaseAddress The physical address that is the start address of
1601+
a memory region.
1602+
@param Length The size in bytes of the memory region.
1603+
@param Attributes Pointer to attributes returned.
1604+
1605+
@retval EFI_SUCCESS The attributes got for the memory region.
1606+
@retval EFI_INVALID_PARAMETER Length is zero.
1607+
Attributes is NULL.
1608+
@retval EFI_NO_MAPPING Attributes are not consistent cross the memory
1609+
region.
1610+
@retval EFI_UNSUPPORTED The processor does not support one or more
1611+
bytes of the memory resource range specified
1612+
by BaseAddress and Length.
1613+
**/
1614+
EFI_STATUS
1615+
EFIAPI
1616+
EfiGetMemoryAttributes (
1617+
IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
1618+
IN EFI_PHYSICAL_ADDRESS BaseAddress,
1619+
IN UINT64 Length,
1620+
OUT UINT64 *Attributes
1621+
)
1622+
{
1623+
PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext;
1624+
EFI_PHYSICAL_ADDRESS Address;
1625+
UINT64 *PageEntry;
1626+
UINT64 MemAttr;
1627+
PAGE_ATTRIBUTE PageAttr;
1628+
INT64 Size;
1629+
UINT64 AddressEncMask;
1630+
1631+
DEBUG ((DEBUG_VERBOSE, "%a: 0x%lx - 0x%lx\n", __func__, BaseAddress, Length));
1632+
1633+
if (!IS_ALIGNED (BaseAddress, EFI_PAGE_SIZE)) {
1634+
DEBUG ((DEBUG_ERROR, "%a: BaseAddress(0x%lx) is not aligned!\n", __func__, BaseAddress));
1635+
return EFI_UNSUPPORTED;
1636+
}
1637+
1638+
if (!IS_ALIGNED (Length, EFI_PAGE_SIZE)) {
1639+
DEBUG ((DEBUG_ERROR, "%a: Length(0x%lx) is not aligned!\n", __func__, Length));
1640+
return EFI_UNSUPPORTED;
1641+
}
1642+
1643+
if (Length == 0) {
1644+
DEBUG ((DEBUG_ERROR, "%a: Length is 0!\n", __func__));
1645+
return RETURN_INVALID_PARAMETER;
1646+
}
1647+
1648+
if (Attributes == NULL) {
1649+
DEBUG ((DEBUG_ERROR, "%a: Attributes is NULL\n", __func__));
1650+
return EFI_INVALID_PARAMETER;
1651+
}
1652+
1653+
Size = (INT64)Length;
1654+
MemAttr = (UINT64)-1;
1655+
1656+
// Make sure AddressEncMask is contained to smallest supported address field.
1657+
//
1658+
AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
1659+
1660+
GetCurrentPagingContext (&CurrentPagingContext);
1661+
1662+
do {
1663+
PageEntry = GetPageTableEntry (&CurrentPagingContext, BaseAddress, &PageAttr);
1664+
if ((PageEntry == NULL) || (PageAttr == PageNone)) {
1665+
return EFI_UNSUPPORTED;
1666+
}
1667+
1668+
//
1669+
// If the memory range is cross page table boundary, make sure they
1670+
// share the same attribute. Return EFI_NO_MAPPING if not.
1671+
//
1672+
*Attributes = GetAttributesFromPageEntry (PageEntry);
1673+
if ((MemAttr != (UINT64)-1) && (*Attributes != MemAttr)) {
1674+
return EFI_NO_MAPPING;
1675+
}
1676+
1677+
switch (PageAttr) {
1678+
case Page4K:
1679+
Address = *PageEntry & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64;
1680+
Size -= (EFI_PAGE_SIZE - (BaseAddress - Address));
1681+
BaseAddress += (EFI_PAGE_SIZE - (BaseAddress - Address));
1682+
break;
1683+
1684+
case Page2M:
1685+
Address = *PageEntry & ~AddressEncMask & PAGING_2M_ADDRESS_MASK_64;
1686+
Size -= SIZE_2MB - (BaseAddress - Address);
1687+
BaseAddress += SIZE_2MB - (BaseAddress - Address);
1688+
break;
1689+
1690+
case Page1G:
1691+
Address = *PageEntry & ~AddressEncMask & PAGING_1G_ADDRESS_MASK_64;
1692+
Size -= SIZE_1GB - (BaseAddress - Address);
1693+
BaseAddress += SIZE_1GB - (BaseAddress - Address);
1694+
break;
1695+
1696+
default:
1697+
return EFI_UNSUPPORTED;
1698+
}
1699+
1700+
MemAttr = *Attributes;
1701+
} while (Size > 0);
1702+
1703+
DEBUG ((DEBUG_VERBOSE, "%a: Attributes is 0x%lx\n", __func__, *Attributes));
1704+
1705+
return EFI_SUCCESS;
1706+
}
1707+
1708+
EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttributeProtocol = {
1709+
EfiGetMemoryAttributes,
1710+
EfiSetMemoryAttributes,
1711+
EfiClearMemoryAttributes,
1712+
};
1713+
1714+
/**
1715+
Install Efi Memory Attribute Protocol.
1716+
1717+
@param Handle A pointer to the EFI_HANDLE on which the interface is to be installed
1718+
1719+
**/
1720+
VOID
1721+
InstallEfiMemoryAttributeProtocol (
1722+
IN EFI_HANDLE Handle
1723+
)
1724+
{
1725+
EFI_STATUS Status;
1726+
1727+
Status = gBS->InstallMultipleProtocolInterfaces (
1728+
&Handle,
1729+
&gEfiMemoryAttributeProtocolGuid,
1730+
&mMemoryAttributeProtocol,
1731+
NULL
1732+
);
1733+
ASSERT_EFI_ERROR (Status);
1734+
}

UefiCpuPkg/CpuDxe/CpuPageTable.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define _PAGE_TABLE_LIB_H_
1111

1212
#include <IndustryStandard/PeImage.h>
13+
#include <Protocol/MemoryAttribute.h>
1314

1415
#define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE BIT0
1516
#define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE BIT1
@@ -153,4 +154,15 @@ GetPagingDetails (
153154
OUT UINT32 **Attributes OPTIONAL
154155
);
155156

157+
/**
158+
Install Efi Memory Attribute Protocol.
159+
160+
@param Handle A pointer to the EFI_HANDLE on which the interface is to be installed
161+
162+
**/
163+
VOID
164+
InstallEfiMemoryAttributeProtocol (
165+
IN EFI_HANDLE Handle
166+
);
167+
156168
#endif

0 commit comments

Comments
 (0)