]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
MdeModulePkg: Apply uncrustify changes
[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
1007 @retval RETURN_SUCCESS Opcode is added.\r
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
1436aea4 1024 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
322ac05f
HW
1025\r
1026 //\r
1027 // Truncation check\r
1028 //\r
1029 if ((Count > MAX_UINT8) ||\r
1436aea4
MK
1030 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_IO_WRITE)))\r
1031 {\r
322ac05f
HW
1032 return RETURN_OUT_OF_RESOURCES;\r
1033 }\r
1436aea4 1034\r
64d14edf 1035 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count));\r
3a03e95e 1036\r
64d14edf 1037 Script = S3BootScriptGetEntryAddAddress (Length);\r
1038 if (Script == NULL) {\r
1039 return RETURN_OUT_OF_RESOURCES;\r
1040 }\r
1436aea4 1041\r
64d14edf 1042 //\r
1043 // save script data\r
1044 //\r
1045 ScriptIoWrite.OpCode = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE;\r
1046 ScriptIoWrite.Length = Length;\r
1047 ScriptIoWrite.Width = Width;\r
1048 ScriptIoWrite.Address = Address;\r
1436aea4
MK
1049 ScriptIoWrite.Count = (UINT32)Count;\r
1050 CopyMem ((VOID *)Script, (VOID *)&ScriptIoWrite, sizeof (EFI_BOOT_SCRIPT_IO_WRITE));\r
1051 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);\r
64d14edf 1052\r
02f49fc2 1053 SyncBootScript (Script);\r
64d14edf 1054\r
1055 return RETURN_SUCCESS;\r
1056}\r
1057\r
1058/**\r
1059 Adds a record for an I/O modify operation into a S3 boot script table\r
1060\r
1061 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1062 @param Address The base address of the I/O operations.\r
1063 @param Data A pointer to the data to be OR-ed.\r
1064 @param DataMask A pointer to the data mask to be AND-ed with the data read from the register\r
1065\r
1066 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1067 @retval RETURN_SUCCESS Opcode is added.\r
1068**/\r
1069RETURN_STATUS\r
1070EFIAPI\r
1071S3BootScriptSaveIoReadWrite (\r
1436aea4
MK
1072 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1073 IN UINT64 Address,\r
1074 IN VOID *Data,\r
1075 IN VOID *DataMask\r
64d14edf 1076 )\r
1077{\r
1436aea4
MK
1078 UINT8 Length;\r
1079 UINT8 *Script;\r
1080 UINT8 WidthInByte;\r
64d14edf 1081 EFI_BOOT_SCRIPT_IO_READ_WRITE ScriptIoReadWrite;\r
1082\r
1436aea4
MK
1083 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
1084 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1085\r
64d14edf 1086 Script = S3BootScriptGetEntryAddAddress (Length);\r
1087 if (Script == NULL) {\r
1088 return RETURN_OUT_OF_RESOURCES;\r
1089 }\r
1436aea4 1090\r
64d14edf 1091 //\r
1092 // Build script data\r
1093 //\r
1094 ScriptIoReadWrite.OpCode = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;\r
1095 ScriptIoReadWrite.Length = Length;\r
1096 ScriptIoReadWrite.Width = Width;\r
1097 ScriptIoReadWrite.Address = Address;\r
3a03e95e 1098\r
1436aea4
MK
1099 CopyMem ((VOID *)Script, (VOID *)&ScriptIoReadWrite, sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE));\r
1100 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);\r
1101 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);\r
64d14edf 1102\r
02f49fc2 1103 SyncBootScript (Script);\r
64d14edf 1104\r
1105 return RETURN_SUCCESS;\r
1106}\r
1436aea4 1107\r
64d14edf 1108/**\r
1109 Adds a record for a memory write operation into a specified boot script table.\r
1110\r
1111 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1112 @param Address The base address of the memory operations\r
1113 @param Count The number of memory operations to perform.\r
1114 @param Buffer The source buffer from which to write the data.\r
1115\r
1116 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1117 @retval RETURN_SUCCESS Opcode is added.\r
1118**/\r
1119RETURN_STATUS\r
1120EFIAPI\r
1121S3BootScriptSaveMemWrite (\r
1436aea4
MK
1122 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1123 IN UINT64 Address,\r
1124 IN UINTN Count,\r
1125 IN VOID *Buffer\r
64d14edf 1126 )\r
1127{\r
1436aea4
MK
1128 UINT8 Length;\r
1129 UINT8 *Script;\r
1130 UINT8 WidthInByte;\r
64d14edf 1131 EFI_BOOT_SCRIPT_MEM_WRITE ScriptMemWrite;\r
3a03e95e 1132\r
1436aea4 1133 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
322ac05f
HW
1134\r
1135 //\r
1136 // Truncation check\r
1137 //\r
1138 if ((Count > MAX_UINT8) ||\r
1436aea4
MK
1139 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)))\r
1140 {\r
322ac05f
HW
1141 return RETURN_OUT_OF_RESOURCES;\r
1142 }\r
1436aea4 1143\r
64d14edf 1144 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count));\r
3a03e95e 1145\r
64d14edf 1146 Script = S3BootScriptGetEntryAddAddress (Length);\r
1147 if (Script == NULL) {\r
1148 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1149 }\r
1436aea4 1150\r
64d14edf 1151 //\r
1152 // Build script data\r
1153 //\r
1436aea4
MK
1154 ScriptMemWrite.OpCode = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE;\r
1155 ScriptMemWrite.Length = Length;\r
1156 ScriptMemWrite.Width = Width;\r
1157 ScriptMemWrite.Address = Address;\r
1158 ScriptMemWrite.Count = (UINT32)Count;\r
3a03e95e 1159\r
1436aea4
MK
1160 CopyMem ((VOID *)Script, (VOID *)&ScriptMemWrite, sizeof (EFI_BOOT_SCRIPT_MEM_WRITE));\r
1161 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);\r
3a03e95e 1162\r
02f49fc2 1163 SyncBootScript (Script);\r
64d14edf 1164\r
1165 return RETURN_SUCCESS;\r
1166}\r
1436aea4 1167\r
64d14edf 1168/**\r
1169 Adds a record for a memory modify operation into a specified boot script table.\r
1170\r
1171 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1172 @param Address The base address of the memory operations. Address needs alignment if required\r
1173 @param Data A pointer to the data to be OR-ed.\r
1174 @param DataMask A pointer to the data mask to be AND-ed with the data read from the register.\r
1175\r
1176 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1177 @retval RETURN_SUCCESS Opcode is added.\r
1178**/\r
1179RETURN_STATUS\r
1180EFIAPI\r
1181S3BootScriptSaveMemReadWrite (\r
1436aea4
MK
1182 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1183 IN UINT64 Address,\r
1184 IN VOID *Data,\r
1185 IN VOID *DataMask\r
64d14edf 1186 )\r
1187{\r
1436aea4
MK
1188 UINT8 Length;\r
1189 UINT8 *Script;\r
1190 UINT8 WidthInByte;\r
64d14edf 1191 EFI_BOOT_SCRIPT_MEM_READ_WRITE ScriptMemReadWrite;\r
3a03e95e 1192\r
1436aea4
MK
1193 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
1194 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1195\r
64d14edf 1196 Script = S3BootScriptGetEntryAddAddress (Length);\r
1197 if (Script == NULL) {\r
1198 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1199 }\r
1436aea4 1200\r
64d14edf 1201 //\r
1202 // Build script data\r
3a03e95e 1203 //\r
1436aea4
MK
1204 ScriptMemReadWrite.OpCode = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;\r
1205 ScriptMemReadWrite.Length = Length;\r
1206 ScriptMemReadWrite.Width = Width;\r
1207 ScriptMemReadWrite.Address = Address;\r
3a03e95e 1208\r
1436aea4
MK
1209 CopyMem ((VOID *)Script, (VOID *)&ScriptMemReadWrite, sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));\r
1210 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);\r
1211 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);\r
64d14edf 1212\r
02f49fc2 1213 SyncBootScript (Script);\r
64d14edf 1214\r
1215 return RETURN_SUCCESS;\r
1216}\r
1436aea4 1217\r
64d14edf 1218/**\r
1219 Adds a record for a PCI configuration space write operation into a specified boot script table.\r
1220\r
1221 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1222 @param Address The address within the PCI configuration space.\r
1223 @param Count The number of PCI operations to perform.\r
1224 @param Buffer The source buffer from which to write the data.\r
1225\r
1226 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1227 @retval RETURN_SUCCESS Opcode is added.\r
2a956f74
SZ
1228 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
1229\r
64d14edf 1230**/\r
1231RETURN_STATUS\r
1232EFIAPI\r
1233S3BootScriptSavePciCfgWrite (\r
1436aea4
MK
1234 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1235 IN UINT64 Address,\r
1236 IN UINTN Count,\r
1237 IN VOID *Buffer\r
64d14edf 1238 )\r
1239{\r
1436aea4
MK
1240 UINT8 Length;\r
1241 UINT8 *Script;\r
1242 UINT8 WidthInByte;\r
64d14edf 1243 EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite;\r
1244\r
1436aea4
MK
1245 if ((Width == S3BootScriptWidthUint64) ||\r
1246 (Width == S3BootScriptWidthFifoUint64) ||\r
1247 (Width == S3BootScriptWidthFillUint64))\r
1248 {\r
2a956f74
SZ
1249 return EFI_INVALID_PARAMETER;\r
1250 }\r
1251\r
1436aea4 1252 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
322ac05f
HW
1253\r
1254 //\r
1255 // Truncation check\r
1256 //\r
1257 if ((Count > MAX_UINT8) ||\r
1436aea4
MK
1258 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)))\r
1259 {\r
322ac05f
HW
1260 return RETURN_OUT_OF_RESOURCES;\r
1261 }\r
1436aea4 1262\r
64d14edf 1263 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));\r
3a03e95e 1264\r
64d14edf 1265 Script = S3BootScriptGetEntryAddAddress (Length);\r
1266 if (Script == NULL) {\r
1267 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1268 }\r
1436aea4 1269\r
64d14edf 1270 //\r
1271 // Build script data\r
1272 //\r
1436aea4
MK
1273 ScriptPciWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE;\r
1274 ScriptPciWrite.Length = Length;\r
1275 ScriptPciWrite.Width = Width;\r
1276 ScriptPciWrite.Address = Address;\r
1277 ScriptPciWrite.Count = (UINT32)Count;\r
3a03e95e 1278\r
1436aea4
MK
1279 CopyMem ((VOID *)Script, (VOID *)&ScriptPciWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));\r
1280 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);\r
3a03e95e 1281\r
02f49fc2 1282 SyncBootScript (Script);\r
64d14edf 1283\r
1284 return RETURN_SUCCESS;\r
1285}\r
1436aea4 1286\r
64d14edf 1287/**\r
1288 Adds a record for a PCI configuration space modify operation into a specified boot script table.\r
1289\r
1290 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1291 @param Address The address within the PCI configuration space.\r
1292 @param Data A pointer to the data to be OR-ed.The size depends on Width.\r
1293 @param DataMask A pointer to the data mask to be AND-ed.\r
1294\r
1295 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1296 @retval RETURN__SUCCESS Opcode is added.\r
2a956f74
SZ
1297 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
1298\r
64d14edf 1299**/\r
1300RETURN_STATUS\r
1301EFIAPI\r
1302S3BootScriptSavePciCfgReadWrite (\r
1436aea4
MK
1303 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1304 IN UINT64 Address,\r
1305 IN VOID *Data,\r
1306 IN VOID *DataMask\r
64d14edf 1307 )\r
1308{\r
1436aea4
MK
1309 UINT8 Length;\r
1310 UINT8 *Script;\r
1311 UINT8 WidthInByte;\r
64d14edf 1312 EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite;\r
1313\r
1436aea4
MK
1314 if ((Width == S3BootScriptWidthUint64) ||\r
1315 (Width == S3BootScriptWidthFifoUint64) ||\r
1316 (Width == S3BootScriptWidthFillUint64))\r
1317 {\r
2a956f74
SZ
1318 return EFI_INVALID_PARAMETER;\r
1319 }\r
1320\r
1436aea4
MK
1321 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
1322 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1323\r
64d14edf 1324 Script = S3BootScriptGetEntryAddAddress (Length);\r
1325 if (Script == NULL) {\r
1326 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1327 }\r
1436aea4 1328\r
64d14edf 1329 //\r
1330 // Build script data\r
3a03e95e 1331 //\r
1436aea4
MK
1332 ScriptPciReadWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;\r
1333 ScriptPciReadWrite.Length = Length;\r
1334 ScriptPciReadWrite.Width = Width;\r
1335 ScriptPciReadWrite.Address = Address;\r
3a03e95e 1336\r
1436aea4
MK
1337 CopyMem ((VOID *)Script, (VOID *)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));\r
1338 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);\r
64d14edf 1339 CopyMem (\r
1436aea4 1340 (VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),\r
64d14edf 1341 DataMask,\r
1342 WidthInByte\r
1343 );\r
1344\r
02f49fc2 1345 SyncBootScript (Script);\r
64d14edf 1346\r
1347 return RETURN_SUCCESS;\r
1348}\r
1436aea4 1349\r
64d14edf 1350/**\r
02f49fc2 1351 Adds a record for a PCI configuration 2 space write operation into a specified boot script table.\r
64d14edf 1352\r
1353 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1354 @param Segment The PCI segment number for Address.\r
1355 @param Address The address within the PCI configuration space.\r
1356 @param Count The number of PCI operations to perform.\r
1357 @param Buffer The source buffer from which to write the data.\r
1358\r
1359 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1360 @retval RETURN_SUCCESS Opcode is added.\r
3d20524a 1361 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
2a956f74 1362\r
64d14edf 1363**/\r
1364RETURN_STATUS\r
1365EFIAPI\r
1366S3BootScriptSavePciCfg2Write (\r
1436aea4
MK
1367 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1368 IN UINT16 Segment,\r
1369 IN UINT64 Address,\r
1370 IN UINTN Count,\r
1371 IN VOID *Buffer\r
64d14edf 1372 )\r
1373{\r
1436aea4
MK
1374 UINT8 Length;\r
1375 UINT8 *Script;\r
1376 UINT8 WidthInByte;\r
64d14edf 1377 EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2;\r
2a956f74 1378\r
1436aea4
MK
1379 if ((Width == S3BootScriptWidthUint64) ||\r
1380 (Width == S3BootScriptWidthFifoUint64) ||\r
1381 (Width == S3BootScriptWidthFillUint64))\r
1382 {\r
2a956f74
SZ
1383 return EFI_INVALID_PARAMETER;\r
1384 }\r
1385\r
1436aea4 1386 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
322ac05f
HW
1387\r
1388 //\r
1389 // Truncation check\r
1390 //\r
1391 if ((Count > MAX_UINT8) ||\r
1436aea4
MK
1392 (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)))\r
1393 {\r
322ac05f
HW
1394 return RETURN_OUT_OF_RESOURCES;\r
1395 }\r
1436aea4 1396\r
64d14edf 1397 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));\r
3a03e95e 1398\r
64d14edf 1399 Script = S3BootScriptGetEntryAddAddress (Length);\r
1400 if (Script == NULL) {\r
1401 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1402 }\r
1436aea4 1403\r
64d14edf 1404 //\r
1405 // Build script data\r
1406 //\r
1436aea4
MK
1407 ScriptPciWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE;\r
1408 ScriptPciWrite2.Length = Length;\r
1409 ScriptPciWrite2.Width = Width;\r
1410 ScriptPciWrite2.Address = Address;\r
1411 ScriptPciWrite2.Segment = Segment;\r
1412 ScriptPciWrite2.Count = (UINT32)Count;\r
3a03e95e 1413\r
1436aea4
MK
1414 CopyMem ((VOID *)Script, (VOID *)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));\r
1415 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);\r
64d14edf 1416\r
02f49fc2 1417 SyncBootScript (Script);\r
64d14edf 1418\r
1419 return RETURN_SUCCESS;\r
1420}\r
1436aea4 1421\r
64d14edf 1422/**\r
02f49fc2 1423 Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.\r
64d14edf 1424\r
1425 @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.\r
1426 @param Segment The PCI segment number for Address.\r
1427 @param Address The address within the PCI configuration space.\r
1428 @param Data A pointer to the data to be OR-ed. The size depends on Width.\r
1429 @param DataMask A pointer to the data mask to be AND-ed.\r
1430\r
1431 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1432 @retval RETURN_SUCCESS Opcode is added.\r
3d20524a 1433 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
2a956f74 1434\r
64d14edf 1435**/\r
1436RETURN_STATUS\r
1437EFIAPI\r
1438S3BootScriptSavePciCfg2ReadWrite (\r
1436aea4
MK
1439 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1440 IN UINT16 Segment,\r
1441 IN UINT64 Address,\r
1442 IN VOID *Data,\r
1443 IN VOID *DataMask\r
64d14edf 1444 )\r
1445{\r
1436aea4
MK
1446 UINT8 Length;\r
1447 UINT8 *Script;\r
1448 UINT8 WidthInByte;\r
64d14edf 1449 EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2;\r
2a956f74 1450\r
1436aea4
MK
1451 if ((Width == S3BootScriptWidthUint64) ||\r
1452 (Width == S3BootScriptWidthFifoUint64) ||\r
1453 (Width == S3BootScriptWidthFillUint64))\r
1454 {\r
2a956f74
SZ
1455 return EFI_INVALID_PARAMETER;\r
1456 }\r
3a03e95e 1457\r
1436aea4
MK
1458 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
1459 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));\r
3a03e95e 1460\r
64d14edf 1461 Script = S3BootScriptGetEntryAddAddress (Length);\r
1462 if (Script == NULL) {\r
1463 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1464 }\r
1436aea4 1465\r
64d14edf 1466 //\r
1467 // Build script data\r
1468 //\r
1436aea4
MK
1469 ScriptPciReadWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;\r
1470 ScriptPciReadWrite2.Length = Length;\r
1471 ScriptPciReadWrite2.Width = Width;\r
1472 ScriptPciReadWrite2.Segment = Segment;\r
1473 ScriptPciReadWrite2.Address = Address;\r
3a03e95e 1474\r
1436aea4
MK
1475 CopyMem ((VOID *)Script, (VOID *)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));\r
1476 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);\r
64d14edf 1477 CopyMem (\r
1436aea4 1478 (VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),\r
64d14edf 1479 DataMask,\r
1480 WidthInByte\r
1481 );\r
3a03e95e 1482\r
02f49fc2 1483 SyncBootScript (Script);\r
64d14edf 1484\r
1485 return RETURN_SUCCESS;\r
1486}\r
2a956f74
SZ
1487\r
1488/**\r
1489 Checks the parameter of S3BootScriptSaveSmbusExecute().\r
1490\r
1491 This function checks the input parameters of SmbusExecute(). If the input parameters are valid\r
1492 for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain\r
1493 error code based on the input SMBus bus protocol.\r
1494\r
3a03e95e 1495 @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,\r
2a956f74
SZ
1496 and PEC.\r
1497 @param Operation Signifies which particular SMBus hardware protocol instance that\r
1498 it will use to execute the SMBus transactions. This SMBus\r
1499 hardware protocol is defined by the SMBus Specification and is\r
1500 not related to EFI.\r
1501 @param Length Signifies the number of bytes that this operation will do. The\r
1502 maximum number of bytes can be revision specific and operation\r
1503 specific. This field will contain the actual number of bytes that\r
1504 are executed for this operation. Not all operations require this\r
1505 argument.\r
1506 @param Buffer Contains the value of data to execute to the SMBus slave device.\r
1507 Not all operations require this argument. The length of this\r
1508 buffer is identified by Length.\r
1509\r
1510 @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus\r
3a03e95e 1511 protocol.\r
2a956f74
SZ
1512 @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
1513 @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
1514 and EfiSmbusQuickWrite. Length is outside the range of valid\r
1515 values.\r
1516 @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
1517 @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
1518\r
1519**/\r
1520EFI_STATUS\r
1521CheckParameters (\r
1436aea4
MK
1522 IN UINTN SmBusAddress,\r
1523 IN EFI_SMBUS_OPERATION Operation,\r
1524 IN OUT UINTN *Length,\r
1525 IN VOID *Buffer\r
2a956f74
SZ
1526 )\r
1527{\r
1436aea4
MK
1528 EFI_STATUS Status;\r
1529 UINTN RequiredLen;\r
1530 EFI_SMBUS_DEVICE_COMMAND Command;\r
1531 BOOLEAN PecCheck;\r
3a03e95e 1532\r
1436aea4
MK
1533 Command = SMBUS_LIB_COMMAND (SmBusAddress);\r
1534 PecCheck = SMBUS_LIB_PEC (SmBusAddress);\r
2a956f74
SZ
1535 //\r
1536 // Set default value to be 2:\r
3a03e95e 1537 // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.\r
2a956f74
SZ
1538 //\r
1539 RequiredLen = 2;\r
1540 Status = EFI_SUCCESS;\r
1541 switch (Operation) {\r
1542 case EfiSmbusQuickRead:\r
1543 case EfiSmbusQuickWrite:\r
1436aea4 1544 if (PecCheck || (Command != 0)) {\r
2a956f74
SZ
1545 return EFI_UNSUPPORTED;\r
1546 }\r
1436aea4 1547\r
2a956f74
SZ
1548 break;\r
1549 case EfiSmbusReceiveByte:\r
1550 case EfiSmbusSendByte:\r
1551 if (Command != 0) {\r
1552 return EFI_UNSUPPORTED;\r
1553 }\r
1436aea4
MK
1554\r
1555 //\r
1556 // Cascade to check length parameter.\r
1557 //\r
2a956f74
SZ
1558 case EfiSmbusReadByte:\r
1559 case EfiSmbusWriteByte:\r
1560 RequiredLen = 1;\r
1436aea4
MK
1561 //\r
1562 // Cascade to check length parameter.\r
1563 //\r
2a956f74
SZ
1564 case EfiSmbusReadWord:\r
1565 case EfiSmbusWriteWord:\r
1566 case EfiSmbusProcessCall:\r
1436aea4 1567 if ((Buffer == NULL) || (Length == NULL)) {\r
2a956f74
SZ
1568 return EFI_INVALID_PARAMETER;\r
1569 } else if (*Length < RequiredLen) {\r
1570 Status = EFI_BUFFER_TOO_SMALL;\r
1571 }\r
1436aea4 1572\r
2a956f74
SZ
1573 *Length = RequiredLen;\r
1574 break;\r
1575 case EfiSmbusReadBlock:\r
1576 case EfiSmbusWriteBlock:\r
1577 case EfiSmbusBWBRProcessCall:\r
3a03e95e
SZ
1578 if ((Buffer == NULL) ||\r
1579 (Length == NULL) ||\r
2a956f74 1580 (*Length < MIN_SMBUS_BLOCK_LEN) ||\r
1436aea4
MK
1581 (*Length > MAX_SMBUS_BLOCK_LEN))\r
1582 {\r
2a956f74
SZ
1583 return EFI_INVALID_PARAMETER;\r
1584 }\r
1436aea4 1585\r
2a956f74
SZ
1586 break;\r
1587 default:\r
1588 return EFI_INVALID_PARAMETER;\r
1589 }\r
1436aea4 1590\r
2a956f74
SZ
1591 return Status;\r
1592}\r
1593\r
64d14edf 1594/**\r
1595 Adds a record for an SMBus command execution into a specified boot script table.\r
1596\r
1597 @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.\r
1598 @param Operation Indicates which particular SMBus protocol it will use to execute the SMBus\r
1599 transactions.\r
1600 @param Length A pointer to signify the number of bytes that this operation will do.\r
1601 @param Buffer Contains the value of data to execute to the SMBUS slave device.\r
3a03e95e 1602\r
64d14edf 1603 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1604 @retval RETURN_SUCCESS Opcode is added.\r
1605**/\r
1606RETURN_STATUS\r
1607EFIAPI\r
1608S3BootScriptSaveSmbusExecute (\r
1436aea4
MK
1609 IN UINTN SmBusAddress,\r
1610 IN EFI_SMBUS_OPERATION Operation,\r
1611 IN UINTN *Length,\r
1612 IN VOID *Buffer\r
64d14edf 1613 )\r
1614{\r
1436aea4
MK
1615 EFI_STATUS Status;\r
1616 UINTN BufferLength;\r
1617 UINT8 DataSize;\r
1618 UINT8 *Script;\r
64d14edf 1619 EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute;\r
1620\r
2a956f74
SZ
1621 if (Length == NULL) {\r
1622 BufferLength = 0;\r
1623 } else {\r
1624 BufferLength = *Length;\r
1625 }\r
1626\r
1627 Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);\r
1628 if (EFI_ERROR (Status)) {\r
1629 return Status;\r
1630 }\r
1631\r
322ac05f
HW
1632 //\r
1633 // Truncation check\r
1634 //\r
1635 if (BufferLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)) {\r
1636 return RETURN_OUT_OF_RESOURCES;\r
1637 }\r
1436aea4 1638\r
2a956f74 1639 DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);\r
3a03e95e 1640\r
64d14edf 1641 Script = S3BootScriptGetEntryAddAddress (DataSize);\r
1642 if (Script == NULL) {\r
1643 return RETURN_OUT_OF_RESOURCES;\r
1644 }\r
1436aea4 1645\r
64d14edf 1646 //\r
1647 // Build script data\r
1648 //\r
1649 ScriptSmbusExecute.OpCode = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE;\r
1650 ScriptSmbusExecute.Length = DataSize;\r
1436aea4 1651 ScriptSmbusExecute.SmBusAddress = (UINT64)SmBusAddress;\r
64d14edf 1652 ScriptSmbusExecute.Operation = Operation;\r
1436aea4 1653 ScriptSmbusExecute.DataSize = (UINT32)BufferLength;\r
64d14edf 1654\r
1436aea4 1655 CopyMem ((VOID *)Script, (VOID *)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));\r
64d14edf 1656 CopyMem (\r
1436aea4 1657 (VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),\r
64d14edf 1658 Buffer,\r
2a956f74 1659 BufferLength\r
64d14edf 1660 );\r
1661\r
02f49fc2 1662 SyncBootScript (Script);\r
64d14edf 1663\r
1664 return RETURN_SUCCESS;\r
1665}\r
1436aea4 1666\r
64d14edf 1667/**\r
1668 Adds a record for an execution stall on the processor into a specified boot script table.\r
1669\r
1670 @param Duration Duration in microseconds of the stall\r
3a03e95e 1671\r
64d14edf 1672 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1673 @retval RETURN_SUCCESS Opcode is added.\r
1674**/\r
1675RETURN_STATUS\r
1676EFIAPI\r
1677S3BootScriptSaveStall (\r
1436aea4 1678 IN UINTN Duration\r
64d14edf 1679 )\r
1680{\r
1436aea4
MK
1681 UINT8 Length;\r
1682 UINT8 *Script;\r
64d14edf 1683 EFI_BOOT_SCRIPT_STALL ScriptStall;\r
1684\r
1685 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));\r
3a03e95e 1686\r
64d14edf 1687 Script = S3BootScriptGetEntryAddAddress (Length);\r
1688 if (Script == NULL) {\r
1689 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1690 }\r
1436aea4 1691\r
64d14edf 1692 //\r
1693 // Build script data\r
1694 //\r
1436aea4
MK
1695 ScriptStall.OpCode = EFI_BOOT_SCRIPT_STALL_OPCODE;\r
1696 ScriptStall.Length = Length;\r
1697 ScriptStall.Duration = Duration;\r
3a03e95e 1698\r
1436aea4 1699 CopyMem ((VOID *)Script, (VOID *)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));\r
3a03e95e 1700\r
02f49fc2 1701 SyncBootScript (Script);\r
64d14edf 1702\r
1703 return RETURN_SUCCESS;\r
1704}\r
1436aea4 1705\r
64d14edf 1706/**\r
02f49fc2 1707 Adds a record for dispatching specified arbitrary code into a specified boot script table.\r
64d14edf 1708\r
1709 @param EntryPoint Entry point of the code to be dispatched.\r
1710 @param Context Argument to be passed into the EntryPoint of the code to be dispatched.\r
3a03e95e 1711\r
64d14edf 1712 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1713 @retval RETURN_SUCCESS Opcode is added.\r
1714**/\r
1715RETURN_STATUS\r
1716EFIAPI\r
1717S3BootScriptSaveDispatch2 (\r
1436aea4
MK
1718 IN VOID *EntryPoint,\r
1719 IN VOID *Context\r
64d14edf 1720 )\r
1721{\r
1436aea4
MK
1722 UINT8 Length;\r
1723 UINT8 *Script;\r
64d14edf 1724 EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;\r
1436aea4 1725\r
64d14edf 1726 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));\r
3a03e95e 1727\r
64d14edf 1728 Script = S3BootScriptGetEntryAddAddress (Length);\r
1729 if (Script == NULL) {\r
1730 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1731 }\r
1436aea4 1732\r
64d14edf 1733 //\r
1734 // Build script data\r
1735 //\r
1736 ScriptDispatch2.OpCode = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;\r
1737 ScriptDispatch2.Length = Length;\r
1738 ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;\r
1436aea4 1739 ScriptDispatch2.Context = (EFI_PHYSICAL_ADDRESS)(UINTN)Context;\r
3a03e95e 1740\r
1436aea4 1741 CopyMem ((VOID *)Script, (VOID *)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));\r
3a03e95e 1742\r
02f49fc2 1743 SyncBootScript (Script);\r
64d14edf 1744\r
1745 return RETURN_SUCCESS;\r
64d14edf 1746}\r
1436aea4 1747\r
64d14edf 1748/**\r
1749 Adds a record for memory reads of the memory location and continues when the exit criteria is\r
1750 satisfied or after a defined duration.\r
57a1b9c4
JY
1751\r
1752 Please aware, below interface is different with PI specification, Vol 5:\r
1753 EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.\r
1754 "Duration" below is microseconds, while "Delay" in PI specification means\r
1755 the number of 100ns units to poll.\r
1756\r
64d14edf 1757 @param Width The width of the memory operations.\r
1758 @param Address The base address of the memory operations.\r
1759 @param BitMask A pointer to the bit mask to be AND-ed with the data read from the register.\r
1760 @param BitValue A pointer to the data value after to be Masked.\r
1761 @param Duration Duration in microseconds of the stall.\r
1762 @param LoopTimes The times of the register polling.\r
1763\r
1764 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1765 @retval RETURN_SUCCESS Opcode is added.\r
1766\r
1767**/\r
1768RETURN_STATUS\r
1769EFIAPI\r
1770S3BootScriptSaveMemPoll (\r
1436aea4
MK
1771 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1772 IN UINT64 Address,\r
1773 IN VOID *BitMask,\r
1774 IN VOID *BitValue,\r
1775 IN UINTN Duration,\r
1776 IN UINT64 LoopTimes\r
64d14edf 1777 )\r
1778{\r
1436aea4
MK
1779 UINT8 Length;\r
1780 UINT8 *Script;\r
1781 UINT8 WidthInByte;\r
1782 EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll;\r
64d14edf 1783\r
1436aea4 1784 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
3a03e95e 1785\r
64d14edf 1786 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));\r
3a03e95e 1787\r
64d14edf 1788 Script = S3BootScriptGetEntryAddAddress (Length);\r
1789 if (Script == NULL) {\r
1790 return RETURN_OUT_OF_RESOURCES;\r
1791 }\r
1436aea4 1792\r
64d14edf 1793 //\r
1794 // Build script data\r
1795 //\r
1436aea4
MK
1796 ScriptMemPoll.OpCode = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;\r
1797 ScriptMemPoll.Length = Length;\r
1798 ScriptMemPoll.Width = Width;\r
1799 ScriptMemPoll.Address = Address;\r
1800 ScriptMemPoll.Duration = Duration;\r
64d14edf 1801 ScriptMemPoll.LoopTimes = LoopTimes;\r
1802\r
1436aea4
MK
1803 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);\r
1804 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);\r
1805 CopyMem ((VOID *)Script, (VOID *)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL));\r
64d14edf 1806\r
02f49fc2 1807 SyncBootScript (Script);\r
64d14edf 1808\r
1809 return RETURN_SUCCESS;\r
1810}\r
1436aea4 1811\r
64d14edf 1812/**\r
1813 Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only\r
1814 used for debugging script issues.\r
3a03e95e 1815\r
64d14edf 1816 @param InformationLength Length of the data in bytes\r
1817 @param Information Information to be logged in the boot scrpit\r
3a03e95e 1818\r
64d14edf 1819 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1820 @retval RETURN_SUCCESS Opcode is added.\r
1821\r
1822**/\r
1823RETURN_STATUS\r
1824EFIAPI\r
1825S3BootScriptSaveInformation (\r
1436aea4
MK
1826 IN UINT32 InformationLength,\r
1827 IN VOID *Information\r
64d14edf 1828 )\r
1829{\r
1436aea4
MK
1830 UINT8 Length;\r
1831 UINT8 *Script;\r
64d14edf 1832 EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;\r
1833\r
322ac05f
HW
1834 //\r
1835 // Truncation check\r
1836 //\r
1837 if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) {\r
1838 return RETURN_OUT_OF_RESOURCES;\r
1839 }\r
1436aea4 1840\r
93b21ade
SZ
1841 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);\r
1842\r
64d14edf 1843 Script = S3BootScriptGetEntryAddAddress (Length);\r
1844 if (Script == NULL) {\r
1845 return RETURN_OUT_OF_RESOURCES;\r
1846 }\r
1436aea4 1847\r
64d14edf 1848 //\r
1849 // Build script data\r
1850 //\r
1436aea4
MK
1851 ScriptInformation.OpCode = EFI_BOOT_SCRIPT_INFORMATION_OPCODE;\r
1852 ScriptInformation.Length = Length;\r
64d14edf 1853\r
3a03e95e 1854 ScriptInformation.InformationLength = InformationLength;\r
64d14edf 1855\r
1436aea4
MK
1856 CopyMem ((VOID *)Script, (VOID *)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
1857 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *)Information, (UINTN)InformationLength);\r
93b21ade 1858\r
02f49fc2 1859 SyncBootScript (Script);\r
93b21ade 1860\r
64d14edf 1861 return RETURN_SUCCESS;\r
64d14edf 1862}\r
1436aea4 1863\r
64d14edf 1864/**\r
1865 Store a string in the boot script table. This opcode is a no-op on dispatch and is only\r
1866 used for debugging script issues.\r
3a03e95e 1867\r
64d14edf 1868 @param String The string to save to boot script table\r
3a03e95e 1869\r
64d14edf 1870 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1871 @retval RETURN_SUCCESS Opcode is added.\r
1872\r
1873**/\r
1874RETURN_STATUS\r
1875EFIAPI\r
1876S3BootScriptSaveInformationAsciiString (\r
1436aea4 1877 IN CONST CHAR8 *String\r
64d14edf 1878 )\r
1879{\r
3a03e95e 1880 return S3BootScriptSaveInformation (\r
1436aea4
MK
1881 (UINT32)AsciiStrLen (String) + 1,\r
1882 (VOID *)String\r
64d14edf 1883 );\r
1884}\r
1436aea4 1885\r
64d14edf 1886/**\r
1887 Adds a record for dispatching specified arbitrary code into a specified boot script table.\r
1888\r
1889 @param EntryPoint Entry point of the code to be dispatched.\r
3a03e95e 1890\r
64d14edf 1891 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1892 @retval RETURN_SUCCESS Opcode is added.\r
1893**/\r
1894RETURN_STATUS\r
1895EFIAPI\r
1896S3BootScriptSaveDispatch (\r
1436aea4 1897 IN VOID *EntryPoint\r
64d14edf 1898 )\r
1899{\r
1436aea4
MK
1900 UINT8 Length;\r
1901 UINT8 *Script;\r
64d14edf 1902 EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;\r
3a03e95e 1903\r
64d14edf 1904 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));\r
3a03e95e 1905\r
64d14edf 1906 Script = S3BootScriptGetEntryAddAddress (Length);\r
1907 if (Script == NULL) {\r
1908 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1909 }\r
1436aea4 1910\r
64d14edf 1911 //\r
1912 // Build script data\r
1913 //\r
1914 ScriptDispatch.OpCode = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;\r
1915 ScriptDispatch.Length = Length;\r
1916 ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;\r
3a03e95e 1917\r
1436aea4 1918 CopyMem ((VOID *)Script, (VOID *)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH));\r
3a03e95e 1919\r
02f49fc2 1920 SyncBootScript (Script);\r
64d14edf 1921\r
1922 return RETURN_SUCCESS;\r
64d14edf 1923}\r
1436aea4 1924\r
64d14edf 1925/**\r
1926 Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a\r
1927 defined duration.\r
3a03e95e
SZ
1928\r
1929 @param Width The width of the I/O operations.\r
64d14edf 1930 @param Address The base address of the I/O operations.\r
1931 @param Data The comparison value used for the polling exit criteria.\r
1932 @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero\r
1933 in Data are ignored when polling the memory address.\r
1934 @param Delay The number of 100ns units to poll. Note that timer available may be of poorer\r
1935 granularity so the delay may be longer.\r
1936\r
1937 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1938 @retval RETURN_SUCCESS Opcode is added.\r
1939\r
1940**/\r
1941RETURN_STATUS\r
1942EFIAPI\r
1943S3BootScriptSaveIoPoll (\r
1436aea4
MK
1944 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
1945 IN UINT64 Address,\r
64d14edf 1946 IN VOID *Data,\r
3a03e95e 1947 IN VOID *DataMask,\r
1436aea4 1948 IN UINT64 Delay\r
64d14edf 1949 )\r
1950{\r
1436aea4
MK
1951 UINT8 WidthInByte;\r
1952 UINT8 *Script;\r
1953 UINT8 Length;\r
64d14edf 1954 EFI_BOOT_SCRIPT_IO_POLL ScriptIoPoll;\r
64d14edf 1955\r
1436aea4
MK
1956 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
1957 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));\r
3a03e95e 1958\r
64d14edf 1959 Script = S3BootScriptGetEntryAddAddress (Length);\r
1960 if (Script == NULL) {\r
1961 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 1962 }\r
1436aea4 1963\r
64d14edf 1964 //\r
1965 // Build script data\r
1966 //\r
1436aea4
MK
1967 ScriptIoPoll.OpCode = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;\r
1968 ScriptIoPoll.Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));\r
1969 ScriptIoPoll.Width = Width;\r
1970 ScriptIoPoll.Address = Address;\r
1971 ScriptIoPoll.Delay = Delay;\r
64d14edf 1972\r
1436aea4
MK
1973 CopyMem ((VOID *)Script, (VOID *)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));\r
1974 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);\r
1975 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);\r
3a03e95e 1976\r
02f49fc2 1977 SyncBootScript (Script);\r
64d14edf 1978\r
1979 return RETURN_SUCCESS;\r
1980}\r
1981\r
1982/**\r
1983 Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or\r
1984 after a defined duration.\r
1985\r
3a03e95e 1986 @param Width The width of the I/O operations.\r
64d14edf 1987 @param Address The address within the PCI configuration space.\r
1988 @param Data The comparison value used for the polling exit criteria.\r
1989 @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero\r
1990 in Data are ignored when polling the memory address\r
1991 @param Delay The number of 100ns units to poll. Note that timer available may be of poorer\r
1992 granularity so the delay may be longer.\r
1993\r
1994 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
1995 @retval RETURN_SUCCESS Opcode is added.\r
2a956f74 1996 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
64d14edf 1997\r
1998**/\r
1999RETURN_STATUS\r
2000EFIAPI\r
2001S3BootScriptSavePciPoll (\r
1436aea4
MK
2002 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
2003 IN UINT64 Address,\r
2004 IN VOID *Data,\r
2005 IN VOID *DataMask,\r
2006 IN UINT64 Delay\r
2007 )\r
64d14edf 2008{\r
1436aea4
MK
2009 UINT8 *Script;\r
2010 UINT8 WidthInByte;\r
2011 UINT8 Length;\r
64d14edf 2012 EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll;\r
2013\r
1436aea4
MK
2014 if ((Width == S3BootScriptWidthUint64) ||\r
2015 (Width == S3BootScriptWidthFifoUint64) ||\r
2016 (Width == S3BootScriptWidthFillUint64))\r
2017 {\r
2a956f74
SZ
2018 return EFI_INVALID_PARAMETER;\r
2019 }\r
2020\r
1436aea4
MK
2021 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
2022 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));\r
3a03e95e 2023\r
64d14edf 2024 Script = S3BootScriptGetEntryAddAddress (Length);\r
2025 if (Script == NULL) {\r
2026 return RETURN_OUT_OF_RESOURCES;\r
2027 }\r
1436aea4 2028\r
64d14edf 2029 //\r
2030 // Build script data\r
2031 //\r
1436aea4
MK
2032 ScriptPciPoll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;\r
2033 ScriptPciPoll.Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));\r
2034 ScriptPciPoll.Width = Width;\r
2035 ScriptPciPoll.Address = Address;\r
2036 ScriptPciPoll.Delay = Delay;\r
64d14edf 2037\r
1436aea4
MK
2038 CopyMem ((VOID *)Script, (VOID *)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));\r
2039 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);\r
2040 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);\r
3a03e95e 2041\r
02f49fc2 2042 SyncBootScript (Script);\r
64d14edf 2043\r
2044 return RETURN_SUCCESS;\r
2045}\r
1436aea4 2046\r
64d14edf 2047/**\r
2048 Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or\r
2049 after a defined duration.\r
2050\r
3a03e95e 2051 @param Width The width of the I/O operations.\r
64d14edf 2052 @param Segment The PCI segment number for Address.\r
2053 @param Address The address within the PCI configuration space.\r
2054 @param Data The comparison value used for the polling exit criteria.\r
2055 @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero\r
2056 in Data are ignored when polling the memory address\r
2057 @param Delay The number of 100ns units to poll. Note that timer available may be of poorer\r
2058 granularity so the delay may be longer.\r
2059\r
2060 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
2061 @retval RETURN_SUCCESS Opcode is added.\r
3d20524a 2062 @note A known Limitations in the implementation which is 64bits operations are not supported.\r
2a956f74 2063\r
64d14edf 2064**/\r
2065RETURN_STATUS\r
2066EFIAPI\r
2067S3BootScriptSavePci2Poll (\r
1436aea4
MK
2068 IN S3_BOOT_SCRIPT_LIB_WIDTH Width,\r
2069 IN UINT16 Segment,\r
2070 IN UINT64 Address,\r
2071 IN VOID *Data,\r
2072 IN VOID *DataMask,\r
2073 IN UINT64 Delay\r
2074 )\r
64d14edf 2075{\r
1436aea4
MK
2076 UINT8 WidthInByte;\r
2077 UINT8 *Script;\r
2078 UINT8 Length;\r
64d14edf 2079 EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll;\r
2a956f74 2080\r
1436aea4
MK
2081 if ((Width == S3BootScriptWidthUint64) ||\r
2082 (Width == S3BootScriptWidthFifoUint64) ||\r
2083 (Width == S3BootScriptWidthFillUint64))\r
2084 {\r
2a956f74
SZ
2085 return EFI_INVALID_PARAMETER;\r
2086 }\r
2087\r
1436aea4
MK
2088 WidthInByte = (UINT8)(0x01 << (Width & 0x03));\r
2089 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));\r
3a03e95e 2090\r
64d14edf 2091 Script = S3BootScriptGetEntryAddAddress (Length);\r
2092 if (Script == NULL) {\r
2093 return RETURN_OUT_OF_RESOURCES;\r
3a03e95e 2094 }\r
1436aea4 2095\r
64d14edf 2096 //\r
2097 // Build script data\r
2098 //\r
1436aea4
MK
2099 ScriptPci2Poll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE;\r
2100 ScriptPci2Poll.Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));\r
2101 ScriptPci2Poll.Width = Width;\r
2102 ScriptPci2Poll.Segment = Segment;\r
2103 ScriptPci2Poll.Address = Address;\r
2104 ScriptPci2Poll.Delay = Delay;\r
64d14edf 2105\r
1436aea4
MK
2106 CopyMem ((VOID *)Script, (VOID *)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));\r
2107 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);\r
2108 CopyMem ((UINT8 *)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);\r
3a03e95e 2109\r
02f49fc2 2110 SyncBootScript (Script);\r
64d14edf 2111\r
2112 return RETURN_SUCCESS;\r
2113}\r
1436aea4 2114\r
64d14edf 2115/**\r
2116 Do the calculation of start address from which a new s3 boot script entry will write into.\r
3a03e95e 2117\r
64d14edf 2118 @param EntryLength The new entry length.\r
2119 @param Position specifies the position in the boot script table where the opcode will be\r
3a03e95e 2120 inserted, either before or after, depending on BeforeOrAfter.\r
64d14edf 2121 @param BeforeOrAfter The flag to indicate to insert the nod before or after the position.\r
2122 This parameter is effective when InsertFlag is TRUE\r
2123 @param Script return out the position from which the a new s3 boot script entry will write into\r
2124**/\r
2125VOID\r
2126S3BootScriptCalculateInsertAddress (\r
1436aea4 2127 IN UINT8 EntryLength,\r
64d14edf 2128 IN VOID *Position OPTIONAL,\r
1436aea4
MK
2129 IN BOOLEAN BeforeOrAfter OPTIONAL,\r
2130 OUT UINT8 **Script\r
64d14edf 2131 )\r
2132{\r
1436aea4
MK
2133 UINTN TableLength;\r
2134 UINT8 *S3TableBase;\r
2135 UINTN PositionOffset;\r
2136 EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
2137\r
2138 //\r
2139 // The entry inserting to table is already added to the end of the table\r
2140 //\r
2141 TableLength = mS3BootScriptTablePtr->TableLength - EntryLength;\r
2142 S3TableBase = mS3BootScriptTablePtr->TableBase;\r
2143 //\r
2144 // calculate the Position offset\r
2145 //\r
2146 if (Position != NULL) {\r
2147 PositionOffset = (UINTN)Position - (UINTN)S3TableBase;\r
2148\r
2149 //\r
2150 // If the BeforeOrAfter is FALSE, that means to insert the node right after the node.\r
2151 //\r
2152 if (!BeforeOrAfter) {\r
2153 CopyMem ((VOID *)&ScriptHeader, Position, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));\r
2154 PositionOffset += (ScriptHeader.Length);\r
2155 }\r
2156\r
2157 //\r
2158 // Insert the node before the adjusted Position\r
2159 //\r
2160 CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);\r
2161 //\r
2162 // calculate the the start address for the new entry.\r
2163 //\r
2164 *Script = S3TableBase + PositionOffset;\r
2165 } else {\r
2166 if (!BeforeOrAfter) {\r
2167 //\r
2168 // Insert the node to the end of the table\r
2169 //\r
2170 *Script = S3TableBase + TableLength;\r
2171 } else {\r
2172 //\r
2173 // Insert the node to the beginning of the table\r
2174 //\r
2175 PositionOffset = (UINTN)sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
2176 CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);\r
2177 *Script = S3TableBase + PositionOffset;\r
2178 }\r
2179 }\r
64d14edf 2180}\r
1436aea4 2181\r
64d14edf 2182/**\r
3a03e95e 2183 Move the last boot script entry to the position\r
64d14edf 2184\r
2185 @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position\r
2186 in the boot script table specified by Position. If Position is NULL or points to\r
2187 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end\r
2188 of the table (if FALSE).\r
2189 @param Position On entry, specifies the position in the boot script table where the opcode will be\r
2190 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies\r
2191 the position of the inserted opcode in the boot script table.\r
2192\r
2193 @retval RETURN_OUT_OF_RESOURCES The table is not available.\r
2194 @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.\r
2195 @retval RETURN_SUCCESS Opcode is inserted.\r
2196**/\r
2197RETURN_STATUS\r
2198EFIAPI\r
2199S3BootScriptMoveLastOpcode (\r
1436aea4
MK
2200 IN BOOLEAN BeforeOrAfter,\r
2201 IN OUT VOID **Position OPTIONAL\r
2202 )\r
64d14edf 2203{\r
1436aea4
MK
2204 UINT8 *Script;\r
2205 VOID *TempPosition;\r
2206 UINTN StartAddress;\r
2207 UINT32 TableLength;\r
64d14edf 2208 EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
1436aea4
MK
2209 BOOLEAN ValidatePosition;\r
2210 UINT8 *LastOpcode;\r
2211 UINT8 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];\r
3a03e95e 2212\r
64d14edf 2213 ValidatePosition = FALSE;\r
1436aea4 2214 TempPosition = (Position == NULL) ? NULL : (*Position);\r
02f49fc2
SZ
2215\r
2216 //\r
2217 // Check that the script is initialized and synced without adding an entry to the script.\r
2218 //\r
2219 Script = S3BootScriptGetEntryAddAddress (0);\r
2220 if (Script == NULL) {\r
2221 return RETURN_OUT_OF_RESOURCES;\r
64d14edf 2222 }\r
1436aea4 2223\r
02f49fc2
SZ
2224 Script = mS3BootScriptTablePtr->TableBase;\r
2225\r
1436aea4
MK
2226 StartAddress = (UINTN)Script;\r
2227 TableLength = mS3BootScriptTablePtr->TableLength;\r
2228 Script = Script + sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);\r
2229 LastOpcode = Script;\r
64d14edf 2230 //\r
2231 // Find the last boot Script Entry which is not the terminate node\r
2232 //\r
1436aea4
MK
2233 while ((UINTN)Script < (UINTN)(StartAddress + TableLength)) {\r
2234 CopyMem ((VOID *)&ScriptHeader, Script, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));\r
2235 if ((TempPosition != NULL) && (TempPosition == Script)) {\r
64d14edf 2236 //\r
3a03e95e 2237 // If the position is specified, the position must be pointed to a boot script entry start address.\r
64d14edf 2238 //\r
2239 ValidatePosition = TRUE;\r
2240 }\r
1436aea4 2241\r
64d14edf 2242 if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {\r
2243 LastOpcode = Script;\r
3a03e95e 2244 }\r
1436aea4
MK
2245\r
2246 Script = Script + ScriptHeader.Length;\r
64d14edf 2247 }\r
1436aea4 2248\r
64d14edf 2249 //\r
2250 // If the position is specified, but not the start of a boot script entry, it is a invalid input\r
2251 //\r
1436aea4 2252 if ((TempPosition != NULL) && !ValidatePosition) {\r
64d14edf 2253 return RETURN_INVALID_PARAMETER;\r
2254 }\r
3a03e95e 2255\r
1436aea4 2256 CopyMem ((VOID *)&ScriptHeader, LastOpcode, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));\r
3a03e95e 2257\r
1436aea4 2258 CopyMem ((VOID *)TempBootScriptEntry, LastOpcode, ScriptHeader.Length);\r
64d14edf 2259 //\r
2260 // Find the right position to write the node in\r
2261 //\r
2262 S3BootScriptCalculateInsertAddress (\r
2263 ScriptHeader.Length,\r
2264 TempPosition,\r
2265 BeforeOrAfter,\r
3a03e95e 2266 &Script\r
1436aea4 2267 );\r
64d14edf 2268 //\r
2269 // Copy the node to Boot script table\r
2270 //\r
1436aea4 2271 CopyMem ((VOID *)Script, (VOID *)TempBootScriptEntry, ScriptHeader.Length);\r
02f49fc2
SZ
2272\r
2273 SyncBootScript (Script);\r
2274\r
64d14edf 2275 //\r
2276 // return out the Position\r
2277 //\r
2278 if (Position != NULL) {\r
2279 *Position = Script;\r
2280 }\r
1436aea4 2281\r
64d14edf 2282 return RETURN_SUCCESS;\r
2283}\r
1436aea4 2284\r
64d14edf 2285/**\r
3a03e95e
SZ
2286 Create a Label node in the boot script table.\r
2287\r
64d14edf 2288 @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position\r
2289 in the boot script table specified by Position. If Position is NULL or points to\r
2290 NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end\r
2291 of the table (if FALSE).\r
2292 @param Position On entry, specifies the position in the boot script table where the opcode will be\r
2293 inserted, either before or after, depending on BeforeOrAfter. On exit, specifies\r
3a03e95e 2294 the position of the inserted opcode in the boot script table.\r
64d14edf 2295 @param InformationLength Length of the label in bytes\r
2296 @param Information Label to be logged in the boot scrpit\r
3a03e95e 2297\r
64d14edf 2298 @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.\r
2299 @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.\r
2300 @retval RETURN_SUCCESS Opcode is added.\r
2301\r
2302**/\r
2303RETURN_STATUS\r
2304EFIAPI\r
2305S3BootScriptLabelInternal (\r
1436aea4
MK
2306 IN BOOLEAN BeforeOrAfter,\r
2307 IN OUT VOID **Position OPTIONAL,\r
2308 IN UINT32 InformationLength,\r
2309 IN CONST CHAR8 *Information\r
64d14edf 2310 )\r
2311{\r
1436aea4
MK
2312 UINT8 Length;\r
2313 UINT8 *Script;\r
64d14edf 2314 EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;\r
3a03e95e 2315\r
322ac05f
HW
2316 //\r
2317 // Truncation check\r
2318 //\r
2319 if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) {\r
2320 return RETURN_OUT_OF_RESOURCES;\r
2321 }\r
1436aea4 2322\r
64d14edf 2323 Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);\r
3a03e95e 2324\r
64d14edf 2325 Script = S3BootScriptGetEntryAddAddress (Length);\r
2326 if (Script == NULL) {\r
2327 return RETURN_OUT_OF_RESOURCES;\r
2328 }\r
1436aea4 2329\r
64d14edf 2330 //\r
2331 // Build script data\r
2332 //\r
1436aea4
MK
2333 ScriptInformation.OpCode = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE;\r
2334 ScriptInformation.Length = Length;\r
64d14edf 2335\r
3a03e95e 2336 ScriptInformation.InformationLength = InformationLength;\r
64d14edf 2337\r
1436aea4
MK
2338 CopyMem ((VOID *)Script, (VOID *)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));\r
2339 CopyMem ((VOID *)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *)Information, (UINTN)InformationLength);\r
93b21ade 2340\r
02f49fc2
SZ
2341 SyncBootScript (Script);\r
2342\r
64d14edf 2343 return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);\r
64d14edf 2344}\r
1436aea4 2345\r
64d14edf 2346/**\r
2347 Find a label within the boot script table and, if not present, optionally create it.\r
2348\r
2349 @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE)\r
3a03e95e 2350 or after (FALSE) the position in the boot script table\r
64d14edf 2351 specified by Position.\r
3a03e95e 2352 @param CreateIfNotFound Specifies whether the label will be created if the label\r
64d14edf 2353 does not exists (TRUE) or not (FALSE).\r
2354 @param Position On entry, specifies the position in the boot script table\r
2355 where the opcode will be inserted, either before or after,\r
2356 depending on BeforeOrAfter. On exit, specifies the position\r
2357 of the inserted opcode in the boot script table.\r
2358 @param Label Points to the label which will be inserted in the boot script table.\r
2359\r
2360 @retval EFI_SUCCESS The operation succeeded. A record was added into the\r
2361 specified script table.\r
2362 @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.\r
3a03e95e 2363 If the opcode is unknow or not supported because of the PCD\r
64d14edf 2364 Feature Flags.\r
2365 @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.\r
2366\r
2367**/\r
2368RETURN_STATUS\r
3a03e95e 2369EFIAPI\r
64d14edf 2370S3BootScriptLabel (\r
1436aea4
MK
2371 IN BOOLEAN BeforeOrAfter,\r
2372 IN BOOLEAN CreateIfNotFound,\r
2373 IN OUT VOID **Position OPTIONAL,\r
2374 IN CONST CHAR8 *Label\r
64d14edf 2375 )\r
2376{\r
1436aea4
MK
2377 UINT8 *Script;\r
2378 UINTN StartAddress;\r
2379 UINT32 TableLength;\r
64d14edf 2380 EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;\r
2381 EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;\r
2382 UINT32 LabelLength;\r
1436aea4 2383\r
64d14edf 2384 //\r
96072947 2385 // Check NULL Label\r
64d14edf 2386 //\r
96072947
JY
2387 if (Label == NULL) {\r
2388 return EFI_INVALID_PARAMETER;\r
2389 }\r
1436aea4 2390\r
96072947
JY
2391 //\r
2392 // Check empty Label\r
2393 //\r
2394 if (Label[0] == '\0') {\r
64d14edf 2395 return EFI_INVALID_PARAMETER;\r
2396 }\r
3a03e95e 2397\r
64d14edf 2398 //\r
02f49fc2
SZ
2399 // Check that the script is initialized and synced without adding an entry to the script.\r
2400 // The code must search for the label first before it knows if a new entry needs\r
64d14edf 2401 // to be added.\r
2402 //\r
2403 Script = S3BootScriptGetEntryAddAddress (0);\r
2404 if (Script == NULL) {\r
2405 return RETURN_OUT_OF_RESOURCES;\r
2406 }\r
3a03e95e 2407\r
64d14edf 2408 //\r
2409 // Check the header and search for existing label.\r
3a03e95e 2410 //\r
64d14edf 2411 Script = mS3BootScriptTablePtr->TableBase;\r
1436aea4 2412 CopyMem ((VOID *)&TableHeader, Script, sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER));\r
64d14edf 2413 if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {\r
2414 return EFI_INVALID_PARAMETER;\r
2415 }\r
3a03e95e 2416\r
1436aea4
MK
2417 StartAddress = (UINTN)Script;\r
2418 TableLength = mS3BootScriptTablePtr->TableLength;\r
2419 Script = Script + TableHeader.Length;\r
2420 while ((UINTN)Script < (UINTN)(StartAddress + TableLength)) {\r
2421 CopyMem ((VOID *)&ScriptHeader, Script, sizeof (EFI_BOOT_SCRIPT_COMMON_HEADER));\r
64d14edf 2422 if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {\r
1436aea4 2423 if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof (EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {\r
3a03e95e 2424 (*Position) = Script;\r
64d14edf 2425 return EFI_SUCCESS;\r
2426 }\r
3a03e95e 2427 }\r
1436aea4
MK
2428\r
2429 Script = Script + ScriptHeader.Length;\r
64d14edf 2430 }\r
1436aea4 2431\r
64d14edf 2432 if (CreateIfNotFound) {\r
1436aea4
MK
2433 LabelLength = (UINT32)AsciiStrSize (Label);\r
2434 return S3BootScriptLabelInternal (BeforeOrAfter, Position, LabelLength, Label);\r
64d14edf 2435 } else {\r
2436 return EFI_NOT_FOUND;\r
3a03e95e 2437 }\r
64d14edf 2438}\r
2439\r
2440/**\r
2441 Compare two positions in the boot script table and return their relative position.\r
2442 @param Position1 The positions in the boot script table to compare\r
2443 @param Position2 The positions in the boot script table to compare\r
2444 @param RelativePosition On return, points to the result of the comparison\r
2445\r
2446 @retval EFI_SUCCESS The operation succeeded. A record was added into the\r
2447 specified script table.\r
2448 @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.\r
3a03e95e 2449 If the opcode is unknow or not supported because of the PCD\r
64d14edf 2450 Feature Flags.\r
2451 @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.\r
2452\r
2453**/\r
2454RETURN_STATUS\r
3a03e95e 2455EFIAPI\r
64d14edf 2456S3BootScriptCompare (\r
1436aea4
MK
2457 IN UINT8 *Position1,\r
2458 IN UINT8 *Position2,\r
2459 OUT UINTN *RelativePosition\r
64d14edf 2460 )\r
2461{\r
1436aea4
MK
2462 UINT8 *Script;\r
2463 UINT32 TableLength;\r
64d14edf 2464\r
64d14edf 2465 if (RelativePosition == NULL) {\r
2466 return EFI_INVALID_PARAMETER;\r
2467 }\r
02f49fc2
SZ
2468\r
2469 //\r
2470 // Check that the script is initialized and synced without adding an entry to the script.\r
2471 //\r
2472 Script = S3BootScriptGetEntryAddAddress (0);\r
2473 if (Script == NULL) {\r
2474 return RETURN_OUT_OF_RESOURCES;\r
2475 }\r
1436aea4 2476\r
02f49fc2
SZ
2477 Script = mS3BootScriptTablePtr->TableBase;\r
2478\r
64d14edf 2479 //\r
879dbe18 2480 // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up\r
64d14edf 2481 //\r
879dbe18 2482 TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);\r
1436aea4 2483 if ((Position1 < Script) || (Position1 > Script+TableLength)) {\r
64d14edf 2484 return EFI_INVALID_PARAMETER;\r
2485 }\r
1436aea4
MK
2486\r
2487 if ((Position2 < Script) || (Position2 > Script+TableLength)) {\r
64d14edf 2488 return EFI_INVALID_PARAMETER;\r
2489 }\r
1436aea4
MK
2490\r
2491 *RelativePosition = (Position1 < Position2) ? -1 : ((Position1 == Position2) ? 0 : 1);\r
3a03e95e 2492\r
64d14edf 2493 return EFI_SUCCESS;\r
2494}\r