]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/TdxLib/AcceptPages.c
MdePkg: Add TdxLib to wrap Tdx operations
[mirror_edk2.git] / MdePkg / Library / TdxLib / AcceptPages.c
CommitLineData
c3001cb7
MX
1/** @file\r
2\r
3 Unaccepted memory is a special type of private memory. In Td guest\r
4 TDCALL [TDG.MEM.PAGE.ACCEPT] is invoked to accept the unaccepted\r
5 memory before use it.\r
6\r
7 Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include <Library/BaseLib.h>\r
13#include <Library/DebugLib.h>\r
14#include <IndustryStandard/Tdx.h>\r
15#include <Uefi/UefiBaseType.h>\r
16#include <Library/TdxLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18\r
19UINT64 mNumberOfDuplicatedAcceptedPages;\r
20\r
21#define TDX_ACCEPTPAGE_MAX_RETRIED 3\r
22\r
23// PageSize is mapped to PageLevel like below:\r
24// 4KB - 0, 2MB - 1\r
25UINT32 mTdxAcceptPageLevelMap[2] = {\r
26 SIZE_4KB,\r
27 SIZE_2MB\r
28};\r
29\r
30#define INVALID_ACCEPT_PAGELEVEL ARRAY_SIZE(mTdxAcceptPageLevelMap)\r
31\r
32/**\r
33 This function gets the PageLevel according to the input page size.\r
34\r
35 @param[in] PageSize Page size\r
36\r
37 @return UINT32 The mapped page level\r
38**/\r
39UINT32\r
40GetGpaPageLevel (\r
41 UINT32 PageSize\r
42 )\r
43{\r
44 UINT32 Index;\r
45\r
46 for (Index = 0; Index < ARRAY_SIZE (mTdxAcceptPageLevelMap); Index++) {\r
47 if (mTdxAcceptPageLevelMap[Index] == PageSize) {\r
48 break;\r
49 }\r
50 }\r
51\r
52 return Index;\r
53}\r
54\r
55/**\r
56 This function accept a pending private page, and initialize the page to\r
57 all-0 using the TD ephemeral private key.\r
58\r
59 Sometimes TDCALL [TDG.MEM.PAGE.ACCEPT] may return\r
60 TDX_EXIT_REASON_PAGE_SIZE_MISMATCH. It indicates the input PageLevel is\r
61 not workable. In this case we need to try to fallback to a smaller\r
62 PageLevel if possible.\r
63\r
64 @param[in] StartAddress Guest physical address of the private\r
65 page to accept. [63:52] and [11:0] must be 0.\r
66 @param[in] NumberOfPages Number of the pages to be accepted.\r
67 @param[in] PageSize GPA page size. Only accept 2M/4K size.\r
68\r
69 @return EFI_SUCCESS Accept successfully\r
70 @return others Indicate other errors\r
71**/\r
72EFI_STATUS\r
73EFIAPI\r
74TdAcceptPages (\r
75 IN UINT64 StartAddress,\r
76 IN UINT64 NumberOfPages,\r
77 IN UINT32 PageSize\r
78 )\r
79{\r
80 EFI_STATUS Status;\r
81 UINT64 Address;\r
82 UINT64 TdxStatus;\r
83 UINT64 Index;\r
84 UINT32 GpaPageLevel;\r
85 UINT32 PageSize2;\r
86 UINTN Retried;\r
87\r
88 Retried = 0;\r
89\r
90 if ((StartAddress & ~0xFFFFFFFFFF000ULL) != 0) {\r
91 ASSERT (FALSE);\r
92 DEBUG ((DEBUG_ERROR, "Accept page address(0x%llx) is not valid. [63:52] and [11:0] must be 0\n", StartAddress));\r
93 return EFI_INVALID_PARAMETER;\r
94 }\r
95\r
96 Address = StartAddress;\r
97\r
98 GpaPageLevel = GetGpaPageLevel (PageSize);\r
99 if (GpaPageLevel == INVALID_ACCEPT_PAGELEVEL) {\r
100 ASSERT (FALSE);\r
101 DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M. Invalid page size - 0x%llx\n", PageSize));\r
102 return EFI_INVALID_PARAMETER;\r
103 }\r
104\r
105 Status = EFI_SUCCESS;\r
106 for (Index = 0; Index < NumberOfPages; Index++) {\r
107 Retried = 0;\r
108\r
109DoAcceptPage:\r
110 TdxStatus = TdCall (TDCALL_TDACCEPTPAGE, Address | GpaPageLevel, 0, 0, 0);\r
111 if (TdxStatus != TDX_EXIT_REASON_SUCCESS) {\r
112 if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED) {\r
113 //\r
114 // Already accepted\r
115 //\r
116 mNumberOfDuplicatedAcceptedPages++;\r
117 DEBUG ((DEBUG_WARN, "Page at Address (0x%llx) has already been accepted. - %d\n", Address, mNumberOfDuplicatedAcceptedPages));\r
118 } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_SIZE_MISMATCH) {\r
119 //\r
120 // GpaPageLevel is mismatch, fall back to a smaller GpaPageLevel if possible\r
121 //\r
122 DEBUG ((DEBUG_VERBOSE, "Address %llx cannot be accepted in PageLevel of %d\n", Address, GpaPageLevel));\r
123\r
124 if (GpaPageLevel == 0) {\r
125 //\r
126 // Cannot fall back to smaller page level\r
127 //\r
128 DEBUG ((DEBUG_ERROR, "AcceptPage cannot fallback from PageLevel %d\n", GpaPageLevel));\r
129 Status = EFI_INVALID_PARAMETER;\r
130 break;\r
131 } else {\r
132 //\r
133 // Fall back to a smaller page size\r
134 //\r
135 PageSize2 = mTdxAcceptPageLevelMap[GpaPageLevel - 1];\r
136 Status = TdAcceptPages (Address, 512, PageSize2);\r
137 if (EFI_ERROR (Status)) {\r
138 break;\r
139 }\r
140 }\r
141 } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_OPERAND_BUSY) {\r
142 //\r
143 // Concurrent TDG.MEM.PAGE.ACCEPT is using the same Secure EPT entry\r
144 // So try it again. There is a max retried count. If Retried exceeds the max count,\r
145 // report the error and quit.\r
146 //\r
147 Retried += 1;\r
148 if (Retried > TDX_ACCEPTPAGE_MAX_RETRIED) {\r
149 DEBUG ((\r
150 DEBUG_ERROR,\r
151 "Address %llx (%d) failed to be accepted because of OPERAND_BUSY. Retried %d time.\n",\r
152 Address,\r
153 Index,\r
154 Retried\r
155 ));\r
156 Status = EFI_INVALID_PARAMETER;\r
157 break;\r
158 } else {\r
159 goto DoAcceptPage;\r
160 }\r
161 } else {\r
162 //\r
163 // Other errors\r
164 //\r
165 DEBUG ((\r
166 DEBUG_ERROR,\r
167 "Address %llx (%d) failed to be accepted. Error = 0x%llx\n",\r
168 Address,\r
169 Index,\r
170 TdxStatus\r
171 ));\r
172 Status = EFI_INVALID_PARAMETER;\r
173 break;\r
174 }\r
175 }\r
176\r
177 Address += PageSize;\r
178 }\r
179\r
180 return Status;\r
181}\r