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