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