2 Full functionality QemuFwCfgS3Lib instance, for DXE phase modules.
4 Copyright (C) 2017, Red Hat, Inc.
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <Library/BaseLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/QemuFwCfgLib.h>
19 #include <Library/QemuFwCfgS3Lib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Protocol/S3SaveState.h>
25 // Event to signal when the S3SaveState protocol interface is installed.
27 STATIC EFI_EVENT mS3SaveStateInstalledEvent
;
30 // Reference to the S3SaveState protocol interface, after it is installed.
32 STATIC EFI_S3_SAVE_STATE_PROTOCOL
*mS3SaveState
;
35 // The control structure is allocated in reserved memory, aligned at 8 bytes.
36 // The client-requested ScratchBuffer will be allocated adjacently, also
37 // aligned at 8 bytes.
39 #define RESERVED_MEM_ALIGNMENT 8
41 STATIC FW_CFG_DMA_ACCESS
*mDmaAccess
;
42 STATIC VOID
*mScratchBuffer
;
43 STATIC UINTN mScratchBufferSize
;
46 // Callback provided by the client, for appending ACPI S3 Boot Script opcodes.
47 // To be called from S3SaveStateInstalledNotify().
49 STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION
*mCallback
;
53 Event notification function for mS3SaveStateInstalledEvent.
58 S3SaveStateInstalledNotify (
65 ASSERT (Event
== mS3SaveStateInstalledEvent
);
67 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
,
68 NULL
/* Registration */, (VOID
**)&mS3SaveState
);
69 if (EFI_ERROR (Status
)) {
73 ASSERT (mCallback
!= NULL
);
75 DEBUG ((DEBUG_INFO
, "%a: %a: DmaAccess@0x%Lx ScratchBuffer@[0x%Lx+0x%Lx]\n",
76 gEfiCallerBaseName
, __FUNCTION__
, (UINT64
)(UINTN
)mDmaAccess
,
77 (UINT64
)(UINTN
)mScratchBuffer
, (UINT64
)mScratchBufferSize
));
78 mCallback (Context
, mScratchBuffer
);
80 gBS
->CloseEvent (mS3SaveStateInstalledEvent
);
81 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) {
160 DEBUG ((DEBUG_ERROR
, "%a: %a: fw_cfg DMA unavailable\n",
161 gEfiCallerBaseName
, __FUNCTION__
));
162 return RETURN_NOT_FOUND
;
166 // Allocate a reserved buffer for the DMA access control structure and the
167 // client data together.
169 if (ScratchBufferSize
>
170 MAX_UINT32
- (RESERVED_MEM_ALIGNMENT
- 1) - sizeof *mDmaAccess
) {
171 DEBUG ((DEBUG_ERROR
, "%a: %a: ScratchBufferSize too big: %Lu\n",
172 gEfiCallerBaseName
, __FUNCTION__
, (UINT64
)ScratchBufferSize
));
173 return RETURN_BAD_BUFFER_SIZE
;
175 mDmaAccess
= AllocateReservedPool ((RESERVED_MEM_ALIGNMENT
- 1) +
176 sizeof *mDmaAccess
+ ScratchBufferSize
);
177 if (mDmaAccess
== NULL
) {
178 DEBUG ((DEBUG_ERROR
, "%a: %a: AllocateReservedPool(): out of resources\n",
179 gEfiCallerBaseName
, __FUNCTION__
));
180 return RETURN_OUT_OF_RESOURCES
;
182 mDmaAccess
= ALIGN_POINTER (mDmaAccess
, RESERVED_MEM_ALIGNMENT
);
185 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the
186 // client's Context to the callback.
188 Status
= gBS
->CreateEvent (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
,
189 S3SaveStateInstalledNotify
, Context
,
190 &mS3SaveStateInstalledEvent
);
191 if (EFI_ERROR (Status
)) {
192 DEBUG ((DEBUG_ERROR
, "%a: %a: CreateEvent(): %r\n", gEfiCallerBaseName
,
193 __FUNCTION__
, Status
));
196 Status
= gBS
->RegisterProtocolNotify (&gEfiS3SaveStateProtocolGuid
,
197 mS3SaveStateInstalledEvent
, &Registration
);
198 if (EFI_ERROR (Status
)) {
199 DEBUG ((DEBUG_ERROR
, "%a: %a: RegisterProtocolNotify(): %r\n",
200 gEfiCallerBaseName
, __FUNCTION__
, Status
));
205 // Set the remaining global variables. For the alignment guarantee on
206 // mScratchBuffer, we rely on the fact that *mDmaAccess has a size that is an
207 // integral multiple of RESERVED_MEM_ALIGNMENT.
209 ASSERT (sizeof *mDmaAccess
% RESERVED_MEM_ALIGNMENT
== 0);
210 mScratchBuffer
= mDmaAccess
+ 1;
211 mScratchBufferSize
= ScratchBufferSize
;
212 mCallback
= Callback
;
215 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.
217 Status
= gBS
->SignalEvent (mS3SaveStateInstalledEvent
);
218 if (EFI_ERROR (Status
)) {
219 DEBUG ((DEBUG_ERROR
, "%a: %a: SignalEvent(): %r\n", gEfiCallerBaseName
,
220 __FUNCTION__
, Status
));
224 return RETURN_SUCCESS
;
227 mScratchBuffer
= NULL
;
228 mScratchBufferSize
= 0;
232 gBS
->CloseEvent (mS3SaveStateInstalledEvent
);
233 mS3SaveStateInstalledEvent
= NULL
;
236 FreePool (mDmaAccess
);
239 return (RETURN_STATUS
)Status
;
244 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
245 and transfer data to it.
247 The opcodes produced by QemuFwCfgS3ScriptWriteBytes() will first restore
248 NumberOfBytes bytes in ScratchBuffer in-place, in reserved memory, then write
249 them to fw_cfg using DMA.
251 If the operation fails during S3 resume, the boot script will hang.
253 This function may only be called from the client module's
254 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
255 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
257 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
258 item to write, expressed as INT32. If
259 FirmwareConfigItem is -1, no selection is
260 made, the write will occur to the currently
261 selected item, at its currently selected
262 offset. Otherwise, the specified item will be
263 selected, and the write will occur at offset
266 @param[in] NumberOfBytes Size of the data to restore in ScratchBuffer,
267 and to write from ScratchBuffer, during S3
268 resume. NumberOfBytes must not exceed
269 ScratchBufferSize, which was passed to
270 QemuFwCfgS3CallWhenBootScriptReady().
272 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
273 Boot Script successfully. There is no way
276 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
278 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
281 @return Error codes from underlying functions.
285 QemuFwCfgS3ScriptWriteBytes (
286 IN INT32 FirmwareConfigItem
,
287 IN UINTN NumberOfBytes
292 UINT64 AccessAddress
;
293 UINT32 ControlPollData
;
294 UINT32 ControlPollMask
;
296 ASSERT (mDmaAccess
!= NULL
);
297 ASSERT (mS3SaveState
!= NULL
);
299 if (FirmwareConfigItem
< -1 || FirmwareConfigItem
> MAX_UINT16
) {
300 return RETURN_INVALID_PARAMETER
;
302 if (NumberOfBytes
> mScratchBufferSize
) {
303 return RETURN_BAD_BUFFER_SIZE
;
307 // Set up a write[+select] fw_cfg DMA command.
309 mDmaAccess
->Control
= FW_CFG_DMA_CTL_WRITE
;
310 if (FirmwareConfigItem
!= -1) {
311 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
312 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
314 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
317 // We ensured the following constraint via mScratchBufferSize in
318 // QemuFwCfgS3CallWhenBootScriptReady().
320 ASSERT (NumberOfBytes
<= MAX_UINT32
);
321 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
323 mDmaAccess
->Address
= SwapBytes64 ((UINTN
)mScratchBuffer
);
326 // Copy mDmaAccess and NumberOfBytes bytes from mScratchBuffer into the boot
327 // script. When executed at S3 resume, this opcode will restore all of them
330 Count
= (UINTN
)mScratchBuffer
+ NumberOfBytes
- (UINTN
)mDmaAccess
;
331 Status
= mS3SaveState
->Write (
332 mS3SaveState
, // This
333 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
334 EfiBootScriptWidthUint8
, // Width
335 (UINT64
)(UINTN
)mDmaAccess
, // Address
337 (VOID
*)mDmaAccess
// Buffer
339 if (EFI_ERROR (Status
)) {
340 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
341 gEfiCallerBaseName
, __FUNCTION__
, Status
));
342 return (RETURN_STATUS
)Status
;
346 // Append an opcode that will write the address of the fw_cfg DMA command to
347 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
348 // The second (highest address, least significant) write will start the
351 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
352 Status
= mS3SaveState
->Write (
353 mS3SaveState
, // This
354 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
355 EfiBootScriptWidthUint32
, // Width
356 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
358 (VOID
*)&AccessAddress
// Buffer
360 if (EFI_ERROR (Status
)) {
361 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
362 gEfiCallerBaseName
, __FUNCTION__
, Status
));
363 return (RETURN_STATUS
)Status
;
367 // The following opcode will wait until the Control word reads as zero
368 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
369 // approximately 58494 years.
372 ControlPollMask
= MAX_UINT32
;
373 Status
= mS3SaveState
->Write (
374 mS3SaveState
, // This
375 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
376 EfiBootScriptWidthUint32
, // Width
377 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
378 (VOID
*)&ControlPollData
, // Data
379 (VOID
*)&ControlPollMask
, // DataMask
382 if (EFI_ERROR (Status
)) {
383 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
384 gEfiCallerBaseName
, __FUNCTION__
, Status
));
385 return (RETURN_STATUS
)Status
;
388 return RETURN_SUCCESS
;
393 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
394 and transfer data from it.
396 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
397 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
400 If the operation fails during S3 resume, the boot script will hang.
402 This function may only be called from the client module's
403 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
404 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
406 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
407 item to read, expressed as INT32. If
408 FirmwareConfigItem is -1, no selection is
409 made, the read will occur from the currently
410 selected item, from its currently selected
411 offset. Otherwise, the specified item will be
412 selected, and the read will occur from offset
415 @param[in] NumberOfBytes Size of the data to read during S3 resume.
416 NumberOfBytes must not exceed
417 ScratchBufferSize, which was passed to
418 QemuFwCfgS3CallWhenBootScriptReady().
420 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
421 Boot Script successfully. There is no way
424 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
426 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
429 @return Error codes from underlying functions.
433 QemuFwCfgS3ScriptReadBytes (
434 IN INT32 FirmwareConfigItem
,
435 IN UINTN NumberOfBytes
439 UINT64 AccessAddress
;
440 UINT32 ControlPollData
;
441 UINT32 ControlPollMask
;
443 ASSERT (mDmaAccess
!= NULL
);
444 ASSERT (mS3SaveState
!= NULL
);
446 if (FirmwareConfigItem
< -1 || FirmwareConfigItem
> MAX_UINT16
) {
447 return RETURN_INVALID_PARAMETER
;
449 if (NumberOfBytes
> mScratchBufferSize
) {
450 return RETURN_BAD_BUFFER_SIZE
;
454 // Set up a read[+select] fw_cfg DMA command.
456 mDmaAccess
->Control
= FW_CFG_DMA_CTL_READ
;
457 if (FirmwareConfigItem
!= -1) {
458 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
459 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
461 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
464 // We ensured the following constraint via mScratchBufferSize in
465 // QemuFwCfgS3CallWhenBootScriptReady().
467 ASSERT (NumberOfBytes
<= MAX_UINT32
);
468 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
470 mDmaAccess
->Address
= SwapBytes64 ((UINTN
)mScratchBuffer
);
473 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
474 // opcode will restore it in-place.
476 Status
= mS3SaveState
->Write (
477 mS3SaveState
, // This
478 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
479 EfiBootScriptWidthUint8
, // Width
480 (UINT64
)(UINTN
)mDmaAccess
, // Address
481 sizeof *mDmaAccess
, // Count
482 (VOID
*)mDmaAccess
// Buffer
484 if (EFI_ERROR (Status
)) {
485 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
486 gEfiCallerBaseName
, __FUNCTION__
, Status
));
487 return (RETURN_STATUS
)Status
;
491 // Append an opcode that will write the address of the fw_cfg DMA command to
492 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
493 // The second (highest address, least significant) write will start the
496 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
497 Status
= mS3SaveState
->Write (
498 mS3SaveState
, // This
499 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
500 EfiBootScriptWidthUint32
, // Width
501 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
503 (VOID
*)&AccessAddress
// Buffer
505 if (EFI_ERROR (Status
)) {
506 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
507 gEfiCallerBaseName
, __FUNCTION__
, Status
));
508 return (RETURN_STATUS
)Status
;
512 // The following opcode will wait until the Control word reads as zero
513 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
514 // approximately 58494 years.
517 ControlPollMask
= MAX_UINT32
;
518 Status
= mS3SaveState
->Write (
519 mS3SaveState
, // This
520 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
521 EfiBootScriptWidthUint32
, // Width
522 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
523 (VOID
*)&ControlPollData
, // Data
524 (VOID
*)&ControlPollMask
, // DataMask
527 if (EFI_ERROR (Status
)) {
528 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
529 gEfiCallerBaseName
, __FUNCTION__
, Status
));
530 return (RETURN_STATUS
)Status
;
533 return RETURN_SUCCESS
;
538 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
539 and increase its offset.
541 If the operation fails during S3 resume, the boot script will hang.
543 This function may only be called from the client module's
544 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
545 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
547 @param[in] FirmwareConfigItem The UINT16 selector key of the firmware config
548 item to advance the offset of, expressed as
549 INT32. If FirmwareConfigItem is -1, no
550 selection is made, and the offset for the
551 currently selected item is increased.
552 Otherwise, the specified item will be
553 selected, and the offset increment will occur
556 @param[in] NumberOfBytes The number of bytes to skip in the subject
559 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
560 Boot Script successfully. There is no way
563 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
565 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.
567 @return Error codes from underlying functions.
571 QemuFwCfgS3ScriptSkipBytes (
572 IN INT32 FirmwareConfigItem
,
573 IN UINTN NumberOfBytes
577 UINT64 AccessAddress
;
578 UINT32 ControlPollData
;
579 UINT32 ControlPollMask
;
581 ASSERT (mDmaAccess
!= NULL
);
582 ASSERT (mS3SaveState
!= NULL
);
584 if (FirmwareConfigItem
< -1 || FirmwareConfigItem
> MAX_UINT16
) {
585 return RETURN_INVALID_PARAMETER
;
587 if (NumberOfBytes
> MAX_UINT32
) {
588 return RETURN_BAD_BUFFER_SIZE
;
592 // Set up a skip[+select] fw_cfg DMA command.
594 mDmaAccess
->Control
= FW_CFG_DMA_CTL_SKIP
;
595 if (FirmwareConfigItem
!= -1) {
596 mDmaAccess
->Control
|= FW_CFG_DMA_CTL_SELECT
;
597 mDmaAccess
->Control
|= (UINT32
)FirmwareConfigItem
<< 16;
599 mDmaAccess
->Control
= SwapBytes32 (mDmaAccess
->Control
);
601 mDmaAccess
->Length
= SwapBytes32 ((UINT32
)NumberOfBytes
);
602 mDmaAccess
->Address
= 0;
605 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
606 // opcode will restore it in-place.
608 Status
= mS3SaveState
->Write (
609 mS3SaveState
, // This
610 EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE
, // OpCode
611 EfiBootScriptWidthUint8
, // Width
612 (UINT64
)(UINTN
)mDmaAccess
, // Address
613 sizeof *mDmaAccess
, // Count
614 (VOID
*)mDmaAccess
// Buffer
616 if (EFI_ERROR (Status
)) {
617 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
618 gEfiCallerBaseName
, __FUNCTION__
, Status
));
619 return (RETURN_STATUS
)Status
;
623 // Append an opcode that will write the address of the fw_cfg DMA command to
624 // the fw_cfg DMA address register, which consists of two 32-bit IO ports.
625 // The second (highest address, least significant) write will start the
628 AccessAddress
= SwapBytes64 ((UINTN
)mDmaAccess
);
629 Status
= mS3SaveState
->Write (
630 mS3SaveState
, // This
631 EFI_BOOT_SCRIPT_IO_WRITE_OPCODE
, // OpCode
632 EfiBootScriptWidthUint32
, // Width
633 (UINT64
)FW_CFG_IO_DMA_ADDRESS
, // Address
635 (VOID
*)&AccessAddress
// Buffer
637 if (EFI_ERROR (Status
)) {
638 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
639 gEfiCallerBaseName
, __FUNCTION__
, Status
));
640 return (RETURN_STATUS
)Status
;
644 // The following opcode will wait until the Control word reads as zero
645 // (transfer complete). As timeout we use MAX_UINT64 * 100ns, which is
646 // approximately 58494 years.
649 ControlPollMask
= MAX_UINT32
;
650 Status
= mS3SaveState
->Write (
651 mS3SaveState
, // This
652 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
653 EfiBootScriptWidthUint32
, // Width
654 (UINT64
)(UINTN
)&mDmaAccess
->Control
, // Address
655 (VOID
*)&ControlPollData
, // Data
656 (VOID
*)&ControlPollMask
, // DataMask
659 if (EFI_ERROR (Status
)) {
660 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
661 gEfiCallerBaseName
, __FUNCTION__
, Status
));
662 return (RETURN_STATUS
)Status
;
665 return RETURN_SUCCESS
;
670 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.
672 If the check fails during S3 resume, the boot script will hang.
674 This function may only be called from the client module's
675 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
676 QemuFwCfgS3CallWhenBootScriptReady() as Callback.
678 @param[in] ScratchData Pointer to the UINT8, UINT16, UINT32 or UINT64 field
679 in ScratchBuffer that should be checked. The caller
680 is responsible for populating the field during S3
681 resume, by calling QemuFwCfgS3ScriptReadBytes() ahead
682 of QemuFwCfgS3ScriptCheckValue().
684 ScratchData must point into ScratchBuffer, which was
685 allocated, and passed to Callback(), by
686 QemuFwCfgS3CallWhenBootScriptReady().
688 ScratchData must be aligned at ValueSize bytes.
690 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field
693 @param[in] ValueMask The value read from ScratchData is binarily AND-ed
694 with ValueMask, and the result is compared against
695 Value. If the masked data equals Value, the check
696 passes, and the boot script can proceed. Otherwise,
697 the check fails, and the boot script hangs.
699 @param[in] Value Refer to ValueMask.
701 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
702 Boot Script successfully. There is no way
705 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.
707 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in
710 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize
713 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't
714 wholly contained in the ScratchBufferSize
715 bytes at ScratchBuffer.
717 @return Error codes from underlying functions.
721 QemuFwCfgS3ScriptCheckValue (
722 IN VOID
*ScratchData
,
728 EFI_BOOT_SCRIPT_WIDTH Width
;
731 ASSERT (mS3SaveState
!= NULL
);
735 Width
= EfiBootScriptWidthUint8
;
739 Width
= EfiBootScriptWidthUint16
;
743 Width
= EfiBootScriptWidthUint32
;
747 Width
= EfiBootScriptWidthUint64
;
751 return RETURN_INVALID_PARAMETER
;
755 (RShiftU64 (ValueMask
, ValueSize
* 8) > 0 ||
756 RShiftU64 (Value
, ValueSize
* 8) > 0)) {
757 return RETURN_INVALID_PARAMETER
;
760 if ((UINTN
)ScratchData
% ValueSize
> 0) {
761 return RETURN_INVALID_PARAMETER
;
764 if (((UINTN
)ScratchData
< (UINTN
)mScratchBuffer
) ||
765 ((UINTN
)ScratchData
> MAX_UINTN
- ValueSize
) ||
766 ((UINTN
)ScratchData
+ ValueSize
>
767 (UINTN
)mScratchBuffer
+ mScratchBufferSize
)) {
768 return RETURN_BAD_BUFFER_SIZE
;
772 // The following opcode will wait "until" (*ScratchData & ValueMask) reads as
773 // Value, considering the least significant ValueSize bytes. As timeout we
774 // use MAX_UINT64 * 100ns, which is approximately 58494 years.
776 Status
= mS3SaveState
->Write (
777 mS3SaveState
, // This
778 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE
, // OpCode
780 (UINT64
)(UINTN
)ScratchData
, // Address
781 (VOID
*)&Value
, // Data
782 (VOID
*)&ValueMask
, // DataMask
785 if (EFI_ERROR (Status
)) {
786 DEBUG ((DEBUG_ERROR
, "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
787 gEfiCallerBaseName
, __FUNCTION__
, Status
));
788 return (RETURN_STATUS
)Status
;
791 return RETURN_SUCCESS
;