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