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