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