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