]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenAcpiPlatformDxe/BootScript.c
OvmfPkg/XenAcpiPlatformDxe: create from AcpiPlatformDxe
[mirror_edk2.git] / OvmfPkg / XenAcpiPlatformDxe / BootScript.c
1 /** @file
2 Append an ACPI S3 Boot Script fragment from the QEMU_LOADER_WRITE_POINTER
3 commands of QEMU's fully processed table linker/loader script.
4
5 Copyright (C) 2017-2021, Red Hat, Inc.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 **/
9
10 #include <Library/BaseLib.h> // CpuDeadLoop()
11 #include <Library/DebugLib.h> // DEBUG()
12 #include <Library/MemoryAllocationLib.h> // AllocatePool()
13 #include <Library/QemuFwCfgS3Lib.h> // QemuFwCfgS3ScriptSkipBytes()
14
15 #include "AcpiPlatform.h"
16
17
18 //
19 // Condensed structure for capturing the fw_cfg operations -- select, skip,
20 // write -- inherent in executing a QEMU_LOADER_WRITE_POINTER command.
21 //
22 typedef struct {
23 UINT16 PointerItem; // resolved from QEMU_LOADER_WRITE_POINTER.PointerFile
24 UINT8 PointerSize; // copied as-is from QEMU_LOADER_WRITE_POINTER
25 UINT32 PointerOffset; // copied as-is from QEMU_LOADER_WRITE_POINTER
26 UINT64 PointerValue; // resolved from QEMU_LOADER_WRITE_POINTER.PointeeFile
27 // and QEMU_LOADER_WRITE_POINTER.PointeeOffset
28 } CONDENSED_WRITE_POINTER;
29
30
31 //
32 // Context structure to accumulate CONDENSED_WRITE_POINTER objects from
33 // QEMU_LOADER_WRITE_POINTER commands.
34 //
35 // Any pointers in this structure own the pointed-to objects; that is, when the
36 // context structure is released, all pointed-to objects must be released too.
37 //
38 struct S3_CONTEXT {
39 CONDENSED_WRITE_POINTER *WritePointers; // one array element per processed
40 // QEMU_LOADER_WRITE_POINTER
41 // command
42 UINTN Allocated; // number of elements allocated for
43 // WritePointers
44 UINTN Used; // number of elements populated in
45 // WritePointers
46 };
47
48
49 //
50 // Scratch buffer, allocated in EfiReservedMemoryType type memory, for the ACPI
51 // S3 Boot Script opcodes to work on.
52 //
53 #pragma pack (1)
54 typedef union {
55 UINT64 PointerValue; // filled in from CONDENSED_WRITE_POINTER.PointerValue
56 } SCRATCH_BUFFER;
57 #pragma pack ()
58
59
60 /**
61 Allocate an S3_CONTEXT object.
62
63 @param[out] S3Context The allocated S3_CONTEXT object is returned
64 through this parameter.
65
66 @param[in] WritePointerCount Number of CONDENSED_WRITE_POINTER elements to
67 allocate room for. WritePointerCount must be
68 positive.
69
70 @retval EFI_SUCCESS Allocation successful.
71
72 @retval EFI_OUT_OF_RESOURCES Out of memory.
73
74 @retval EFI_INVALID_PARAMETER WritePointerCount is zero.
75 **/
76 EFI_STATUS
77 AllocateS3Context (
78 OUT S3_CONTEXT **S3Context,
79 IN UINTN WritePointerCount
80 )
81 {
82 EFI_STATUS Status;
83 S3_CONTEXT *Context;
84
85 if (WritePointerCount == 0) {
86 return EFI_INVALID_PARAMETER;
87 }
88
89 Context = AllocateZeroPool (sizeof *Context);
90 if (Context == NULL) {
91 return EFI_OUT_OF_RESOURCES;
92 }
93
94 Context->WritePointers = AllocatePool (WritePointerCount *
95 sizeof *Context->WritePointers);
96 if (Context->WritePointers == NULL) {
97 Status = EFI_OUT_OF_RESOURCES;
98 goto FreeContext;
99 }
100
101 Context->Allocated = WritePointerCount;
102 *S3Context = Context;
103 return EFI_SUCCESS;
104
105 FreeContext:
106 FreePool (Context);
107
108 return Status;
109 }
110
111
112 /**
113 Release an S3_CONTEXT object.
114
115 @param[in] S3Context The object to release.
116 **/
117 VOID
118 ReleaseS3Context (
119 IN S3_CONTEXT *S3Context
120 )
121 {
122 FreePool (S3Context->WritePointers);
123 FreePool (S3Context);
124 }
125
126
127 /**
128 Save the information necessary to replicate a QEMU_LOADER_WRITE_POINTER
129 command during S3 resume, in condensed format.
130
131 This function is to be called from ProcessCmdWritePointer(), after all the
132 sanity checks have passed, and before the fw_cfg operations are performed.
133
134 @param[in,out] S3Context The S3_CONTEXT object into which the caller wants
135 to save the information that was derived from
136 QEMU_LOADER_WRITE_POINTER.
137
138 @param[in] PointerItem The FIRMWARE_CONFIG_ITEM that
139 QEMU_LOADER_WRITE_POINTER.PointerFile was resolved
140 to, expressed as a UINT16 value.
141
142 @param[in] PointerSize Copied directly from
143 QEMU_LOADER_WRITE_POINTER.PointerSize.
144
145 @param[in] PointerOffset Copied directly from
146 QEMU_LOADER_WRITE_POINTER.PointerOffset.
147
148 @param[in] PointerValue The base address of the allocated / downloaded
149 fw_cfg blob that is identified by
150 QEMU_LOADER_WRITE_POINTER.PointeeFile, plus
151 QEMU_LOADER_WRITE_POINTER.PointeeOffset.
152
153 @retval EFI_SUCCESS The information derived from
154 QEMU_LOADER_WRITE_POINTER has been successfully
155 absorbed into S3Context.
156
157 @retval EFI_OUT_OF_RESOURCES No room available in S3Context.
158 **/
159 EFI_STATUS
160 SaveCondensedWritePointerToS3Context (
161 IN OUT S3_CONTEXT *S3Context,
162 IN UINT16 PointerItem,
163 IN UINT8 PointerSize,
164 IN UINT32 PointerOffset,
165 IN UINT64 PointerValue
166 )
167 {
168 CONDENSED_WRITE_POINTER *Condensed;
169
170 if (S3Context->Used == S3Context->Allocated) {
171 return EFI_OUT_OF_RESOURCES;
172 }
173 Condensed = S3Context->WritePointers + S3Context->Used;
174 Condensed->PointerItem = PointerItem;
175 Condensed->PointerSize = PointerSize;
176 Condensed->PointerOffset = PointerOffset;
177 Condensed->PointerValue = PointerValue;
178 DEBUG ((DEBUG_VERBOSE, "%a: 0x%04x/[0x%08x+%d] := 0x%Lx (%Lu)\n",
179 __FUNCTION__, PointerItem, PointerOffset, PointerSize, PointerValue,
180 (UINT64)S3Context->Used));
181 ++S3Context->Used;
182 return EFI_SUCCESS;
183 }
184
185
186 /**
187 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.
188 **/
189 STATIC
190 VOID
191 EFIAPI
192 AppendFwCfgBootScript (
193 IN OUT VOID *Context, OPTIONAL
194 IN OUT VOID *ExternalScratchBuffer
195 )
196 {
197 S3_CONTEXT *S3Context;
198 SCRATCH_BUFFER *ScratchBuffer;
199 UINTN Index;
200
201 S3Context = Context;
202 ScratchBuffer = ExternalScratchBuffer;
203
204 for (Index = 0; Index < S3Context->Used; ++Index) {
205 CONST CONDENSED_WRITE_POINTER *Condensed;
206 RETURN_STATUS Status;
207
208 Condensed = &S3Context->WritePointers[Index];
209
210 Status = QemuFwCfgS3ScriptSkipBytes (Condensed->PointerItem,
211 Condensed->PointerOffset);
212 if (RETURN_ERROR (Status)) {
213 goto FatalError;
214 }
215
216 ScratchBuffer->PointerValue = Condensed->PointerValue;
217 Status = QemuFwCfgS3ScriptWriteBytes (-1, Condensed->PointerSize);
218 if (RETURN_ERROR (Status)) {
219 goto FatalError;
220 }
221 }
222
223 DEBUG ((DEBUG_VERBOSE, "%a: boot script fragment saved\n", __FUNCTION__));
224
225 ReleaseS3Context (S3Context);
226 return;
227
228 FatalError:
229 ASSERT (FALSE);
230 CpuDeadLoop ();
231 }
232
233
234 /**
235 Translate and append the information from an S3_CONTEXT object to the ACPI S3
236 Boot Script.
237
238 The effects of a successful call to this function cannot be undone.
239
240 @param[in] S3Context The S3_CONTEXT object to translate to ACPI S3 Boot
241 Script opcodes. If the function returns successfully,
242 the caller must set the S3Context pointer -- originally
243 returned by AllocateS3Context() -- immediately to NULL,
244 because the ownership of S3Context has been transferred.
245
246 @retval EFI_SUCCESS The translation of S3Context to ACPI S3 Boot Script
247 opcodes has been successfully executed or queued. (This
248 includes the case when S3Context was empty on input and
249 no ACPI S3 Boot Script opcodes have been necessary to
250 produce.)
251
252 @return Error codes from underlying functions.
253 **/
254 EFI_STATUS
255 TransferS3ContextToBootScript (
256 IN S3_CONTEXT *S3Context
257 )
258 {
259 RETURN_STATUS Status;
260
261 if (S3Context->Used == 0) {
262 ReleaseS3Context (S3Context);
263 return EFI_SUCCESS;
264 }
265
266 Status = QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript,
267 S3Context, sizeof (SCRATCH_BUFFER));
268 return (EFI_STATUS)Status;
269 }