]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3Dxe.c
OvmfPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgS3Lib / QemuFwCfgS3Dxe.c
CommitLineData
7bb57805
LE
1/** @file\r
2 Full functionality QemuFwCfgS3Lib instance, for DXE phase modules.\r
3\r
4 Copyright (C) 2017, Red Hat, Inc.\r
5\r
b26f0cf9 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7bb57805
LE
7**/\r
8\r
9#include <Library/BaseLib.h>\r
10#include <Library/DebugLib.h>\r
11#include <Library/MemoryAllocationLib.h>\r
12#include <Library/QemuFwCfgLib.h>\r
13#include <Library/QemuFwCfgS3Lib.h>\r
14#include <Library/UefiBootServicesTableLib.h>\r
15#include <Protocol/S3SaveState.h>\r
16\r
17\r
18//\r
19// Event to signal when the S3SaveState protocol interface is installed.\r
20//\r
21STATIC EFI_EVENT mS3SaveStateInstalledEvent;\r
22\r
23//\r
24// Reference to the S3SaveState protocol interface, after it is installed.\r
25//\r
26STATIC EFI_S3_SAVE_STATE_PROTOCOL *mS3SaveState;\r
27\r
28//\r
29// The control structure is allocated in reserved memory, aligned at 8 bytes.\r
30// The client-requested ScratchBuffer will be allocated adjacently, also\r
31// aligned at 8 bytes.\r
32//\r
33#define RESERVED_MEM_ALIGNMENT 8\r
34\r
35STATIC FW_CFG_DMA_ACCESS *mDmaAccess;\r
36STATIC VOID *mScratchBuffer;\r
37STATIC UINTN mScratchBufferSize;\r
38\r
39//\r
40// Callback provided by the client, for appending ACPI S3 Boot Script opcodes.\r
41// To be called from S3SaveStateInstalledNotify().\r
42//\r
43STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *mCallback;\r
44\r
45\r
46/**\r
47 Event notification function for mS3SaveStateInstalledEvent.\r
48**/\r
49STATIC\r
50VOID\r
51EFIAPI\r
52S3SaveStateInstalledNotify (\r
53 IN EFI_EVENT Event,\r
54 IN VOID *Context\r
55 )\r
56{\r
57 EFI_STATUS Status;\r
58\r
59 ASSERT (Event == mS3SaveStateInstalledEvent);\r
60\r
61 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid,\r
62 NULL /* Registration */, (VOID **)&mS3SaveState);\r
63 if (EFI_ERROR (Status)) {\r
64 return;\r
65 }\r
66\r
67 ASSERT (mCallback != NULL);\r
68\r
69 DEBUG ((DEBUG_INFO, "%a: %a: DmaAccess@0x%Lx ScratchBuffer@[0x%Lx+0x%Lx]\n",\r
70 gEfiCallerBaseName, __FUNCTION__, (UINT64)(UINTN)mDmaAccess,\r
71 (UINT64)(UINTN)mScratchBuffer, (UINT64)mScratchBufferSize));\r
72 mCallback (Context, mScratchBuffer);\r
73\r
74 gBS->CloseEvent (mS3SaveStateInstalledEvent);\r
75 mS3SaveStateInstalledEvent = NULL;\r
76}\r
77\r
78\r
79/**\r
80 Install the client module's FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION callback for\r
81 when the production of ACPI S3 Boot Script opcodes becomes possible.\r
82\r
83 Take ownership of the client-provided Context, and pass it to the callback\r
84 function, when the latter is invoked.\r
85\r
86 Allocate scratch space for those ACPI S3 Boot Script opcodes to work upon\r
87 that the client will produce in the callback function.\r
88\r
89 @param[in] Callback FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION to invoke\r
90 when the production of ACPI S3 Boot Script\r
91 opcodes becomes possible. Callback() may be\r
92 called immediately from\r
93 QemuFwCfgS3CallWhenBootScriptReady().\r
94\r
95 @param[in,out] Context Client-provided data structure for the\r
96 Callback() callback function to consume.\r
97\r
98 If Context points to dynamically allocated\r
99 memory, then Callback() must release it.\r
100\r
101 If Context points to dynamically allocated\r
102 memory, and\r
103 QemuFwCfgS3CallWhenBootScriptReady() returns\r
104 successfully, then the caller of\r
105 QemuFwCfgS3CallWhenBootScriptReady() must\r
106 neither dereference nor even evaluate Context\r
107 any longer, as ownership of the referenced area\r
108 has been transferred to Callback().\r
109\r
110 @param[in] ScratchBufferSize The size of the scratch buffer that will hold,\r
111 in reserved memory, all client data read,\r
112 written, and checked by the ACPI S3 Boot Script\r
113 opcodes produced by Callback().\r
114\r
115 @retval RETURN_UNSUPPORTED The library instance does not support this\r
116 function.\r
117\r
118 @retval RETURN_NOT_FOUND The fw_cfg DMA interface to QEMU is\r
119 unavailable.\r
120\r
121 @retval RETURN_BAD_BUFFER_SIZE ScratchBufferSize is too large.\r
122\r
123 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.\r
124\r
125 @retval RETURN_SUCCESS Callback() has been installed, and the\r
126 ownership of Context has been transferred.\r
127 Reserved memory has been allocated for the\r
128 scratch buffer.\r
129\r
130 A successful invocation of\r
131 QemuFwCfgS3CallWhenBootScriptReady() cannot\r
132 be rolled back.\r
133\r
134 @return Error codes from underlying functions.\r
135**/\r
7bb57805 136RETURN_STATUS\r
08bed3fb 137EFIAPI\r
7bb57805
LE
138QemuFwCfgS3CallWhenBootScriptReady (\r
139 IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *Callback,\r
140 IN OUT VOID *Context, OPTIONAL\r
141 IN UINTN ScratchBufferSize\r
142 )\r
143{\r
144 EFI_STATUS Status;\r
145 VOID *Registration;\r
146\r
147 //\r
148 // Basic fw_cfg is certainly available, as we can only be here after a\r
149 // successful call to QemuFwCfgS3Enabled(). Check fw_cfg DMA availability.\r
150 //\r
151 ASSERT (QemuFwCfgIsAvailable ());\r
152 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);\r
153 if ((QemuFwCfgRead32 () & FW_CFG_F_DMA) == 0) {\r
154 DEBUG ((DEBUG_ERROR, "%a: %a: fw_cfg DMA unavailable\n",\r
155 gEfiCallerBaseName, __FUNCTION__));\r
156 return RETURN_NOT_FOUND;\r
157 }\r
158\r
159 //\r
160 // Allocate a reserved buffer for the DMA access control structure and the\r
161 // client data together.\r
162 //\r
163 if (ScratchBufferSize >\r
164 MAX_UINT32 - (RESERVED_MEM_ALIGNMENT - 1) - sizeof *mDmaAccess) {\r
165 DEBUG ((DEBUG_ERROR, "%a: %a: ScratchBufferSize too big: %Lu\n",\r
166 gEfiCallerBaseName, __FUNCTION__, (UINT64)ScratchBufferSize));\r
167 return RETURN_BAD_BUFFER_SIZE;\r
168 }\r
169 mDmaAccess = AllocateReservedPool ((RESERVED_MEM_ALIGNMENT - 1) +\r
170 sizeof *mDmaAccess + ScratchBufferSize);\r
171 if (mDmaAccess == NULL) {\r
172 DEBUG ((DEBUG_ERROR, "%a: %a: AllocateReservedPool(): out of resources\n",\r
173 gEfiCallerBaseName, __FUNCTION__));\r
174 return RETURN_OUT_OF_RESOURCES;\r
175 }\r
176 mDmaAccess = ALIGN_POINTER (mDmaAccess, RESERVED_MEM_ALIGNMENT);\r
177\r
178 //\r
179 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the\r
180 // client's Context to the callback.\r
181 //\r
182 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,\r
183 S3SaveStateInstalledNotify, Context,\r
184 &mS3SaveStateInstalledEvent);\r
185 if (EFI_ERROR (Status)) {\r
186 DEBUG ((DEBUG_ERROR, "%a: %a: CreateEvent(): %r\n", gEfiCallerBaseName,\r
187 __FUNCTION__, Status));\r
188 goto FreeDmaAccess;\r
189 }\r
190 Status = gBS->RegisterProtocolNotify (&gEfiS3SaveStateProtocolGuid,\r
191 mS3SaveStateInstalledEvent, &Registration);\r
192 if (EFI_ERROR (Status)) {\r
193 DEBUG ((DEBUG_ERROR, "%a: %a: RegisterProtocolNotify(): %r\n",\r
194 gEfiCallerBaseName, __FUNCTION__, Status));\r
195 goto CloseEvent;\r
196 }\r
197\r
198 //\r
199 // Set the remaining global variables. For the alignment guarantee on\r
200 // mScratchBuffer, we rely on the fact that *mDmaAccess has a size that is an\r
201 // integral multiple of RESERVED_MEM_ALIGNMENT.\r
202 //\r
203 ASSERT (sizeof *mDmaAccess % RESERVED_MEM_ALIGNMENT == 0);\r
204 mScratchBuffer = mDmaAccess + 1;\r
205 mScratchBufferSize = ScratchBufferSize;\r
206 mCallback = Callback;\r
207\r
208 //\r
209 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.\r
210 //\r
211 Status = gBS->SignalEvent (mS3SaveStateInstalledEvent);\r
212 if (EFI_ERROR (Status)) {\r
213 DEBUG ((DEBUG_ERROR, "%a: %a: SignalEvent(): %r\n", gEfiCallerBaseName,\r
214 __FUNCTION__, Status));\r
215 goto NullGlobals;\r
216 }\r
217\r
218 return RETURN_SUCCESS;\r
219\r
220NullGlobals:\r
221 mScratchBuffer = NULL;\r
222 mScratchBufferSize = 0;\r
223 mCallback = NULL;\r
224\r
225CloseEvent:\r
226 gBS->CloseEvent (mS3SaveStateInstalledEvent);\r
227 mS3SaveStateInstalledEvent = NULL;\r
228\r
229FreeDmaAccess:\r
230 FreePool (mDmaAccess);\r
231 mDmaAccess = NULL;\r
232\r
233 return (RETURN_STATUS)Status;\r
234}\r
235\r
236\r
237/**\r
238 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,\r
239 and transfer data to it.\r
240\r
241 The opcodes produced by QemuFwCfgS3ScriptWriteBytes() will first restore\r
242 NumberOfBytes bytes in ScratchBuffer in-place, in reserved memory, then write\r
243 them to fw_cfg using DMA.\r
244\r
245 If the operation fails during S3 resume, the boot script will hang.\r
246\r
247 This function may only be called from the client module's\r
248 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
249 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
250\r
251 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config\r
252 item to write, expressed as INT32. If\r
253 FirmwareConfigItem is -1, no selection is\r
254 made, the write will occur to the currently\r
255 selected item, at its currently selected\r
256 offset. Otherwise, the specified item will be\r
257 selected, and the write will occur at offset\r
258 0.\r
259\r
260 @param[in] NumberOfBytes Size of the data to restore in ScratchBuffer,\r
261 and to write from ScratchBuffer, during S3\r
262 resume. NumberOfBytes must not exceed\r
263 ScratchBufferSize, which was passed to\r
264 QemuFwCfgS3CallWhenBootScriptReady().\r
265\r
266 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
267 Boot Script successfully. There is no way\r
268 to undo this action.\r
269\r
270 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.\r
271\r
272 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than\r
273 ScratchBufferSize.\r
274\r
275 @return Error codes from underlying functions.\r
276**/\r
7bb57805 277RETURN_STATUS\r
08bed3fb 278EFIAPI\r
7bb57805
LE
279QemuFwCfgS3ScriptWriteBytes (\r
280 IN INT32 FirmwareConfigItem,\r
281 IN UINTN NumberOfBytes\r
282 )\r
283{\r
284 UINTN Count;\r
285 EFI_STATUS Status;\r
286 UINT64 AccessAddress;\r
287 UINT32 ControlPollData;\r
288 UINT32 ControlPollMask;\r
289\r
290 ASSERT (mDmaAccess != NULL);\r
291 ASSERT (mS3SaveState != NULL);\r
292\r
293 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {\r
294 return RETURN_INVALID_PARAMETER;\r
295 }\r
296 if (NumberOfBytes > mScratchBufferSize) {\r
297 return RETURN_BAD_BUFFER_SIZE;\r
298 }\r
299\r
300 //\r
301 // Set up a write[+select] fw_cfg DMA command.\r
302 //\r
303 mDmaAccess->Control = FW_CFG_DMA_CTL_WRITE;\r
304 if (FirmwareConfigItem != -1) {\r
305 mDmaAccess->Control |= FW_CFG_DMA_CTL_SELECT;\r
306 mDmaAccess->Control |= (UINT32)FirmwareConfigItem << 16;\r
307 }\r
308 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);\r
309\r
310 //\r
311 // We ensured the following constraint via mScratchBufferSize in\r
312 // QemuFwCfgS3CallWhenBootScriptReady().\r
313 //\r
314 ASSERT (NumberOfBytes <= MAX_UINT32);\r
315 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);\r
316\r
317 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);\r
318\r
319 //\r
320 // Copy mDmaAccess and NumberOfBytes bytes from mScratchBuffer into the boot\r
321 // script. When executed at S3 resume, this opcode will restore all of them\r
322 // in-place.\r
323 //\r
324 Count = (UINTN)mScratchBuffer + NumberOfBytes - (UINTN)mDmaAccess;\r
325 Status = mS3SaveState->Write (\r
326 mS3SaveState, // This\r
327 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
328 EfiBootScriptWidthUint8, // Width\r
329 (UINT64)(UINTN)mDmaAccess, // Address\r
330 Count, // Count\r
331 (VOID *)mDmaAccess // Buffer\r
332 );\r
333 if (EFI_ERROR (Status)) {\r
334 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
335 gEfiCallerBaseName, __FUNCTION__, Status));\r
336 return (RETURN_STATUS)Status;\r
337 }\r
338\r
339 //\r
340 // Append an opcode that will write the address of the fw_cfg DMA command to\r
341 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.\r
342 // The second (highest address, least significant) write will start the\r
343 // transfer.\r
344 //\r
345 AccessAddress = SwapBytes64 ((UINTN)mDmaAccess);\r
346 Status = mS3SaveState->Write (\r
347 mS3SaveState, // This\r
348 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
349 EfiBootScriptWidthUint32, // Width\r
350 (UINT64)FW_CFG_IO_DMA_ADDRESS, // Address\r
351 (UINTN)2, // Count\r
352 (VOID *)&AccessAddress // Buffer\r
353 );\r
354 if (EFI_ERROR (Status)) {\r
355 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
356 gEfiCallerBaseName, __FUNCTION__, Status));\r
357 return (RETURN_STATUS)Status;\r
358 }\r
359\r
360 //\r
361 // The following opcode will wait until the Control word reads as zero\r
362 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is\r
363 // approximately 58494 years.\r
364 //\r
365 ControlPollData = 0;\r
366 ControlPollMask = MAX_UINT32;\r
367 Status = mS3SaveState->Write (\r
368 mS3SaveState, // This\r
369 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
370 EfiBootScriptWidthUint32, // Width\r
371 (UINT64)(UINTN)&mDmaAccess->Control, // Address\r
372 (VOID *)&ControlPollData, // Data\r
373 (VOID *)&ControlPollMask, // DataMask\r
374 MAX_UINT64 // Delay\r
375 );\r
376 if (EFI_ERROR (Status)) {\r
377 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
378 gEfiCallerBaseName, __FUNCTION__, Status));\r
379 return (RETURN_STATUS)Status;\r
380 }\r
381\r
382 return RETURN_SUCCESS;\r
383}\r
384\r
385\r
386/**\r
387 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,\r
388 and transfer data from it.\r
389\r
390 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes\r
391 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved\r
392 memory.\r
393\r
394 If the operation fails during S3 resume, the boot script will hang.\r
395\r
396 This function may only be called from the client module's\r
397 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
398 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
399\r
400 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config\r
401 item to read, expressed as INT32. If\r
402 FirmwareConfigItem is -1, no selection is\r
403 made, the read will occur from the currently\r
404 selected item, from its currently selected\r
405 offset. Otherwise, the specified item will be\r
406 selected, and the read will occur from offset\r
407 0.\r
408\r
409 @param[in] NumberOfBytes Size of the data to read during S3 resume.\r
410 NumberOfBytes must not exceed\r
411 ScratchBufferSize, which was passed to\r
412 QemuFwCfgS3CallWhenBootScriptReady().\r
413\r
414 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
415 Boot Script successfully. There is no way\r
416 to undo this action.\r
417\r
418 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.\r
419\r
420 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than\r
421 ScratchBufferSize.\r
422\r
423 @return Error codes from underlying functions.\r
424**/\r
7bb57805 425RETURN_STATUS\r
08bed3fb 426EFIAPI\r
7bb57805
LE
427QemuFwCfgS3ScriptReadBytes (\r
428 IN INT32 FirmwareConfigItem,\r
429 IN UINTN NumberOfBytes\r
430 )\r
431{\r
432 EFI_STATUS Status;\r
433 UINT64 AccessAddress;\r
434 UINT32 ControlPollData;\r
435 UINT32 ControlPollMask;\r
436\r
437 ASSERT (mDmaAccess != NULL);\r
438 ASSERT (mS3SaveState != NULL);\r
439\r
440 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {\r
441 return RETURN_INVALID_PARAMETER;\r
442 }\r
443 if (NumberOfBytes > mScratchBufferSize) {\r
444 return RETURN_BAD_BUFFER_SIZE;\r
445 }\r
446\r
447 //\r
448 // Set up a read[+select] fw_cfg DMA command.\r
449 //\r
450 mDmaAccess->Control = FW_CFG_DMA_CTL_READ;\r
451 if (FirmwareConfigItem != -1) {\r
452 mDmaAccess->Control |= FW_CFG_DMA_CTL_SELECT;\r
453 mDmaAccess->Control |= (UINT32)FirmwareConfigItem << 16;\r
454 }\r
455 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);\r
456\r
457 //\r
458 // We ensured the following constraint via mScratchBufferSize in\r
459 // QemuFwCfgS3CallWhenBootScriptReady().\r
460 //\r
461 ASSERT (NumberOfBytes <= MAX_UINT32);\r
462 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);\r
463\r
464 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);\r
465\r
466 //\r
467 // Copy mDmaAccess into the boot script. When executed at S3 resume, this\r
468 // opcode will restore it in-place.\r
469 //\r
470 Status = mS3SaveState->Write (\r
471 mS3SaveState, // This\r
472 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
473 EfiBootScriptWidthUint8, // Width\r
474 (UINT64)(UINTN)mDmaAccess, // Address\r
475 sizeof *mDmaAccess, // Count\r
476 (VOID *)mDmaAccess // Buffer\r
477 );\r
478 if (EFI_ERROR (Status)) {\r
479 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
480 gEfiCallerBaseName, __FUNCTION__, Status));\r
481 return (RETURN_STATUS)Status;\r
482 }\r
483\r
484 //\r
485 // Append an opcode that will write the address of the fw_cfg DMA command to\r
486 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.\r
487 // The second (highest address, least significant) write will start the\r
488 // transfer.\r
489 //\r
490 AccessAddress = SwapBytes64 ((UINTN)mDmaAccess);\r
491 Status = mS3SaveState->Write (\r
492 mS3SaveState, // This\r
493 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
494 EfiBootScriptWidthUint32, // Width\r
495 (UINT64)FW_CFG_IO_DMA_ADDRESS, // Address\r
496 (UINTN)2, // Count\r
497 (VOID *)&AccessAddress // Buffer\r
498 );\r
499 if (EFI_ERROR (Status)) {\r
500 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
501 gEfiCallerBaseName, __FUNCTION__, Status));\r
502 return (RETURN_STATUS)Status;\r
503 }\r
504\r
505 //\r
506 // The following opcode will wait until the Control word reads as zero\r
507 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is\r
508 // approximately 58494 years.\r
509 //\r
510 ControlPollData = 0;\r
511 ControlPollMask = MAX_UINT32;\r
512 Status = mS3SaveState->Write (\r
513 mS3SaveState, // This\r
514 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
515 EfiBootScriptWidthUint32, // Width\r
516 (UINT64)(UINTN)&mDmaAccess->Control, // Address\r
517 (VOID *)&ControlPollData, // Data\r
518 (VOID *)&ControlPollMask, // DataMask\r
519 MAX_UINT64 // Delay\r
520 );\r
521 if (EFI_ERROR (Status)) {\r
522 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
523 gEfiCallerBaseName, __FUNCTION__, Status));\r
524 return (RETURN_STATUS)Status;\r
525 }\r
526\r
527 return RETURN_SUCCESS;\r
528}\r
529\r
530\r
531/**\r
532 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,\r
533 and increase its offset.\r
534\r
535 If the operation fails during S3 resume, the boot script will hang.\r
536\r
537 This function may only be called from the client module's\r
538 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
539 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
540\r
541 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config\r
542 item to advance the offset of, expressed as\r
543 INT32. If FirmwareConfigItem is -1, no\r
544 selection is made, and the offset for the\r
545 currently selected item is increased.\r
546 Otherwise, the specified item will be\r
547 selected, and the offset increment will occur\r
548 from offset 0.\r
549\r
550 @param[in] NumberOfBytes The number of bytes to skip in the subject\r
551 fw_cfg item.\r
552\r
553 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
554 Boot Script successfully. There is no way\r
555 to undo this action.\r
556\r
557 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.\r
558\r
559 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.\r
560\r
561 @return Error codes from underlying functions.\r
562**/\r
7bb57805 563RETURN_STATUS\r
08bed3fb 564EFIAPI\r
7bb57805
LE
565QemuFwCfgS3ScriptSkipBytes (\r
566 IN INT32 FirmwareConfigItem,\r
567 IN UINTN NumberOfBytes\r
568 )\r
569{\r
570 EFI_STATUS Status;\r
571 UINT64 AccessAddress;\r
572 UINT32 ControlPollData;\r
573 UINT32 ControlPollMask;\r
574\r
575 ASSERT (mDmaAccess != NULL);\r
576 ASSERT (mS3SaveState != NULL);\r
577\r
578 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {\r
579 return RETURN_INVALID_PARAMETER;\r
580 }\r
581 if (NumberOfBytes > MAX_UINT32) {\r
582 return RETURN_BAD_BUFFER_SIZE;\r
583 }\r
584\r
585 //\r
586 // Set up a skip[+select] fw_cfg DMA command.\r
587 //\r
588 mDmaAccess->Control = FW_CFG_DMA_CTL_SKIP;\r
589 if (FirmwareConfigItem != -1) {\r
590 mDmaAccess->Control |= FW_CFG_DMA_CTL_SELECT;\r
591 mDmaAccess->Control |= (UINT32)FirmwareConfigItem << 16;\r
592 }\r
593 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);\r
594\r
595 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);\r
596 mDmaAccess->Address = 0;\r
597\r
598 //\r
599 // Copy mDmaAccess into the boot script. When executed at S3 resume, this\r
600 // opcode will restore it in-place.\r
601 //\r
602 Status = mS3SaveState->Write (\r
603 mS3SaveState, // This\r
604 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
605 EfiBootScriptWidthUint8, // Width\r
606 (UINT64)(UINTN)mDmaAccess, // Address\r
607 sizeof *mDmaAccess, // Count\r
608 (VOID *)mDmaAccess // Buffer\r
609 );\r
610 if (EFI_ERROR (Status)) {\r
611 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
612 gEfiCallerBaseName, __FUNCTION__, Status));\r
613 return (RETURN_STATUS)Status;\r
614 }\r
615\r
616 //\r
617 // Append an opcode that will write the address of the fw_cfg DMA command to\r
618 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.\r
619 // The second (highest address, least significant) write will start the\r
620 // transfer.\r
621 //\r
622 AccessAddress = SwapBytes64 ((UINTN)mDmaAccess);\r
623 Status = mS3SaveState->Write (\r
624 mS3SaveState, // This\r
625 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
626 EfiBootScriptWidthUint32, // Width\r
627 (UINT64)FW_CFG_IO_DMA_ADDRESS, // Address\r
628 (UINTN)2, // Count\r
629 (VOID *)&AccessAddress // Buffer\r
630 );\r
631 if (EFI_ERROR (Status)) {\r
632 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
633 gEfiCallerBaseName, __FUNCTION__, Status));\r
634 return (RETURN_STATUS)Status;\r
635 }\r
636\r
637 //\r
638 // The following opcode will wait until the Control word reads as zero\r
639 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is\r
640 // approximately 58494 years.\r
641 //\r
642 ControlPollData = 0;\r
643 ControlPollMask = MAX_UINT32;\r
644 Status = mS3SaveState->Write (\r
645 mS3SaveState, // This\r
646 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
647 EfiBootScriptWidthUint32, // Width\r
648 (UINT64)(UINTN)&mDmaAccess->Control, // Address\r
649 (VOID *)&ControlPollData, // Data\r
650 (VOID *)&ControlPollMask, // DataMask\r
651 MAX_UINT64 // Delay\r
652 );\r
653 if (EFI_ERROR (Status)) {\r
654 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
655 gEfiCallerBaseName, __FUNCTION__, Status));\r
656 return (RETURN_STATUS)Status;\r
657 }\r
658\r
659 return RETURN_SUCCESS;\r
660}\r
661\r
662\r
663/**\r
664 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.\r
665\r
666 If the check fails during S3 resume, the boot script will hang.\r
667\r
668 This function may only be called from the client module's\r
669 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
670 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
671\r
672 @param[in] ScratchData Pointer to the UINT8, UINT16, UINT32 or UINT64 field\r
673 in ScratchBuffer that should be checked. The caller\r
674 is responsible for populating the field during S3\r
675 resume, by calling QemuFwCfgS3ScriptReadBytes() ahead\r
676 of QemuFwCfgS3ScriptCheckValue().\r
677\r
678 ScratchData must point into ScratchBuffer, which was\r
679 allocated, and passed to Callback(), by\r
680 QemuFwCfgS3CallWhenBootScriptReady().\r
681\r
682 ScratchData must be aligned at ValueSize bytes.\r
683\r
684 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field\r
685 to check.\r
686\r
687 @param[in] ValueMask The value read from ScratchData is binarily AND-ed\r
688 with ValueMask, and the result is compared against\r
689 Value. If the masked data equals Value, the check\r
690 passes, and the boot script can proceed. Otherwise,\r
691 the check fails, and the boot script hangs.\r
692\r
693 @param[in] Value Refer to ValueMask.\r
694\r
695 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
696 Boot Script successfully. There is no way\r
697 to undo this action.\r
698\r
699 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.\r
700\r
701 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in\r
702 ValueSize bytes.\r
703\r
704 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize\r
705 bytes.\r
706\r
707 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't\r
708 wholly contained in the ScratchBufferSize\r
709 bytes at ScratchBuffer.\r
710\r
711 @return Error codes from underlying functions.\r
712**/\r
7bb57805 713RETURN_STATUS\r
08bed3fb 714EFIAPI\r
7bb57805
LE
715QemuFwCfgS3ScriptCheckValue (\r
716 IN VOID *ScratchData,\r
717 IN UINT8 ValueSize,\r
718 IN UINT64 ValueMask,\r
719 IN UINT64 Value\r
720 )\r
721{\r
722 EFI_BOOT_SCRIPT_WIDTH Width;\r
723 EFI_STATUS Status;\r
724\r
725 ASSERT (mS3SaveState != NULL);\r
726\r
727 switch (ValueSize) {\r
728 case 1:\r
729 Width = EfiBootScriptWidthUint8;\r
730 break;\r
731\r
732 case 2:\r
733 Width = EfiBootScriptWidthUint16;\r
734 break;\r
735\r
736 case 4:\r
737 Width = EfiBootScriptWidthUint32;\r
738 break;\r
739\r
740 case 8:\r
741 Width = EfiBootScriptWidthUint64;\r
742 break;\r
743\r
744 default:\r
745 return RETURN_INVALID_PARAMETER;\r
746 }\r
747\r
748 if (ValueSize < 8 &&\r
749 (RShiftU64 (ValueMask, ValueSize * 8) > 0 ||\r
750 RShiftU64 (Value, ValueSize * 8) > 0)) {\r
751 return RETURN_INVALID_PARAMETER;\r
752 }\r
753\r
754 if ((UINTN)ScratchData % ValueSize > 0) {\r
755 return RETURN_INVALID_PARAMETER;\r
756 }\r
757\r
758 if (((UINTN)ScratchData < (UINTN)mScratchBuffer) ||\r
759 ((UINTN)ScratchData > MAX_UINTN - ValueSize) ||\r
760 ((UINTN)ScratchData + ValueSize >\r
761 (UINTN)mScratchBuffer + mScratchBufferSize)) {\r
762 return RETURN_BAD_BUFFER_SIZE;\r
763 }\r
764\r
765 //\r
766 // The following opcode will wait "until" (*ScratchData & ValueMask) reads as\r
767 // Value, considering the least significant ValueSize bytes. As timeout we\r
768 // use MAX_UINT64 * 100ns, which is approximately 58494 years.\r
769 //\r
770 Status = mS3SaveState->Write (\r
771 mS3SaveState, // This\r
772 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
773 Width, // Width\r
774 (UINT64)(UINTN)ScratchData, // Address\r
775 (VOID *)&Value, // Data\r
776 (VOID *)&ValueMask, // DataMask\r
777 MAX_UINT64 // Delay\r
778 );\r
779 if (EFI_ERROR (Status)) {\r
780 DEBUG ((DEBUG_ERROR, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
781 gEfiCallerBaseName, __FUNCTION__, Status));\r
782 return (RETURN_STATUS)Status;\r
783 }\r
784\r
785 return RETURN_SUCCESS;\r
786}\r