]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3Dxe.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgS3Lib / QemuFwCfgS3Dxe.c
1 /** @file
2 Full functionality QemuFwCfgS3Lib instance, for DXE phase modules.
3
4 Copyright (C) 2017, Red Hat, Inc.
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
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>
16
17 //
18 // Event to signal when the S3SaveState protocol interface is installed.
19 //
20 STATIC EFI_EVENT mS3SaveStateInstalledEvent;
21
22 //
23 // Reference to the S3SaveState protocol interface, after it is installed.
24 //
25 STATIC EFI_S3_SAVE_STATE_PROTOCOL *mS3SaveState;
26
27 //
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.
31 //
32 #define RESERVED_MEM_ALIGNMENT 8
33
34 STATIC FW_CFG_DMA_ACCESS *mDmaAccess;
35 STATIC VOID *mScratchBuffer;
36 STATIC UINTN mScratchBufferSize;
37
38 //
39 // Callback provided by the client, for appending ACPI S3 Boot Script opcodes.
40 // To be called from S3SaveStateInstalledNotify().
41 //
42 STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *mCallback;
43
44 /**
45 Event notification function for mS3SaveStateInstalledEvent.
46 **/
47 STATIC
48 VOID
49 EFIAPI
50 S3SaveStateInstalledNotify (
51 IN EFI_EVENT Event,
52 IN VOID *Context
53 )
54 {
55 EFI_STATUS Status;
56
57 ASSERT (Event == mS3SaveStateInstalledEvent);
58
59 Status = gBS->LocateProtocol (
60 &gEfiS3SaveStateProtocolGuid,
61 NULL /* Registration */,
62 (VOID **)&mS3SaveState
63 );
64 if (EFI_ERROR (Status)) {
65 return;
66 }
67
68 ASSERT (mCallback != NULL);
69
70 DEBUG ((
71 DEBUG_INFO,
72 "%a: %a: DmaAccess@0x%Lx ScratchBuffer@[0x%Lx+0x%Lx]\n",
73 gEfiCallerBaseName,
74 __FUNCTION__,
75 (UINT64)(UINTN)mDmaAccess,
76 (UINT64)(UINTN)mScratchBuffer,
77 (UINT64)mScratchBufferSize
78 ));
79 mCallback (Context, mScratchBuffer);
80
81 gBS->CloseEvent (mS3SaveStateInstalledEvent);
82 mS3SaveStateInstalledEvent = NULL;
83 }
84
85 /**
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.
88
89 Take ownership of the client-provided Context, and pass it to the callback
90 function, when the latter is invoked.
91
92 Allocate scratch space for those ACPI S3 Boot Script opcodes to work upon
93 that the client will produce in the callback function.
94
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().
100
101 @param[in,out] Context Client-provided data structure for the
102 Callback() callback function to consume.
103
104 If Context points to dynamically allocated
105 memory, then Callback() must release it.
106
107 If Context points to dynamically allocated
108 memory, and
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().
115
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().
120
121 @retval RETURN_UNSUPPORTED The library instance does not support this
122 function.
123
124 @retval RETURN_NOT_FOUND The fw_cfg DMA interface to QEMU is
125 unavailable.
126
127 @retval RETURN_BAD_BUFFER_SIZE ScratchBufferSize is too large.
128
129 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
130
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
134 scratch buffer.
135
136 A successful invocation of
137 QemuFwCfgS3CallWhenBootScriptReady() cannot
138 be rolled back.
139
140 @return Error codes from underlying functions.
141 **/
142 RETURN_STATUS
143 EFIAPI
144 QemuFwCfgS3CallWhenBootScriptReady (
145 IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *Callback,
146 IN OUT VOID *Context OPTIONAL,
147 IN UINTN ScratchBufferSize
148 )
149 {
150 EFI_STATUS Status;
151 VOID *Registration;
152
153 //
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.
156 //
157 ASSERT (QemuFwCfgIsAvailable ());
158 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
159 if ((QemuFwCfgRead32 () & FW_CFG_F_DMA) == 0) {
160 DEBUG ((
161 DEBUG_ERROR,
162 "%a: %a: fw_cfg DMA unavailable\n",
163 gEfiCallerBaseName,
164 __FUNCTION__
165 ));
166 return RETURN_NOT_FOUND;
167 }
168
169 //
170 // Allocate a reserved buffer for the DMA access control structure and the
171 // client data together.
172 //
173 if (ScratchBufferSize >
174 MAX_UINT32 - (RESERVED_MEM_ALIGNMENT - 1) - sizeof *mDmaAccess)
175 {
176 DEBUG ((
177 DEBUG_ERROR,
178 "%a: %a: ScratchBufferSize too big: %Lu\n",
179 gEfiCallerBaseName,
180 __FUNCTION__,
181 (UINT64)ScratchBufferSize
182 ));
183 return RETURN_BAD_BUFFER_SIZE;
184 }
185
186 mDmaAccess = AllocateReservedPool (
187 (RESERVED_MEM_ALIGNMENT - 1) +
188 sizeof *mDmaAccess + ScratchBufferSize
189 );
190 if (mDmaAccess == NULL) {
191 DEBUG ((
192 DEBUG_ERROR,
193 "%a: %a: AllocateReservedPool(): out of resources\n",
194 gEfiCallerBaseName,
195 __FUNCTION__
196 ));
197 return RETURN_OUT_OF_RESOURCES;
198 }
199
200 mDmaAccess = ALIGN_POINTER (mDmaAccess, RESERVED_MEM_ALIGNMENT);
201
202 //
203 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the
204 // client's Context to the callback.
205 //
206 Status = gBS->CreateEvent (
207 EVT_NOTIFY_SIGNAL,
208 TPL_CALLBACK,
209 S3SaveStateInstalledNotify,
210 Context,
211 &mS3SaveStateInstalledEvent
212 );
213 if (EFI_ERROR (Status)) {
214 DEBUG ((
215 DEBUG_ERROR,
216 "%a: %a: CreateEvent(): %r\n",
217 gEfiCallerBaseName,
218 __FUNCTION__,
219 Status
220 ));
221 goto FreeDmaAccess;
222 }
223
224 Status = gBS->RegisterProtocolNotify (
225 &gEfiS3SaveStateProtocolGuid,
226 mS3SaveStateInstalledEvent,
227 &Registration
228 );
229 if (EFI_ERROR (Status)) {
230 DEBUG ((
231 DEBUG_ERROR,
232 "%a: %a: RegisterProtocolNotify(): %r\n",
233 gEfiCallerBaseName,
234 __FUNCTION__,
235 Status
236 ));
237 goto CloseEvent;
238 }
239
240 //
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.
244 //
245 ASSERT (sizeof *mDmaAccess % RESERVED_MEM_ALIGNMENT == 0);
246 mScratchBuffer = mDmaAccess + 1;
247 mScratchBufferSize = ScratchBufferSize;
248 mCallback = Callback;
249
250 //
251 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.
252 //
253 Status = gBS->SignalEvent (mS3SaveStateInstalledEvent);
254 if (EFI_ERROR (Status)) {
255 DEBUG ((
256 DEBUG_ERROR,
257 "%a: %a: SignalEvent(): %r\n",
258 gEfiCallerBaseName,
259 __FUNCTION__,
260 Status
261 ));
262 goto NullGlobals;
263 }
264
265 return RETURN_SUCCESS;
266
267 NullGlobals:
268 mScratchBuffer = NULL;
269 mScratchBufferSize = 0;
270 mCallback = NULL;
271
272 CloseEvent:
273 gBS->CloseEvent (mS3SaveStateInstalledEvent);
274 mS3SaveStateInstalledEvent = NULL;
275
276 FreeDmaAccess:
277 FreePool (mDmaAccess);
278 mDmaAccess = NULL;
279
280 return (RETURN_STATUS)Status;
281 }
282
283 /**
284 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
285 and transfer data to it.
286
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.
290
291 If the operation fails during S3 resume, the boot script will hang.
292
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.
296
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
304 0.
305
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().
311
312 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
313 Boot Script successfully. There is no way
314 to undo this action.
315
316 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
317
318 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
319 ScratchBufferSize.
320
321 @return Error codes from underlying functions.
322 **/
323 RETURN_STATUS
324 EFIAPI
325 QemuFwCfgS3ScriptWriteBytes (
326 IN INT32 FirmwareConfigItem,
327 IN UINTN NumberOfBytes
328 )
329 {
330 UINTN Count;
331 EFI_STATUS Status;
332 UINT64 AccessAddress;
333 UINT32 ControlPollData;
334 UINT32 ControlPollMask;
335
336 ASSERT (mDmaAccess != NULL);
337 ASSERT (mS3SaveState != NULL);
338
339 if ((FirmwareConfigItem < -1) || (FirmwareConfigItem > MAX_UINT16)) {
340 return RETURN_INVALID_PARAMETER;
341 }
342
343 if (NumberOfBytes > mScratchBufferSize) {
344 return RETURN_BAD_BUFFER_SIZE;
345 }
346
347 //
348 // Set up a write[+select] fw_cfg DMA command.
349 //
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;
354 }
355
356 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
357
358 //
359 // We ensured the following constraint via mScratchBufferSize in
360 // QemuFwCfgS3CallWhenBootScriptReady().
361 //
362 ASSERT (NumberOfBytes <= MAX_UINT32);
363 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
364
365 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);
366
367 //
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
370 // in-place.
371 //
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
378 Count, // Count
379 (VOID *)mDmaAccess // Buffer
380 );
381 if (EFI_ERROR (Status)) {
382 DEBUG ((
383 DEBUG_ERROR,
384 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
385 gEfiCallerBaseName,
386 __FUNCTION__,
387 Status
388 ));
389 return (RETURN_STATUS)Status;
390 }
391
392 //
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
396 // transfer.
397 //
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
404 (UINTN)2, // Count
405 (VOID *)&AccessAddress // Buffer
406 );
407 if (EFI_ERROR (Status)) {
408 DEBUG ((
409 DEBUG_ERROR,
410 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
411 gEfiCallerBaseName,
412 __FUNCTION__,
413 Status
414 ));
415 return (RETURN_STATUS)Status;
416 }
417
418 //
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.
422 //
423 ControlPollData = 0;
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
432 MAX_UINT64 // Delay
433 );
434 if (EFI_ERROR (Status)) {
435 DEBUG ((
436 DEBUG_ERROR,
437 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
438 gEfiCallerBaseName,
439 __FUNCTION__,
440 Status
441 ));
442 return (RETURN_STATUS)Status;
443 }
444
445 return RETURN_SUCCESS;
446 }
447
448 /**
449 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
450 and transfer data from it.
451
452 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
453 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
454 memory.
455
456 If the operation fails during S3 resume, the boot script will hang.
457
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.
461
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
469 0.
470
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().
475
476 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
477 Boot Script successfully. There is no way
478 to undo this action.
479
480 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
481
482 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
483 ScratchBufferSize.
484
485 @return Error codes from underlying functions.
486 **/
487 RETURN_STATUS
488 EFIAPI
489 QemuFwCfgS3ScriptReadBytes (
490 IN INT32 FirmwareConfigItem,
491 IN UINTN NumberOfBytes
492 )
493 {
494 EFI_STATUS Status;
495 UINT64 AccessAddress;
496 UINT32 ControlPollData;
497 UINT32 ControlPollMask;
498
499 ASSERT (mDmaAccess != NULL);
500 ASSERT (mS3SaveState != NULL);
501
502 if ((FirmwareConfigItem < -1) || (FirmwareConfigItem > MAX_UINT16)) {
503 return RETURN_INVALID_PARAMETER;
504 }
505
506 if (NumberOfBytes > mScratchBufferSize) {
507 return RETURN_BAD_BUFFER_SIZE;
508 }
509
510 //
511 // Set up a read[+select] fw_cfg DMA command.
512 //
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;
517 }
518
519 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
520
521 //
522 // We ensured the following constraint via mScratchBufferSize in
523 // QemuFwCfgS3CallWhenBootScriptReady().
524 //
525 ASSERT (NumberOfBytes <= MAX_UINT32);
526 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
527
528 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);
529
530 //
531 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
532 // opcode will restore it in-place.
533 //
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
541 );
542 if (EFI_ERROR (Status)) {
543 DEBUG ((
544 DEBUG_ERROR,
545 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
546 gEfiCallerBaseName,
547 __FUNCTION__,
548 Status
549 ));
550 return (RETURN_STATUS)Status;
551 }
552
553 //
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
557 // transfer.
558 //
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
565 (UINTN)2, // Count
566 (VOID *)&AccessAddress // Buffer
567 );
568 if (EFI_ERROR (Status)) {
569 DEBUG ((
570 DEBUG_ERROR,
571 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
572 gEfiCallerBaseName,
573 __FUNCTION__,
574 Status
575 ));
576 return (RETURN_STATUS)Status;
577 }
578
579 //
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.
583 //
584 ControlPollData = 0;
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
593 MAX_UINT64 // Delay
594 );
595 if (EFI_ERROR (Status)) {
596 DEBUG ((
597 DEBUG_ERROR,
598 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
599 gEfiCallerBaseName,
600 __FUNCTION__,
601 Status
602 ));
603 return (RETURN_STATUS)Status;
604 }
605
606 return RETURN_SUCCESS;
607 }
608
609 /**
610 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
611 and increase its offset.
612
613 If the operation fails during S3 resume, the boot script will hang.
614
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.
618
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
626 from offset 0.
627
628 @param[in] NumberOfBytes The number of bytes to skip in the subject
629 fw_cfg item.
630
631 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
632 Boot Script successfully. There is no way
633 to undo this action.
634
635 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
636
637 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.
638
639 @return Error codes from underlying functions.
640 **/
641 RETURN_STATUS
642 EFIAPI
643 QemuFwCfgS3ScriptSkipBytes (
644 IN INT32 FirmwareConfigItem,
645 IN UINTN NumberOfBytes
646 )
647 {
648 EFI_STATUS Status;
649 UINT64 AccessAddress;
650 UINT32 ControlPollData;
651 UINT32 ControlPollMask;
652
653 ASSERT (mDmaAccess != NULL);
654 ASSERT (mS3SaveState != NULL);
655
656 if ((FirmwareConfigItem < -1) || (FirmwareConfigItem > MAX_UINT16)) {
657 return RETURN_INVALID_PARAMETER;
658 }
659
660 if (NumberOfBytes > MAX_UINT32) {
661 return RETURN_BAD_BUFFER_SIZE;
662 }
663
664 //
665 // Set up a skip[+select] fw_cfg DMA command.
666 //
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;
671 }
672
673 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
674
675 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
676 mDmaAccess->Address = 0;
677
678 //
679 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
680 // opcode will restore it in-place.
681 //
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
689 );
690 if (EFI_ERROR (Status)) {
691 DEBUG ((
692 DEBUG_ERROR,
693 "%a: %a: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",
694 gEfiCallerBaseName,
695 __FUNCTION__,
696 Status
697 ));
698 return (RETURN_STATUS)Status;
699 }
700
701 //
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
705 // transfer.
706 //
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
713 (UINTN)2, // Count
714 (VOID *)&AccessAddress // Buffer
715 );
716 if (EFI_ERROR (Status)) {
717 DEBUG ((
718 DEBUG_ERROR,
719 "%a: %a: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",
720 gEfiCallerBaseName,
721 __FUNCTION__,
722 Status
723 ));
724 return (RETURN_STATUS)Status;
725 }
726
727 //
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.
731 //
732 ControlPollData = 0;
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
741 MAX_UINT64 // Delay
742 );
743 if (EFI_ERROR (Status)) {
744 DEBUG ((
745 DEBUG_ERROR,
746 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
747 gEfiCallerBaseName,
748 __FUNCTION__,
749 Status
750 ));
751 return (RETURN_STATUS)Status;
752 }
753
754 return RETURN_SUCCESS;
755 }
756
757 /**
758 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.
759
760 If the check fails during S3 resume, the boot script will hang.
761
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.
765
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().
771
772 ScratchData must point into ScratchBuffer, which was
773 allocated, and passed to Callback(), by
774 QemuFwCfgS3CallWhenBootScriptReady().
775
776 ScratchData must be aligned at ValueSize bytes.
777
778 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field
779 to check.
780
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.
786
787 @param[in] Value Refer to ValueMask.
788
789 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
790 Boot Script successfully. There is no way
791 to undo this action.
792
793 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.
794
795 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in
796 ValueSize bytes.
797
798 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize
799 bytes.
800
801 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't
802 wholly contained in the ScratchBufferSize
803 bytes at ScratchBuffer.
804
805 @return Error codes from underlying functions.
806 **/
807 RETURN_STATUS
808 EFIAPI
809 QemuFwCfgS3ScriptCheckValue (
810 IN VOID *ScratchData,
811 IN UINT8 ValueSize,
812 IN UINT64 ValueMask,
813 IN UINT64 Value
814 )
815 {
816 EFI_BOOT_SCRIPT_WIDTH Width;
817 EFI_STATUS Status;
818
819 ASSERT (mS3SaveState != NULL);
820
821 switch (ValueSize) {
822 case 1:
823 Width = EfiBootScriptWidthUint8;
824 break;
825
826 case 2:
827 Width = EfiBootScriptWidthUint16;
828 break;
829
830 case 4:
831 Width = EfiBootScriptWidthUint32;
832 break;
833
834 case 8:
835 Width = EfiBootScriptWidthUint64;
836 break;
837
838 default:
839 return RETURN_INVALID_PARAMETER;
840 }
841
842 if ((ValueSize < 8) &&
843 ((RShiftU64 (ValueMask, ValueSize * 8) > 0) ||
844 (RShiftU64 (Value, ValueSize * 8) > 0)))
845 {
846 return RETURN_INVALID_PARAMETER;
847 }
848
849 if ((UINTN)ScratchData % ValueSize > 0) {
850 return RETURN_INVALID_PARAMETER;
851 }
852
853 if (((UINTN)ScratchData < (UINTN)mScratchBuffer) ||
854 ((UINTN)ScratchData > MAX_UINTN - ValueSize) ||
855 ((UINTN)ScratchData + ValueSize >
856 (UINTN)mScratchBuffer + mScratchBufferSize))
857 {
858 return RETURN_BAD_BUFFER_SIZE;
859 }
860
861 //
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.
865 //
866 Status = mS3SaveState->Write (
867 mS3SaveState, // This
868 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode
869 Width, // Width
870 (UINT64)(UINTN)ScratchData, // Address
871 (VOID *)&Value, // Data
872 (VOID *)&ValueMask, // DataMask
873 MAX_UINT64 // Delay
874 );
875 if (EFI_ERROR (Status)) {
876 DEBUG ((
877 DEBUG_ERROR,
878 "%a: %a: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",
879 gEfiCallerBaseName,
880 __FUNCTION__,
881 Status
882 ));
883 return (RETURN_STATUS)Status;
884 }
885
886 return RETURN_SUCCESS;
887 }