]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/SmmIoLib/SmmIoLib.c
MdePkg: Apply uncrustify changes
[mirror_edk2.git] / MdePkg / Library / SmmIoLib / SmmIoLib.c
CommitLineData
f9320738
JY
1/** @file\r
2 Instance of SMM IO check library.\r
3\r
4 SMM IO check library library implementation. This library consumes GCD to collect all valid\r
5 IO space defined by a platform.\r
6 A platform may have its own SmmIoLib instance to exclude more IO space.\r
7\r
8 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
9344f092 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
f9320738
JY
10\r
11**/\r
12\r
f9320738
JY
13#include <PiSmm.h>\r
14\r
15#include <Library/BaseLib.h>\r
16#include <Library/BaseMemoryLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/SmmServicesTableLib.h>\r
21#include <Library/HobLib.h>\r
22#include <Library/DxeServicesTableLib.h>\r
23#include <Protocol/SmmReadyToLock.h>\r
24#include <Protocol/SmmEndOfDxe.h>\r
25\r
2f88bd3a
MK
26EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mSmmIoLibGcdMemSpace = NULL;\r
27UINTN mSmmIoLibGcdMemNumberOfDesc = 0;\r
f9320738
JY
28\r
29EFI_PHYSICAL_ADDRESS mSmmIoLibInternalMaximumSupportMemAddress = 0;\r
30\r
2f88bd3a
MK
31VOID *mSmmIoLibRegistrationEndOfDxe;\r
32VOID *mSmmIoLibRegistrationReadyToLock;\r
f9320738 33\r
2f88bd3a 34BOOLEAN mSmmIoLibReadyToLock = FALSE;\r
f9320738
JY
35\r
36/**\r
37 Calculate and save the maximum support address.\r
38\r
39**/\r
40VOID\r
41SmmIoLibInternalCalculateMaximumSupportAddress (\r
42 VOID\r
43 )\r
44{\r
2f88bd3a
MK
45 VOID *Hob;\r
46 UINT32 RegEax;\r
47 UINT8 MemPhysicalAddressBits;\r
f9320738
JY
48\r
49 //\r
50 // Get physical address bits supported.\r
51 //\r
52 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
53 if (Hob != NULL) {\r
2f88bd3a 54 MemPhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;\r
f9320738
JY
55 } else {\r
56 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
57 if (RegEax >= 0x80000008) {\r
58 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
2f88bd3a 59 MemPhysicalAddressBits = (UINT8)RegEax;\r
f9320738
JY
60 } else {\r
61 MemPhysicalAddressBits = 36;\r
62 }\r
63 }\r
2f88bd3a 64\r
f9320738
JY
65 //\r
66 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
67 //\r
68 ASSERT (MemPhysicalAddressBits <= 52);\r
69 if (MemPhysicalAddressBits > 48) {\r
70 MemPhysicalAddressBits = 48;\r
71 }\r
72\r
73 //\r
74 // Save the maximum support address in one global variable\r
75 //\r
76 mSmmIoLibInternalMaximumSupportMemAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, MemPhysicalAddressBits) - 1);\r
77 DEBUG ((DEBUG_INFO, "mSmmIoLibInternalMaximumSupportMemAddress = 0x%lx\n", mSmmIoLibInternalMaximumSupportMemAddress));\r
78}\r
79\r
80/**\r
81 This function check if the MMIO resource is valid per processor architecture and\r
82 valid per platform design.\r
83\r
84 @param BaseAddress The MMIO start address to be checked.\r
85 @param Length The MMIO length to be checked.\r
86 @param Owner A GUID representing the owner of the resource.\r
87 This GUID may be used by producer to correlate the device ownership of the resource.\r
88 NULL means no specific owner.\r
89\r
90 @retval TRUE This MMIO resource is valid per processor architecture and valid per platform design.\r
91 @retval FALSE This MMIO resource is not valid per processor architecture or valid per platform design.\r
92**/\r
93BOOLEAN\r
94EFIAPI\r
95SmmIsMmioValid (\r
96 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
97 IN UINT64 Length,\r
98 IN EFI_GUID *Owner OPTIONAL\r
99 )\r
100{\r
2f88bd3a
MK
101 UINTN Index;\r
102 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;\r
103 BOOLEAN InValidRegion;\r
f9320738
JY
104\r
105 //\r
106 // Check override.\r
107 // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid.\r
108 //\r
109 if ((Length > mSmmIoLibInternalMaximumSupportMemAddress) ||\r
110 (BaseAddress > mSmmIoLibInternalMaximumSupportMemAddress) ||\r
2f88bd3a
MK
111 ((Length != 0) && (BaseAddress > (mSmmIoLibInternalMaximumSupportMemAddress - (Length - 1)))))\r
112 {\r
f9320738
JY
113 //\r
114 // Overflow happen\r
115 //\r
116 DEBUG ((\r
117 DEBUG_ERROR,\r
118 "SmmIsMmioValid: Overflow: BaseAddress (0x%lx) - Length (0x%lx), MaximumSupportMemAddress (0x%lx)\n",\r
119 BaseAddress,\r
120 Length,\r
121 mSmmIoLibInternalMaximumSupportMemAddress\r
122 ));\r
123 return FALSE;\r
124 }\r
125\r
126 //\r
127 // Check override for valid MMIO region\r
128 //\r
129 if (mSmmIoLibReadyToLock) {\r
130 InValidRegion = FALSE;\r
2f88bd3a 131 for (Index = 0; Index < mSmmIoLibGcdMemNumberOfDesc; Index++) {\r
f9320738
JY
132 Desc = &mSmmIoLibGcdMemSpace[Index];\r
133 if ((Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
134 (BaseAddress >= Desc->BaseAddress) &&\r
2f88bd3a
MK
135 ((BaseAddress + Length) <= (Desc->BaseAddress + Desc->Length)))\r
136 {\r
f9320738
JY
137 InValidRegion = TRUE;\r
138 }\r
139 }\r
140\r
141 if (!InValidRegion) {\r
142 DEBUG ((\r
143 DEBUG_ERROR,\r
144 "SmmIsMmioValid: Not in valid MMIO region: BaseAddress (0x%lx) - Length (0x%lx)\n",\r
145 BaseAddress,\r
146 Length\r
147 ));\r
148 return FALSE;\r
149 }\r
150 }\r
2f88bd3a 151\r
f9320738
JY
152 return TRUE;\r
153}\r
154\r
155/**\r
7b5d848d 156 Merge continuous entries whose type is EfiGcdMemoryTypeMemoryMappedIo.\r
f9320738
JY
157\r
158 @param[in, out] GcdMemoryMap A pointer to the buffer in which firmware places\r
159 the current GCD memory map.\r
160 @param[in, out] NumberOfDescriptors A pointer to the number of the\r
161 GcdMemoryMap buffer. On input, this is the number of\r
162 the current GCD memory map. On output,\r
163 it is the number of new GCD memory map after merge.\r
164**/\r
165STATIC\r
166VOID\r
167MergeGcdMmioEntry (\r
168 IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *GcdMemoryMap,\r
169 IN OUT UINTN *NumberOfDescriptors\r
170 )\r
171{\r
2f88bd3a
MK
172 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *GcdMemoryMapEntry;\r
173 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *GcdMemoryMapEnd;\r
174 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *NewGcdMemoryMapEntry;\r
175 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *NextGcdMemoryMapEntry;\r
f9320738 176\r
2f88bd3a 177 GcdMemoryMapEntry = GcdMemoryMap;\r
f9320738 178 NewGcdMemoryMapEntry = GcdMemoryMap;\r
2f88bd3a 179 GcdMemoryMapEnd = (EFI_GCD_MEMORY_SPACE_DESCRIPTOR *)((UINT8 *)GcdMemoryMap + (*NumberOfDescriptors) * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
f9320738 180 while ((UINTN)GcdMemoryMapEntry < (UINTN)GcdMemoryMapEnd) {\r
2f88bd3a 181 CopyMem (NewGcdMemoryMapEntry, GcdMemoryMapEntry, sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
f9320738
JY
182 NextGcdMemoryMapEntry = GcdMemoryMapEntry + 1;\r
183\r
184 do {\r
185 if (((UINTN)NextGcdMemoryMapEntry < (UINTN)GcdMemoryMapEnd) &&\r
186 (GcdMemoryMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && (NextGcdMemoryMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
2f88bd3a
MK
187 ((GcdMemoryMapEntry->BaseAddress + GcdMemoryMapEntry->Length) == NextGcdMemoryMapEntry->BaseAddress))\r
188 {\r
f9320738
JY
189 GcdMemoryMapEntry->Length += NextGcdMemoryMapEntry->Length;\r
190 if (NewGcdMemoryMapEntry != GcdMemoryMapEntry) {\r
191 NewGcdMemoryMapEntry->Length += NextGcdMemoryMapEntry->Length;\r
192 }\r
193\r
194 NextGcdMemoryMapEntry = NextGcdMemoryMapEntry + 1;\r
195 continue;\r
196 } else {\r
197 GcdMemoryMapEntry = NextGcdMemoryMapEntry - 1;\r
198 break;\r
199 }\r
200 } while (TRUE);\r
201\r
2f88bd3a 202 GcdMemoryMapEntry = GcdMemoryMapEntry + 1;\r
f9320738
JY
203 NewGcdMemoryMapEntry = NewGcdMemoryMapEntry + 1;\r
204 }\r
205\r
2f88bd3a 206 *NumberOfDescriptors = ((UINTN)NewGcdMemoryMapEntry - (UINTN)GcdMemoryMap) / sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR);\r
f9320738 207\r
2f88bd3a 208 return;\r
f9320738
JY
209}\r
210\r
211/**\r
212 Notification for SMM EndOfDxe protocol.\r
213\r
214 @param[in] Protocol Points to the protocol's unique identifier.\r
215 @param[in] Interface Points to the interface instance.\r
216 @param[in] Handle The handle on which the interface was installed.\r
217\r
7b5d848d
SZ
218 @retval EFI_SUCCESS Notification runs successfully.\r
219 @retval EFI_OUT_OF_RESOURCES No enough resources to save GCD MMIO map.\r
f9320738
JY
220**/\r
221EFI_STATUS\r
222EFIAPI\r
223SmmIoLibInternalEndOfDxeNotify (\r
224 IN CONST EFI_GUID *Protocol,\r
225 IN VOID *Interface,\r
226 IN EFI_HANDLE Handle\r
227 )\r
228{\r
229 UINTN NumberOfDescriptors;\r
230 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;\r
231 EFI_STATUS Status;\r
232\r
233 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);\r
234 if (!EFI_ERROR (Status)) {\r
f9320738
JY
235 MergeGcdMmioEntry (MemSpaceMap, &NumberOfDescriptors);\r
236\r
237 mSmmIoLibGcdMemSpace = AllocateCopyPool (NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR), MemSpaceMap);\r
7b5d848d
SZ
238 ASSERT (mSmmIoLibGcdMemSpace != NULL);\r
239 if (mSmmIoLibGcdMemSpace == NULL) {\r
f9320738 240 gBS->FreePool (MemSpaceMap);\r
7b5d848d 241 return EFI_OUT_OF_RESOURCES;\r
f9320738
JY
242 }\r
243\r
244 mSmmIoLibGcdMemNumberOfDesc = NumberOfDescriptors;\r
245 gBS->FreePool (MemSpaceMap);\r
246 }\r
247\r
248 return EFI_SUCCESS;\r
249}\r
250\r
251/**\r
252 Notification for SMM ReadyToLock protocol.\r
253\r
254 @param[in] Protocol Points to the protocol's unique identifier.\r
255 @param[in] Interface Points to the interface instance.\r
256 @param[in] Handle The handle on which the interface was installed.\r
257\r
258 @retval EFI_SUCCESS Notification runs successfully.\r
259**/\r
260EFI_STATUS\r
261EFIAPI\r
262SmmIoLibInternalReadyToLockNotify (\r
263 IN CONST EFI_GUID *Protocol,\r
264 IN VOID *Interface,\r
265 IN EFI_HANDLE Handle\r
266 )\r
267{\r
268 mSmmIoLibReadyToLock = TRUE;\r
269 return EFI_SUCCESS;\r
270}\r
271\r
272/**\r
273 The constructor function initializes the Smm IO library\r
274\r
275 @param ImageHandle The firmware allocated handle for the EFI image.\r
276 @param SystemTable A pointer to the EFI System Table.\r
277\r
278 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
279\r
280**/\r
281EFI_STATUS\r
282EFIAPI\r
283SmmIoLibConstructor (\r
284 IN EFI_HANDLE ImageHandle,\r
285 IN EFI_SYSTEM_TABLE *SystemTable\r
286 )\r
287{\r
2f88bd3a 288 EFI_STATUS Status;\r
f9320738
JY
289\r
290 //\r
291 // Calculate and save maximum support address\r
292 //\r
293 SmmIoLibInternalCalculateMaximumSupportAddress ();\r
294\r
295 //\r
296 // Register EndOfDxe to get GCD resource map\r
297 //\r
298 Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, SmmIoLibInternalEndOfDxeNotify, &mSmmIoLibRegistrationEndOfDxe);\r
299 ASSERT_EFI_ERROR (Status);\r
300\r
301 //\r
302 // Register ready to lock so that we can know when to check valid resource region\r
303 //\r
304 Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, SmmIoLibInternalReadyToLockNotify, &mSmmIoLibRegistrationReadyToLock);\r
305 ASSERT_EFI_ERROR (Status);\r
306\r
307 return EFI_SUCCESS;\r
308}\r
309\r
310/**\r
311 The destructor function frees resource used in the Smm IO library\r
312\r
313 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
314 @param[in] SystemTable A pointer to the EFI System Table.\r
315\r
316 @retval EFI_SUCCESS The deconstructor always returns EFI_SUCCESS.\r
317**/\r
318EFI_STATUS\r
319EFIAPI\r
320SmmIoLibDestructor (\r
321 IN EFI_HANDLE ImageHandle,\r
322 IN EFI_SYSTEM_TABLE *SystemTable\r
323 )\r
324{\r
325 gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, NULL, &mSmmIoLibRegistrationEndOfDxe);\r
326 gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, NULL, &mSmmIoLibRegistrationReadyToLock);\r
327 return EFI_SUCCESS;\r
328}\r