]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgS3Lib/QemuFwCfgS3Dxe.c
0bd6cf939904db99388dd382b73ff197dd57d264
[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 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
10
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.
13 **/
14
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>
22
23
24 //
25 // Event to signal when the S3SaveState protocol interface is installed.
26 //
27 STATIC EFI_EVENT mS3SaveStateInstalledEvent;
28
29 //
30 // Reference to the S3SaveState protocol interface, after it is installed.
31 //
32 STATIC EFI_S3_SAVE_STATE_PROTOCOL *mS3SaveState;
33
34 //
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.
38 //
39 #define RESERVED_MEM_ALIGNMENT 8
40
41 STATIC FW_CFG_DMA_ACCESS *mDmaAccess;
42 STATIC VOID *mScratchBuffer;
43 STATIC UINTN mScratchBufferSize;
44
45 //
46 // Callback provided by the client, for appending ACPI S3 Boot Script opcodes.
47 // To be called from S3SaveStateInstalledNotify().
48 //
49 STATIC FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *mCallback;
50
51
52 /**
53 Event notification function for mS3SaveStateInstalledEvent.
54 **/
55 STATIC
56 VOID
57 EFIAPI
58 S3SaveStateInstalledNotify (
59 IN EFI_EVENT Event,
60 IN VOID *Context
61 )
62 {
63 EFI_STATUS Status;
64
65 ASSERT (Event == mS3SaveStateInstalledEvent);
66
67 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid,
68 NULL /* Registration */, (VOID **)&mS3SaveState);
69 if (EFI_ERROR (Status)) {
70 return;
71 }
72
73 ASSERT (mCallback != NULL);
74
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);
79
80 gBS->CloseEvent (mS3SaveStateInstalledEvent);
81 mS3SaveStateInstalledEvent = NULL;
82 }
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 EFIAPI
143 RETURN_STATUS
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 ((DEBUG_ERROR, "%a: %a: fw_cfg DMA unavailable\n",
161 gEfiCallerBaseName, __FUNCTION__));
162 return RETURN_NOT_FOUND;
163 }
164
165 //
166 // Allocate a reserved buffer for the DMA access control structure and the
167 // client data together.
168 //
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;
174 }
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;
181 }
182 mDmaAccess = ALIGN_POINTER (mDmaAccess, RESERVED_MEM_ALIGNMENT);
183
184 //
185 // Set up a protocol notify for EFI_S3_SAVE_STATE_PROTOCOL. Forward the
186 // client's Context to the callback.
187 //
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));
194 goto FreeDmaAccess;
195 }
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));
201 goto CloseEvent;
202 }
203
204 //
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.
208 //
209 ASSERT (sizeof *mDmaAccess % RESERVED_MEM_ALIGNMENT == 0);
210 mScratchBuffer = mDmaAccess + 1;
211 mScratchBufferSize = ScratchBufferSize;
212 mCallback = Callback;
213
214 //
215 // Kick the event; EFI_S3_SAVE_STATE_PROTOCOL could be available already.
216 //
217 Status = gBS->SignalEvent (mS3SaveStateInstalledEvent);
218 if (EFI_ERROR (Status)) {
219 DEBUG ((DEBUG_ERROR, "%a: %a: SignalEvent(): %r\n", gEfiCallerBaseName,
220 __FUNCTION__, Status));
221 goto NullGlobals;
222 }
223
224 return RETURN_SUCCESS;
225
226 NullGlobals:
227 mScratchBuffer = NULL;
228 mScratchBufferSize = 0;
229 mCallback = NULL;
230
231 CloseEvent:
232 gBS->CloseEvent (mS3SaveStateInstalledEvent);
233 mS3SaveStateInstalledEvent = NULL;
234
235 FreeDmaAccess:
236 FreePool (mDmaAccess);
237 mDmaAccess = NULL;
238
239 return (RETURN_STATUS)Status;
240 }
241
242
243 /**
244 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
245 and transfer data to it.
246
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.
250
251 If the operation fails during S3 resume, the boot script will hang.
252
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.
256
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
264 0.
265
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().
271
272 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
273 Boot Script successfully. There is no way
274 to undo this action.
275
276 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
277
278 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
279 ScratchBufferSize.
280
281 @return Error codes from underlying functions.
282 **/
283 EFIAPI
284 RETURN_STATUS
285 QemuFwCfgS3ScriptWriteBytes (
286 IN INT32 FirmwareConfigItem,
287 IN UINTN NumberOfBytes
288 )
289 {
290 UINTN Count;
291 EFI_STATUS Status;
292 UINT64 AccessAddress;
293 UINT32 ControlPollData;
294 UINT32 ControlPollMask;
295
296 ASSERT (mDmaAccess != NULL);
297 ASSERT (mS3SaveState != NULL);
298
299 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {
300 return RETURN_INVALID_PARAMETER;
301 }
302 if (NumberOfBytes > mScratchBufferSize) {
303 return RETURN_BAD_BUFFER_SIZE;
304 }
305
306 //
307 // Set up a write[+select] fw_cfg DMA command.
308 //
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;
313 }
314 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
315
316 //
317 // We ensured the following constraint via mScratchBufferSize in
318 // QemuFwCfgS3CallWhenBootScriptReady().
319 //
320 ASSERT (NumberOfBytes <= MAX_UINT32);
321 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
322
323 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);
324
325 //
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
328 // in-place.
329 //
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
336 Count, // Count
337 (VOID *)mDmaAccess // Buffer
338 );
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;
343 }
344
345 //
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
349 // transfer.
350 //
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
357 (UINTN)2, // Count
358 (VOID *)&AccessAddress // Buffer
359 );
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;
364 }
365
366 //
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.
370 //
371 ControlPollData = 0;
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
380 MAX_UINT64 // Delay
381 );
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;
386 }
387
388 return RETURN_SUCCESS;
389 }
390
391
392 /**
393 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
394 and transfer data from it.
395
396 The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
397 bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
398 memory.
399
400 If the operation fails during S3 resume, the boot script will hang.
401
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.
405
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
413 0.
414
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().
419
420 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
421 Boot Script successfully. There is no way
422 to undo this action.
423
424 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
425
426 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is larger than
427 ScratchBufferSize.
428
429 @return Error codes from underlying functions.
430 **/
431 EFIAPI
432 RETURN_STATUS
433 QemuFwCfgS3ScriptReadBytes (
434 IN INT32 FirmwareConfigItem,
435 IN UINTN NumberOfBytes
436 )
437 {
438 EFI_STATUS Status;
439 UINT64 AccessAddress;
440 UINT32 ControlPollData;
441 UINT32 ControlPollMask;
442
443 ASSERT (mDmaAccess != NULL);
444 ASSERT (mS3SaveState != NULL);
445
446 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {
447 return RETURN_INVALID_PARAMETER;
448 }
449 if (NumberOfBytes > mScratchBufferSize) {
450 return RETURN_BAD_BUFFER_SIZE;
451 }
452
453 //
454 // Set up a read[+select] fw_cfg DMA command.
455 //
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;
460 }
461 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
462
463 //
464 // We ensured the following constraint via mScratchBufferSize in
465 // QemuFwCfgS3CallWhenBootScriptReady().
466 //
467 ASSERT (NumberOfBytes <= MAX_UINT32);
468 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
469
470 mDmaAccess->Address = SwapBytes64 ((UINTN)mScratchBuffer);
471
472 //
473 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
474 // opcode will restore it in-place.
475 //
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
483 );
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;
488 }
489
490 //
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
494 // transfer.
495 //
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
502 (UINTN)2, // Count
503 (VOID *)&AccessAddress // Buffer
504 );
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;
509 }
510
511 //
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.
515 //
516 ControlPollData = 0;
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
525 MAX_UINT64 // Delay
526 );
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;
531 }
532
533 return RETURN_SUCCESS;
534 }
535
536
537 /**
538 Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
539 and increase its offset.
540
541 If the operation fails during S3 resume, the boot script will hang.
542
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.
546
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
554 from offset 0.
555
556 @param[in] NumberOfBytes The number of bytes to skip in the subject
557 fw_cfg item.
558
559 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
560 Boot Script successfully. There is no way
561 to undo this action.
562
563 @retval RETURN_INVALID_PARAMETER FirmwareConfigItem is invalid.
564
565 @retval RETURN_BAD_BUFFER_SIZE NumberOfBytes is too large.
566
567 @return Error codes from underlying functions.
568 **/
569 EFIAPI
570 RETURN_STATUS
571 QemuFwCfgS3ScriptSkipBytes (
572 IN INT32 FirmwareConfigItem,
573 IN UINTN NumberOfBytes
574 )
575 {
576 EFI_STATUS Status;
577 UINT64 AccessAddress;
578 UINT32 ControlPollData;
579 UINT32 ControlPollMask;
580
581 ASSERT (mDmaAccess != NULL);
582 ASSERT (mS3SaveState != NULL);
583
584 if (FirmwareConfigItem < -1 || FirmwareConfigItem > MAX_UINT16) {
585 return RETURN_INVALID_PARAMETER;
586 }
587 if (NumberOfBytes > MAX_UINT32) {
588 return RETURN_BAD_BUFFER_SIZE;
589 }
590
591 //
592 // Set up a skip[+select] fw_cfg DMA command.
593 //
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;
598 }
599 mDmaAccess->Control = SwapBytes32 (mDmaAccess->Control);
600
601 mDmaAccess->Length = SwapBytes32 ((UINT32)NumberOfBytes);
602 mDmaAccess->Address = 0;
603
604 //
605 // Copy mDmaAccess into the boot script. When executed at S3 resume, this
606 // opcode will restore it in-place.
607 //
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
615 );
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;
620 }
621
622 //
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
626 // transfer.
627 //
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
634 (UINTN)2, // Count
635 (VOID *)&AccessAddress // Buffer
636 );
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;
641 }
642
643 //
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.
647 //
648 ControlPollData = 0;
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
657 MAX_UINT64 // Delay
658 );
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;
663 }
664
665 return RETURN_SUCCESS;
666 }
667
668
669 /**
670 Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.
671
672 If the check fails during S3 resume, the boot script will hang.
673
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.
677
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().
683
684 ScratchData must point into ScratchBuffer, which was
685 allocated, and passed to Callback(), by
686 QemuFwCfgS3CallWhenBootScriptReady().
687
688 ScratchData must be aligned at ValueSize bytes.
689
690 @param[in] ValueSize One of 1, 2, 4 or 8, specifying the size of the field
691 to check.
692
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.
698
699 @param[in] Value Refer to ValueMask.
700
701 @retval RETURN_SUCCESS The opcodes were appended to the ACPI S3
702 Boot Script successfully. There is no way
703 to undo this action.
704
705 @retval RETURN_INVALID_PARAMETER ValueSize is invalid.
706
707 @retval RETURN_INVALID_PARAMETER ValueMask or Value cannot be represented in
708 ValueSize bytes.
709
710 @retval RETURN_INVALID_PARAMETER ScratchData is not aligned at ValueSize
711 bytes.
712
713 @retval RETURN_BAD_BUFFER_SIZE The ValueSize bytes at ScratchData aren't
714 wholly contained in the ScratchBufferSize
715 bytes at ScratchBuffer.
716
717 @return Error codes from underlying functions.
718 **/
719 EFIAPI
720 RETURN_STATUS
721 QemuFwCfgS3ScriptCheckValue (
722 IN VOID *ScratchData,
723 IN UINT8 ValueSize,
724 IN UINT64 ValueMask,
725 IN UINT64 Value
726 )
727 {
728 EFI_BOOT_SCRIPT_WIDTH Width;
729 EFI_STATUS Status;
730
731 ASSERT (mS3SaveState != NULL);
732
733 switch (ValueSize) {
734 case 1:
735 Width = EfiBootScriptWidthUint8;
736 break;
737
738 case 2:
739 Width = EfiBootScriptWidthUint16;
740 break;
741
742 case 4:
743 Width = EfiBootScriptWidthUint32;
744 break;
745
746 case 8:
747 Width = EfiBootScriptWidthUint64;
748 break;
749
750 default:
751 return RETURN_INVALID_PARAMETER;
752 }
753
754 if (ValueSize < 8 &&
755 (RShiftU64 (ValueMask, ValueSize * 8) > 0 ||
756 RShiftU64 (Value, ValueSize * 8) > 0)) {
757 return RETURN_INVALID_PARAMETER;
758 }
759
760 if ((UINTN)ScratchData % ValueSize > 0) {
761 return RETURN_INVALID_PARAMETER;
762 }
763
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;
769 }
770
771 //
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.
775 //
776 Status = mS3SaveState->Write (
777 mS3SaveState, // This
778 EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, // OpCode
779 Width, // Width
780 (UINT64)(UINTN)ScratchData, // Address
781 (VOID *)&Value, // Data
782 (VOID *)&ValueMask, // DataMask
783 MAX_UINT64 // Delay
784 );
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;
789 }
790
791 return RETURN_SUCCESS;
792 }