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