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>
18 // Event to signal when the S3SaveState protocol interface is installed.
20 STATIC EFI_EVENT mS3SaveStateInstalledEvent
;
23 // Reference to the S3SaveState protocol interface, after it is installed.
25 STATIC EFI_S3_SAVE_STATE_PROTOCOL
*mS3SaveState
;
28 // The control structure is allocated in reserved memory, aligned at 8 bytes.
29 // The client-requested ScratchBuffer will be allocated adjacently, also
30 // aligned at 8 bytes.
32 #define RESERVED_MEM_ALIGNMENT 8
34 STATIC FW_CFG_DMA_ACCESS
*mDmaAccess
;
35 STATIC VOID
*mScratchBuffer
;
36 STATIC UINTN mScratchBufferSize
;
39 // Callback provided by the client, for appending ACPI S3 Boot Script opcodes.
40 // To be called from S3SaveStateInstalledNotify().
42 STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION
*mCallback
;
45 Event notification function for mS3SaveStateInstalledEvent.
50 S3SaveStateInstalledNotify (
57 ASSERT (Event
== mS3SaveStateInstalledEvent
);
59 Status
= gBS
->LocateProtocol (
60 &gEfiS3SaveStateProtocolGuid
,
61 NULL
/* Registration */,
62 (VOID
**)&mS3SaveState
64 if (EFI_ERROR (Status
)) {
68 ASSERT (mCallback
!= NULL
);
72 "%a: %a: DmaAccess@0x%Lx ScratchBuffer@[0x%Lx+0x%Lx]\n",
75 (UINT64
)(UINTN
)mDmaAccess
,
76 (UINT64
)(UINTN
)mScratchBuffer
,
77 (UINT64
)mScratchBufferSize
79 mCallback (Context
, mScratchBuffer
);
81 gBS
->CloseEvent (mS3SaveStateInstalledEvent
);
82 mS3SaveStateInstalledEvent
= NULL
;
86 Install the client module's FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION callback for
87 when the production of ACPI S3 Boot Script opcodes becomes possible.
89 Take ownership of the client-provided Context, and pass it to the callback
90 function, when the latter is invoked.
92 Allocate scratch space for those ACPI S3 Boot Script opcodes to work upon
93 that the client will produce in the callback function.
95 @param[in] Callback FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION to invoke
96 when the production of ACPI S3 Boot Script
97 opcodes becomes possible. Callback() may be
98 called immediately from
99 QemuFwCfgS3CallWhenBootScriptReady().
101 @param[in,out] Context Client-provided data structure for the
102 Callback() callback function to consume.
104 If Context points to dynamically allocated
105 memory, then Callback() must release it.
107 If Context points to dynamically allocated
109 QemuFwCfgS3CallWhenBootScriptReady() returns
110 successfully, then the caller of
111 QemuFwCfgS3CallWhenBootScriptReady() must
112 neither dereference nor even evaluate Context
113 any longer, as ownership of the referenced area
114 has been transferred to Callback().
116 @param[in] ScratchBufferSize The size of the scratch buffer that will hold,
117 in reserved memory, all client data read,
118 written, and checked by the ACPI S3 Boot Script
119 opcodes produced by Callback().
121 @retval RETURN_UNSUPPORTED The library instance does not support this
124 @retval RETURN_NOT_FOUND The fw_cfg DMA interface to QEMU is
127 @retval RETURN_BAD_BUFFER_SIZE ScratchBufferSize is too large.
129 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
131 @retval RETURN_SUCCESS Callback() has been installed, and the
132 ownership of Context has been transferred.
133 Reserved memory has been allocated for the
136 A successful invocation of
137 QemuFwCfgS3CallWhenBootScriptReady() cannot
140 @return Error codes from underlying functions.
144 QemuFwCfgS3CallWhenBootScriptReady (
145 IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION
*Callback
,
146 IN OUT VOID
*Context OPTIONAL
,
147 IN UINTN ScratchBufferSize
154 // Basic fw_cfg is certainly available, as we can only be here after a
155 // successful call to QemuFwCfgS3Enabled(). Check fw_cfg DMA availability.
157 ASSERT (QemuFwCfgIsAvailable ());
158 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
159 if ((QemuFwCfgRead32 () & FW_CFG_F_DMA
) == 0) {
162 "%a: %a: fw_cfg DMA unavailable\n",
166 return RETURN_NOT_FOUND
;
170 // Allocate a reserved buffer for the DMA access control structure and the
171 // client data together.
173 if (ScratchBufferSize
>
174 MAX_UINT32
- (RESERVED_MEM_ALIGNMENT
- 1) - sizeof *mDmaAccess
)
178 "%a: %a: ScratchBufferSize too big: %Lu\n",
181 (UINT64
)ScratchBufferSize
183 return RETURN_BAD_BUFFER_SIZE
;
186 mDmaAccess
= AllocateReservedPool (
187 (RESERVED_MEM_ALIGNMENT
- 1) +
188 sizeof *mDmaAccess
+ ScratchBufferSize
190 if (mDmaAccess
== NULL
) {
193 "%a: %a: AllocateReservedPool(): out of resources\n",
197 return RETURN_OUT_OF_RESOURCES
;
200 mDmaAccess
= ALIGN_POINTER (mDmaAccess
, RESERVED_MEM_ALIGNMENT
);
203 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the
204 // client's Context to the callback.
206 Status
= gBS
->CreateEvent (
209 S3SaveStateInstalledNotify
,
211 &mS3SaveStateInstalledEvent
213 if (EFI_ERROR (Status
)) {
216 "%a: %a: CreateEvent(): %r\n",
224 Status
= gBS
->RegisterProtocolNotify (
225 &gEfiS3SaveStateProtocolGuid
,
226 mS3SaveStateInstalledEvent
,
229 if (EFI_ERROR (Status
)) {
232 "%a: %a: RegisterProtocolNotify(): %r\n",
241 // Set the remaining global variables. For the alignment guarantee on
242 // mScratchBuffer, we rely on the fact that *mDmaAccess has a size that is an
243 // integral multiple of RESERVED_MEM_ALIGNMENT.
245 ASSERT (sizeof *mDmaAccess
% RESERVED_MEM_ALIGNMENT
== 0);
246 mScratchBuffer
= mDmaAccess
+ 1;
247 mScratchBufferSize
= ScratchBufferSize
;
248 mCallback
= Callback
;
251 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.
253 Status
= gBS
->SignalEvent (mS3SaveStateInstalledEvent
);
254 if (EFI_ERROR (Status
)) {
257 "%a: %a: SignalEvent(): %r\n",
265 return RETURN_SUCCESS
;
268 mScratchBuffer
= NULL
;
269 mScratchBufferSize
= 0;
273 gBS
->CloseEvent (mS3SaveStateInstalledEvent
);
274 mS3SaveStateInstalledEvent
= NULL
;
277 FreePool (mDmaAccess
);
280 return (RETURN_STATUS
)Status
;
284 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
285 and transfer data to it.
287 The opcodes produced by QemuFwCfgS3ScriptWriteBytes() will first restore
288 NumberOfBytes bytes in ScratchBuffer in-place, in reserved memory, then write
289 them to fw_cfg using DMA.
291 If the operation fails during S3 resume, the boot script will hang.
293 This function may only be called from the client module's
294 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
295 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
297 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
298 item to write, expressed as INT32. If
299 FirmwareConfigItem is -1, no selection is
300 made, the write will occur to the currently
301 selected item, at its currently selected
302 offset. Otherwise, the specified item will be
303 selected, and the write will occur at offset
306 @param[in] NumberOfBytes Size of the data to restore in ScratchBuffer,
307 and to write from ScratchBuffer, during S3
308 resume. NumberOfBytes must not exceed
309 ScratchBufferSize, which was passed to
310 QemuFwCfgS3CallWhenBootScriptReady().
312 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
313 Boot Script successfully. There is no way
316 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
318 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
321 @return Error codes from underlying functions.
325 QemuFwCfgS3ScriptWriteBytes (
326 IN INT32 FirmwareConfigItem
,
327 IN UINTN NumberOfBytes
332 UINT64 AccessAddress
;
333 UINT32 ControlPollData
;
334 UINT32 ControlPollMask
;
336 ASSERT (mDmaAccess
!= NULL
);
337 ASSERT (mS3SaveState
!= NULL
);
339 if ((FirmwareConfigItem
< -1) || (FirmwareConfigItem
> MAX_UINT16
)) {
340 return RETURN_INVALID_PARAMETER
;
343 if (NumberOfBytes
> mScratchBufferSize
) {
344 return RETURN_BAD_BUFFER_SIZE
;
348 // Set up a write[+select] fw_cfg DMA command.
350 mDmaAccess
->Control
= FW_CFG_DMA_CTL_WRITE
;
351 if (FirmwareConfigItem
!= -1) {
352 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
353 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
356 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
359 // We ensured the following constraint via mScratchBufferSize in
360 // QemuFwCfgS3CallWhenBootScriptReady().
362 ASSERT (NumberOfBytes
<= MAX_UINT32
);
363 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
365 mDmaAccess
->Address
= SwapBytes64 ((UINTN
)mScratchBuffer
);
368 // Copy mDmaAccess and NumberOfBytes bytes from mScratchBuffer into the boot
369 // script. When executed at S3 resume, this opcode will restore all of them
372 Count
= (UINTN
)mScratchBuffer
+ NumberOfBytes
- (UINTN
)mDmaAccess
;
373 Status
= mS3SaveState
->Write (
374 mS3SaveState
, // This
375 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
376 EfiBootScriptWidthUint8
, // Width
377 (UINT64
)(UINTN
)mDmaAccess
, // Address
379 (VOID
*)mDmaAccess
// Buffer
381 if (EFI_ERROR (Status
)) {
384 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
389 return (RETURN_STATUS
)Status
;
393 // Append an opcode that will write the address of the fw_cfg DMA command to
394 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
395 // The second (highest address, least significant) write will start the
398 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
399 Status
= mS3SaveState
->Write (
400 mS3SaveState
, // This
401 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
402 EfiBootScriptWidthUint32
, // Width
403 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
405 (VOID
*)&AccessAddress
// Buffer
407 if (EFI_ERROR (Status
)) {
410 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
415 return (RETURN_STATUS
)Status
;
419 // The following opcode will wait until the Control word reads as zero
420 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
421 // approximately 58494 years.
424 ControlPollMask
= MAX_UINT32
;
425 Status
= mS3SaveState
->Write (
426 mS3SaveState
, // This
427 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
428 EfiBootScriptWidthUint32
, // Width
429 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
430 (VOID
*)&ControlPollData
, // Data
431 (VOID
*)&ControlPollMask
, // DataMask
434 if (EFI_ERROR (Status
)) {
437 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
442 return (RETURN_STATUS
)Status
;
445 return RETURN_SUCCESS
;
449 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
450 and transfer data from it.
452 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
453 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
456 If the operation fails during S3 resume, the boot script will hang.
458 This function may only be called from the client module's
459 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
460 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
462 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
463 item to read, expressed as INT32. If
464 FirmwareConfigItem is -1, no selection is
465 made, the read will occur from the currently
466 selected item, from its currently selected
467 offset. Otherwise, the specified item will be
468 selected, and the read will occur from offset
471 @param[in] NumberOfBytes Size of the data to read during S3 resume.
472 NumberOfBytes must not exceed
473 ScratchBufferSize, which was passed to
474 QemuFwCfgS3CallWhenBootScriptReady().
476 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
477 Boot Script successfully. There is no way
480 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
482 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
485 @return Error codes from underlying functions.
489 QemuFwCfgS3ScriptReadBytes (
490 IN INT32 FirmwareConfigItem
,
491 IN UINTN NumberOfBytes
495 UINT64 AccessAddress
;
496 UINT32 ControlPollData
;
497 UINT32 ControlPollMask
;
499 ASSERT (mDmaAccess
!= NULL
);
500 ASSERT (mS3SaveState
!= NULL
);
502 if ((FirmwareConfigItem
< -1) || (FirmwareConfigItem
> MAX_UINT16
)) {
503 return RETURN_INVALID_PARAMETER
;
506 if (NumberOfBytes
> mScratchBufferSize
) {
507 return RETURN_BAD_BUFFER_SIZE
;
511 // Set up a read[+select] fw_cfg DMA command.
513 mDmaAccess
->Control
= FW_CFG_DMA_CTL_READ
;
514 if (FirmwareConfigItem
!= -1) {
515 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
516 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
519 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
522 // We ensured the following constraint via mScratchBufferSize in
523 // QemuFwCfgS3CallWhenBootScriptReady().
525 ASSERT (NumberOfBytes
<= MAX_UINT32
);
526 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
528 mDmaAccess
->Address
= SwapBytes64 ((UINTN
)mScratchBuffer
);
531 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
532 // opcode will restore it in-place.
534 Status
= mS3SaveState
->Write (
535 mS3SaveState
, // This
536 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
537 EfiBootScriptWidthUint8
, // Width
538 (UINT64
)(UINTN
)mDmaAccess
, // Address
539 sizeof *mDmaAccess
, // Count
540 (VOID
*)mDmaAccess
// Buffer
542 if (EFI_ERROR (Status
)) {
545 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
550 return (RETURN_STATUS
)Status
;
554 // Append an opcode that will write the address of the fw_cfg DMA command to
555 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
556 // The second (highest address, least significant) write will start the
559 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
560 Status
= mS3SaveState
->Write (
561 mS3SaveState
, // This
562 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
563 EfiBootScriptWidthUint32
, // Width
564 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
566 (VOID
*)&AccessAddress
// Buffer
568 if (EFI_ERROR (Status
)) {
571 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
576 return (RETURN_STATUS
)Status
;
580 // The following opcode will wait until the Control word reads as zero
581 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
582 // approximately 58494 years.
585 ControlPollMask
= MAX_UINT32
;
586 Status
= mS3SaveState
->Write (
587 mS3SaveState
, // This
588 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
589 EfiBootScriptWidthUint32
, // Width
590 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
591 (VOID
*)&ControlPollData
, // Data
592 (VOID
*)&ControlPollMask
, // DataMask
595 if (EFI_ERROR (Status
)) {
598 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
603 return (RETURN_STATUS
)Status
;
606 return RETURN_SUCCESS
;
610 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
611 and increase its offset.
613 If the operation fails during S3 resume, the boot script will hang.
615 This function may only be called from the client module's
616 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
617 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
619 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
620 item to advance the offset of, expressed as
621 INT32. If FirmwareConfigItem is -1, no
622 selection is made, and the offset for the
623 currently selected item is increased.
624 Otherwise, the specified item will be
625 selected, and the offset increment will occur
628 @param[in] NumberOfBytes The number of bytes to skip in the subject
631 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
632 Boot Script successfully. There is no way
635 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
637 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.
639 @return Error codes from underlying functions.
643 QemuFwCfgS3ScriptSkipBytes (
644 IN INT32 FirmwareConfigItem
,
645 IN UINTN NumberOfBytes
649 UINT64 AccessAddress
;
650 UINT32 ControlPollData
;
651 UINT32 ControlPollMask
;
653 ASSERT (mDmaAccess
!= NULL
);
654 ASSERT (mS3SaveState
!= NULL
);
656 if ((FirmwareConfigItem
< -1) || (FirmwareConfigItem
> MAX_UINT16
)) {
657 return RETURN_INVALID_PARAMETER
;
660 if (NumberOfBytes
> MAX_UINT32
) {
661 return RETURN_BAD_BUFFER_SIZE
;
665 // Set up a skip[+select] fw_cfg DMA command.
667 mDmaAccess
->Control
= FW_CFG_DMA_CTL_SKIP
;
668 if (FirmwareConfigItem
!= -1) {
669 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
670 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
673 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
675 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
676 mDmaAccess
->Address
= 0;
679 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
680 // opcode will restore it in-place.
682 Status
= mS3SaveState
->Write (
683 mS3SaveState
, // This
684 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
685 EfiBootScriptWidthUint8
, // Width
686 (UINT64
)(UINTN
)mDmaAccess
, // Address
687 sizeof *mDmaAccess
, // Count
688 (VOID
*)mDmaAccess
// Buffer
690 if (EFI_ERROR (Status
)) {
693 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
698 return (RETURN_STATUS
)Status
;
702 // Append an opcode that will write the address of the fw_cfg DMA command to
703 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
704 // The second (highest address, least significant) write will start the
707 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
708 Status
= mS3SaveState
->Write (
709 mS3SaveState
, // This
710 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
711 EfiBootScriptWidthUint32
, // Width
712 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
714 (VOID
*)&AccessAddress
// Buffer
716 if (EFI_ERROR (Status
)) {
719 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
724 return (RETURN_STATUS
)Status
;
728 // The following opcode will wait until the Control word reads as zero
729 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
730 // approximately 58494 years.
733 ControlPollMask
= MAX_UINT32
;
734 Status
= mS3SaveState
->Write (
735 mS3SaveState
, // This
736 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
737 EfiBootScriptWidthUint32
, // Width
738 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
739 (VOID
*)&ControlPollData
, // Data
740 (VOID
*)&ControlPollMask
, // DataMask
743 if (EFI_ERROR (Status
)) {
746 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
751 return (RETURN_STATUS
)Status
;
754 return RETURN_SUCCESS
;
758 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.
760 If the check fails during S3 resume, the boot script will hang.
762 This function may only be called from the client module's
763 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
764 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
766 @param[in] ScratchData Pointer to the UINT8, UINT16, UINT32 or UINT64 field
767 in ScratchBuffer that should be checked. The caller
768 is responsible for populating the field during S3
769 resume, by calling QemuFwCfgS3ScriptReadBytes() ahead
770 of QemuFwCfgS3ScriptCheckValue().
772 ScratchData must point into ScratchBuffer, which was
773 allocated, and passed to Callback(), by
774 QemuFwCfgS3CallWhenBootScriptReady().
776 ScratchData must be aligned at ValueSize bytes.
778 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field
781 @param[in] ValueMask The value read from ScratchData is binarily AND-ed
782 with ValueMask, and the result is compared against
783 Value. If the masked data equals Value, the check
784 passes, and the boot script can proceed. Otherwise,
785 the check fails, and the boot script hangs.
787 @param[in] Value Refer to ValueMask.
789 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
790 Boot Script successfully. There is no way
793 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.
795 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in
798 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize
801 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't
802 wholly contained in the ScratchBufferSize
803 bytes at ScratchBuffer.
805 @return Error codes from underlying functions.
809 QemuFwCfgS3ScriptCheckValue (
810 IN VOID
*ScratchData
,
816 EFI_BOOT_SCRIPT_WIDTH Width
;
819 ASSERT (mS3SaveState
!= NULL
);
823 Width
= EfiBootScriptWidthUint8
;
827 Width
= EfiBootScriptWidthUint16
;
831 Width
= EfiBootScriptWidthUint32
;
835 Width
= EfiBootScriptWidthUint64
;
839 return RETURN_INVALID_PARAMETER
;
842 if ((ValueSize
< 8) &&
843 ((RShiftU64 (ValueMask
, ValueSize
* 8) > 0) ||
844 (RShiftU64 (Value
, ValueSize
* 8) > 0)))
846 return RETURN_INVALID_PARAMETER
;
849 if ((UINTN
)ScratchData
% ValueSize
> 0) {
850 return RETURN_INVALID_PARAMETER
;
853 if (((UINTN
)ScratchData
< (UINTN
)mScratchBuffer
) ||
854 ((UINTN
)ScratchData
> MAX_UINTN
- ValueSize
) ||
855 ((UINTN
)ScratchData
+ ValueSize
>
856 (UINTN
)mScratchBuffer
+ mScratchBufferSize
))
858 return RETURN_BAD_BUFFER_SIZE
;
862 // The following opcode will wait "until" (*ScratchData & ValueMask) reads as
863 // Value, considering the least significant ValueSize bytes. As timeout we
864 // use MAX_UINT64 * 100ns, which is approximately 58494 years.
866 Status
= mS3SaveState
->Write (
867 mS3SaveState
, // This
868 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
870 (UINT64
)(UINTN
)ScratchData
, // Address
871 (VOID
*)&Value
, // Data
872 (VOID
*)&ValueMask
, // DataMask
875 if (EFI_ERROR (Status
)) {
878 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
883 return (RETURN_STATUS
)Status
;
886 return RETURN_SUCCESS
;