]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3Dxe.c
OvmfPkg: Replace BSD License with BSD+Patent License
[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 //
19 // Event to signal when the S3SaveState protocol interface is installed.
20 //
21 STATIC EFI_EVENT mS3SaveStateInstalledEvent;
22
23 //
24 // Reference to the S3SaveState protocol interface, after it is installed.
25 //
26 STATIC EFI_S3_SAVE_STATE_PROTOCOL *mS3SaveState;
27
28 //
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.
32 //
33 #define RESERVED_MEM_ALIGNMENT 8
34
35 STATIC FW_CFG_DMA_ACCESS *mDmaAccess;
36 STATIC VOID *mScratchBuffer;
37 STATIC UINTN mScratchBufferSize;
38
39 //
40 // Callback provided by the client, for appending ACPI S3 Boot Script opcodes.
41 // To be called from S3SaveStateInstalledNotify().
42 //
43 STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *mCallback;
44
45
46 /**
47 Event notification function for mS3SaveStateInstalledEvent.
48 **/
49 STATIC
50 VOID
51 EFIAPI
52 S3SaveStateInstalledNotify (
53 IN EFI_EVENT Event,
54 IN VOID *Context
55 )
56 {
57 EFI_STATUS Status;
58
59 ASSERT (Event == mS3SaveStateInstalledEvent);
60
61 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid,
62 NULL /* Registration */, (VOID **)&mS3SaveState);
63 if (EFI_ERROR (Status)) {
64 return;
65 }
66
67 ASSERT (mCallback != NULL);
68
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);
73
74 gBS->CloseEvent (mS3SaveStateInstalledEvent);
75 mS3SaveStateInstalledEvent = NULL;
76 }
77
78
79 /**
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.
82
83 Take ownership of the client-provided Context, and pass it to the callback
84 function, when the latter is invoked.
85
86 Allocate scratch space for those ACPI S3 Boot Script opcodes to work upon
87 that the client will produce in the callback function.
88
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().
94
95 @param[in,out] Context Client-provided data structure for the
96 Callback() callback function to consume.
97
98 If Context points to dynamically allocated
99 memory, then Callback() must release it.
100
101 If Context points to dynamically allocated
102 memory, and
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().
109
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().
114
115 @retval RETURN_UNSUPPORTED The library instance does not support this
116 function.
117
118 @retval RETURN_NOT_FOUND The fw_cfg DMA interface to QEMU is
119 unavailable.
120
121 @retval RETURN_BAD_BUFFER_SIZE ScratchBufferSize is too large.
122
123 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
124
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
128 scratch buffer.
129
130 A successful invocation of
131 QemuFwCfgS3CallWhenBootScriptReady() cannot
132 be rolled back.
133
134 @return Error codes from underlying functions.
135 **/
136 RETURN_STATUS
137 EFIAPI
138 QemuFwCfgS3CallWhenBootScriptReady (
139 IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *Callback,
140 IN OUT VOID *Context, OPTIONAL
141 IN UINTN ScratchBufferSize
142 )
143 {
144 EFI_STATUS Status;
145 VOID *Registration;
146
147 //
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.
150 //
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;
157 }
158
159 //
160 // Allocate a reserved buffer for the DMA access control structure and the
161 // client data together.
162 //
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;
168 }
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;
175 }
176 mDmaAccess = ALIGN_POINTER (mDmaAccess, RESERVED_MEM_ALIGNMENT);
177
178 //
179 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the
180 // client's Context to the callback.
181 //
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));
188 goto FreeDmaAccess;
189 }
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));
195 goto CloseEvent;
196 }
197
198 //
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.
202 //
203 ASSERT (sizeof *mDmaAccess % RESERVED_MEM_ALIGNMENT == 0);
204 mScratchBuffer = mDmaAccess + 1;
205 mScratchBufferSize = ScratchBufferSize;
206 mCallback = Callback;
207
208 //
209 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.
210 //
211 Status = gBS->SignalEvent (mS3SaveStateInstalledEvent);
212 if (EFI_ERROR (Status)) {
213 DEBUG ((DEBUG_ERROR, "%a: %a: SignalEvent(): %r\n", gEfiCallerBaseName,
214 __FUNCTION__, Status));
215 goto NullGlobals;
216 }
217
218 return RETURN_SUCCESS;
219
220 NullGlobals:
221 mScratchBuffer = NULL;
222 mScratchBufferSize = 0;
223 mCallback = NULL;
224
225 CloseEvent:
226 gBS->CloseEvent (mS3SaveStateInstalledEvent);
227 mS3SaveStateInstalledEvent = NULL;
228
229 FreeDmaAccess:
230 FreePool (mDmaAccess);
231 mDmaAccess = NULL;
232
233 return (RETURN_STATUS)Status;
234 }
235
236
237 /**
238 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
239 and transfer data to it.
240
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.
244
245 If the operation fails during S3 resume, the boot script will hang.
246
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.
250
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
258 0.
259
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().
265
266 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
267 Boot Script successfully. There is no way
268 to undo this action.
269
270 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
271
272 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
273 ScratchBufferSize.
274
275 @return Error codes from underlying functions.
276 **/
277 RETURN_STATUS
278 EFIAPI
279 QemuFwCfgS3ScriptWriteBytes (
280 IN INT32 FirmwareConfigItem,
281 IN UINTN NumberOfBytes
282 )
283 {
284 UINTN Count;
285 EFI_STATUS Status;
286 UINT64 AccessAddress;
287 UINT32 ControlPollData;
288 UINT32 ControlPollMask;
289
290 ASSERT (mDmaAccess != NULL);
291 ASSERT (mS3SaveState != NULL);
292
293 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {
294 return RETURN_INVALID_PARAMETER;
295 }
296 if (NumberOfBytes > mScratchBufferSize) {
297 return RETURN_BAD_BUFFER_SIZE;
298 }
299
300 //
301 // Set up a write[+select] fw_cfg DMA command.
302 //
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;
307 }
308 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
309
310 //
311 // We ensured the following constraint via mScratchBufferSize in
312 // QemuFwCfgS3CallWhenBootScriptReady().
313 //
314 ASSERT (NumberOfBytes <= MAX_UINT32);
315 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
316
317 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);
318
319 //
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
322 // in-place.
323 //
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
330 Count, // Count
331 (VOID *)mDmaAccess // Buffer
332 );
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;
337 }
338
339 //
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
343 // transfer.
344 //
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
351 (UINTN)2, // Count
352 (VOID *)&AccessAddress // Buffer
353 );
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;
358 }
359
360 //
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.
364 //
365 ControlPollData = 0;
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
374 MAX_UINT64 // Delay
375 );
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;
380 }
381
382 return RETURN_SUCCESS;
383 }
384
385
386 /**
387 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
388 and transfer data from it.
389
390 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
391 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
392 memory.
393
394 If the operation fails during S3 resume, the boot script will hang.
395
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.
399
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
407 0.
408
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().
413
414 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
415 Boot Script successfully. There is no way
416 to undo this action.
417
418 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
419
420 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
421 ScratchBufferSize.
422
423 @return Error codes from underlying functions.
424 **/
425 RETURN_STATUS
426 EFIAPI
427 QemuFwCfgS3ScriptReadBytes (
428 IN INT32 FirmwareConfigItem,
429 IN UINTN NumberOfBytes
430 )
431 {
432 EFI_STATUS Status;
433 UINT64 AccessAddress;
434 UINT32 ControlPollData;
435 UINT32 ControlPollMask;
436
437 ASSERT (mDmaAccess != NULL);
438 ASSERT (mS3SaveState != NULL);
439
440 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {
441 return RETURN_INVALID_PARAMETER;
442 }
443 if (NumberOfBytes > mScratchBufferSize) {
444 return RETURN_BAD_BUFFER_SIZE;
445 }
446
447 //
448 // Set up a read[+select] fw_cfg DMA command.
449 //
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;
454 }
455 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
456
457 //
458 // We ensured the following constraint via mScratchBufferSize in
459 // QemuFwCfgS3CallWhenBootScriptReady().
460 //
461 ASSERT (NumberOfBytes <= MAX_UINT32);
462 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
463
464 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);
465
466 //
467 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
468 // opcode will restore it in-place.
469 //
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
477 );
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;
482 }
483
484 //
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
488 // transfer.
489 //
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
496 (UINTN)2, // Count
497 (VOID *)&AccessAddress // Buffer
498 );
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;
503 }
504
505 //
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.
509 //
510 ControlPollData = 0;
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
519 MAX_UINT64 // Delay
520 );
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;
525 }
526
527 return RETURN_SUCCESS;
528 }
529
530
531 /**
532 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
533 and increase its offset.
534
535 If the operation fails during S3 resume, the boot script will hang.
536
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.
540
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
548 from offset 0.
549
550 @param[in] NumberOfBytes The number of bytes to skip in the subject
551 fw_cfg item.
552
553 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
554 Boot Script successfully. There is no way
555 to undo this action.
556
557 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
558
559 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.
560
561 @return Error codes from underlying functions.
562 **/
563 RETURN_STATUS
564 EFIAPI
565 QemuFwCfgS3ScriptSkipBytes (
566 IN INT32 FirmwareConfigItem,
567 IN UINTN NumberOfBytes
568 )
569 {
570 EFI_STATUS Status;
571 UINT64 AccessAddress;
572 UINT32 ControlPollData;
573 UINT32 ControlPollMask;
574
575 ASSERT (mDmaAccess != NULL);
576 ASSERT (mS3SaveState != NULL);
577
578 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {
579 return RETURN_INVALID_PARAMETER;
580 }
581 if (NumberOfBytes > MAX_UINT32) {
582 return RETURN_BAD_BUFFER_SIZE;
583 }
584
585 //
586 // Set up a skip[+select] fw_cfg DMA command.
587 //
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;
592 }
593 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
594
595 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
596 mDmaAccess->Address = 0;
597
598 //
599 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
600 // opcode will restore it in-place.
601 //
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
609 );
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;
614 }
615
616 //
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
620 // transfer.
621 //
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
628 (UINTN)2, // Count
629 (VOID *)&AccessAddress // Buffer
630 );
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;
635 }
636
637 //
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.
641 //
642 ControlPollData = 0;
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
651 MAX_UINT64 // Delay
652 );
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;
657 }
658
659 return RETURN_SUCCESS;
660 }
661
662
663 /**
664 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.
665
666 If the check fails during S3 resume, the boot script will hang.
667
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.
671
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().
677
678 ScratchData must point into ScratchBuffer, which was
679 allocated, and passed to Callback(), by
680 QemuFwCfgS3CallWhenBootScriptReady().
681
682 ScratchData must be aligned at ValueSize bytes.
683
684 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field
685 to check.
686
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.
692
693 @param[in] Value Refer to ValueMask.
694
695 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
696 Boot Script successfully. There is no way
697 to undo this action.
698
699 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.
700
701 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in
702 ValueSize bytes.
703
704 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize
705 bytes.
706
707 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't
708 wholly contained in the ScratchBufferSize
709 bytes at ScratchBuffer.
710
711 @return Error codes from underlying functions.
712 **/
713 RETURN_STATUS
714 EFIAPI
715 QemuFwCfgS3ScriptCheckValue (
716 IN VOID *ScratchData,
717 IN UINT8 ValueSize,
718 IN UINT64 ValueMask,
719 IN UINT64 Value
720 )
721 {
722 EFI_BOOT_SCRIPT_WIDTH Width;
723 EFI_STATUS Status;
724
725 ASSERT (mS3SaveState != NULL);
726
727 switch (ValueSize) {
728 case 1:
729 Width = EfiBootScriptWidthUint8;
730 break;
731
732 case 2:
733 Width = EfiBootScriptWidthUint16;
734 break;
735
736 case 4:
737 Width = EfiBootScriptWidthUint32;
738 break;
739
740 case 8:
741 Width = EfiBootScriptWidthUint64;
742 break;
743
744 default:
745 return RETURN_INVALID_PARAMETER;
746 }
747
748 if (ValueSize < 8 &&
749 (RShiftU64 (ValueMask, ValueSize * 8) > 0 ||
750 RShiftU64 (Value, ValueSize * 8) > 0)) {
751 return RETURN_INVALID_PARAMETER;
752 }
753
754 if ((UINTN)ScratchData % ValueSize > 0) {
755 return RETURN_INVALID_PARAMETER;
756 }
757
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;
763 }
764
765 //
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.
769 //
770 Status = mS3SaveState->Write (
771 mS3SaveState, // This
772 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode
773 Width, // Width
774 (UINT64)(UINTN)ScratchData, // Address
775 (VOID *)&Value, // Data
776 (VOID *)&ValueMask, // DataMask
777 MAX_UINT64 // Delay
778 );
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;
783 }
784
785 return RETURN_SUCCESS;
786 }