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