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