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