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