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