]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3Dxe.c
OvmfPkg: Apply uncrustify changes
[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
7bb57805
LE
17//\r
18// Event to signal when the S3SaveState protocol interface is installed.\r
19//\r
ac0a286f 20STATIC EFI_EVENT mS3SaveStateInstalledEvent;\r
7bb57805
LE
21\r
22//\r
23// Reference to the S3SaveState protocol interface, after it is installed.\r
24//\r
ac0a286f 25STATIC EFI_S3_SAVE_STATE_PROTOCOL *mS3SaveState;\r
7bb57805
LE
26\r
27//\r
28// The control structure is allocated in reserved memory, aligned at 8 bytes.\r
29// The client-requested ScratchBuffer will be allocated adjacently, also\r
30// aligned at 8 bytes.\r
31//\r
ac0a286f 32#define RESERVED_MEM_ALIGNMENT 8\r
7bb57805 33\r
ac0a286f
MK
34STATIC FW_CFG_DMA_ACCESS *mDmaAccess;\r
35STATIC VOID *mScratchBuffer;\r
36STATIC UINTN mScratchBufferSize;\r
7bb57805
LE
37\r
38//\r
39// Callback provided by the client, for appending ACPI S3 Boot Script opcodes.\r
40// To be called from S3SaveStateInstalledNotify().\r
41//\r
ac0a286f 42STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *mCallback;\r
7bb57805
LE
43\r
44/**\r
45 Event notification function for mS3SaveStateInstalledEvent.\r
46**/\r
47STATIC\r
48VOID\r
49EFIAPI\r
50S3SaveStateInstalledNotify (\r
ac0a286f
MK
51 IN EFI_EVENT Event,\r
52 IN VOID *Context\r
7bb57805
LE
53 )\r
54{\r
ac0a286f 55 EFI_STATUS Status;\r
7bb57805
LE
56\r
57 ASSERT (Event == mS3SaveStateInstalledEvent);\r
58\r
ac0a286f
MK
59 Status = gBS->LocateProtocol (\r
60 &gEfiS3SaveStateProtocolGuid,\r
61 NULL /* Registration */,\r
62 (VOID **)&mS3SaveState\r
63 );\r
7bb57805
LE
64 if (EFI_ERROR (Status)) {\r
65 return;\r
66 }\r
67\r
68 ASSERT (mCallback != NULL);\r
69\r
ac0a286f
MK
70 DEBUG ((\r
71 DEBUG_INFO,\r
72 "%a: %a: DmaAccess@0x%Lx ScratchBuffer@[0x%Lx+0x%Lx]\n",\r
73 gEfiCallerBaseName,\r
74 __FUNCTION__,\r
75 (UINT64)(UINTN)mDmaAccess,\r
76 (UINT64)(UINTN)mScratchBuffer,\r
77 (UINT64)mScratchBufferSize\r
78 ));\r
7bb57805
LE
79 mCallback (Context, mScratchBuffer);\r
80\r
81 gBS->CloseEvent (mS3SaveStateInstalledEvent);\r
82 mS3SaveStateInstalledEvent = NULL;\r
83}\r
84\r
7bb57805
LE
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 144QemuFwCfgS3CallWhenBootScriptReady (\r
ac0a286f
MK
145 IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *Callback,\r
146 IN OUT VOID *Context OPTIONAL,\r
147 IN UINTN ScratchBufferSize\r
7bb57805
LE
148 )\r
149{\r
ac0a286f
MK
150 EFI_STATUS Status;\r
151 VOID *Registration;\r
7bb57805
LE
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
ac0a286f
MK
160 DEBUG ((\r
161 DEBUG_ERROR,\r
162 "%a: %a: fw_cfg DMA unavailable\n",\r
163 gEfiCallerBaseName,\r
164 __FUNCTION__\r
165 ));\r
7bb57805
LE
166 return RETURN_NOT_FOUND;\r
167 }\r
168\r
169 //\r
170 // Allocate a reserved buffer for the DMA access control structure and the\r
171 // client data together.\r
172 //\r
173 if (ScratchBufferSize >\r
ac0a286f
MK
174 MAX_UINT32 - (RESERVED_MEM_ALIGNMENT - 1) - sizeof *mDmaAccess)\r
175 {\r
176 DEBUG ((\r
177 DEBUG_ERROR,\r
178 "%a: %a: ScratchBufferSize too big: %Lu\n",\r
179 gEfiCallerBaseName,\r
180 __FUNCTION__,\r
181 (UINT64)ScratchBufferSize\r
182 ));\r
7bb57805
LE
183 return RETURN_BAD_BUFFER_SIZE;\r
184 }\r
ac0a286f
MK
185\r
186 mDmaAccess = AllocateReservedPool (\r
187 (RESERVED_MEM_ALIGNMENT - 1) +\r
188 sizeof *mDmaAccess + ScratchBufferSize\r
189 );\r
7bb57805 190 if (mDmaAccess == NULL) {\r
ac0a286f
MK
191 DEBUG ((\r
192 DEBUG_ERROR,\r
193 "%a: %a: AllocateReservedPool(): out of resources\n",\r
194 gEfiCallerBaseName,\r
195 __FUNCTION__\r
196 ));\r
7bb57805
LE
197 return RETURN_OUT_OF_RESOURCES;\r
198 }\r
ac0a286f 199\r
7bb57805
LE
200 mDmaAccess = ALIGN_POINTER (mDmaAccess, RESERVED_MEM_ALIGNMENT);\r
201\r
202 //\r
203 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the\r
204 // client's Context to the callback.\r
205 //\r
ac0a286f
MK
206 Status = gBS->CreateEvent (\r
207 EVT_NOTIFY_SIGNAL,\r
208 TPL_CALLBACK,\r
209 S3SaveStateInstalledNotify,\r
210 Context,\r
211 &mS3SaveStateInstalledEvent\r
212 );\r
7bb57805 213 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
214 DEBUG ((\r
215 DEBUG_ERROR,\r
216 "%a: %a: CreateEvent(): %r\n",\r
217 gEfiCallerBaseName,\r
218 __FUNCTION__,\r
219 Status\r
220 ));\r
7bb57805
LE
221 goto FreeDmaAccess;\r
222 }\r
ac0a286f
MK
223\r
224 Status = gBS->RegisterProtocolNotify (\r
225 &gEfiS3SaveStateProtocolGuid,\r
226 mS3SaveStateInstalledEvent,\r
227 &Registration\r
228 );\r
7bb57805 229 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
230 DEBUG ((\r
231 DEBUG_ERROR,\r
232 "%a: %a: RegisterProtocolNotify(): %r\n",\r
233 gEfiCallerBaseName,\r
234 __FUNCTION__,\r
235 Status\r
236 ));\r
7bb57805
LE
237 goto CloseEvent;\r
238 }\r
239\r
240 //\r
241 // Set the remaining global variables. For the alignment guarantee on\r
242 // mScratchBuffer, we rely on the fact that *mDmaAccess has a size that is an\r
243 // integral multiple of RESERVED_MEM_ALIGNMENT.\r
244 //\r
245 ASSERT (sizeof *mDmaAccess % RESERVED_MEM_ALIGNMENT == 0);\r
ac0a286f 246 mScratchBuffer = mDmaAccess + 1;\r
7bb57805 247 mScratchBufferSize = ScratchBufferSize;\r
ac0a286f 248 mCallback = Callback;\r
7bb57805
LE
249\r
250 //\r
251 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.\r
252 //\r
253 Status = gBS->SignalEvent (mS3SaveStateInstalledEvent);\r
254 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
255 DEBUG ((\r
256 DEBUG_ERROR,\r
257 "%a: %a: SignalEvent(): %r\n",\r
258 gEfiCallerBaseName,\r
259 __FUNCTION__,\r
260 Status\r
261 ));\r
7bb57805
LE
262 goto NullGlobals;\r
263 }\r
264\r
265 return RETURN_SUCCESS;\r
266\r
267NullGlobals:\r
ac0a286f 268 mScratchBuffer = NULL;\r
7bb57805 269 mScratchBufferSize = 0;\r
ac0a286f 270 mCallback = NULL;\r
7bb57805
LE
271\r
272CloseEvent:\r
273 gBS->CloseEvent (mS3SaveStateInstalledEvent);\r
274 mS3SaveStateInstalledEvent = NULL;\r
275\r
276FreeDmaAccess:\r
277 FreePool (mDmaAccess);\r
278 mDmaAccess = NULL;\r
279\r
280 return (RETURN_STATUS)Status;\r
281}\r
282\r
7bb57805
LE
283/**\r
284 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,\r
285 and transfer data to it.\r
286\r
287 The opcodes produced by QemuFwCfgS3ScriptWriteBytes() will first restore\r
288 NumberOfBytes bytes in ScratchBuffer in-place, in reserved memory, then write\r
289 them to fw_cfg using DMA.\r
290\r
291 If the operation fails during S3 resume, the boot script will hang.\r
292\r
293 This function may only be called from the client module's\r
294 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
295 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
296\r
297 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config\r
298 item to write, expressed as INT32. If\r
299 FirmwareConfigItem is -1, no selection is\r
300 made, the write will occur to the currently\r
301 selected item, at its currently selected\r
302 offset. Otherwise, the specified item will be\r
303 selected, and the write will occur at offset\r
304 0.\r
305\r
306 @param[in] NumberOfBytes Size of the data to restore in ScratchBuffer,\r
307 and to write from ScratchBuffer, during S3\r
308 resume. NumberOfBytes must not exceed\r
309 ScratchBufferSize, which was passed to\r
310 QemuFwCfgS3CallWhenBootScriptReady().\r
311\r
312 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
313 Boot Script successfully. There is no way\r
314 to undo this action.\r
315\r
316 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.\r
317\r
318 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than\r
319 ScratchBufferSize.\r
320\r
321 @return Error codes from underlying functions.\r
322**/\r
7bb57805 323RETURN_STATUS\r
08bed3fb 324EFIAPI\r
7bb57805 325QemuFwCfgS3ScriptWriteBytes (\r
ac0a286f
MK
326 IN INT32 FirmwareConfigItem,\r
327 IN UINTN NumberOfBytes\r
7bb57805
LE
328 )\r
329{\r
ac0a286f
MK
330 UINTN Count;\r
331 EFI_STATUS Status;\r
332 UINT64 AccessAddress;\r
333 UINT32 ControlPollData;\r
334 UINT32 ControlPollMask;\r
7bb57805
LE
335\r
336 ASSERT (mDmaAccess != NULL);\r
337 ASSERT (mS3SaveState != NULL);\r
338\r
ac0a286f 339 if ((FirmwareConfigItem < -1) || (FirmwareConfigItem > MAX_UINT16)) {\r
7bb57805
LE
340 return RETURN_INVALID_PARAMETER;\r
341 }\r
ac0a286f 342\r
7bb57805
LE
343 if (NumberOfBytes > mScratchBufferSize) {\r
344 return RETURN_BAD_BUFFER_SIZE;\r
345 }\r
346\r
347 //\r
348 // Set up a write[+select] fw_cfg DMA command.\r
349 //\r
350 mDmaAccess->Control = FW_CFG_DMA_CTL_WRITE;\r
351 if (FirmwareConfigItem != -1) {\r
352 mDmaAccess->Control |= FW_CFG_DMA_CTL_SELECT;\r
353 mDmaAccess->Control |= (UINT32)FirmwareConfigItem << 16;\r
354 }\r
ac0a286f 355\r
7bb57805
LE
356 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);\r
357\r
358 //\r
359 // We ensured the following constraint via mScratchBufferSize in\r
360 // QemuFwCfgS3CallWhenBootScriptReady().\r
361 //\r
362 ASSERT (NumberOfBytes <= MAX_UINT32);\r
363 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);\r
364\r
365 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);\r
366\r
367 //\r
368 // Copy mDmaAccess and NumberOfBytes bytes from mScratchBuffer into the boot\r
369 // script. When executed at S3 resume, this opcode will restore all of them\r
370 // in-place.\r
371 //\r
ac0a286f 372 Count = (UINTN)mScratchBuffer + NumberOfBytes - (UINTN)mDmaAccess;\r
7bb57805
LE
373 Status = mS3SaveState->Write (\r
374 mS3SaveState, // This\r
375 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
376 EfiBootScriptWidthUint8, // Width\r
377 (UINT64)(UINTN)mDmaAccess, // Address\r
378 Count, // Count\r
379 (VOID *)mDmaAccess // Buffer\r
380 );\r
381 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
382 DEBUG ((\r
383 DEBUG_ERROR,\r
384 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
385 gEfiCallerBaseName,\r
386 __FUNCTION__,\r
387 Status\r
388 ));\r
7bb57805
LE
389 return (RETURN_STATUS)Status;\r
390 }\r
391\r
392 //\r
393 // Append an opcode that will write the address of the fw_cfg DMA command to\r
394 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.\r
395 // The second (highest address, least significant) write will start the\r
396 // transfer.\r
397 //\r
398 AccessAddress = SwapBytes64 ((UINTN)mDmaAccess);\r
ac0a286f
MK
399 Status = mS3SaveState->Write (\r
400 mS3SaveState, // This\r
401 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
402 EfiBootScriptWidthUint32, // Width\r
403 (UINT64)FW_CFG_IO_DMA_ADDRESS, // Address\r
404 (UINTN)2, // Count\r
405 (VOID *)&AccessAddress // Buffer\r
406 );\r
7bb57805 407 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
408 DEBUG ((\r
409 DEBUG_ERROR,\r
410 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
411 gEfiCallerBaseName,\r
412 __FUNCTION__,\r
413 Status\r
414 ));\r
7bb57805
LE
415 return (RETURN_STATUS)Status;\r
416 }\r
417\r
418 //\r
419 // The following opcode will wait until the Control word reads as zero\r
420 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is\r
421 // approximately 58494 years.\r
422 //\r
423 ControlPollData = 0;\r
424 ControlPollMask = MAX_UINT32;\r
ac0a286f
MK
425 Status = mS3SaveState->Write (\r
426 mS3SaveState, // This\r
427 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
428 EfiBootScriptWidthUint32, // Width\r
429 (UINT64)(UINTN)&mDmaAccess->Control, // Address\r
430 (VOID *)&ControlPollData, // Data\r
431 (VOID *)&ControlPollMask, // DataMask\r
432 MAX_UINT64 // Delay\r
433 );\r
7bb57805 434 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
435 DEBUG ((\r
436 DEBUG_ERROR,\r
437 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
438 gEfiCallerBaseName,\r
439 __FUNCTION__,\r
440 Status\r
441 ));\r
7bb57805
LE
442 return (RETURN_STATUS)Status;\r
443 }\r
444\r
445 return RETURN_SUCCESS;\r
446}\r
447\r
7bb57805
LE
448/**\r
449 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,\r
450 and transfer data from it.\r
451\r
452 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes\r
453 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved\r
454 memory.\r
455\r
456 If the operation fails during S3 resume, the boot script will hang.\r
457\r
458 This function may only be called from the client module's\r
459 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
460 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
461\r
462 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config\r
463 item to read, expressed as INT32. If\r
464 FirmwareConfigItem is -1, no selection is\r
465 made, the read will occur from the currently\r
466 selected item, from its currently selected\r
467 offset. Otherwise, the specified item will be\r
468 selected, and the read will occur from offset\r
469 0.\r
470\r
471 @param[in] NumberOfBytes Size of the data to read during S3 resume.\r
472 NumberOfBytes must not exceed\r
473 ScratchBufferSize, which was passed to\r
474 QemuFwCfgS3CallWhenBootScriptReady().\r
475\r
476 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
477 Boot Script successfully. There is no way\r
478 to undo this action.\r
479\r
480 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.\r
481\r
482 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than\r
483 ScratchBufferSize.\r
484\r
485 @return Error codes from underlying functions.\r
486**/\r
7bb57805 487RETURN_STATUS\r
08bed3fb 488EFIAPI\r
7bb57805 489QemuFwCfgS3ScriptReadBytes (\r
ac0a286f
MK
490 IN INT32 FirmwareConfigItem,\r
491 IN UINTN NumberOfBytes\r
7bb57805
LE
492 )\r
493{\r
ac0a286f
MK
494 EFI_STATUS Status;\r
495 UINT64 AccessAddress;\r
496 UINT32 ControlPollData;\r
497 UINT32 ControlPollMask;\r
7bb57805
LE
498\r
499 ASSERT (mDmaAccess != NULL);\r
500 ASSERT (mS3SaveState != NULL);\r
501\r
ac0a286f 502 if ((FirmwareConfigItem < -1) || (FirmwareConfigItem > MAX_UINT16)) {\r
7bb57805
LE
503 return RETURN_INVALID_PARAMETER;\r
504 }\r
ac0a286f 505\r
7bb57805
LE
506 if (NumberOfBytes > mScratchBufferSize) {\r
507 return RETURN_BAD_BUFFER_SIZE;\r
508 }\r
509\r
510 //\r
511 // Set up a read[+select] fw_cfg DMA command.\r
512 //\r
513 mDmaAccess->Control = FW_CFG_DMA_CTL_READ;\r
514 if (FirmwareConfigItem != -1) {\r
515 mDmaAccess->Control |= FW_CFG_DMA_CTL_SELECT;\r
516 mDmaAccess->Control |= (UINT32)FirmwareConfigItem << 16;\r
517 }\r
ac0a286f 518\r
7bb57805
LE
519 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);\r
520\r
521 //\r
522 // We ensured the following constraint via mScratchBufferSize in\r
523 // QemuFwCfgS3CallWhenBootScriptReady().\r
524 //\r
525 ASSERT (NumberOfBytes <= MAX_UINT32);\r
526 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);\r
527\r
528 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);\r
529\r
530 //\r
531 // Copy mDmaAccess into the boot script. When executed at S3 resume, this\r
532 // opcode will restore it in-place.\r
533 //\r
534 Status = mS3SaveState->Write (\r
535 mS3SaveState, // This\r
536 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
537 EfiBootScriptWidthUint8, // Width\r
538 (UINT64)(UINTN)mDmaAccess, // Address\r
539 sizeof *mDmaAccess, // Count\r
540 (VOID *)mDmaAccess // Buffer\r
541 );\r
542 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
543 DEBUG ((\r
544 DEBUG_ERROR,\r
545 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
546 gEfiCallerBaseName,\r
547 __FUNCTION__,\r
548 Status\r
549 ));\r
7bb57805
LE
550 return (RETURN_STATUS)Status;\r
551 }\r
552\r
553 //\r
554 // Append an opcode that will write the address of the fw_cfg DMA command to\r
555 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.\r
556 // The second (highest address, least significant) write will start the\r
557 // transfer.\r
558 //\r
559 AccessAddress = SwapBytes64 ((UINTN)mDmaAccess);\r
ac0a286f
MK
560 Status = mS3SaveState->Write (\r
561 mS3SaveState, // This\r
562 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
563 EfiBootScriptWidthUint32, // Width\r
564 (UINT64)FW_CFG_IO_DMA_ADDRESS, // Address\r
565 (UINTN)2, // Count\r
566 (VOID *)&AccessAddress // Buffer\r
567 );\r
7bb57805 568 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
569 DEBUG ((\r
570 DEBUG_ERROR,\r
571 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
572 gEfiCallerBaseName,\r
573 __FUNCTION__,\r
574 Status\r
575 ));\r
7bb57805
LE
576 return (RETURN_STATUS)Status;\r
577 }\r
578\r
579 //\r
580 // The following opcode will wait until the Control word reads as zero\r
581 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is\r
582 // approximately 58494 years.\r
583 //\r
584 ControlPollData = 0;\r
585 ControlPollMask = MAX_UINT32;\r
ac0a286f
MK
586 Status = mS3SaveState->Write (\r
587 mS3SaveState, // This\r
588 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
589 EfiBootScriptWidthUint32, // Width\r
590 (UINT64)(UINTN)&mDmaAccess->Control, // Address\r
591 (VOID *)&ControlPollData, // Data\r
592 (VOID *)&ControlPollMask, // DataMask\r
593 MAX_UINT64 // Delay\r
594 );\r
7bb57805 595 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
596 DEBUG ((\r
597 DEBUG_ERROR,\r
598 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
599 gEfiCallerBaseName,\r
600 __FUNCTION__,\r
601 Status\r
602 ));\r
7bb57805
LE
603 return (RETURN_STATUS)Status;\r
604 }\r
605\r
606 return RETURN_SUCCESS;\r
607}\r
608\r
7bb57805
LE
609/**\r
610 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,\r
611 and increase its offset.\r
612\r
613 If the operation fails during S3 resume, the boot script will hang.\r
614\r
615 This function may only be called from the client module's\r
616 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
617 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
618\r
619 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config\r
620 item to advance the offset of, expressed as\r
621 INT32. If FirmwareConfigItem is -1, no\r
622 selection is made, and the offset for the\r
623 currently selected item is increased.\r
624 Otherwise, the specified item will be\r
625 selected, and the offset increment will occur\r
626 from offset 0.\r
627\r
628 @param[in] NumberOfBytes The number of bytes to skip in the subject\r
629 fw_cfg item.\r
630\r
631 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
632 Boot Script successfully. There is no way\r
633 to undo this action.\r
634\r
635 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.\r
636\r
637 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.\r
638\r
639 @return Error codes from underlying functions.\r
640**/\r
7bb57805 641RETURN_STATUS\r
08bed3fb 642EFIAPI\r
7bb57805 643QemuFwCfgS3ScriptSkipBytes (\r
ac0a286f
MK
644 IN INT32 FirmwareConfigItem,\r
645 IN UINTN NumberOfBytes\r
7bb57805
LE
646 )\r
647{\r
ac0a286f
MK
648 EFI_STATUS Status;\r
649 UINT64 AccessAddress;\r
650 UINT32 ControlPollData;\r
651 UINT32 ControlPollMask;\r
7bb57805
LE
652\r
653 ASSERT (mDmaAccess != NULL);\r
654 ASSERT (mS3SaveState != NULL);\r
655\r
ac0a286f 656 if ((FirmwareConfigItem < -1) || (FirmwareConfigItem > MAX_UINT16)) {\r
7bb57805
LE
657 return RETURN_INVALID_PARAMETER;\r
658 }\r
ac0a286f 659\r
7bb57805
LE
660 if (NumberOfBytes > MAX_UINT32) {\r
661 return RETURN_BAD_BUFFER_SIZE;\r
662 }\r
663\r
664 //\r
665 // Set up a skip[+select] fw_cfg DMA command.\r
666 //\r
667 mDmaAccess->Control = FW_CFG_DMA_CTL_SKIP;\r
668 if (FirmwareConfigItem != -1) {\r
669 mDmaAccess->Control |= FW_CFG_DMA_CTL_SELECT;\r
670 mDmaAccess->Control |= (UINT32)FirmwareConfigItem << 16;\r
671 }\r
ac0a286f 672\r
7bb57805
LE
673 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);\r
674\r
ac0a286f 675 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);\r
7bb57805
LE
676 mDmaAccess->Address = 0;\r
677\r
678 //\r
679 // Copy mDmaAccess into the boot script. When executed at S3 resume, this\r
680 // opcode will restore it in-place.\r
681 //\r
682 Status = mS3SaveState->Write (\r
683 mS3SaveState, // This\r
684 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
685 EfiBootScriptWidthUint8, // Width\r
686 (UINT64)(UINTN)mDmaAccess, // Address\r
687 sizeof *mDmaAccess, // Count\r
688 (VOID *)mDmaAccess // Buffer\r
689 );\r
690 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
691 DEBUG ((\r
692 DEBUG_ERROR,\r
693 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
694 gEfiCallerBaseName,\r
695 __FUNCTION__,\r
696 Status\r
697 ));\r
7bb57805
LE
698 return (RETURN_STATUS)Status;\r
699 }\r
700\r
701 //\r
702 // Append an opcode that will write the address of the fw_cfg DMA command to\r
703 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.\r
704 // The second (highest address, least significant) write will start the\r
705 // transfer.\r
706 //\r
707 AccessAddress = SwapBytes64 ((UINTN)mDmaAccess);\r
ac0a286f
MK
708 Status = mS3SaveState->Write (\r
709 mS3SaveState, // This\r
710 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
711 EfiBootScriptWidthUint32, // Width\r
712 (UINT64)FW_CFG_IO_DMA_ADDRESS, // Address\r
713 (UINTN)2, // Count\r
714 (VOID *)&AccessAddress // Buffer\r
715 );\r
7bb57805 716 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
717 DEBUG ((\r
718 DEBUG_ERROR,\r
719 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
720 gEfiCallerBaseName,\r
721 __FUNCTION__,\r
722 Status\r
723 ));\r
7bb57805
LE
724 return (RETURN_STATUS)Status;\r
725 }\r
726\r
727 //\r
728 // The following opcode will wait until the Control word reads as zero\r
729 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is\r
730 // approximately 58494 years.\r
731 //\r
732 ControlPollData = 0;\r
733 ControlPollMask = MAX_UINT32;\r
ac0a286f
MK
734 Status = mS3SaveState->Write (\r
735 mS3SaveState, // This\r
736 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
737 EfiBootScriptWidthUint32, // Width\r
738 (UINT64)(UINTN)&mDmaAccess->Control, // Address\r
739 (VOID *)&ControlPollData, // Data\r
740 (VOID *)&ControlPollMask, // DataMask\r
741 MAX_UINT64 // Delay\r
742 );\r
7bb57805 743 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
744 DEBUG ((\r
745 DEBUG_ERROR,\r
746 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
747 gEfiCallerBaseName,\r
748 __FUNCTION__,\r
749 Status\r
750 ));\r
7bb57805
LE
751 return (RETURN_STATUS)Status;\r
752 }\r
753\r
754 return RETURN_SUCCESS;\r
755}\r
756\r
7bb57805
LE
757/**\r
758 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.\r
759\r
760 If the check fails during S3 resume, the boot script will hang.\r
761\r
762 This function may only be called from the client module's\r
763 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to\r
764 QemuFwCfgS3CallWhenBootScriptReady() as Callback.\r
765\r
766 @param[in] ScratchData Pointer to the UINT8, UINT16, UINT32 or UINT64 field\r
767 in ScratchBuffer that should be checked. The caller\r
768 is responsible for populating the field during S3\r
769 resume, by calling QemuFwCfgS3ScriptReadBytes() ahead\r
770 of QemuFwCfgS3ScriptCheckValue().\r
771\r
772 ScratchData must point into ScratchBuffer, which was\r
773 allocated, and passed to Callback(), by\r
774 QemuFwCfgS3CallWhenBootScriptReady().\r
775\r
776 ScratchData must be aligned at ValueSize bytes.\r
777\r
778 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field\r
779 to check.\r
780\r
781 @param[in] ValueMask The value read from ScratchData is binarily AND-ed\r
782 with ValueMask, and the result is compared against\r
783 Value. If the masked data equals Value, the check\r
784 passes, and the boot script can proceed. Otherwise,\r
785 the check fails, and the boot script hangs.\r
786\r
787 @param[in] Value Refer to ValueMask.\r
788\r
789 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3\r
790 Boot Script successfully. There is no way\r
791 to undo this action.\r
792\r
793 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.\r
794\r
795 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in\r
796 ValueSize bytes.\r
797\r
798 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize\r
799 bytes.\r
800\r
801 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't\r
802 wholly contained in the ScratchBufferSize\r
803 bytes at ScratchBuffer.\r
804\r
805 @return Error codes from underlying functions.\r
806**/\r
7bb57805 807RETURN_STATUS\r
08bed3fb 808EFIAPI\r
7bb57805 809QemuFwCfgS3ScriptCheckValue (\r
ac0a286f
MK
810 IN VOID *ScratchData,\r
811 IN UINT8 ValueSize,\r
812 IN UINT64 ValueMask,\r
813 IN UINT64 Value\r
7bb57805
LE
814 )\r
815{\r
ac0a286f
MK
816 EFI_BOOT_SCRIPT_WIDTH Width;\r
817 EFI_STATUS Status;\r
7bb57805
LE
818\r
819 ASSERT (mS3SaveState != NULL);\r
820\r
821 switch (ValueSize) {\r
ac0a286f
MK
822 case 1:\r
823 Width = EfiBootScriptWidthUint8;\r
824 break;\r
7bb57805 825\r
ac0a286f
MK
826 case 2:\r
827 Width = EfiBootScriptWidthUint16;\r
828 break;\r
7bb57805 829\r
ac0a286f
MK
830 case 4:\r
831 Width = EfiBootScriptWidthUint32;\r
832 break;\r
7bb57805 833\r
ac0a286f
MK
834 case 8:\r
835 Width = EfiBootScriptWidthUint64;\r
836 break;\r
7bb57805 837\r
ac0a286f
MK
838 default:\r
839 return RETURN_INVALID_PARAMETER;\r
7bb57805
LE
840 }\r
841\r
ac0a286f
MK
842 if ((ValueSize < 8) &&\r
843 ((RShiftU64 (ValueMask, ValueSize * 8) > 0) ||\r
844 (RShiftU64 (Value, ValueSize * 8) > 0)))\r
845 {\r
7bb57805
LE
846 return RETURN_INVALID_PARAMETER;\r
847 }\r
848\r
849 if ((UINTN)ScratchData % ValueSize > 0) {\r
850 return RETURN_INVALID_PARAMETER;\r
851 }\r
852\r
853 if (((UINTN)ScratchData < (UINTN)mScratchBuffer) ||\r
854 ((UINTN)ScratchData > MAX_UINTN - ValueSize) ||\r
855 ((UINTN)ScratchData + ValueSize >\r
ac0a286f
MK
856 (UINTN)mScratchBuffer + mScratchBufferSize))\r
857 {\r
7bb57805
LE
858 return RETURN_BAD_BUFFER_SIZE;\r
859 }\r
860\r
861 //\r
862 // The following opcode will wait "until" (*ScratchData & ValueMask) reads as\r
863 // Value, considering the least significant ValueSize bytes. As timeout we\r
864 // use MAX_UINT64 * 100ns, which is approximately 58494 years.\r
865 //\r
866 Status = mS3SaveState->Write (\r
867 mS3SaveState, // This\r
868 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode\r
869 Width, // Width\r
870 (UINT64)(UINTN)ScratchData, // Address\r
871 (VOID *)&Value, // Data\r
872 (VOID *)&ValueMask, // DataMask\r
873 MAX_UINT64 // Delay\r
874 );\r
875 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
876 DEBUG ((\r
877 DEBUG_ERROR,\r
878 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
879 gEfiCallerBaseName,\r
880 __FUNCTION__,\r
881 Status\r
882 ));\r
7bb57805
LE
883 return (RETURN_STATUS)Status;\r
884 }\r
885\r
886 return RETURN_SUCCESS;\r
887}\r