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