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