]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / MdeModulePkg / Library / PiDxeS3BootScriptLib / BootScriptSave.c
CommitLineData
64d14edf 1/** @file\r
cfd79783
SZ
2 Save the S3 data to S3 boot script.\r
3\r
9c08b3e7 4 Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>\r
64d14edf 5\r
9d510e61 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
64d14edf 7\r
8**/\r
9#include "InternalBootScriptLib.h"\r
10\r
11/**\r
12\r
13 Data structure usage:\r
14\r
960f2d53
SZ
15 +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr\r
16 | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock)\r
17 | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr\r
18 | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm)\r
19 | TableMemoryPageNumber |--|-|----\r
20 | AtRuntime | | | |\r
21 | InSmm | | | |\r
22 | BootTimeScriptLength |--|-|---|---\r
23 | SmmLocked | | | | |\r
24 | BackFromS3 | | | | |\r
25 +------------------------------+ | | | |\r
26 | | | |\r
27 +------------------------------+<-- | | |\r
28 | EFI_BOOT_SCRIPT_TABLE_HEADER | | | |\r
29 | TableLength |----|-- | |\r
30 +------------------------------+ | | | |\r
31 | ...... | | | | |\r
32 +------------------------------+<---- | | |\r
33 | EFI_BOOT_SCRIPT_TERMINATE | | | |\r
34 +------------------------------+<------ | |\r
35 | |\r
36 | |\r
37 mBootScriptDataBootTimeGuid LockBox: | |\r
38 Used to restore data after back from S3| |\r
39 to handle potential INSERT boot script | |\r
40 at runtime. | |\r
41 +------------------------------+ | |\r
42 | Boot Time Boot Script | | |\r
43 | Before SmmReadyToLock | | |\r
44 | | | |\r
45 | | | |\r
46 +------------------------------+ | |\r
47 | Boot Time Boot Script | | |\r
48 | After SmmReadyToLock InSmm | | |\r
49 | | | |\r
50 +------------------------------+<-------|--|\r
51 | |\r
52 | |\r
53 mBootScriptDataGuid LockBox: (IN_PLACE) | |\r
54 Used to restore data at S3 resume. | |\r
55 +------------------------------+ | |\r
56 | Boot Time Boot Script | | |\r
57 | Before SmmReadyToLock | | |\r
58 | | | |\r
59 | | | |\r
60 +------------------------------+ | |\r
61 | Boot Time Boot Script | | |\r
62 | After SmmReadyToLock InSmm | | |\r
63 | | | |\r
64 +------------------------------+<-------|---\r
65 | Runtime Boot Script | |\r
66 | After SmmReadyToLock InSmm | |\r
67 +------------------------------+ |\r
68 | ...... | |\r
69 +------------------------------+<--------\r
70\r
71\r
72 mBootScriptTableBaseGuid LockBox: (IN_PLACE)\r
73 +------------------------------+\r
74 | mS3BootScriptTablePtr-> |\r
75 | TableBase |\r
76 +------------------------------+\r
77\r
78\r
79 mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE)\r
80 SMM private data with BackFromS3 = TRUE\r
81 at runtime. S3 will help restore it to\r
82 tell the Library the system is back from S3.\r
83 +------------------------------+\r
64d14edf 84 | SCRIPT_TABLE_PRIVATE_DATA |\r
960f2d53
SZ
85 | TableBase |\r
86 | TableLength |\r
87 | TableMemoryPageNumber |\r
88 | AtRuntime |\r
89 | InSmm |\r
90 | BootTimeScriptLength |\r
91 | SmmLocked |\r
92 | BackFromS3 = TRUE |\r
93 +------------------------------+\r
64d14edf 94\r
95**/\r
96\r
97SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr;\r
960f2d53 98\r
64d14edf 99//\r
960f2d53 100// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm.\r
64d14edf 101//\r
3aa764ed 102SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr;\r
64d14edf 103\r
104EFI_GUID mBootScriptDataGuid = {\r
ce68d3bc 105 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 }\r
64d14edf 106};\r
107\r
960f2d53 108EFI_GUID mBootScriptDataBootTimeGuid = {\r
02f49fc2
SZ
109 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d }\r
110};\r
111\r
960f2d53 112EFI_GUID mBootScriptTableBaseGuid = {\r
ce68d3bc 113 0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 }\r
64d14edf 114};\r
115\r
960f2d53
SZ
116EFI_GUID mBootScriptSmmPrivateDataGuid = {\r
117 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 }\r
118};\r
119\r
cfd79783
SZ
120EFI_EVENT mEventDxeSmmReadyToLock = NULL;\r
121VOID *mRegistrationSmmExitBootServices = NULL;\r
122VOID *mRegistrationSmmLegacyBoot = NULL;\r
123VOID *mRegistrationSmmReadyToLock = NULL;\r
124BOOLEAN mS3BootScriptTableAllocated = FALSE;\r
125BOOLEAN mS3BootScriptTableSmmAllocated = FALSE;\r
a7636346 126EFI_SMM_SYSTEM_TABLE2 *mBootScriptSmst = NULL;\r
9c08b3e7 127BOOLEAN mS3BootScriptAcpiS3Enable = TRUE;\r
cfd79783 128\r
64d14edf 129/**\r
3a03e95e
SZ
130 This is an internal function to add a terminate node the entry, recalculate the table\r
131 length and fill into the table.\r
132\r
133 @return the base address of the boot script table.\r
64d14edf 134 **/\r
135UINT8*\r
136S3BootScriptInternalCloseTable (\r
137 VOID\r
138 )\r
139{\r
140 UINT8 *S3TableBase;\r
141 EFI_BOOT_SCRIPT_TERMINATE ScriptTerminate;\r
142 EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;\r
143 S3TableBase = mS3BootScriptTablePtr->TableBase;\r
3a03e95e 144\r
64d14edf 145 if (S3TableBase == NULL) {\r
146 //\r
147 // the table is not exist\r
148 //\r
149 return S3TableBase;\r
150 }\r
151 //\r
152 // Append the termination entry.\r
153 //\r
154 ScriptTerminate.OpCode = S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE;\r
155 ScriptTerminate.Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TERMINATE);\r
156 CopyMem (mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength, &ScriptTerminate, sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
157 //\r
158 // fill the table length\r
159 //\r
160 ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(mS3BootScriptTablePtr->TableBase);\r
161 ScriptTableInfo->TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);\r
3a03e95e
SZ
162\r
163\r
164\r
64d14edf 165 return S3TableBase;\r
166 //\r
3a03e95e 167 // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to\r
960f2d53
SZ
168 // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE).\r
169 // Because maybe after SmmReadyToLock, we still need add entries into the table,\r
170 // and the entry should be added start before this TERMINATE node.\r
64d14edf 171 //\r
3a03e95e 172}\r
64d14edf 173\r
174/**\r
175 This function save boot script data to LockBox.\r
960f2d53 176\r
64d14edf 177**/\r
178VOID\r
179SaveBootScriptDataToLockBox (\r
180 VOID\r
181 )\r
182{\r
f6ec0c77 183 EFI_STATUS Status;\r
f6ec0c77 184\r
64d14edf 185 //\r
960f2d53
SZ
186 // Save whole memory copy into LockBox.\r
187 // It will be used to restore data at S3 resume.\r
64d14edf 188 //\r
189 Status = SaveLockBox (\r
190 &mBootScriptDataGuid,\r
191 (VOID *)mS3BootScriptTablePtr->TableBase,\r
960f2d53 192 EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber)\r
64d14edf 193 );\r
194 ASSERT_EFI_ERROR (Status);\r
195\r
196 Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
197 ASSERT_EFI_ERROR (Status);\r
198\r
199 //\r
200 // Just need save TableBase.\r
201 // Do not update other field because they will NOT be used in S3.\r
202 //\r
203 Status = SaveLockBox (\r
960f2d53 204 &mBootScriptTableBaseGuid,\r
64d14edf 205 (VOID *)&mS3BootScriptTablePtr->TableBase,\r
206 sizeof(mS3BootScriptTablePtr->TableBase)\r
207 );\r
208 ASSERT_EFI_ERROR (Status);\r
209\r
960f2d53 210 Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
64d14edf 211 ASSERT_EFI_ERROR (Status);\r
212}\r
213\r
214/**\r
215 This is the Event call back function to notify the Library the system is entering\r
960f2d53 216 SmmLocked phase.\r
3a03e95e 217\r
64d14edf 218 @param Event Pointer to this event\r
3a03e95e 219 @param Context Event handler private data\r
64d14edf 220 **/\r
221VOID\r
222EFIAPI\r
223S3BootScriptEventCallBack (\r
224 IN EFI_EVENT Event,\r
225 IN VOID *Context\r
226 )\r
227{\r
228 EFI_STATUS Status;\r
229 VOID *Interface;\r
230\r
231 //\r
232 // Try to locate it because EfiCreateProtocolNotifyEvent will trigger it once when registration.\r
233 // Just return if it is not found.\r
234 //\r
235 Status = gBS->LocateProtocol (\r
236 &gEfiDxeSmmReadyToLockProtocolGuid,\r
237 NULL,\r
238 &Interface\r
239 );\r
240 if (EFI_ERROR (Status)) {\r
241 return ;\r
242 }\r
243\r
244 //\r
960f2d53
SZ
245 // Here we should tell the library that we are entering SmmLocked phase.\r
246 // and the memory page number occupied by the table should not grow anymore.\r
64d14edf 247 //\r
960f2d53 248 if (!mS3BootScriptTablePtr->SmmLocked) {\r
64d14edf 249 //\r
960f2d53
SZ
250 // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table\r
251 // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate\r
252 // node on every add to boot script table.\r
64d14edf 253 //\r
254 S3BootScriptInternalCloseTable ();\r
960f2d53 255 mS3BootScriptTablePtr->SmmLocked = TRUE;\r
64d14edf 256\r
257 //\r
258 // Save BootScript data to lockbox\r
259 //\r
260 SaveBootScriptDataToLockBox ();\r
261 }\r
960f2d53
SZ
262}\r
263\r
64d14edf 264/**\r
960f2d53
SZ
265 This is the Event call back function is triggered in SMM to notify the Library\r
266 the system is entering SmmLocked phase and set InSmm flag.\r
267\r
64d14edf 268 @param Protocol Points to the protocol's unique identifier\r
269 @param Interface Points to the interface instance\r
270 @param Handle The handle on which the interface was installed\r
271\r
272 @retval EFI_SUCCESS SmmEventCallback runs successfully\r
273 **/\r
274EFI_STATUS\r
275EFIAPI\r
276S3BootScriptSmmEventCallBack (\r
277 IN CONST EFI_GUID *Protocol,\r
278 IN VOID *Interface,\r
279 IN EFI_HANDLE Handle\r
280 )\r
281{\r
282 //\r
283 // Check if it is already done\r
284 //\r
3aa764ed 285 if (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr) {\r
64d14edf 286 return EFI_SUCCESS;\r
287 }\r
288\r
289 //\r
960f2d53 290 // Last chance to call-out, just make sure SmmLocked is set.\r
64d14edf 291 //\r
292 S3BootScriptEventCallBack (NULL, NULL);\r
293\r
294 //\r
3aa764ed 295 // Save a SMM copy. If TableBase is NOT null, it means SMM copy has been ready, skip copy mem.\r
64d14edf 296 //\r
3aa764ed
SZ
297 if (mS3BootScriptTableSmmPtr->TableBase == NULL) {\r
298 CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));\r
960f2d53
SZ
299\r
300 //\r
301 // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.\r
302 // InSmm will only be checked if SmmLocked is TRUE.\r
303 //\r
304 mS3BootScriptTableSmmPtr->InSmm = TRUE;\r
3aa764ed 305 }\r
64d14edf 306 //\r
960f2d53 307 // We should not use ACPI Reserved copy, because it is not safe.\r
64d14edf 308 //\r
3aa764ed 309 mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr;\r
64d14edf 310\r
960f2d53
SZ
311 return EFI_SUCCESS;\r
312}\r
313\r
314/**\r
315 This function is to save boot time boot script data to LockBox.\r
316\r
317 Because there may be INSERT boot script at runtime in SMM.\r
318 The boot time copy will be used to restore data after back from S3.\r
319 Otherwise the data inserted may cause some boot time boot script data lost\r
320 if only BootScriptData used.\r
321\r
322**/\r
323VOID\r
324SaveBootTimeDataToLockBox (\r
325 VOID\r
326 )\r
327{\r
328 EFI_STATUS Status;\r
329\r
64d14edf 330 //\r
960f2d53
SZ
331 // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first,\r
332 // and then save the data to BootScriptDataBootTime LockBox.\r
64d14edf 333 //\r
960f2d53
SZ
334 Status = RestoreLockBox (\r
335 &mBootScriptDataGuid,\r
336 NULL,\r
337 NULL\r
338 );\r
339 ASSERT_EFI_ERROR (Status);\r
340\r
341 //\r
342 // Save BootScriptDataBootTime\r
343 // It will be used to restore data after back from S3.\r
344 //\r
345 Status = SaveLockBox (\r
346 &mBootScriptDataBootTimeGuid,\r
347 (VOID *) mS3BootScriptTablePtr->TableBase,\r
348 mS3BootScriptTablePtr->BootTimeScriptLength\r
349 );\r
350 ASSERT_EFI_ERROR (Status);\r
351}\r
352\r
353/**\r
354 This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime.\r
355 S3 resume will help restore it to tell the Library the system is back from S3.\r
356\r
357**/\r
358VOID\r
359SaveSmmPriviateDataToLockBoxAtRuntime (\r
360 VOID\r
361 )\r
362{\r
363 EFI_STATUS Status;\r
364\r
365 //\r
366 // Save boot script SMM private data with BackFromS3 = TRUE.\r
367 //\r
368 mS3BootScriptTablePtr->BackFromS3 = TRUE;\r
369 Status = SaveLockBox (\r
370 &mBootScriptSmmPrivateDataGuid,\r
371 (VOID *) mS3BootScriptTablePtr,\r
372 sizeof (SCRIPT_TABLE_PRIVATE_DATA)\r
373 );\r
374 ASSERT_EFI_ERROR (Status);\r
375\r
376 Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
377 ASSERT_EFI_ERROR (Status);\r
64d14edf 378\r
379 //\r
960f2d53 380 // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3.\r
64d14edf 381 //\r
960f2d53
SZ
382 mS3BootScriptTablePtr->BackFromS3 = FALSE;\r
383}\r
384\r
385/**\r
386 This is the Event call back function is triggered in SMM to notify the Library\r
387 the system is entering runtime phase.\r
388\r
389 @param[in] Protocol Points to the protocol's unique identifier\r
390 @param[in] Interface Points to the interface instance\r
391 @param[in] Handle The handle on which the interface was installed\r
392\r
393 @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully\r
394 **/\r
395EFI_STATUS\r
396EFIAPI\r
397S3BootScriptSmmAtRuntimeCallBack (\r
398 IN CONST EFI_GUID *Protocol,\r
399 IN VOID *Interface,\r
400 IN EFI_HANDLE Handle\r
401 )\r
402{\r
403 if (!mS3BootScriptTablePtr->AtRuntime) {\r
404 mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
405 SaveBootTimeDataToLockBox ();\r
406\r
407 mS3BootScriptTablePtr->AtRuntime = TRUE;\r
408 SaveSmmPriviateDataToLockBoxAtRuntime ();\r
409 }\r
64d14edf 410\r
411 return EFI_SUCCESS;\r
412}\r
413\r
414/**\r
415 Library Constructor.\r
3a03e95e
SZ
416 this function just identify it is a smm driver or non-smm driver linked against\r
417 with the library\r
64d14edf 418\r
419 @param ImageHandle The firmware allocated handle for the EFI image.\r
420 @param SystemTable A pointer to the EFI System Table.\r
421\r
cfd79783
SZ
422 @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.\r
423\r
64d14edf 424**/\r
425RETURN_STATUS\r
426EFIAPI\r
427S3BootScriptLibInitialize (\r
428 IN EFI_HANDLE ImageHandle,\r
429 IN EFI_SYSTEM_TABLE *SystemTable\r
430 )\r
431{\r
432 EFI_STATUS Status;\r
433 SCRIPT_TABLE_PRIVATE_DATA *S3TablePtr;\r
3aa764ed 434 SCRIPT_TABLE_PRIVATE_DATA *S3TableSmmPtr;\r
64d14edf 435 VOID *Registration;\r
436 EFI_SMM_BASE2_PROTOCOL *SmmBase2;\r
437 BOOLEAN InSmm;\r
64d14edf 438 EFI_PHYSICAL_ADDRESS Buffer;\r
439\r
ed9db1b9 440 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
9c08b3e7 441 mS3BootScriptAcpiS3Enable = FALSE;\r
ed9db1b9
CC
442 DEBUG ((DEBUG_INFO, "%a: Skip S3BootScript because ACPI S3 disabled.\n", gEfiCallerBaseName));\r
443 return RETURN_SUCCESS;\r
444 }\r
445\r
64d14edf 446 S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);\r
447 //\r
448 // The Boot script private data is not be initialized. create it\r
449 //\r
450 if (S3TablePtr == 0) {\r
451 Buffer = SIZE_4GB - 1;\r
452 Status = gBS->AllocatePages (\r
453 AllocateMaxAddress,\r
960f2d53 454 EfiReservedMemoryType,\r
64d14edf 455 EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),\r
456 &Buffer\r
457 );\r
cfd79783
SZ
458 ASSERT_EFI_ERROR (Status);\r
459 mS3BootScriptTableAllocated = TRUE;\r
64d14edf 460 S3TablePtr = (VOID *) (UINTN) Buffer;\r
461\r
ca49b6f9
SZ
462 Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr);\r
463 ASSERT_EFI_ERROR (Status);\r
cfd79783 464 ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));\r
64d14edf 465 //\r
960f2d53 466 // Create event to notify the library system enter the SmmLocked phase.\r
64d14edf 467 //\r
cfd79783
SZ
468 mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent (\r
469 &gEfiDxeSmmReadyToLockProtocolGuid,\r
470 TPL_CALLBACK,\r
471 S3BootScriptEventCallBack,\r
472 NULL,\r
473 &Registration\r
474 );\r
475 ASSERT (mEventDxeSmmReadyToLock != NULL);\r
960f2d53 476 }\r
64d14edf 477 mS3BootScriptTablePtr = S3TablePtr;\r
478\r
479 //\r
480 // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver.\r
481 //\r
482 Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);\r
483 if (EFI_ERROR (Status)) {\r
484 return RETURN_SUCCESS;\r
485 }\r
486 Status = SmmBase2->InSmm (SmmBase2, &InSmm);\r
487 if (EFI_ERROR (Status)) {\r
488 return RETURN_SUCCESS;\r
489 }\r
490 if (!InSmm) {\r
491 return RETURN_SUCCESS;\r
492 }\r
493 //\r
494 // Good, we are in SMM\r
495 //\r
a7636346 496 Status = SmmBase2->GetSmstLocation (SmmBase2, &mBootScriptSmst);\r
64d14edf 497 if (EFI_ERROR (Status)) {\r
498 return RETURN_SUCCESS;\r
499 }\r
500\r
3aa764ed
SZ
501 S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);\r
502 //\r
503 // The Boot script private data in SMM is not be initialized. create it\r
504 //\r
505 if (S3TableSmmPtr == 0) {\r
a7636346
SZ
506 Status = mBootScriptSmst->SmmAllocatePool (\r
507 EfiRuntimeServicesData,\r
508 sizeof(SCRIPT_TABLE_PRIVATE_DATA),\r
509 (VOID **) &S3TableSmmPtr\r
510 );\r
cfd79783
SZ
511 ASSERT_EFI_ERROR (Status);\r
512 mS3BootScriptTableSmmAllocated = TRUE;\r
3aa764ed 513\r
ca49b6f9
SZ
514 Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);\r
515 ASSERT_EFI_ERROR (Status);\r
3aa764ed 516 ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));\r
960f2d53
SZ
517\r
518 //\r
519 // Register SmmExitBootServices and SmmLegacyBoot notification.\r
520 //\r
a7636346
SZ
521 Status = mBootScriptSmst->SmmRegisterProtocolNotify (\r
522 &gEdkiiSmmExitBootServicesProtocolGuid,\r
523 S3BootScriptSmmAtRuntimeCallBack,\r
524 &mRegistrationSmmExitBootServices\r
525 );\r
960f2d53
SZ
526 ASSERT_EFI_ERROR (Status);\r
527\r
a7636346
SZ
528 Status = mBootScriptSmst->SmmRegisterProtocolNotify (\r
529 &gEdkiiSmmLegacyBootProtocolGuid,\r
530 S3BootScriptSmmAtRuntimeCallBack,\r
531 &mRegistrationSmmLegacyBoot\r
532 );\r
960f2d53 533 ASSERT_EFI_ERROR (Status);\r
3aa764ed
SZ
534 }\r
535 mS3BootScriptTableSmmPtr = S3TableSmmPtr;\r
536\r
64d14edf 537 //\r
960f2d53 538 // Register SmmReadyToLock notification.\r
64d14edf 539 //\r
a7636346
SZ
540 Status = mBootScriptSmst->SmmRegisterProtocolNotify (\r
541 &gEfiSmmReadyToLockProtocolGuid,\r
542 S3BootScriptSmmEventCallBack,\r
543 &mRegistrationSmmReadyToLock\r
544 );\r
64d14edf 545 ASSERT_EFI_ERROR (Status);\r
546\r
547 return RETURN_SUCCESS;\r
548}\r
cfd79783
SZ
549\r
550/**\r
551 Library Destructor to free the resources allocated by\r
552 S3BootScriptLibInitialize() and unregister callbacks.\r
553\r
554 NOTICE: The destructor doesn't support unloading as a separate action, and it\r
555 only supports unloading if the containing driver's entry point function fails.\r
556\r
557 @param ImageHandle The firmware allocated handle for the EFI image.\r
558 @param SystemTable A pointer to the EFI System Table.\r
559\r
560 @retval RETURN_SUCCESS The destructor always returns RETURN_SUCCESS.\r
561\r
562**/\r
563RETURN_STATUS\r
564EFIAPI\r
565S3BootScriptLibDeinitialize (\r
566 IN EFI_HANDLE ImageHandle,\r
567 IN EFI_SYSTEM_TABLE *SystemTable\r
568 )\r
569{\r
570 EFI_STATUS Status;\r
571\r
9c08b3e7 572 if (!mS3BootScriptAcpiS3Enable) {\r
ed9db1b9
CC
573 return RETURN_SUCCESS;\r
574 }\r
575\r
87000d77 576 DEBUG ((DEBUG_INFO, "%a() in %a module\n", __FUNCTION__, gEfiCallerBaseName));\r
cfd79783
SZ
577\r
578 if (mEventDxeSmmReadyToLock != NULL) {\r
579 //\r
580 // Close the DxeSmmReadyToLock event.\r
581 //\r
582 Status = gBS->CloseEvent (mEventDxeSmmReadyToLock);\r
583 ASSERT_EFI_ERROR (Status);\r
584 }\r
585\r
a7636346 586 if (mBootScriptSmst != NULL) {\r
cfd79783
SZ
587 if (mRegistrationSmmExitBootServices != NULL) {\r
588 //\r
589 // Unregister SmmExitBootServices notification.\r
590 //\r
a7636346
SZ
591 Status = mBootScriptSmst->SmmRegisterProtocolNotify (\r
592 &gEdkiiSmmExitBootServicesProtocolGuid,\r
593 NULL,\r
594 &mRegistrationSmmExitBootServices\r
595 );\r
cfd79783
SZ
596 ASSERT_EFI_ERROR (Status);\r
597 }\r
598 if (mRegistrationSmmLegacyBoot != NULL) {\r
599 //\r
600 // Unregister SmmLegacyBoot notification.\r
601 //\r
a7636346
SZ
602 Status = mBootScriptSmst->SmmRegisterProtocolNotify (\r
603 &gEdkiiSmmLegacyBootProtocolGuid,\r
604 NULL,\r
605 &mRegistrationSmmLegacyBoot\r
606 );\r
cfd79783
SZ
607 ASSERT_EFI_ERROR (Status);\r
608 }\r
609 if (mRegistrationSmmReadyToLock != NULL) {\r
610 //\r
611 // Unregister SmmReadyToLock notification.\r
612 //\r
a7636346
SZ
613 Status = mBootScriptSmst->SmmRegisterProtocolNotify (\r
614 &gEfiSmmReadyToLockProtocolGuid,\r
615 NULL,\r
616 &mRegistrationSmmReadyToLock\r
617 );\r
cfd79783
SZ
618 ASSERT_EFI_ERROR (Status);\r
619 }\r
620 }\r
621\r
622 //\r
623 // Free the resources allocated and set PCDs to 0.\r
624 //\r
625 if (mS3BootScriptTableAllocated) {\r
626 Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) mS3BootScriptTablePtr, EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)));\r
627 ASSERT_EFI_ERROR (Status);\r
628 Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, 0);\r
629 ASSERT_EFI_ERROR (Status);\r
630 }\r
a7636346
SZ
631 if ((mBootScriptSmst != NULL) && mS3BootScriptTableSmmAllocated) {\r
632 Status = mBootScriptSmst->SmmFreePool (mS3BootScriptTableSmmPtr);\r
cfd79783
SZ
633 ASSERT_EFI_ERROR (Status);\r
634 Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, 0);\r
635 ASSERT_EFI_ERROR (Status);\r
636 }\r
637\r
638 return RETURN_SUCCESS;\r
639}\r
640\r
64d14edf 641/**\r
642 To get the start address from which a new boot time s3 boot script entry will write into.\r
643 If the table is not exist, the functio will first allocate a buffer for the table\r
3a03e95e 644 If the table buffer is not enough for the new entry, in non-smm mode, the funtion will\r
64d14edf 645 invoke reallocate to enlarge buffer.\r
3a03e95e 646\r
64d14edf 647 @param EntryLength the new entry length.\r
3a03e95e
SZ
648\r
649 @retval the address from which the a new s3 boot script entry will write into\r
64d14edf 650 **/\r
651UINT8*\r
652S3BootScriptGetBootTimeEntryAddAddress (\r
653 UINT8 EntryLength\r
654 )\r
655{\r
656 EFI_PHYSICAL_ADDRESS S3TableBase;\r
657 EFI_PHYSICAL_ADDRESS NewS3TableBase;\r
658 UINT8 *NewEntryPtr;\r
659 UINT32 TableLength;\r
660 UINT16 PageNumber;\r
661 EFI_STATUS Status;\r
662 EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;\r
3a03e95e 663\r
64d14edf 664 S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase);\r
665 if (S3TableBase == 0) {\r
960f2d53 666 //\r
3a03e95e 667 // The table is not exist. This is the first to add entry.\r
960f2d53 668 // Allocate ACPI script table space under 4G memory.\r
64d14edf 669 //\r
670 S3TableBase = 0xffffffff;\r
671 Status = gBS->AllocatePages (\r
672 AllocateMaxAddress,\r
960f2d53 673 EfiReservedMemoryType,\r
64d14edf 674 2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),\r
675 (EFI_PHYSICAL_ADDRESS*)&S3TableBase\r
676 );\r
3a03e95e 677\r
64d14edf 678 if (EFI_ERROR(Status)) {\r
679 ASSERT_EFI_ERROR (Status);\r
680 return 0;\r
681 }\r
682 //\r
683 // Fill Table Header\r
684 //\r
685 ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase;\r
686 ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;\r
687 ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
0a4a5b7b 688 ScriptTableInfo->Version = BOOT_SCRIPT_TABLE_VERSION;\r
64d14edf 689 ScriptTableInfo->TableLength = 0; // will be calculate at CloseTable\r
690 mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
691 mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase;\r
692 mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16)(2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));\r
693 }\r
3a03e95e 694\r
64d14edf 695 // Here we do not count the reserved memory for runtime script table.\r
960f2d53 696 PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));\r
64d14edf 697 TableLength = mS3BootScriptTablePtr->TableLength;\r
16f69227 698 if (EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {\r
3a03e95e 699 //\r
64d14edf 700 // The buffer is too small to hold the table, Reallocate the buffer\r
701 //\r
702 NewS3TableBase = 0xffffffff;\r
703 Status = gBS->AllocatePages (\r
704 AllocateMaxAddress,\r
960f2d53 705 EfiReservedMemoryType,\r
64d14edf 706 2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),\r
707 (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase\r
708 );\r
3a03e95e 709\r
64d14edf 710 if (EFI_ERROR(Status)) {\r
711 ASSERT_EFI_ERROR (Status);\r
712 return 0;\r
713 }\r
3a03e95e 714\r
64d14edf 715 CopyMem ((VOID*)(UINTN)NewS3TableBase, (VOID*)(UINTN)S3TableBase, TableLength);\r
716 gBS->FreePages (S3TableBase, mS3BootScriptTablePtr->TableMemoryPageNumber);\r
3a03e95e 717\r
64d14edf 718 mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)NewS3TableBase;\r
3a03e95e 719 mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16) (2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));\r
64d14edf 720 }\r
721 //\r
3a03e95e 722 // calculate the the start address for the new entry.\r
64d14edf 723 //\r
724 NewEntryPtr = mS3BootScriptTablePtr->TableBase + TableLength;\r
3a03e95e 725\r
64d14edf 726 //\r
727 // update the table lenghth\r
728 //\r
729 mS3BootScriptTablePtr->TableLength = TableLength + EntryLength;\r
3a03e95e 730\r
64d14edf 731 //\r
732 // In the boot time, we will not append the termination entry to the boot script\r
3a03e95e
SZ
733 // table until the callers think there is no boot time data that should be added and\r
734 // it is caller's responsibility to explicit call the CloseTable.\r
64d14edf 735 //\r
736 //\r
3a03e95e
SZ
737\r
738 return NewEntryPtr;\r
64d14edf 739}\r
740/**\r
960f2d53 741 To get the start address from which a new runtime(after SmmReadyToLock) s3 boot script entry will write into.\r
64d14edf 742 In this case, it should be ensured that there is enough buffer to hold the entry.\r
3a03e95e 743\r
64d14edf 744 @param EntryLength the new entry length.\r
3a03e95e 745\r
960f2d53 746 @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into\r
64d14edf 747 **/\r
748UINT8*\r
749S3BootScriptGetRuntimeEntryAddAddress (\r
750 UINT8 EntryLength\r
751 )\r
752{\r
753 UINT8 *NewEntryPtr;\r
3a03e95e
SZ
754\r
755 NewEntryPtr = NULL;\r
64d14edf 756 //\r
3a03e95e 757 // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node.\r
64d14edf 758 //\r
16f69227 759 if ((mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) {\r
3a03e95e 760 NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength;\r
64d14edf 761 mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength;\r
762 //\r
763 // Append a terminate node on every insert\r
764 //\r
765 S3BootScriptInternalCloseTable ();\r
766 }\r
3a03e95e 767 return (UINT8*)NewEntryPtr;\r
64d14edf 768}\r
960f2d53
SZ
769\r
770/**\r
771 This function is to restore boot time boot script data from LockBox.\r
772\r
773**/\r
774VOID\r
775RestoreBootTimeDataFromLockBox (\r
776 VOID\r
777 )\r
778{\r
779 EFI_STATUS Status;\r
780 UINTN LockBoxLength;\r
781\r
782 //\r
783 // Restore boot time boot script data from LockBox.\r
784 //\r
785 LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength;\r
786 Status = RestoreLockBox (\r
787 &mBootScriptDataBootTimeGuid,\r
788 (VOID *) mS3BootScriptTablePtr->TableBase,\r
789 &LockBoxLength\r
790 );\r
791 ASSERT_EFI_ERROR (Status);\r
792\r
793 //\r
794 // Update the data to BootScriptData LockBox.\r
795 //\r
796 Status = UpdateLockBox (\r
797 &mBootScriptDataGuid,\r
798 0,\r
799 (VOID *) mS3BootScriptTablePtr->TableBase,\r
800 LockBoxLength\r
801 );\r
802 ASSERT_EFI_ERROR (Status);\r
803\r
804 //\r
805 // Update TableLength.\r
806 //\r
807 mS3BootScriptTablePtr->TableLength = (UINT32) (mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
808}\r
809\r
64d14edf 810/**\r
811 To get the start address from which a new s3 boot script entry will write into.\r
3a03e95e 812\r
64d14edf 813 @param EntryLength the new entry length.\r
3a03e95e
SZ
814\r
815 @retval the address from which the a new s3 boot script entry will write into\r
816 **/\r
817UINT8*\r
64d14edf 818S3BootScriptGetEntryAddAddress (\r
819 UINT8 EntryLength\r
820 )\r
821{\r
822 UINT8* NewEntryPtr;\r
64d14edf 823\r
9c08b3e7 824 if (!mS3BootScriptAcpiS3Enable) {\r
ed9db1b9
CC
825 return NULL;\r
826 }\r
827\r
960f2d53 828 if (mS3BootScriptTablePtr->SmmLocked) {\r
64d14edf 829 //\r
960f2d53 830 // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script.\r
64d14edf 831 //\r
832 if (!mS3BootScriptTablePtr->InSmm) {\r
833 //\r
960f2d53
SZ
834 // Add DEBUG ERROR, so that we can find it after SmmReadyToLock.\r
835 // Do not use ASSERT, because we may have test to invoke this interface.\r
64d14edf 836 //\r
87000d77 837 DEBUG ((DEBUG_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n"));\r
64d14edf 838 return NULL;\r
839 }\r
840\r
960f2d53 841 if (mS3BootScriptTablePtr->BackFromS3) {\r
64d14edf 842 //\r
960f2d53
SZ
843 // Back from S3, restore boot time boot script data from LockBox\r
844 // and set BackFromS3 flag back to FALSE.\r
64d14edf 845 //\r
960f2d53
SZ
846 RestoreBootTimeDataFromLockBox ();\r
847 mS3BootScriptTablePtr->BackFromS3 = FALSE;\r
64d14edf 848 }\r
849\r
850 NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength);\r
960f2d53 851 } else {\r
64d14edf 852 NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength);\r
3a03e95e 853 }\r
64d14edf 854 return NewEntryPtr;\r
3a03e95e
SZ
855\r
856}\r
64d14edf 857\r
858/**\r
859 Sync BootScript LockBox data.\r
02f49fc2
SZ
860\r
861 @param Script The address from where the boot script has been added or updated.\r
862\r
64d14edf 863**/\r
864VOID\r
865SyncBootScript (\r
02f49fc2 866 IN UINT8 *Script\r
64d14edf 867 )\r
868{\r
869 EFI_STATUS Status;\r
960f2d53
SZ
870 UINT32 ScriptOffset;\r
871 UINT32 TotalScriptLength;\r
02f49fc2 872\r
960f2d53 873 if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) {\r
02f49fc2 874 //\r
960f2d53
SZ
875 // If it is not after SmmReadyToLock in SMM,\r
876 // just return.\r
02f49fc2 877 //\r
64d14edf 878 return ;\r
879 }\r
02f49fc2 880\r
960f2d53
SZ
881 ScriptOffset = (UINT32) (Script - mS3BootScriptTablePtr->TableBase);\r
882\r
883 TotalScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));\r
884\r
64d14edf 885 //\r
02f49fc2 886 // Update BootScriptData\r
64d14edf 887 // So in S3 resume, the data can be restored correctly.\r
888 //\r
889 Status = UpdateLockBox (\r
890 &mBootScriptDataGuid,\r
02f49fc2
SZ
891 ScriptOffset,\r
892 (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset),\r
960f2d53
SZ
893 TotalScriptLength - ScriptOffset\r
894 );\r
895 ASSERT_EFI_ERROR (Status);\r
896\r
897 //\r
898 // Now the length field is updated, need sync to lockbox.\r
899 // So at S3 resume, the data can be restored correctly.\r
900 //\r
901 Status = UpdateLockBox (\r
902 &mBootScriptDataGuid,\r
903 OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),\r
904 &TotalScriptLength,\r
905 sizeof (TotalScriptLength)\r
64d14edf 906 );\r
907 ASSERT_EFI_ERROR (Status);\r
908}\r
909\r
3a03e95e
SZ
910/**\r
911 This is an function to close the S3 boot script table. The function could only be called in\r
912 BOOT time phase. To comply with the Framework spec definition on\r
64d14edf 913 EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable(), this function will fulfill following things:\r
914 1. Closes the specified boot script table\r
3a03e95e
SZ
915 2. It allocates a new memory pool to duplicate all the boot scripts in the specified table.\r
916 Once this function is called, the table maintained by the library will be destroyed\r
64d14edf 917 after it is copied into the allocated pool.\r
3a03e95e 918 3. Any attempts to add a script record after calling this function will cause a new table\r
64d14edf 919 to be created by the library.\r
3a03e95e 920 4. The base address of the allocated pool will be returned in Address. Note that after\r
64d14edf 921 using the boot script table, the CALLER is responsible for freeing the pool that is allocated\r
3a03e95e 922 by this function.\r
64d14edf 923\r
3a03e95e 924 In Spec PI1.1, this EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is retired. To provides this API for now is\r
64d14edf 925 for Framework Spec compatibility.\r
3a03e95e
SZ
926\r
927 If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out\r
928 how to get the script to run at S3 resume because the boot script maintained by the lib will be\r
64d14edf 929 destroyed.\r
3a03e95e
SZ
930\r
931 @return the base address of the new copy of the boot script table.\r
64d14edf 932 @note this function could only called in boot time phase\r
933\r
934**/\r
935UINT8*\r
936EFIAPI\r
937S3BootScriptCloseTable (\r
938 VOID\r
939 )\r
940{\r
941 UINT8 *S3TableBase;\r
942 UINT32 TableLength;\r
943 UINT8 *Buffer;\r
944 EFI_STATUS Status;\r
945 EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;\r
3a03e95e
SZ
946\r
947 S3TableBase = mS3BootScriptTablePtr->TableBase;\r
64d14edf 948 if (S3TableBase == 0) {\r
3a03e95e 949 return 0;\r
64d14edf 950 }\r
951 //\r
952 // Append the termination record the S3 boot script table\r
953 //\r
954 S3BootScriptInternalCloseTable();\r
955 TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);\r
956 //\r
3a03e95e 957 // Allocate the buffer and copy the boot script to the buffer.\r
64d14edf 958 //\r
959 Status = gBS->AllocatePool (\r
960 EfiBootServicesData,\r
961 (UINTN)TableLength,\r
962 (VOID **) &Buffer\r
963 );\r
964 if (EFI_ERROR (Status)) {\r
3a03e95e 965 return 0;\r
64d14edf 966 }\r
967 CopyMem (Buffer, S3TableBase, TableLength);\r
3a03e95e 968\r
64d14edf 969 //\r
3a03e95e 970 // Destroy the table maintained by the library so that the next write operation\r
64d14edf 971 // will write the record to the first entry of the table.\r
972 //\r
973 // Fill the table header.\r
974 ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)S3TableBase;\r
975 ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;\r
976 ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
977 ScriptTableInfo->TableLength = 0; // will be calculate at close the table\r
3a03e95e 978\r
64d14edf 979 mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
980 return Buffer;\r
981}\r
982/**\r
3a03e95e 983 Save I/O write to boot script\r
64d14edf 984\r
985 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
986 @param Address The base address of the I/O operations.\r
987 @param Count The number of I/O operations to perform.\r
988 @param Buffer The source buffer from which to write data.\r
989\r
990 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
991 @retval RETURN_SUCCESS Opcode is added.\r
992**/\r
993RETURN_STATUS\r
994EFIAPI\r
995S3BootScriptSaveIoWrite (\r
996 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
997 IN UINT64 Address,\r
998 IN UINTN Count,\r
999 IN VOID *Buffer\r
1000 )\r
1001\r
1002{\r
1003 UINT8 Length;\r
1004 UINT8 *Script;\r
1005 UINT8 WidthInByte;\r
1006 EFI_BOOT_SCRIPT_IO_WRITE ScriptIoWrite;\r
1007\r
1008 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
322ac05f
HW
1009\r
1010 //\r
1011 // Truncation check\r
1012 //\r
1013 if ((Count > MAX_UINT8) ||\r
1014 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_IO_WRITE))) {\r
1015 return RETURN_OUT_OF_RESOURCES;\r
1016 }\r
64d14edf 1017 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count));\r
3a03e95e 1018\r
64d14edf 1019 Script = S3BootScriptGetEntryAddAddress (Length);\r
1020 if (Script == NULL) {\r
1021 return RETURN_OUT_OF_RESOURCES;\r
1022 }\r
1023 //\r
1024 // save script data\r
1025 //\r
1026 ScriptIoWrite.OpCode = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE;\r
1027 ScriptIoWrite.Length = Length;\r
1028 ScriptIoWrite.Width = Width;\r
1029 ScriptIoWrite.Address = Address;\r
1030 ScriptIoWrite.Count = (UINT32) Count;\r
1031 CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));\r
1032 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);\r
1033\r
02f49fc2 1034 SyncBootScript (Script);\r
64d14edf 1035\r
1036 return RETURN_SUCCESS;\r
1037}\r
1038\r
1039/**\r
1040 Adds a record for an I/O modify operation into a S3 boot script table\r
1041\r
1042 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1043 @param Address The base address of the I/O operations.\r
1044 @param Data A pointer to the data to be OR-ed.\r
1045 @param DataMask A pointer to the data mask to be AND-ed with the data read from the register\r
1046\r
1047 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1048 @retval RETURN_SUCCESS Opcode is added.\r
1049**/\r
1050RETURN_STATUS\r
1051EFIAPI\r
1052S3BootScriptSaveIoReadWrite (\r
1053 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1054 IN UINT64 Address,\r
1055 IN VOID *Data,\r
1056 IN VOID *DataMask\r
1057 )\r
1058{\r
1059 UINT8 Length;\r
1060 UINT8 *Script;\r
1061 UINT8 WidthInByte;\r
1062 EFI_BOOT_SCRIPT_IO_READ_WRITE ScriptIoReadWrite;\r
1063\r
1064 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
1065 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1066\r
64d14edf 1067 Script = S3BootScriptGetEntryAddAddress (Length);\r
1068 if (Script == NULL) {\r
1069 return RETURN_OUT_OF_RESOURCES;\r
1070 }\r
1071 //\r
1072 // Build script data\r
1073 //\r
1074 ScriptIoReadWrite.OpCode = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;\r
1075 ScriptIoReadWrite.Length = Length;\r
1076 ScriptIoReadWrite.Width = Width;\r
1077 ScriptIoReadWrite.Address = Address;\r
3a03e95e 1078\r
64d14edf 1079 CopyMem ((VOID*)Script, (VOID*)&ScriptIoReadWrite, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));\r
1080 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);\r
1081 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);\r
1082\r
02f49fc2 1083 SyncBootScript (Script);\r
64d14edf 1084\r
1085 return RETURN_SUCCESS;\r
1086}\r
1087/**\r
1088 Adds a record for a memory write operation into a specified boot script table.\r
1089\r
1090 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1091 @param Address The base address of the memory operations\r
1092 @param Count The number of memory operations to perform.\r
1093 @param Buffer The source buffer from which to write the data.\r
1094\r
1095 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1096 @retval RETURN_SUCCESS Opcode is added.\r
1097**/\r
1098RETURN_STATUS\r
1099EFIAPI\r
1100S3BootScriptSaveMemWrite (\r
1101 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1102 IN UINT64 Address,\r
1103 IN UINTN Count,\r
1104 IN VOID *Buffer\r
1105 )\r
1106{\r
1107 UINT8 Length;\r
1108 UINT8 *Script;\r
1109 UINT8 WidthInByte;\r
1110 EFI_BOOT_SCRIPT_MEM_WRITE ScriptMemWrite;\r
3a03e95e 1111\r
64d14edf 1112 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
322ac05f
HW
1113\r
1114 //\r
1115 // Truncation check\r
1116 //\r
1117 if ((Count > MAX_UINT8) ||\r
1118 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_MEM_WRITE))) {\r
1119 return RETURN_OUT_OF_RESOURCES;\r
1120 }\r
64d14edf 1121 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count));\r
3a03e95e 1122\r
64d14edf 1123 Script = S3BootScriptGetEntryAddAddress (Length);\r
1124 if (Script == NULL) {\r
1125 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1126 }\r
64d14edf 1127 //\r
1128 // Build script data\r
1129 //\r
1130 ScriptMemWrite.OpCode = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE;\r
1131 ScriptMemWrite.Length = Length;\r
1132 ScriptMemWrite.Width = Width;\r
1133 ScriptMemWrite.Address = Address;\r
1134 ScriptMemWrite.Count = (UINT32) Count;\r
3a03e95e 1135\r
64d14edf 1136 CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));\r
1137 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);\r
3a03e95e 1138\r
02f49fc2 1139 SyncBootScript (Script);\r
64d14edf 1140\r
1141 return RETURN_SUCCESS;\r
1142}\r
1143/**\r
1144 Adds a record for a memory modify operation into a specified boot script table.\r
1145\r
1146 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1147 @param Address The base address of the memory operations. Address needs alignment if required\r
1148 @param Data A pointer to the data to be OR-ed.\r
1149 @param DataMask A pointer to the data mask to be AND-ed with the data read from the register.\r
1150\r
1151 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1152 @retval RETURN_SUCCESS Opcode is added.\r
1153**/\r
1154RETURN_STATUS\r
1155EFIAPI\r
1156S3BootScriptSaveMemReadWrite (\r
1157 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1158 IN UINT64 Address,\r
1159 IN VOID *Data,\r
1160 IN VOID *DataMask\r
1161 )\r
1162{\r
1163 UINT8 Length;\r
1164 UINT8 *Script;\r
1165 UINT8 WidthInByte;\r
1166 EFI_BOOT_SCRIPT_MEM_READ_WRITE ScriptMemReadWrite;\r
3a03e95e 1167\r
64d14edf 1168 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
1169 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1170\r
64d14edf 1171 Script = S3BootScriptGetEntryAddAddress (Length);\r
1172 if (Script == NULL) {\r
1173 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1174 }\r
64d14edf 1175 //\r
1176 // Build script data\r
3a03e95e 1177 //\r
64d14edf 1178 ScriptMemReadWrite.OpCode = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;\r
1179 ScriptMemReadWrite.Length = Length;\r
1180 ScriptMemReadWrite.Width = Width;\r
1181 ScriptMemReadWrite.Address = Address;\r
3a03e95e 1182\r
64d14edf 1183 CopyMem ((VOID*)Script, (VOID*)&ScriptMemReadWrite , sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));\r
1184 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);\r
1185 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);\r
1186\r
02f49fc2 1187 SyncBootScript (Script);\r
64d14edf 1188\r
1189 return RETURN_SUCCESS;\r
1190}\r
1191/**\r
1192 Adds a record for a PCI configuration space write operation into a specified boot script table.\r
1193\r
1194 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1195 @param Address The address within the PCI configuration space.\r
1196 @param Count The number of PCI operations to perform.\r
1197 @param Buffer The source buffer from which to write the data.\r
1198\r
1199 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1200 @retval RETURN_SUCCESS Opcode is added.\r
2a956f74
SZ
1201 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
1202\r
64d14edf 1203**/\r
1204RETURN_STATUS\r
1205EFIAPI\r
1206S3BootScriptSavePciCfgWrite (\r
1207 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1208 IN UINT64 Address,\r
1209 IN UINTN Count,\r
1210 IN VOID *Buffer\r
1211 )\r
1212{\r
1213 UINT8 Length;\r
1214 UINT8 *Script;\r
1215 UINT8 WidthInByte;\r
1216 EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite;\r
1217\r
2a956f74
SZ
1218 if (Width == S3BootScriptWidthUint64 ||\r
1219 Width == S3BootScriptWidthFifoUint64 ||\r
1220 Width == S3BootScriptWidthFillUint64) {\r
1221 return EFI_INVALID_PARAMETER;\r
1222 }\r
1223\r
64d14edf 1224 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
322ac05f
HW
1225\r
1226 //\r
1227 // Truncation check\r
1228 //\r
1229 if ((Count > MAX_UINT8) ||\r
1230 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE))) {\r
1231 return RETURN_OUT_OF_RESOURCES;\r
1232 }\r
64d14edf 1233 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));\r
3a03e95e 1234\r
64d14edf 1235 Script = S3BootScriptGetEntryAddAddress (Length);\r
1236 if (Script == NULL) {\r
1237 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1238 }\r
64d14edf 1239 //\r
1240 // Build script data\r
1241 //\r
1242 ScriptPciWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE;\r
1243 ScriptPciWrite.Length = Length;\r
1244 ScriptPciWrite.Width = Width;\r
1245 ScriptPciWrite.Address = Address;\r
1246 ScriptPciWrite.Count = (UINT32) Count;\r
3a03e95e 1247\r
64d14edf 1248 CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));\r
1249 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);\r
3a03e95e 1250\r
02f49fc2 1251 SyncBootScript (Script);\r
64d14edf 1252\r
1253 return RETURN_SUCCESS;\r
1254}\r
1255/**\r
1256 Adds a record for a PCI configuration space modify operation into a specified boot script table.\r
1257\r
1258 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1259 @param Address The address within the PCI configuration space.\r
1260 @param Data A pointer to the data to be OR-ed.The size depends on Width.\r
1261 @param DataMask A pointer to the data mask to be AND-ed.\r
1262\r
1263 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1264 @retval RETURN__SUCCESS Opcode is added.\r
2a956f74
SZ
1265 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
1266\r
64d14edf 1267**/\r
1268RETURN_STATUS\r
1269EFIAPI\r
1270S3BootScriptSavePciCfgReadWrite (\r
1271 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1272 IN UINT64 Address,\r
1273 IN VOID *Data,\r
1274 IN VOID *DataMask\r
1275 )\r
1276{\r
1277 UINT8 Length;\r
1278 UINT8 *Script;\r
1279 UINT8 WidthInByte;\r
1280 EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite;\r
1281\r
2a956f74
SZ
1282 if (Width == S3BootScriptWidthUint64 ||\r
1283 Width == S3BootScriptWidthFifoUint64 ||\r
1284 Width == S3BootScriptWidthFillUint64) {\r
1285 return EFI_INVALID_PARAMETER;\r
1286 }\r
1287\r
64d14edf 1288 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
1289 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1290\r
64d14edf 1291 Script = S3BootScriptGetEntryAddAddress (Length);\r
1292 if (Script == NULL) {\r
1293 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1294 }\r
64d14edf 1295 //\r
1296 // Build script data\r
3a03e95e 1297 //\r
64d14edf 1298 ScriptPciReadWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;\r
1299 ScriptPciReadWrite.Length = Length;\r
1300 ScriptPciReadWrite.Width = Width;\r
1301 ScriptPciReadWrite.Address = Address;\r
3a03e95e 1302\r
64d14edf 1303 CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));\r
1304 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);\r
1305 CopyMem (\r
1306 (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),\r
1307 DataMask,\r
1308 WidthInByte\r
1309 );\r
1310\r
02f49fc2 1311 SyncBootScript (Script);\r
64d14edf 1312\r
1313 return RETURN_SUCCESS;\r
1314}\r
1315/**\r
02f49fc2 1316 Adds a record for a PCI configuration 2 space write operation into a specified boot script table.\r
64d14edf 1317\r
1318 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1319 @param Segment The PCI segment number for Address.\r
1320 @param Address The address within the PCI configuration space.\r
1321 @param Count The number of PCI operations to perform.\r
1322 @param Buffer The source buffer from which to write the data.\r
1323\r
1324 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1325 @retval RETURN_SUCCESS Opcode is added.\r
3d20524a 1326 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
2a956f74 1327\r
64d14edf 1328**/\r
1329RETURN_STATUS\r
1330EFIAPI\r
1331S3BootScriptSavePciCfg2Write (\r
1332 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1333 IN UINT16 Segment,\r
1334 IN UINT64 Address,\r
1335 IN UINTN Count,\r
1336 IN VOID *Buffer\r
1337 )\r
1338{\r
1339 UINT8 Length;\r
1340 UINT8 *Script;\r
1341 UINT8 WidthInByte;\r
1342 EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2;\r
2a956f74 1343\r
3d20524a 1344 if (Width == S3BootScriptWidthUint64 ||\r
2a956f74
SZ
1345 Width == S3BootScriptWidthFifoUint64 ||\r
1346 Width == S3BootScriptWidthFillUint64) {\r
1347 return EFI_INVALID_PARAMETER;\r
1348 }\r
1349\r
64d14edf 1350 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
322ac05f
HW
1351\r
1352 //\r
1353 // Truncation check\r
1354 //\r
1355 if ((Count > MAX_UINT8) ||\r
1356 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE))) {\r
1357 return RETURN_OUT_OF_RESOURCES;\r
1358 }\r
64d14edf 1359 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));\r
3a03e95e 1360\r
64d14edf 1361 Script = S3BootScriptGetEntryAddAddress (Length);\r
1362 if (Script == NULL) {\r
1363 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1364 }\r
64d14edf 1365 //\r
1366 // Build script data\r
1367 //\r
1368 ScriptPciWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE;\r
1369 ScriptPciWrite2.Length = Length;\r
1370 ScriptPciWrite2.Width = Width;\r
1371 ScriptPciWrite2.Address = Address;\r
1372 ScriptPciWrite2.Segment = Segment;\r
1373 ScriptPciWrite2.Count = (UINT32)Count;\r
3a03e95e 1374\r
64d14edf 1375 CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));\r
1376 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);\r
1377\r
02f49fc2 1378 SyncBootScript (Script);\r
64d14edf 1379\r
1380 return RETURN_SUCCESS;\r
1381}\r
1382/**\r
02f49fc2 1383 Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.\r
64d14edf 1384\r
1385 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1386 @param Segment The PCI segment number for Address.\r
1387 @param Address The address within the PCI configuration space.\r
1388 @param Data A pointer to the data to be OR-ed. The size depends on Width.\r
1389 @param DataMask A pointer to the data mask to be AND-ed.\r
1390\r
1391 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1392 @retval RETURN_SUCCESS Opcode is added.\r
3d20524a 1393 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
2a956f74 1394\r
64d14edf 1395**/\r
1396RETURN_STATUS\r
1397EFIAPI\r
1398S3BootScriptSavePciCfg2ReadWrite (\r
1399 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1400 IN UINT16 Segment,\r
1401 IN UINT64 Address,\r
1402 IN VOID *Data,\r
1403 IN VOID *DataMask\r
1404 )\r
1405{\r
1406 UINT8 Length;\r
1407 UINT8 *Script;\r
1408 UINT8 WidthInByte;\r
1409 EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2;\r
2a956f74 1410\r
3d20524a 1411 if (Width == S3BootScriptWidthUint64 ||\r
2a956f74
SZ
1412 Width == S3BootScriptWidthFifoUint64 ||\r
1413 Width == S3BootScriptWidthFillUint64) {\r
1414 return EFI_INVALID_PARAMETER;\r
1415 }\r
3a03e95e 1416\r
64d14edf 1417 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
1418 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1419\r
64d14edf 1420 Script = S3BootScriptGetEntryAddAddress (Length);\r
1421 if (Script == NULL) {\r
1422 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1423 }\r
64d14edf 1424 //\r
1425 // Build script data\r
1426 //\r
1427 ScriptPciReadWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;\r
1428 ScriptPciReadWrite2.Length = Length;\r
1429 ScriptPciReadWrite2.Width = Width;\r
1430 ScriptPciReadWrite2.Segment = Segment;\r
1431 ScriptPciReadWrite2.Address = Address;\r
3a03e95e 1432\r
64d14edf 1433 CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));\r
1434 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);\r
1435 CopyMem (\r
1436 (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),\r
1437 DataMask,\r
1438 WidthInByte\r
1439 );\r
3a03e95e 1440\r
02f49fc2 1441 SyncBootScript (Script);\r
64d14edf 1442\r
1443 return RETURN_SUCCESS;\r
1444}\r
2a956f74
SZ
1445\r
1446/**\r
1447 Checks the parameter of S3BootScriptSaveSmbusExecute().\r
1448\r
1449 This function checks the input parameters of SmbusExecute(). If the input parameters are valid\r
1450 for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain\r
1451 error code based on the input SMBus bus protocol.\r
1452\r
3a03e95e 1453 @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,\r
2a956f74
SZ
1454 and PEC.\r
1455 @param Operation Signifies which particular SMBus hardware protocol instance that\r
1456 it will use to execute the SMBus transactions. This SMBus\r
1457 hardware protocol is defined by the SMBus Specification and is\r
1458 not related to EFI.\r
1459 @param Length Signifies the number of bytes that this operation will do. The\r
1460 maximum number of bytes can be revision specific and operation\r
1461 specific. This field will contain the actual number of bytes that\r
1462 are executed for this operation. Not all operations require this\r
1463 argument.\r
1464 @param Buffer Contains the value of data to execute to the SMBus slave device.\r
1465 Not all operations require this argument. The length of this\r
1466 buffer is identified by Length.\r
1467\r
1468 @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus\r
3a03e95e 1469 protocol.\r
2a956f74
SZ
1470 @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
1471 @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
1472 and EfiSmbusQuickWrite. Length is outside the range of valid\r
1473 values.\r
1474 @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
1475 @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
1476\r
1477**/\r
1478EFI_STATUS\r
1479CheckParameters (\r
1480 IN UINTN SmBusAddress,\r
1481 IN EFI_SMBUS_OPERATION Operation,\r
1482 IN OUT UINTN *Length,\r
1483 IN VOID *Buffer\r
1484 )\r
1485{\r
1486 EFI_STATUS Status;\r
1487 UINTN RequiredLen;\r
1488 EFI_SMBUS_DEVICE_COMMAND Command;\r
1489 BOOLEAN PecCheck;\r
3a03e95e 1490\r
2a956f74
SZ
1491 Command = SMBUS_LIB_COMMAND (SmBusAddress);\r
1492 PecCheck = SMBUS_LIB_PEC (SmBusAddress);\r
1493 //\r
1494 // Set default value to be 2:\r
3a03e95e 1495 // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.\r
2a956f74
SZ
1496 //\r
1497 RequiredLen = 2;\r
1498 Status = EFI_SUCCESS;\r
1499 switch (Operation) {\r
1500 case EfiSmbusQuickRead:\r
1501 case EfiSmbusQuickWrite:\r
1502 if (PecCheck || Command != 0) {\r
1503 return EFI_UNSUPPORTED;\r
1504 }\r
1505 break;\r
1506 case EfiSmbusReceiveByte:\r
1507 case EfiSmbusSendByte:\r
1508 if (Command != 0) {\r
1509 return EFI_UNSUPPORTED;\r
1510 }\r
1511 //\r
1512 // Cascade to check length parameter.\r
1513 //\r
1514 case EfiSmbusReadByte:\r
1515 case EfiSmbusWriteByte:\r
1516 RequiredLen = 1;\r
1517 //\r
1518 // Cascade to check length parameter.\r
1519 //\r
1520 case EfiSmbusReadWord:\r
1521 case EfiSmbusWriteWord:\r
1522 case EfiSmbusProcessCall:\r
1523 if (Buffer == NULL || Length == NULL) {\r
1524 return EFI_INVALID_PARAMETER;\r
1525 } else if (*Length < RequiredLen) {\r
1526 Status = EFI_BUFFER_TOO_SMALL;\r
1527 }\r
1528 *Length = RequiredLen;\r
1529 break;\r
1530 case EfiSmbusReadBlock:\r
1531 case EfiSmbusWriteBlock:\r
1532 case EfiSmbusBWBRProcessCall:\r
3a03e95e
SZ
1533 if ((Buffer == NULL) ||\r
1534 (Length == NULL) ||\r
2a956f74
SZ
1535 (*Length < MIN_SMBUS_BLOCK_LEN) ||\r
1536 (*Length > MAX_SMBUS_BLOCK_LEN)) {\r
1537 return EFI_INVALID_PARAMETER;\r
1538 }\r
1539 break;\r
1540 default:\r
1541 return EFI_INVALID_PARAMETER;\r
1542 }\r
1543 return Status;\r
1544}\r
1545\r
64d14edf 1546/**\r
1547 Adds a record for an SMBus command execution into a specified boot script table.\r
1548\r
1549 @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.\r
1550 @param Operation Indicates which particular SMBus protocol it will use to execute the SMBus\r
1551 transactions.\r
1552 @param Length A pointer to signify the number of bytes that this operation will do.\r
1553 @param Buffer Contains the value of data to execute to the SMBUS slave device.\r
3a03e95e 1554\r
64d14edf 1555 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1556 @retval RETURN_SUCCESS Opcode is added.\r
1557**/\r
1558RETURN_STATUS\r
1559EFIAPI\r
1560S3BootScriptSaveSmbusExecute (\r
3a03e95e 1561 IN UINTN SmBusAddress,\r
64d14edf 1562 IN EFI_SMBUS_OPERATION Operation,\r
1563 IN UINTN *Length,\r
1564 IN VOID *Buffer\r
1565 )\r
1566{\r
2a956f74
SZ
1567 EFI_STATUS Status;\r
1568 UINTN BufferLength;\r
64d14edf 1569 UINT8 DataSize;\r
1570 UINT8 *Script;\r
1571 EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute;\r
1572\r
2a956f74
SZ
1573 if (Length == NULL) {\r
1574 BufferLength = 0;\r
1575 } else {\r
1576 BufferLength = *Length;\r
1577 }\r
1578\r
1579 Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);\r
1580 if (EFI_ERROR (Status)) {\r
1581 return Status;\r
1582 }\r
1583\r
322ac05f
HW
1584 //\r
1585 // Truncation check\r
1586 //\r
1587 if (BufferLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)) {\r
1588 return RETURN_OUT_OF_RESOURCES;\r
1589 }\r
2a956f74 1590 DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);\r
3a03e95e 1591\r
64d14edf 1592 Script = S3BootScriptGetEntryAddAddress (DataSize);\r
1593 if (Script == NULL) {\r
1594 return RETURN_OUT_OF_RESOURCES;\r
1595 }\r
1596 //\r
1597 // Build script data\r
1598 //\r
1599 ScriptSmbusExecute.OpCode = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE;\r
1600 ScriptSmbusExecute.Length = DataSize;\r
1601 ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress;\r
1602 ScriptSmbusExecute.Operation = Operation;\r
2a956f74 1603 ScriptSmbusExecute.DataSize = (UINT32) BufferLength;\r
64d14edf 1604\r
1605 CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));\r
1606 CopyMem (\r
1607 (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),\r
1608 Buffer,\r
2a956f74 1609 BufferLength\r
64d14edf 1610 );\r
1611\r
02f49fc2 1612 SyncBootScript (Script);\r
64d14edf 1613\r
1614 return RETURN_SUCCESS;\r
1615}\r
1616/**\r
1617 Adds a record for an execution stall on the processor into a specified boot script table.\r
1618\r
1619 @param Duration Duration in microseconds of the stall\r
3a03e95e 1620\r
64d14edf 1621 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1622 @retval RETURN_SUCCESS Opcode is added.\r
1623**/\r
1624RETURN_STATUS\r
1625EFIAPI\r
1626S3BootScriptSaveStall (\r
1627 IN UINTN Duration\r
1628 )\r
1629{\r
1630 UINT8 Length;\r
1631 UINT8 *Script;\r
1632 EFI_BOOT_SCRIPT_STALL ScriptStall;\r
1633\r
1634 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));\r
3a03e95e 1635\r
64d14edf 1636 Script = S3BootScriptGetEntryAddAddress (Length);\r
1637 if (Script == NULL) {\r
1638 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1639 }\r
64d14edf 1640 //\r
1641 // Build script data\r
1642 //\r
1643 ScriptStall.OpCode = EFI_BOOT_SCRIPT_STALL_OPCODE;\r
1644 ScriptStall.Length = Length;\r
1645 ScriptStall.Duration = Duration;\r
3a03e95e 1646\r
64d14edf 1647 CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));\r
3a03e95e 1648\r
02f49fc2 1649 SyncBootScript (Script);\r
64d14edf 1650\r
1651 return RETURN_SUCCESS;\r
1652}\r
1653/**\r
02f49fc2 1654 Adds a record for dispatching specified arbitrary code into a specified boot script table.\r
64d14edf 1655\r
1656 @param EntryPoint Entry point of the code to be dispatched.\r
1657 @param Context Argument to be passed into the EntryPoint of the code to be dispatched.\r
3a03e95e 1658\r
64d14edf 1659 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1660 @retval RETURN_SUCCESS Opcode is added.\r
1661**/\r
1662RETURN_STATUS\r
1663EFIAPI\r
1664S3BootScriptSaveDispatch2 (\r
1665 IN VOID *EntryPoint,\r
1666 IN VOID *Context\r
1667 )\r
1668{\r
1669 UINT8 Length;\r
1670 UINT8 *Script;\r
1671 EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;\r
1672 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));\r
3a03e95e 1673\r
64d14edf 1674 Script = S3BootScriptGetEntryAddAddress (Length);\r
1675 if (Script == NULL) {\r
1676 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1677 }\r
64d14edf 1678 //\r
1679 // Build script data\r
1680 //\r
1681 ScriptDispatch2.OpCode = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;\r
1682 ScriptDispatch2.Length = Length;\r
1683 ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;\r
1684 ScriptDispatch2.Context = (EFI_PHYSICAL_ADDRESS)(UINTN)Context;\r
3a03e95e 1685\r
64d14edf 1686 CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));\r
3a03e95e 1687\r
02f49fc2 1688 SyncBootScript (Script);\r
64d14edf 1689\r
1690 return RETURN_SUCCESS;\r
1691\r
1692}\r
1693/**\r
1694 Adds a record for memory reads of the memory location and continues when the exit criteria is\r
1695 satisfied or after a defined duration.\r
57a1b9c4
JY
1696\r
1697 Please aware, below interface is different with PI specification, Vol 5:\r
1698 EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.\r
1699 "Duration" below is microseconds, while "Delay" in PI specification means\r
1700 the number of 100ns units to poll.\r
1701\r
64d14edf 1702 @param Width The width of the memory operations.\r
1703 @param Address The base address of the memory operations.\r
1704 @param BitMask A pointer to the bit mask to be AND-ed with the data read from the register.\r
1705 @param BitValue A pointer to the data value after to be Masked.\r
1706 @param Duration Duration in microseconds of the stall.\r
1707 @param LoopTimes The times of the register polling.\r
1708\r
1709 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1710 @retval RETURN_SUCCESS Opcode is added.\r
1711\r
1712**/\r
1713RETURN_STATUS\r
1714EFIAPI\r
1715S3BootScriptSaveMemPoll (\r
1716 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1717 IN UINT64 Address,\r
1718 IN VOID *BitMask,\r
1719 IN VOID *BitValue,\r
1720 IN UINTN Duration,\r
63042a71 1721 IN UINT64 LoopTimes\r
64d14edf 1722 )\r
1723{\r
1724 UINT8 Length;\r
1725 UINT8 *Script;\r
3a03e95e
SZ
1726 UINT8 WidthInByte;\r
1727 EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll;\r
64d14edf 1728\r
1729 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
3a03e95e 1730\r
64d14edf 1731 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));\r
3a03e95e 1732\r
64d14edf 1733 Script = S3BootScriptGetEntryAddAddress (Length);\r
1734 if (Script == NULL) {\r
1735 return RETURN_OUT_OF_RESOURCES;\r
1736 }\r
1737 //\r
1738 // Build script data\r
1739 //\r
1740 ScriptMemPoll.OpCode = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;\r
1741 ScriptMemPoll.Length = Length;\r
3a03e95e 1742 ScriptMemPoll.Width = Width;\r
64d14edf 1743 ScriptMemPoll.Address = Address;\r
1744 ScriptMemPoll.Duration = Duration;\r
1745 ScriptMemPoll.LoopTimes = LoopTimes;\r
1746\r
1747 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);\r
1748 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);\r
3a03e95e 1749 CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL));\r
64d14edf 1750\r
02f49fc2 1751 SyncBootScript (Script);\r
64d14edf 1752\r
1753 return RETURN_SUCCESS;\r
1754}\r
1755/**\r
1756 Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only\r
1757 used for debugging script issues.\r
3a03e95e 1758\r
64d14edf 1759 @param InformationLength Length of the data in bytes\r
1760 @param Information Information to be logged in the boot scrpit\r
3a03e95e 1761\r
64d14edf 1762 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1763 @retval RETURN_SUCCESS Opcode is added.\r
1764\r
1765**/\r
1766RETURN_STATUS\r
1767EFIAPI\r
1768S3BootScriptSaveInformation (\r
3a03e95e 1769 IN UINT32 InformationLength,\r
64d14edf 1770 IN VOID *Information\r
1771 )\r
1772{\r
64d14edf 1773 UINT8 Length;\r
1774 UINT8 *Script;\r
64d14edf 1775 EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;\r
1776\r
322ac05f
HW
1777 //\r
1778 // Truncation check\r
1779 //\r
1780 if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) {\r
1781 return RETURN_OUT_OF_RESOURCES;\r
1782 }\r
93b21ade
SZ
1783 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);\r
1784\r
64d14edf 1785 Script = S3BootScriptGetEntryAddAddress (Length);\r
1786 if (Script == NULL) {\r
1787 return RETURN_OUT_OF_RESOURCES;\r
1788 }\r
1789 //\r
1790 // Build script data\r
1791 //\r
1792 ScriptInformation.OpCode = EFI_BOOT_SCRIPT_INFORMATION_OPCODE;\r
1793 ScriptInformation.Length = Length;\r
1794\r
1795\r
3a03e95e 1796 ScriptInformation.InformationLength = InformationLength;\r
64d14edf 1797\r
93b21ade
SZ
1798 CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
1799 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);\r
1800\r
02f49fc2 1801 SyncBootScript (Script);\r
93b21ade 1802\r
64d14edf 1803 return RETURN_SUCCESS;\r
1804\r
1805}\r
1806/**\r
1807 Store a string in the boot script table. This opcode is a no-op on dispatch and is only\r
1808 used for debugging script issues.\r
3a03e95e 1809\r
64d14edf 1810 @param String The string to save to boot script table\r
3a03e95e 1811\r
64d14edf 1812 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1813 @retval RETURN_SUCCESS Opcode is added.\r
1814\r
1815**/\r
1816RETURN_STATUS\r
1817EFIAPI\r
1818S3BootScriptSaveInformationAsciiString (\r
1819 IN CONST CHAR8 *String\r
1820 )\r
1821{\r
3a03e95e
SZ
1822 return S3BootScriptSaveInformation (\r
1823 (UINT32) AsciiStrLen (String) + 1,\r
64d14edf 1824 (VOID*) String\r
1825 );\r
1826}\r
1827/**\r
1828 Adds a record for dispatching specified arbitrary code into a specified boot script table.\r
1829\r
1830 @param EntryPoint Entry point of the code to be dispatched.\r
3a03e95e 1831\r
64d14edf 1832 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1833 @retval RETURN_SUCCESS Opcode is added.\r
1834**/\r
1835RETURN_STATUS\r
1836EFIAPI\r
1837S3BootScriptSaveDispatch (\r
1838 IN VOID *EntryPoint\r
1839 )\r
1840{\r
1841 UINT8 Length;\r
1842 UINT8 *Script;\r
1843 EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;\r
3a03e95e 1844\r
64d14edf 1845 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));\r
3a03e95e 1846\r
64d14edf 1847 Script = S3BootScriptGetEntryAddAddress (Length);\r
1848 if (Script == NULL) {\r
1849 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1850 }\r
64d14edf 1851 //\r
1852 // Build script data\r
1853 //\r
1854 ScriptDispatch.OpCode = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;\r
1855 ScriptDispatch.Length = Length;\r
1856 ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;\r
3a03e95e
SZ
1857\r
1858 CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH));\r
1859\r
02f49fc2 1860 SyncBootScript (Script);\r
64d14edf 1861\r
1862 return RETURN_SUCCESS;\r
1863\r
1864}\r
1865/**\r
1866 Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a\r
1867 defined duration.\r
3a03e95e
SZ
1868\r
1869 @param Width The width of the I/O operations.\r
64d14edf 1870 @param Address The base address of the I/O operations.\r
1871 @param Data The comparison value used for the polling exit criteria.\r
1872 @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero\r
1873 in Data are ignored when polling the memory address.\r
1874 @param Delay The number of 100ns units to poll. Note that timer available may be of poorer\r
1875 granularity so the delay may be longer.\r
1876\r
1877 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1878 @retval RETURN_SUCCESS Opcode is added.\r
1879\r
1880**/\r
1881RETURN_STATUS\r
1882EFIAPI\r
1883S3BootScriptSaveIoPoll (\r
1884 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1885 IN UINT64 Address,\r
1886 IN VOID *Data,\r
3a03e95e
SZ
1887 IN VOID *DataMask,\r
1888 IN UINT64 Delay\r
64d14edf 1889 )\r
1890{\r
3a03e95e 1891 UINT8 WidthInByte;\r
64d14edf 1892 UINT8 *Script;\r
1893 UINT8 Length;\r
1894 EFI_BOOT_SCRIPT_IO_POLL ScriptIoPoll;\r
64d14edf 1895\r
3a03e95e
SZ
1896\r
1897 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
64d14edf 1898 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));\r
3a03e95e 1899\r
64d14edf 1900 Script = S3BootScriptGetEntryAddAddress (Length);\r
1901 if (Script == NULL) {\r
1902 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1903 }\r
64d14edf 1904 //\r
1905 // Build script data\r
1906 //\r
1907 ScriptIoPoll.OpCode = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;\r
1908 ScriptIoPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));\r
3a03e95e 1909 ScriptIoPoll.Width = Width;\r
64d14edf 1910 ScriptIoPoll.Address = Address;\r
1911 ScriptIoPoll.Delay = Delay;\r
1912\r
3a03e95e 1913 CopyMem ((VOID*)Script, (VOID*)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));\r
64d14edf 1914 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);\r
1915 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);\r
3a03e95e 1916\r
02f49fc2 1917 SyncBootScript (Script);\r
64d14edf 1918\r
1919 return RETURN_SUCCESS;\r
1920}\r
1921\r
1922/**\r
1923 Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or\r
1924 after a defined duration.\r
1925\r
3a03e95e 1926 @param Width The width of the I/O operations.\r
64d14edf 1927 @param Address The address within the PCI configuration space.\r
1928 @param Data The comparison value used for the polling exit criteria.\r
1929 @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero\r
1930 in Data are ignored when polling the memory address\r
1931 @param Delay The number of 100ns units to poll. Note that timer available may be of poorer\r
1932 granularity so the delay may be longer.\r
1933\r
1934 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1935 @retval RETURN_SUCCESS Opcode is added.\r
2a956f74 1936 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
64d14edf 1937\r
1938**/\r
1939RETURN_STATUS\r
1940EFIAPI\r
1941S3BootScriptSavePciPoll (\r
1942 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1943 IN UINT64 Address,\r
1944 IN VOID *Data,\r
1945 IN VOID *DataMask,\r
1946 IN UINT64 Delay\r
1947)\r
1948{\r
1949 UINT8 *Script;\r
3a03e95e 1950 UINT8 WidthInByte;\r
64d14edf 1951 UINT8 Length;\r
1952 EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll;\r
1953\r
2a956f74
SZ
1954 if (Width == S3BootScriptWidthUint64 ||\r
1955 Width == S3BootScriptWidthFifoUint64 ||\r
1956 Width == S3BootScriptWidthFillUint64) {\r
1957 return EFI_INVALID_PARAMETER;\r
1958 }\r
1959\r
64d14edf 1960 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
1961 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));\r
3a03e95e 1962\r
64d14edf 1963 Script = S3BootScriptGetEntryAddAddress (Length);\r
1964 if (Script == NULL) {\r
1965 return RETURN_OUT_OF_RESOURCES;\r
1966 }\r
1967 //\r
1968 // Build script data\r
1969 //\r
1970 ScriptPciPoll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;\r
1971 ScriptPciPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));\r
3a03e95e 1972 ScriptPciPoll.Width = Width;\r
64d14edf 1973 ScriptPciPoll.Address = Address;\r
1974 ScriptPciPoll.Delay = Delay;\r
1975\r
1976 CopyMem ((VOID*)Script, (VOID*)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));\r
1977 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);\r
1978 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);\r
3a03e95e 1979\r
02f49fc2 1980 SyncBootScript (Script);\r
64d14edf 1981\r
1982 return RETURN_SUCCESS;\r
1983}\r
1984/**\r
1985 Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or\r
1986 after a defined duration.\r
1987\r
3a03e95e 1988 @param Width The width of the I/O operations.\r
64d14edf 1989 @param Segment The PCI segment number for Address.\r
1990 @param Address The address within the PCI configuration space.\r
1991 @param Data The comparison value used for the polling exit criteria.\r
1992 @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero\r
1993 in Data are ignored when polling the memory address\r
1994 @param Delay The number of 100ns units to poll. Note that timer available may be of poorer\r
1995 granularity so the delay may be longer.\r
1996\r
1997 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1998 @retval RETURN_SUCCESS Opcode is added.\r
3d20524a 1999 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
2a956f74 2000\r
64d14edf 2001**/\r
2002RETURN_STATUS\r
2003EFIAPI\r
2004S3BootScriptSavePci2Poll (\r
2005 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
2006 IN UINT16 Segment,\r
2007 IN UINT64 Address,\r
2008 IN VOID *Data,\r
2009 IN VOID *DataMask,\r
2010 IN UINT64 Delay\r
2011)\r
2012{\r
3a03e95e 2013 UINT8 WidthInByte;\r
64d14edf 2014 UINT8 *Script;\r
2015 UINT8 Length;\r
2016 EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll;\r
2a956f74 2017\r
3d20524a 2018 if (Width == S3BootScriptWidthUint64 ||\r
2a956f74
SZ
2019 Width == S3BootScriptWidthFifoUint64 ||\r
2020 Width == S3BootScriptWidthFillUint64) {\r
2021 return EFI_INVALID_PARAMETER;\r
2022 }\r
2023\r
64d14edf 2024 WidthInByte = (UINT8) (0x01 << (Width & 0x03));\r
2025 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));\r
3a03e95e 2026\r
64d14edf 2027 Script = S3BootScriptGetEntryAddAddress (Length);\r
2028 if (Script == NULL) {\r
2029 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 2030 }\r
64d14edf 2031 //\r
2032 // Build script data\r
2033 //\r
2034 ScriptPci2Poll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE;\r
2035 ScriptPci2Poll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));\r
3a03e95e 2036 ScriptPci2Poll.Width = Width;\r
64d14edf 2037 ScriptPci2Poll.Segment = Segment;\r
2038 ScriptPci2Poll.Address = Address;\r
2039 ScriptPci2Poll.Delay = Delay;\r
2040\r
2041 CopyMem ((VOID*)Script, (VOID*)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));\r
2042 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);\r
2043 CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);\r
3a03e95e 2044\r
02f49fc2 2045 SyncBootScript (Script);\r
64d14edf 2046\r
2047 return RETURN_SUCCESS;\r
2048}\r
2049/**\r
2050 Do the calculation of start address from which a new s3 boot script entry will write into.\r
3a03e95e 2051\r
64d14edf 2052 @param EntryLength The new entry length.\r
2053 @param Position specifies the position in the boot script table where the opcode will be\r
3a03e95e 2054 inserted, either before or after, depending on BeforeOrAfter.\r
64d14edf 2055 @param BeforeOrAfter The flag to indicate to insert the nod before or after the position.\r
2056 This parameter is effective when InsertFlag is TRUE\r
2057 @param Script return out the position from which the a new s3 boot script entry will write into\r
2058**/\r
2059VOID\r
2060S3BootScriptCalculateInsertAddress (\r
2061 IN UINT8 EntryLength,\r
2062 IN VOID *Position OPTIONAL,\r
2063 IN BOOLEAN BeforeOrAfter OPTIONAL,\r
3a03e95e 2064 OUT UINT8 **Script\r
64d14edf 2065 )\r
2066{\r
2067 UINTN TableLength;\r
2068 UINT8 *S3TableBase;\r
3a03e95e 2069 UINTN PositionOffset;\r
64d14edf 2070 EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
2071 //\r
2072 // The entry inserting to table is already added to the end of the table\r
2073 //\r
2074 TableLength = mS3BootScriptTablePtr->TableLength - EntryLength;\r
2075 S3TableBase = mS3BootScriptTablePtr->TableBase ;\r
3a03e95e 2076 //\r
64d14edf 2077 // calculate the Position offset\r
2078 //\r
2079 if (Position != NULL) {\r
809e2bbf 2080 PositionOffset = (UINTN)Position - (UINTN)S3TableBase;\r
3a03e95e 2081\r
64d14edf 2082 //\r
2083 // If the BeforeOrAfter is FALSE, that means to insert the node right after the node.\r
2084 //\r
2085 if (!BeforeOrAfter) {\r
3a03e95e 2086 CopyMem ((VOID*)&ScriptHeader, Position, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));\r
64d14edf 2087 PositionOffset += (ScriptHeader.Length);\r
2088 }\r
3a03e95e 2089 //\r
64d14edf 2090 // Insert the node before the adjusted Position\r
2091 //\r
3a03e95e 2092 CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);\r
64d14edf 2093 //\r
3a03e95e 2094 // calculate the the start address for the new entry.\r
64d14edf 2095 //\r
2096 *Script = S3TableBase + PositionOffset;\r
3a03e95e 2097\r
64d14edf 2098 } else {\r
2099 if (!BeforeOrAfter) {\r
2100 //\r
2101 // Insert the node to the end of the table\r
2102 //\r
3a03e95e 2103 *Script = S3TableBase + TableLength;\r
64d14edf 2104 } else {\r
3a03e95e 2105 //\r
64d14edf 2106 // Insert the node to the beginning of the table\r
2107 //\r
2108 PositionOffset = (UINTN) sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);\r
3a03e95e
SZ
2109 CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);\r
2110 *Script = S3TableBase + PositionOffset;\r
64d14edf 2111 }\r
3a03e95e 2112 }\r
64d14edf 2113}\r
2114/**\r
3a03e95e 2115 Move the last boot script entry to the position\r
64d14edf 2116\r
2117 @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position\r
2118 in the boot script table specified by Position. If Position is NULL or points to\r
2119 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end\r
2120 of the table (if FALSE).\r
2121 @param Position On entry, specifies the position in the boot script table where the opcode will be\r
2122 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies\r
2123 the position of the inserted opcode in the boot script table.\r
2124\r
2125 @retval RETURN_OUT_OF_RESOURCES The table is not available.\r
2126 @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.\r
2127 @retval RETURN_SUCCESS Opcode is inserted.\r
2128**/\r
2129RETURN_STATUS\r
2130EFIAPI\r
2131S3BootScriptMoveLastOpcode (\r
2132 IN BOOLEAN BeforeOrAfter,\r
2133 IN OUT VOID **Position OPTIONAL\r
2134)\r
2135{\r
2136 UINT8* Script;\r
3a03e95e 2137 VOID *TempPosition;\r
64d14edf 2138 UINTN StartAddress;\r
2139 UINT32 TableLength;\r
2140 EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
2141 BOOLEAN ValidatePosition;\r
2142 UINT8* LastOpcode;\r
2143 UINT8 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];\r
3a03e95e 2144\r
64d14edf 2145 ValidatePosition = FALSE;\r
2146 TempPosition = (Position == NULL) ? NULL:(*Position);\r
02f49fc2
SZ
2147\r
2148 //\r
2149 // Check that the script is initialized and synced without adding an entry to the script.\r
2150 //\r
2151 Script = S3BootScriptGetEntryAddAddress (0);\r
2152 if (Script == NULL) {\r
2153 return RETURN_OUT_OF_RESOURCES;\r
64d14edf 2154 }\r
02f49fc2
SZ
2155 Script = mS3BootScriptTablePtr->TableBase;\r
2156\r
64d14edf 2157 StartAddress = (UINTN) Script;\r
2158 TableLength = mS3BootScriptTablePtr->TableLength;\r
2159 Script = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);\r
2160 LastOpcode = Script;\r
2161 //\r
2162 // Find the last boot Script Entry which is not the terminate node\r
2163 //\r
3a03e95e
SZ
2164 while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {\r
2165 CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));\r
64d14edf 2166 if (TempPosition != NULL && TempPosition == Script) {\r
2167 //\r
3a03e95e 2168 // If the position is specified, the position must be pointed to a boot script entry start address.\r
64d14edf 2169 //\r
2170 ValidatePosition = TRUE;\r
2171 }\r
2172 if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {\r
2173 LastOpcode = Script;\r
3a03e95e 2174 }\r
64d14edf 2175 Script = Script + ScriptHeader.Length;\r
2176 }\r
2177 //\r
2178 // If the position is specified, but not the start of a boot script entry, it is a invalid input\r
2179 //\r
2180 if (TempPosition != NULL && !ValidatePosition) {\r
2181 return RETURN_INVALID_PARAMETER;\r
2182 }\r
3a03e95e
SZ
2183\r
2184 CopyMem ((VOID*)&ScriptHeader, LastOpcode, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));\r
2185\r
2186 CopyMem((VOID*)TempBootScriptEntry, LastOpcode, ScriptHeader.Length);\r
64d14edf 2187 //\r
2188 // Find the right position to write the node in\r
2189 //\r
2190 S3BootScriptCalculateInsertAddress (\r
2191 ScriptHeader.Length,\r
2192 TempPosition,\r
2193 BeforeOrAfter,\r
3a03e95e 2194 &Script\r
64d14edf 2195 );\r
2196 //\r
2197 // Copy the node to Boot script table\r
2198 //\r
02f49fc2
SZ
2199 CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length);\r
2200\r
2201 SyncBootScript (Script);\r
2202\r
64d14edf 2203 //\r
2204 // return out the Position\r
2205 //\r
2206 if (Position != NULL) {\r
2207 *Position = Script;\r
2208 }\r
2209 return RETURN_SUCCESS;\r
2210}\r
2211/**\r
3a03e95e
SZ
2212 Create a Label node in the boot script table.\r
2213\r
64d14edf 2214 @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position\r
2215 in the boot script table specified by Position. If Position is NULL or points to\r
2216 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end\r
2217 of the table (if FALSE).\r
2218 @param Position On entry, specifies the position in the boot script table where the opcode will be\r
2219 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies\r
3a03e95e 2220 the position of the inserted opcode in the boot script table.\r
64d14edf 2221 @param InformationLength Length of the label in bytes\r
2222 @param Information Label to be logged in the boot scrpit\r
3a03e95e 2223\r
64d14edf 2224 @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.\r
2225 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
2226 @retval RETURN_SUCCESS Opcode is added.\r
2227\r
2228**/\r
2229RETURN_STATUS\r
2230EFIAPI\r
2231S3BootScriptLabelInternal (\r
2232 IN BOOLEAN BeforeOrAfter,\r
3a03e95e
SZ
2233 IN OUT VOID **Position OPTIONAL,\r
2234 IN UINT32 InformationLength,\r
64d14edf 2235 IN CONST CHAR8 *Information\r
2236 )\r
2237{\r
2238 UINT8 Length;\r
2239 UINT8 *Script;\r
64d14edf 2240 EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;\r
3a03e95e 2241\r
322ac05f
HW
2242 //\r
2243 // Truncation check\r
2244 //\r
2245 if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) {\r
2246 return RETURN_OUT_OF_RESOURCES;\r
2247 }\r
64d14edf 2248 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);\r
3a03e95e 2249\r
64d14edf 2250 Script = S3BootScriptGetEntryAddAddress (Length);\r
2251 if (Script == NULL) {\r
2252 return RETURN_OUT_OF_RESOURCES;\r
2253 }\r
64d14edf 2254 //\r
2255 // Build script data\r
2256 //\r
2257 ScriptInformation.OpCode = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE;\r
2258 ScriptInformation.Length = Length;\r
2259\r
2260\r
3a03e95e 2261 ScriptInformation.InformationLength = InformationLength;\r
64d14edf 2262\r
93b21ade
SZ
2263 CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
2264 CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);\r
2265\r
02f49fc2
SZ
2266 SyncBootScript (Script);\r
2267\r
64d14edf 2268 return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);\r
2269\r
2270}\r
2271/**\r
2272 Find a label within the boot script table and, if not present, optionally create it.\r
2273\r
2274 @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE)\r
3a03e95e 2275 or after (FALSE) the position in the boot script table\r
64d14edf 2276 specified by Position.\r
3a03e95e 2277 @param CreateIfNotFound Specifies whether the label will be created if the label\r
64d14edf 2278 does not exists (TRUE) or not (FALSE).\r
2279 @param Position On entry, specifies the position in the boot script table\r
2280 where the opcode will be inserted, either before or after,\r
2281 depending on BeforeOrAfter. On exit, specifies the position\r
2282 of the inserted opcode in the boot script table.\r
2283 @param Label Points to the label which will be inserted in the boot script table.\r
2284\r
2285 @retval EFI_SUCCESS The operation succeeded. A record was added into the\r
2286 specified script table.\r
2287 @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.\r
3a03e95e 2288 If the opcode is unknow or not supported because of the PCD\r
64d14edf 2289 Feature Flags.\r
2290 @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.\r
2291\r
2292**/\r
2293RETURN_STATUS\r
3a03e95e 2294EFIAPI\r
64d14edf 2295S3BootScriptLabel (\r
2296 IN BOOLEAN BeforeOrAfter,\r
2297 IN BOOLEAN CreateIfNotFound,\r
2298 IN OUT VOID **Position OPTIONAL,\r
2299 IN CONST CHAR8 *Label\r
2300 )\r
2301{\r
2302 UINT8* Script;\r
2303 UINTN StartAddress;\r
2304 UINT32 TableLength;\r
2305 EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
2306 EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;\r
2307 UINT32 LabelLength;\r
2308 //\r
96072947 2309 // Check NULL Label\r
64d14edf 2310 //\r
96072947
JY
2311 if (Label == NULL) {\r
2312 return EFI_INVALID_PARAMETER;\r
2313 }\r
2314 //\r
2315 // Check empty Label\r
2316 //\r
2317 if (Label[0] == '\0') {\r
64d14edf 2318 return EFI_INVALID_PARAMETER;\r
2319 }\r
3a03e95e 2320\r
64d14edf 2321 //\r
02f49fc2
SZ
2322 // Check that the script is initialized and synced without adding an entry to the script.\r
2323 // The code must search for the label first before it knows if a new entry needs\r
64d14edf 2324 // to be added.\r
2325 //\r
2326 Script = S3BootScriptGetEntryAddAddress (0);\r
2327 if (Script == NULL) {\r
2328 return RETURN_OUT_OF_RESOURCES;\r
2329 }\r
3a03e95e 2330\r
64d14edf 2331 //\r
2332 // Check the header and search for existing label.\r
3a03e95e 2333 //\r
64d14edf 2334 Script = mS3BootScriptTablePtr->TableBase;\r
2335 CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));\r
2336 if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {\r
2337 return EFI_INVALID_PARAMETER;\r
2338 }\r
2339 StartAddress = (UINTN) Script;\r
2340 TableLength = mS3BootScriptTablePtr->TableLength;\r
2341 Script = Script + TableHeader.Length;\r
2342 while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {\r
3a03e95e
SZ
2343\r
2344 CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));\r
64d14edf 2345 if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {\r
2346 if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof(EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {\r
3a03e95e 2347 (*Position) = Script;\r
64d14edf 2348 return EFI_SUCCESS;\r
2349 }\r
3a03e95e 2350 }\r
64d14edf 2351 Script = Script + ScriptHeader.Length;\r
2352 }\r
2353 if (CreateIfNotFound) {\r
2354 LabelLength = (UINT32)AsciiStrSize(Label);\r
3a03e95e 2355 return S3BootScriptLabelInternal (BeforeOrAfter,Position, LabelLength, Label);\r
64d14edf 2356 } else {\r
2357 return EFI_NOT_FOUND;\r
3a03e95e 2358 }\r
64d14edf 2359}\r
2360\r
2361/**\r
2362 Compare two positions in the boot script table and return their relative position.\r
2363 @param Position1 The positions in the boot script table to compare\r
2364 @param Position2 The positions in the boot script table to compare\r
2365 @param RelativePosition On return, points to the result of the comparison\r
2366\r
2367 @retval EFI_SUCCESS The operation succeeded. A record was added into the\r
2368 specified script table.\r
2369 @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.\r
3a03e95e 2370 If the opcode is unknow or not supported because of the PCD\r
64d14edf 2371 Feature Flags.\r
2372 @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.\r
2373\r
2374**/\r
2375RETURN_STATUS\r
3a03e95e 2376EFIAPI\r
64d14edf 2377S3BootScriptCompare (\r
2378 IN UINT8 *Position1,\r
2379 IN UINT8 *Position2,\r
2380 OUT UINTN *RelativePosition\r
2381 )\r
2382{\r
2383 UINT8* Script;\r
3a03e95e 2384 UINT32 TableLength;\r
64d14edf 2385\r
64d14edf 2386 if (RelativePosition == NULL) {\r
2387 return EFI_INVALID_PARAMETER;\r
2388 }\r
02f49fc2
SZ
2389\r
2390 //\r
2391 // Check that the script is initialized and synced without adding an entry to the script.\r
2392 //\r
2393 Script = S3BootScriptGetEntryAddAddress (0);\r
2394 if (Script == NULL) {\r
2395 return RETURN_OUT_OF_RESOURCES;\r
2396 }\r
2397 Script = mS3BootScriptTablePtr->TableBase;\r
2398\r
64d14edf 2399 //\r
879dbe18 2400 // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up\r
64d14edf 2401 //\r
879dbe18 2402 TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);\r
64d14edf 2403 if (Position1 < Script || Position1 > Script+TableLength) {\r
2404 return EFI_INVALID_PARAMETER;\r
2405 }\r
2406 if (Position2 < Script || Position2 > Script+TableLength) {\r
2407 return EFI_INVALID_PARAMETER;\r
2408 }\r
2409 *RelativePosition = (Position1 < Position2)?-1:((Position1 == Position2)?0:1);\r
3a03e95e 2410\r
64d14edf 2411 return EFI_SUCCESS;\r
2412}\r