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