OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
HttpBootCustomRead.c
Go to the documentation of this file.
1
9
12
13typedef struct {
14 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
16
17STATIC
18EFI_STATUS
20 IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext,
21 IN OUT VOID **Data,
22 IN OUT UINT32 *DataSize
23 )
24{
25 EFI_STATUS Status;
26
27 Status = CreateVirtualFileFileNameCopy (L"__HTTPBoot__.dmg", *Data, *DataSize, NULL, &DmgPreloadContext->DmgFile);
28
29 if (EFI_ERROR (Status)) {
30 FreePool (Data);
31 } else {
32 DmgPreloadContext->DmgFileSize = *DataSize;
33 }
34
35 *Data = NULL;
36 *DataSize = 0;
37
38 return Status;
39}
40
41STATIC
42EFI_STATUS
44 IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext,
45 IN OUT VOID **Data,
46 IN OUT UINT32 *DataSize
47 )
48{
49 DmgPreloadContext->ChunklistBuffer = *Data;
50 DmgPreloadContext->ChunklistFileSize = *DataSize;
51
52 *Data = NULL;
53 *DataSize = 0;
54
55 return EFI_SUCCESS;
56}
57
58STATIC
59VOID
61 IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext
62 )
63{
64 if (DmgPreloadContext->ChunklistBuffer != NULL) {
65 FreePool (DmgPreloadContext->ChunklistBuffer);
66 }
67
68 DmgPreloadContext->ChunklistFileSize = 0;
69 if (DmgPreloadContext->DmgFile != NULL) {
70 DmgPreloadContext->DmgFile->Close (DmgPreloadContext->DmgFile);
71 DmgPreloadContext->DmgFile = NULL;
72 }
73
74 DmgPreloadContext->DmgFileSize = 0;
75}
76
77//
78// Equivalent to lines in original BmBoot.c which free RAM disk unconditionally
79// when image loaded from RAM disk exits:
80// https://github.com/tianocore/edk2/blob/a6648418c1600f0a81f2914d9dd14de1adbfe598/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c#L2061-L2071
81//
82EFI_STATUS
83EFIAPI
85 IN VOID *Context
86 )
87{
88 CUSTOM_FREE_CONTEXT *CustomFreeContext;
89
90 if (Context != NULL) {
91 CustomFreeContext = Context;
92 if (CustomFreeContext->RamDiskDevicePath != NULL) {
93 BmDestroyRamDisk (CustomFreeContext->RamDiskDevicePath);
94 FreePool (CustomFreeContext->RamDiskDevicePath);
95 }
96
97 FreePool (CustomFreeContext);
98 }
99
100 return EFI_SUCCESS;
101}
102
103//
104// Within BmExpandLoadFiles:
105// - Only DevicePath will be set if we're returning a boot file on an HTTP
106// Boot native ram disk (from .iso or .img). In this case the first and
107// second calls to LoadFile occur inside this method.
108// - The boot file is then loaded from the RAM disk (via the returned
109// device path) in a subsequent call to gBS->LoadImage made by the
110// caller.
111// - The above applies in the orginal and our modified method.
112// - Our method is modified from EDK-II original so that the second LoadFile
113// call will also be made inside the method, and Data and DataSize will be
114// filled in, if a single .efi file is loaded.
115// - In the EDK-II original, final loading of .efi files is delayed to the
116// subsequent call to GetFileBufferByFilePath in BmGetLoadOptionBuffer.
117// - Note that in the HttpBootDxe LoadFile implementation (which will be
118// used by the original and our modified code), if HTTP chunked transfer
119// encoding is used then the entire file is downloaded (chunked HTTP GET)
120// and cached (in a linked list of fixed-sized download sections, not
121// corresponding in size to the actual HTTP chunks) in order to get its
122// size, before the final buffer for the file can be allocated; then within
123// the second LoadFile call the file is transferred from this cache into
124// the final allocated buffer.
125// - For non-chunked (so, more or less, normal) transfer encoding, the
126// file size is available from a simple HTTP HEAD request, then in the
127// second LoadFile call the file HTTP GET is written directly into
128// allocated buffer.
129// - So chunked transfer encoding should ideally be avoided, especially
130// for large downloads, but is supported here and in the original.
131//
132EFI_STATUS
133EFIAPI
135 IN OC_STORAGE_CONTEXT *Storage,
136 IN OC_BOOT_ENTRY *ChosenEntry,
137 OUT VOID **Data,
138 OUT UINT32 *DataSize,
139 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
140 OUT EFI_HANDLE *StorageHandle,
141 OUT EFI_DEVICE_PATH_PROTOCOL **StoragePath,
142 IN OC_DMG_LOADING_SUPPORT DmgLoading,
143 OUT OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext,
144 OUT VOID **Context
145 )
146{
147 EFI_STATUS Status;
148 CUSTOM_FREE_CONTEXT *CustomFreeContext;
149 CHAR8 *OtherUri;
150 BOOLEAN GotDmgFirst;
151 EFI_DEVICE_PATH_PROTOCOL *OtherLoadFile;
152 EFI_DEVICE_PATH_PROTOCOL *OtherDevicePath;
153
154 ASSERT (Context != NULL);
155 *Context = NULL;
156
157 CustomFreeContext = AllocateZeroPool (sizeof (CUSTOM_FREE_CONTEXT));
158 if (CustomFreeContext == NULL) {
159 return EFI_OUT_OF_RESOURCES;
160 }
161
162 gDmgLoading = DmgLoading;
163
165
166 //
167 // Load the first (or only) file. This method has been extended to
168 // abort early (avoiding a pointless, long, slow load of a DMG) if DmgLoading
169 // is disabled and the requested file extension is `.dmg` (or `.chunklist`).
170 //
171 *DevicePath = BmExpandLoadFiles (ChosenEntry->DevicePath, Data, DataSize, TRUE);
172
173 if (*DevicePath == NULL) {
174 FreePool (CustomFreeContext);
175 return EFI_NOT_FOUND;
176 }
177
178 Status = EFI_SUCCESS;
179 GotDmgFirst = FALSE;
180 OtherUri = NULL;
181
182 //
183 // Only potentially treat first file as .dmg/.chunklist if it was loaded as
184 // a normal single file. HttpBootDxe Content-Type header handling may force
185 // any file, regardless of extension, to be treated as an .iso or .img and
186 // loaded as a RAM disk.
187 //
188 if (*DataSize != 0) {
189 Status = ExtractOtherUriFromDevicePath (*DevicePath, ".dmg", ".chunklist", &OtherUri, FALSE);
190 if (!EFI_ERROR (Status)) {
191 GotDmgFirst = TRUE;
192 Status = SetDmgPreloadDmgFile (DmgPreloadContext, Data, DataSize);
193 if (EFI_ERROR (Status)) {
194 FreePool (OtherUri);
195 OtherUri = NULL;
196 }
197 } else {
198 Status = ExtractOtherUriFromDevicePath (*DevicePath, ".chunklist", ".dmg", &OtherUri, FALSE);
199 if (!EFI_ERROR (Status)) {
200 Status = SetDmgPreloadChunklist (DmgPreloadContext, Data, DataSize);
201 if (EFI_ERROR (Status)) {
202 FreePool (OtherUri);
203 OtherUri = NULL;
204 }
205 } else if (Status == EFI_NOT_FOUND) {
206 Status = EFI_SUCCESS;
207 OtherUri = NULL;
208 }
209 }
210 }
211
212 //
213 // Is there a potential matched file?
214 //
215 if (OtherUri != NULL) {
216 //
217 // Always require .dmg if .chunklist was fetched first; only fetch (and
218 // require) .chunklist after .dmg when it will be used.
219 //
220 if (!GotDmgFirst || (DmgLoading == OcDmgLoadingAppleSigned)) {
221 Status = HttpBootAddUri (ChosenEntry->DevicePath, OtherUri, OcStringFormatAscii, &OtherLoadFile);
222 if (!EFI_ERROR (Status)) {
223 //
224 // Sort out cramped spacing between the two HTTP Boot calls.
225 // Hopefully should not affect GUI-based firmware.
226 //
227 Print (L"\n");
228
229 //
230 // Load the second file of .dmg/.chunklist pair.
231 //
232 OtherDevicePath = BmExpandLoadFiles (OtherLoadFile, Data, DataSize, TRUE);
233 FreePool (OtherLoadFile);
234 if (OtherDevicePath == NULL) {
235 DEBUG ((DEBUG_INFO, "NETB: Failed to fetch required matching file %a\r", OtherUri));
236 Status = EFI_NOT_FOUND;
237 } else {
238 if (GotDmgFirst) {
239 FreePool (OtherDevicePath);
240 Status = SetDmgPreloadChunklist (DmgPreloadContext, Data, DataSize);
241 } else {
242 FreePool (*DevicePath);
243 *DevicePath = OtherDevicePath;
244 Status = SetDmgPreloadDmgFile (DmgPreloadContext, Data, DataSize);
245 }
246 }
247 }
248 }
249
250 FreePool (OtherUri);
251 }
252
253 //
254 // Sort out OC debug messages following HTTP Boot progress message on the same line, after completion.
255 //
256 Print (L"\n");
257
258 if (EFI_ERROR (Status)) {
259 FreeDmgPreloadContext (DmgPreloadContext);
260 FreePool (CustomFreeContext);
261 FreePool (*DevicePath);
262 *DevicePath = NULL;
263 return Status;
264 }
265
266 //
267 // It is okay to follow EDK-II code and check for this when it might not be there.
268 //
269 CustomFreeContext->RamDiskDevicePath = BmGetRamDiskDevicePath (*DevicePath);
270 *Context = CustomFreeContext;
271
272 return EFI_SUCCESS;
273}
274
275//
276// There is no possibility of DMGs, chunklists or ISOs with PXE boot.
277//
278EFI_STATUS
279EFIAPI
281 IN OC_STORAGE_CONTEXT *Storage,
282 IN OC_BOOT_ENTRY *ChosenEntry,
283 OUT VOID **Data,
284 OUT UINT32 *DataSize,
285 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
286 OUT EFI_HANDLE *StorageHandle,
287 OUT EFI_DEVICE_PATH_PROTOCOL **StoragePath,
288 IN OC_DMG_LOADING_SUPPORT DmgLoading,
289 OUT OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext,
290 OUT VOID **Context
291 )
292{
294
295 *DevicePath = BmExpandLoadFiles (ChosenEntry->DevicePath, Data, DataSize, FALSE);
296
297 return (*DevicePath == NULL ? EFI_NOT_FOUND : EFI_SUCCESS);
298}
EFI_DEVICE_PATH_PROTOCOL * BmExpandLoadFiles(IN EFI_DEVICE_PATH_PROTOCOL *FilePath, OUT VOID **Data, OUT UINT32 *DataSize, IN BOOLEAN ValidateHttp)
Definition BmBoot.c:530
EFI_DEVICE_PATH_PROTOCOL * BmGetRamDiskDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *FilePath)
Definition BmBoot.c:267
VOID BmDestroyRamDisk(IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath)
Definition BmBoot.c:345
@ EfiConsoleControlScreenText
OC_DMG_LOADING_SUPPORT gDmgLoading
STATIC EFI_STATUS SetDmgPreloadDmgFile(IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext, IN OUT VOID **Data, IN OUT UINT32 *DataSize)
EFI_STATUS EFIAPI PxeBootCustomRead(IN OC_STORAGE_CONTEXT *Storage, IN OC_BOOT_ENTRY *ChosenEntry, OUT VOID **Data, OUT UINT32 *DataSize, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT EFI_HANDLE *StorageHandle, OUT EFI_DEVICE_PATH_PROTOCOL **StoragePath, IN OC_DMG_LOADING_SUPPORT DmgLoading, OUT OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext, OUT VOID **Context)
EFI_STATUS EFIAPI HttpBootCustomRead(IN OC_STORAGE_CONTEXT *Storage, IN OC_BOOT_ENTRY *ChosenEntry, OUT VOID **Data, OUT UINT32 *DataSize, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT EFI_HANDLE *StorageHandle, OUT EFI_DEVICE_PATH_PROTOCOL **StoragePath, IN OC_DMG_LOADING_SUPPORT DmgLoading, OUT OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext, OUT VOID **Context)
EFI_STATUS EFIAPI HttpBootCustomFree(IN VOID *Context)
STATIC VOID FreeDmgPreloadContext(IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext)
STATIC EFI_STATUS SetDmgPreloadChunklist(IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext, IN OUT VOID **Data, IN OUT UINT32 *DataSize)
EFI_STATUS HttpBootAddUri(EFI_DEVICE_PATH_PROTOCOL *DevicePath, VOID *Uri, OC_STRING_FORMAT StringFormat, EFI_DEVICE_PATH_PROTOCOL **UriDevicePath)
Definition Uri.c:231
EFI_STATUS ExtractOtherUriFromDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CHAR8 *FromExt, IN CHAR8 *ToExt, OUT CHAR8 **OtherUri, IN BOOLEAN OnlySearchForFromExt)
Definition Uri.c:186
OC_DMG_LOADING_SUPPORT
@ OcDmgLoadingAppleSigned
EFI_CONSOLE_CONTROL_SCREEN_MODE OcConsoleControlSetMode(IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode)
@ OcStringFormatAscii
Definition OcStringLib.h:50
EFI_STATUS CreateVirtualFileFileNameCopy(IN CONST CHAR16 *FileName, IN VOID *FileBuffer, IN UINT64 FileSize, IN CONST EFI_TIME *ModificationTime OPTIONAL, OUT EFI_FILE_PROTOCOL **File)
#define ASSERT(x)
Definition coder.h:55
EFI_DEVICE_PATH_PROTOCOL * RamDiskDevicePath