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