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