2 Full functionality QemuFwCfgS3Lib instance, for DXE phase modules.
4 Copyright (C) 2017, Red Hat, Inc.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/BaseLib.h>
10 #include <Library/DebugLib.h>
11 #include <Library/MemoryAllocationLib.h>
12 #include <Library/QemuFwCfgLib.h>
13 #include <Library/QemuFwCfgS3Lib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Protocol/S3SaveState.h>
19 // Event to signal when the S3SaveState protocol interface is installed.
21 STATIC EFI_EVENT mS3SaveStateInstalledEvent
;
24 // Reference to the S3SaveState protocol interface, after it is installed.
26 STATIC EFI_S3_SAVE_STATE_PROTOCOL
*mS3SaveState
;
29 // The control structure is allocated in reserved memory, aligned at 8 bytes.
30 // The client-requested ScratchBuffer will be allocated adjacently, also
31 // aligned at 8 bytes.
33 #define RESERVED_MEM_ALIGNMENT 8
35 STATIC FW_CFG_DMA_ACCESS
*mDmaAccess
;
36 STATIC VOID
*mScratchBuffer
;
37 STATIC UINTN mScratchBufferSize
;
40 // Callback provided by the client, for appending ACPI S3 Boot Script opcodes.
41 // To be called from S3SaveStateInstalledNotify().
43 STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION
*mCallback
;
47 Event notification function for mS3SaveStateInstalledEvent.
52 S3SaveStateInstalledNotify (
59 ASSERT (Event
== mS3SaveStateInstalledEvent
);
61 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
,
62 NULL
/* Registration */, (VOID
**)&mS3SaveState
);
63 if (EFI_ERROR (Status
)) {
67 ASSERT (mCallback
!= NULL
);
69 DEBUG ((DEBUG_INFO
, "%a: %a: DmaAccess@0x%Lx ScratchBuffer@[0x%Lx+0x%Lx]\n",
70 gEfiCallerBaseName
, __FUNCTION__
, (UINT64
)(UINTN
)mDmaAccess
,
71 (UINT64
)(UINTN
)mScratchBuffer
, (UINT64
)mScratchBufferSize
));
72 mCallback (Context
, mScratchBuffer
);
74 gBS
->CloseEvent (mS3SaveStateInstalledEvent
);
75 mS3SaveStateInstalledEvent
= NULL
;
80 Install the client module's FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION callback for
81 when the production of ACPI S3 Boot Script opcodes becomes possible.
83 Take ownership of the client-provided Context, and pass it to the callback
84 function, when the latter is invoked.
86 Allocate scratch space for those ACPI S3 Boot Script opcodes to work upon
87 that the client will produce in the callback function.
89 @param[in] Callback FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION to invoke
90 when the production of ACPI S3 Boot Script
91 opcodes becomes possible. Callback() may be
92 called immediately from
93 QemuFwCfgS3CallWhenBootScriptReady().
95 @param[in,out] Context Client-provided data structure for the
96 Callback() callback function to consume.
98 If Context points to dynamically allocated
99 memory, then Callback() must release it.
101 If Context points to dynamically allocated
103 QemuFwCfgS3CallWhenBootScriptReady() returns
104 successfully, then the caller of
105 QemuFwCfgS3CallWhenBootScriptReady() must
106 neither dereference nor even evaluate Context
107 any longer, as ownership of the referenced area
108 has been transferred to Callback().
110 @param[in] ScratchBufferSize The size of the scratch buffer that will hold,
111 in reserved memory, all client data read,
112 written, and checked by the ACPI S3 Boot Script
113 opcodes produced by Callback().
115 @retval RETURN_UNSUPPORTED The library instance does not support this
118 @retval RETURN_NOT_FOUND The fw_cfg DMA interface to QEMU is
121 @retval RETURN_BAD_BUFFER_SIZE ScratchBufferSize is too large.
123 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
125 @retval RETURN_SUCCESS Callback() has been installed, and the
126 ownership of Context has been transferred.
127 Reserved memory has been allocated for the
130 A successful invocation of
131 QemuFwCfgS3CallWhenBootScriptReady() cannot
134 @return Error codes from underlying functions.
138 QemuFwCfgS3CallWhenBootScriptReady (
139 IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION
*Callback
,
140 IN OUT VOID
*Context
, OPTIONAL
141 IN UINTN ScratchBufferSize
148 // Basic fw_cfg is certainly available, as we can only be here after a
149 // successful call to QemuFwCfgS3Enabled(). Check fw_cfg DMA availability.
151 ASSERT (QemuFwCfgIsAvailable ());
152 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
153 if ((QemuFwCfgRead32 () & FW_CFG_F_DMA
) == 0) {
154 DEBUG ((DEBUG_ERROR
, "%a: %a: fw_cfg DMA unavailable\n",
155 gEfiCallerBaseName
, __FUNCTION__
));
156 return RETURN_NOT_FOUND
;
160 // Allocate a reserved buffer for the DMA access control structure and the
161 // client data together.
163 if (ScratchBufferSize
>
164 MAX_UINT32
- (RESERVED_MEM_ALIGNMENT
- 1) - sizeof *mDmaAccess
) {
165 DEBUG ((DEBUG_ERROR
, "%a: %a: ScratchBufferSize too big: %Lu\n",
166 gEfiCallerBaseName
, __FUNCTION__
, (UINT64
)ScratchBufferSize
));
167 return RETURN_BAD_BUFFER_SIZE
;
169 mDmaAccess
= AllocateReservedPool ((RESERVED_MEM_ALIGNMENT
- 1) +
170 sizeof *mDmaAccess
+ ScratchBufferSize
);
171 if (mDmaAccess
== NULL
) {
172 DEBUG ((DEBUG_ERROR
, "%a: %a: AllocateReservedPool(): out of resources\n",
173 gEfiCallerBaseName
, __FUNCTION__
));
174 return RETURN_OUT_OF_RESOURCES
;
176 mDmaAccess
= ALIGN_POINTER (mDmaAccess
, RESERVED_MEM_ALIGNMENT
);
179 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the
180 // client's Context to the callback.
182 Status
= gBS
->CreateEvent (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
,
183 S3SaveStateInstalledNotify
, Context
,
184 &mS3SaveStateInstalledEvent
);
185 if (EFI_ERROR (Status
)) {
186 DEBUG ((DEBUG_ERROR
, "%a: %a: CreateEvent(): %r\n", gEfiCallerBaseName
,
187 __FUNCTION__
, Status
));
190 Status
= gBS
->RegisterProtocolNotify (&gEfiS3SaveStateProtocolGuid
,
191 mS3SaveStateInstalledEvent
, &Registration
);
192 if (EFI_ERROR (Status
)) {
193 DEBUG ((DEBUG_ERROR
, "%a: %a: RegisterProtocolNotify(): %r\n",
194 gEfiCallerBaseName
, __FUNCTION__
, Status
));
199 // Set the remaining global variables. For the alignment guarantee on
200 // mScratchBuffer, we rely on the fact that *mDmaAccess has a size that is an
201 // integral multiple of RESERVED_MEM_ALIGNMENT.
203 ASSERT (sizeof *mDmaAccess
% RESERVED_MEM_ALIGNMENT
== 0);
204 mScratchBuffer
= mDmaAccess
+ 1;
205 mScratchBufferSize
= ScratchBufferSize
;
206 mCallback
= Callback
;
209 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.
211 Status
= gBS
->SignalEvent (mS3SaveStateInstalledEvent
);
212 if (EFI_ERROR (Status
)) {
213 DEBUG ((DEBUG_ERROR
, "%a: %a: SignalEvent(): %r\n", gEfiCallerBaseName
,
214 __FUNCTION__
, Status
));
218 return RETURN_SUCCESS
;
221 mScratchBuffer
= NULL
;
222 mScratchBufferSize
= 0;
226 gBS
->CloseEvent (mS3SaveStateInstalledEvent
);
227 mS3SaveStateInstalledEvent
= NULL
;
230 FreePool (mDmaAccess
);
233 return (RETURN_STATUS
)Status
;
238 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
239 and transfer data to it.
241 The opcodes produced by QemuFwCfgS3ScriptWriteBytes() will first restore
242 NumberOfBytes bytes in ScratchBuffer in-place, in reserved memory, then write
243 them to fw_cfg using DMA.
245 If the operation fails during S3 resume, the boot script will hang.
247 This function may only be called from the client module's
248 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
249 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
251 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
252 item to write, expressed as INT32. If
253 FirmwareConfigItem is -1, no selection is
254 made, the write will occur to the currently
255 selected item, at its currently selected
256 offset. Otherwise, the specified item will be
257 selected, and the write will occur at offset
260 @param[in] NumberOfBytes Size of the data to restore in ScratchBuffer,
261 and to write from ScratchBuffer, during S3
262 resume. NumberOfBytes must not exceed
263 ScratchBufferSize, which was passed to
264 QemuFwCfgS3CallWhenBootScriptReady().
266 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
267 Boot Script successfully. There is no way
270 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
272 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
275 @return Error codes from underlying functions.
279 QemuFwCfgS3ScriptWriteBytes (
280 IN INT32 FirmwareConfigItem
,
281 IN UINTN NumberOfBytes
286 UINT64 AccessAddress
;
287 UINT32 ControlPollData
;
288 UINT32 ControlPollMask
;
290 ASSERT (mDmaAccess
!= NULL
);
291 ASSERT (mS3SaveState
!= NULL
);
293 if (FirmwareConfigItem
< -1 || FirmwareConfigItem
> MAX_UINT16
) {
294 return RETURN_INVALID_PARAMETER
;
296 if (NumberOfBytes
> mScratchBufferSize
) {
297 return RETURN_BAD_BUFFER_SIZE
;
301 // Set up a write[+select] fw_cfg DMA command.
303 mDmaAccess
->Control
= FW_CFG_DMA_CTL_WRITE
;
304 if (FirmwareConfigItem
!= -1) {
305 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
306 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
308 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
311 // We ensured the following constraint via mScratchBufferSize in
312 // QemuFwCfgS3CallWhenBootScriptReady().
314 ASSERT (NumberOfBytes
<= MAX_UINT32
);
315 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
317 mDmaAccess
->Address
= SwapBytes64 ((UINTN
)mScratchBuffer
);
320 // Copy mDmaAccess and NumberOfBytes bytes from mScratchBuffer into the boot
321 // script. When executed at S3 resume, this opcode will restore all of them
324 Count
= (UINTN
)mScratchBuffer
+ NumberOfBytes
- (UINTN
)mDmaAccess
;
325 Status
= mS3SaveState
->Write (
326 mS3SaveState
, // This
327 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
328 EfiBootScriptWidthUint8
, // Width
329 (UINT64
)(UINTN
)mDmaAccess
, // Address
331 (VOID
*)mDmaAccess
// Buffer
333 if (EFI_ERROR (Status
)) {
334 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
335 gEfiCallerBaseName
, __FUNCTION__
, Status
));
336 return (RETURN_STATUS
)Status
;
340 // Append an opcode that will write the address of the fw_cfg DMA command to
341 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
342 // The second (highest address, least significant) write will start the
345 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
346 Status
= mS3SaveState
->Write (
347 mS3SaveState
, // This
348 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
349 EfiBootScriptWidthUint32
, // Width
350 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
352 (VOID
*)&AccessAddress
// Buffer
354 if (EFI_ERROR (Status
)) {
355 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
356 gEfiCallerBaseName
, __FUNCTION__
, Status
));
357 return (RETURN_STATUS
)Status
;
361 // The following opcode will wait until the Control word reads as zero
362 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
363 // approximately 58494 years.
366 ControlPollMask
= MAX_UINT32
;
367 Status
= mS3SaveState
->Write (
368 mS3SaveState
, // This
369 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
370 EfiBootScriptWidthUint32
, // Width
371 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
372 (VOID
*)&ControlPollData
, // Data
373 (VOID
*)&ControlPollMask
, // DataMask
376 if (EFI_ERROR (Status
)) {
377 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
378 gEfiCallerBaseName
, __FUNCTION__
, Status
));
379 return (RETURN_STATUS
)Status
;
382 return RETURN_SUCCESS
;
387 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
388 and transfer data from it.
390 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
391 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
394 If the operation fails during S3 resume, the boot script will hang.
396 This function may only be called from the client module's
397 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
398 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
400 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
401 item to read, expressed as INT32. If
402 FirmwareConfigItem is -1, no selection is
403 made, the read will occur from the currently
404 selected item, from its currently selected
405 offset. Otherwise, the specified item will be
406 selected, and the read will occur from offset
409 @param[in] NumberOfBytes Size of the data to read during S3 resume.
410 NumberOfBytes must not exceed
411 ScratchBufferSize, which was passed to
412 QemuFwCfgS3CallWhenBootScriptReady().
414 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
415 Boot Script successfully. There is no way
418 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
420 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
423 @return Error codes from underlying functions.
427 QemuFwCfgS3ScriptReadBytes (
428 IN INT32 FirmwareConfigItem
,
429 IN UINTN NumberOfBytes
433 UINT64 AccessAddress
;
434 UINT32 ControlPollData
;
435 UINT32 ControlPollMask
;
437 ASSERT (mDmaAccess
!= NULL
);
438 ASSERT (mS3SaveState
!= NULL
);
440 if (FirmwareConfigItem
< -1 || FirmwareConfigItem
> MAX_UINT16
) {
441 return RETURN_INVALID_PARAMETER
;
443 if (NumberOfBytes
> mScratchBufferSize
) {
444 return RETURN_BAD_BUFFER_SIZE
;
448 // Set up a read[+select] fw_cfg DMA command.
450 mDmaAccess
->Control
= FW_CFG_DMA_CTL_READ
;
451 if (FirmwareConfigItem
!= -1) {
452 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
453 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
455 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
458 // We ensured the following constraint via mScratchBufferSize in
459 // QemuFwCfgS3CallWhenBootScriptReady().
461 ASSERT (NumberOfBytes
<= MAX_UINT32
);
462 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
464 mDmaAccess
->Address
= SwapBytes64 ((UINTN
)mScratchBuffer
);
467 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
468 // opcode will restore it in-place.
470 Status
= mS3SaveState
->Write (
471 mS3SaveState
, // This
472 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
473 EfiBootScriptWidthUint8
, // Width
474 (UINT64
)(UINTN
)mDmaAccess
, // Address
475 sizeof *mDmaAccess
, // Count
476 (VOID
*)mDmaAccess
// Buffer
478 if (EFI_ERROR (Status
)) {
479 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
480 gEfiCallerBaseName
, __FUNCTION__
, Status
));
481 return (RETURN_STATUS
)Status
;
485 // Append an opcode that will write the address of the fw_cfg DMA command to
486 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
487 // The second (highest address, least significant) write will start the
490 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
491 Status
= mS3SaveState
->Write (
492 mS3SaveState
, // This
493 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
494 EfiBootScriptWidthUint32
, // Width
495 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
497 (VOID
*)&AccessAddress
// Buffer
499 if (EFI_ERROR (Status
)) {
500 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
501 gEfiCallerBaseName
, __FUNCTION__
, Status
));
502 return (RETURN_STATUS
)Status
;
506 // The following opcode will wait until the Control word reads as zero
507 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
508 // approximately 58494 years.
511 ControlPollMask
= MAX_UINT32
;
512 Status
= mS3SaveState
->Write (
513 mS3SaveState
, // This
514 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
515 EfiBootScriptWidthUint32
, // Width
516 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
517 (VOID
*)&ControlPollData
, // Data
518 (VOID
*)&ControlPollMask
, // DataMask
521 if (EFI_ERROR (Status
)) {
522 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
523 gEfiCallerBaseName
, __FUNCTION__
, Status
));
524 return (RETURN_STATUS
)Status
;
527 return RETURN_SUCCESS
;
532 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
533 and increase its offset.
535 If the operation fails during S3 resume, the boot script will hang.
537 This function may only be called from the client module's
538 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
539 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
541 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
542 item to advance the offset of, expressed as
543 INT32. If FirmwareConfigItem is -1, no
544 selection is made, and the offset for the
545 currently selected item is increased.
546 Otherwise, the specified item will be
547 selected, and the offset increment will occur
550 @param[in] NumberOfBytes The number of bytes to skip in the subject
553 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
554 Boot Script successfully. There is no way
557 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
559 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.
561 @return Error codes from underlying functions.
565 QemuFwCfgS3ScriptSkipBytes (
566 IN INT32 FirmwareConfigItem
,
567 IN UINTN NumberOfBytes
571 UINT64 AccessAddress
;
572 UINT32 ControlPollData
;
573 UINT32 ControlPollMask
;
575 ASSERT (mDmaAccess
!= NULL
);
576 ASSERT (mS3SaveState
!= NULL
);
578 if (FirmwareConfigItem
< -1 || FirmwareConfigItem
> MAX_UINT16
) {
579 return RETURN_INVALID_PARAMETER
;
581 if (NumberOfBytes
> MAX_UINT32
) {
582 return RETURN_BAD_BUFFER_SIZE
;
586 // Set up a skip[+select] fw_cfg DMA command.
588 mDmaAccess
->Control
= FW_CFG_DMA_CTL_SKIP
;
589 if (FirmwareConfigItem
!= -1) {
590 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
591 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
593 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
595 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
596 mDmaAccess
->Address
= 0;
599 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
600 // opcode will restore it in-place.
602 Status
= mS3SaveState
->Write (
603 mS3SaveState
, // This
604 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
605 EfiBootScriptWidthUint8
, // Width
606 (UINT64
)(UINTN
)mDmaAccess
, // Address
607 sizeof *mDmaAccess
, // Count
608 (VOID
*)mDmaAccess
// Buffer
610 if (EFI_ERROR (Status
)) {
611 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
612 gEfiCallerBaseName
, __FUNCTION__
, Status
));
613 return (RETURN_STATUS
)Status
;
617 // Append an opcode that will write the address of the fw_cfg DMA command to
618 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
619 // The second (highest address, least significant) write will start the
622 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
623 Status
= mS3SaveState
->Write (
624 mS3SaveState
, // This
625 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
626 EfiBootScriptWidthUint32
, // Width
627 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
629 (VOID
*)&AccessAddress
// Buffer
631 if (EFI_ERROR (Status
)) {
632 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
633 gEfiCallerBaseName
, __FUNCTION__
, Status
));
634 return (RETURN_STATUS
)Status
;
638 // The following opcode will wait until the Control word reads as zero
639 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
640 // approximately 58494 years.
643 ControlPollMask
= MAX_UINT32
;
644 Status
= mS3SaveState
->Write (
645 mS3SaveState
, // This
646 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
647 EfiBootScriptWidthUint32
, // Width
648 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
649 (VOID
*)&ControlPollData
, // Data
650 (VOID
*)&ControlPollMask
, // DataMask
653 if (EFI_ERROR (Status
)) {
654 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
655 gEfiCallerBaseName
, __FUNCTION__
, Status
));
656 return (RETURN_STATUS
)Status
;
659 return RETURN_SUCCESS
;
664 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.
666 If the check fails during S3 resume, the boot script will hang.
668 This function may only be called from the client module's
669 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
670 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
672 @param[in] ScratchData Pointer to the UINT8, UINT16, UINT32 or UINT64 field
673 in ScratchBuffer that should be checked. The caller
674 is responsible for populating the field during S3
675 resume, by calling QemuFwCfgS3ScriptReadBytes() ahead
676 of QemuFwCfgS3ScriptCheckValue().
678 ScratchData must point into ScratchBuffer, which was
679 allocated, and passed to Callback(), by
680 QemuFwCfgS3CallWhenBootScriptReady().
682 ScratchData must be aligned at ValueSize bytes.
684 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field
687 @param[in] ValueMask The value read from ScratchData is binarily AND-ed
688 with ValueMask, and the result is compared against
689 Value. If the masked data equals Value, the check
690 passes, and the boot script can proceed. Otherwise,
691 the check fails, and the boot script hangs.
693 @param[in] Value Refer to ValueMask.
695 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
696 Boot Script successfully. There is no way
699 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.
701 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in
704 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize
707 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't
708 wholly contained in the ScratchBufferSize
709 bytes at ScratchBuffer.
711 @return Error codes from underlying functions.
715 QemuFwCfgS3ScriptCheckValue (
716 IN VOID
*ScratchData
,
722 EFI_BOOT_SCRIPT_WIDTH Width
;
725 ASSERT (mS3SaveState
!= NULL
);
729 Width
= EfiBootScriptWidthUint8
;
733 Width
= EfiBootScriptWidthUint16
;
737 Width
= EfiBootScriptWidthUint32
;
741 Width
= EfiBootScriptWidthUint64
;
745 return RETURN_INVALID_PARAMETER
;
749 (RShiftU64 (ValueMask
, ValueSize
* 8) > 0 ||
750 RShiftU64 (Value
, ValueSize
* 8) > 0)) {
751 return RETURN_INVALID_PARAMETER
;
754 if ((UINTN
)ScratchData
% ValueSize
> 0) {
755 return RETURN_INVALID_PARAMETER
;
758 if (((UINTN
)ScratchData
< (UINTN
)mScratchBuffer
) ||
759 ((UINTN
)ScratchData
> MAX_UINTN
- ValueSize
) ||
760 ((UINTN
)ScratchData
+ ValueSize
>
761 (UINTN
)mScratchBuffer
+ mScratchBufferSize
)) {
762 return RETURN_BAD_BUFFER_SIZE
;
766 // The following opcode will wait "until" (*ScratchData & ValueMask) reads as
767 // Value, considering the least significant ValueSize bytes. As timeout we
768 // use MAX_UINT64 * 100ns, which is approximately 58494 years.
770 Status
= mS3SaveState
->Write (
771 mS3SaveState
, // This
772 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
774 (UINT64
)(UINTN
)ScratchData
, // Address
775 (VOID
*)&Value
, // Data
776 (VOID
*)&ValueMask
, // DataMask
779 if (EFI_ERROR (Status
)) {
780 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
781 gEfiCallerBaseName
, __FUNCTION__
, Status
));
782 return (RETURN_STATUS
)Status
;
785 return RETURN_SUCCESS
;