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