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