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