OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcAppleDiskImageLib.c
Go to the documentation of this file.
1
13#include <Uefi.h>
14
15#include <Protocol/SimpleFileSystem.h>
16
17#include <Library/BaseLib.h>
18#include <Library/BaseMemoryLib.h>
19#include <Library/BaseOverflowLib.h>
20#include <Library/DebugLib.h>
21#include <Library/MemoryAllocationLib.h>
25#include <Library/OcFileLib.h>
26
28
29BOOLEAN
31 OUT OC_APPLE_DISK_IMAGE_CONTEXT *Context,
33 IN UINTN FileSize
34 )
35{
36 BOOLEAN Result;
37 UINTN TrailerOffset;
39 UINT32 DmgBlockCount;
41 UINT32 SwappedSig;
42 UINT64 OffsetTop;
43
44 UINT32 HeaderSize;
45 UINT64 DataForkOffset;
46 UINT64 DataForkLength;
47 UINT32 SegmentCount;
48 APPLE_DISK_IMAGE_CHECKSUM DataForkChecksum;
49 UINT64 XmlOffset;
50 UINT64 XmlLength;
51 UINT64 SectorCount;
52
53 CHAR8 *PlistData;
54
55 ASSERT (Context != NULL);
56 ASSERT (ExtentTable != NULL);
57 ASSERT (FileSize > 0);
58
59 if (FileSize <= sizeof (Trailer)) {
60 DEBUG ((
61 DEBUG_INFO,
62 "OCDI: DMG file size error: %u/%u\n",
63 FileSize,
64 (UINT32)sizeof (Trailer)
65 ));
66 return FALSE;
67 }
68
69 SwappedSig = SwapBytes32 (APPLE_DISK_IMAGE_MAGIC);
70
71 TrailerOffset = (FileSize - sizeof (Trailer));
72
73 Result = OcAppleRamDiskRead (
75 TrailerOffset,
76 sizeof (Trailer),
77 &Trailer
78 );
79 if (!Result || (Trailer.Signature != SwappedSig)) {
80 DEBUG ((
81 DEBUG_INFO,
82 "OCDI: DMG trailer error: %d - %Lx/%Lx - %X/%X\n",
83 Result,
84 (UINT64)TrailerOffset,
85 (UINT64)FileSize,
86 SwappedSig,
87 Trailer.Signature
88 ));
89 return FALSE;
90 }
91
92 HeaderSize = SwapBytes32 (Trailer.HeaderSize);
93 DataForkOffset = SwapBytes64 (Trailer.DataForkOffset);
94 DataForkLength = SwapBytes64 (Trailer.DataForkLength);
95 SegmentCount = SwapBytes32 (Trailer.SegmentCount);
96 XmlOffset = SwapBytes64 (Trailer.XmlOffset);
97 XmlLength = SwapBytes64 (Trailer.XmlLength);
98 SectorCount = SwapBytes64 (Trailer.SectorCount);
99 DataForkChecksum.Size = SwapBytes32 (Trailer.DataForkChecksum.Size);
100
101 if ( (HeaderSize != sizeof (Trailer))
102 || (XmlLength == 0)
103 || (XmlLength > MAX_UINT32)
104 || (DataForkChecksum.Size > (sizeof (DataForkChecksum.Data) * 8))
105 || (SectorCount == 0))
106 {
107 DEBUG ((
108 DEBUG_INFO,
109 "OCDI: DMG context error: %u/%Lu/%Lu/%u/%u\n",
110 HeaderSize,
111 XmlLength,
112 SectorCount,
113 DataForkChecksum.Size
114 ));
115 return FALSE;
116 }
117
118 if ((SegmentCount != 0) && (SegmentCount != 1)) {
119 DEBUG ((DEBUG_ERROR, "OCDI: Multiple segments are unsupported\n"));
120 return FALSE;
121 }
122
123 Result = BaseOverflowMulU64 (
124 SectorCount,
126 &OffsetTop
127 );
128 if (Result || (OffsetTop > MAX_UINTN)) {
129 DEBUG ((DEBUG_INFO, "OCDI: DMG sector error: %Lu %Lu\n", SectorCount, OffsetTop));
130 return FALSE;
131 }
132
133 Result = BaseOverflowAddU64 (
134 XmlOffset,
135 XmlLength,
136 &OffsetTop
137 );
138 if (Result || (OffsetTop > TrailerOffset)) {
139 DEBUG ((DEBUG_INFO, "OCDI: DMG xml error: %Lu %Lu %Lu %Lu\n", XmlOffset, XmlLength, OffsetTop, TrailerOffset));
140 return FALSE;
141 }
142
143 Result = BaseOverflowAddU64 (
144 DataForkOffset,
145 DataForkLength,
146 &OffsetTop
147 );
148 if (Result || (OffsetTop > TrailerOffset)) {
149 DEBUG ((DEBUG_INFO, "OCDI: DMG data error: %Lu %Lu %Lu %Lu\n", DataForkOffset, DataForkLength, OffsetTop, TrailerOffset));
150 return FALSE;
151 }
152
153 PlistData = AllocatePool ((UINT32)XmlLength);
154 if (PlistData == NULL) {
155 DEBUG ((DEBUG_INFO, "OCDI: DMG plist alloc error: %Lu\n", XmlLength));
156 return FALSE;
157 }
158
159 Result = OcAppleRamDiskRead (
161 (UINTN)XmlOffset,
162 (UINTN)XmlLength,
163 PlistData
164 );
165 if (!Result) {
166 DEBUG ((DEBUG_INFO, "OCDI: DMG plist read error: %Lu %Lu\n", XmlOffset, XmlLength));
167 FreePool (PlistData);
168 return FALSE;
169 }
170
171 Result = InternalParsePlist (
172 PlistData,
173 (UINT32)XmlLength,
174 (UINTN)SectorCount,
175 (UINTN)DataForkOffset,
176 (UINTN)DataForkLength,
177 &DmgBlockCount,
178 &DmgBlocks
179 );
180
181 FreePool (PlistData);
182
183 if (!Result) {
184 DEBUG ((DEBUG_INFO, "OCDI: DMG plist parse error: %Lu %Lu\n", XmlOffset, XmlLength));
185 return FALSE;
186 }
187
188 Context->ExtentTable = ExtentTable;
189 Context->BlockCount = DmgBlockCount;
190 Context->Blocks = DmgBlocks;
191 Context->SectorCount = (UINTN)SectorCount;
192
193 return TRUE;
194}
195
196BOOLEAN
198 OUT OC_APPLE_DISK_IMAGE_CONTEXT *Context,
199 IN EFI_FILE_PROTOCOL *File
200 )
201{
202 EFI_STATUS Status;
203 BOOLEAN Result;
204
205 UINT32 FileSize;
207
208 ASSERT (Context != NULL);
209 ASSERT (File != NULL);
210
211 Status = OcGetFileSize (File, &FileSize);
212 if (EFI_ERROR (Status)) {
213 DEBUG ((DEBUG_INFO, "OCDI: Failed to retrieve DMG file size\n"));
214 return FALSE;
215 }
216
217 ExtentTable = OcAppleRamDiskAllocate (FileSize, EfiACPIMemoryNVS);
218 if (ExtentTable == NULL) {
219 DEBUG ((DEBUG_INFO, "OCDI: Failed to allocate DMG data\n"));
220 return FALSE;
221 }
222
223 Result = OcAppleRamDiskLoadFile (ExtentTable, File, FileSize);
224 if (!Result) {
225 DEBUG ((DEBUG_INFO, "OCDI: Failed to load DMG file\n"));
226
228 return FALSE;
229 }
230
231 Result = OcAppleDiskImageInitializeContext (Context, ExtentTable, FileSize);
232 if (!Result) {
233 DEBUG ((DEBUG_INFO, "OCDI: Failed to initialise DMG context\n"));
234
236 return FALSE;
237 }
238
239 return TRUE;
240}
241
242BOOLEAN
244 IN OUT OC_APPLE_DISK_IMAGE_CONTEXT *Context,
245 IN OUT OC_APPLE_CHUNKLIST_CONTEXT *ChunklistContext
246 )
247{
248 ASSERT (Context != NULL);
249 ASSERT (ChunklistContext != NULL);
250
252 ChunklistContext,
253 Context->ExtentTable
254 );
255}
256
257VOID
260 )
261{
262 UINT32 Index;
263
264 ASSERT (Context != NULL);
265
266 for (Index = 0; Index < Context->BlockCount; ++Index) {
267 FreePool (Context->Blocks[Index]);
268 }
269
270 FreePool (Context->Blocks);
271}
272
273VOID
276 )
277{
278 OcAppleRamDiskFree (Context->ExtentTable);
280}
281
282BOOLEAN
284 IN OC_APPLE_DISK_IMAGE_CONTEXT *Context,
285 IN UINTN Lba,
286 IN UINTN BufferSize,
287 OUT VOID *Buffer
288 )
289{
290 BOOLEAN Result;
291
294 UINT64 ChunkTotalLength;
295 UINT64 ChunkLength;
296 UINT64 ChunkOffset;
297 UINT8 *ChunkData;
298 UINT8 *ChunkDataCompressed;
299
300 UINTN LbaCurrent;
301 UINTN LbaOffset;
302 UINTN LbaLength;
303 UINTN RemainingBufferSize;
304 UINTN BufferChunkSize;
305 UINT8 *BufferCurrent;
306
307 UINTN OutSize;
308
309 ASSERT (Context != NULL);
310 ASSERT (Buffer != NULL);
311 ASSERT (Lba < Context->SectorCount);
312
313 LbaCurrent = Lba;
314 RemainingBufferSize = BufferSize;
315 BufferCurrent = Buffer;
316
317 while (RemainingBufferSize > 0) {
318 Result = InternalGetBlockChunk (Context, LbaCurrent, &BlockData, &Chunk);
319 if (!Result) {
320 return FALSE;
321 }
322
323 LbaOffset = (LbaCurrent - (UINTN)DMG_SECTOR_START_ABS (BlockData, Chunk));
324 LbaLength = ((UINTN)Chunk->SectorCount - LbaOffset);
325
326 Result = BaseOverflowMulU64 (
327 LbaOffset,
329 &ChunkOffset
330 );
331 if (Result) {
332 return FALSE;
333 }
334
335 Result = BaseOverflowMulU64 (
336 Chunk->SectorCount,
338 &ChunkTotalLength
339 );
340 if (Result) {
341 return FALSE;
342 }
343
344 ChunkLength = (ChunkTotalLength - ChunkOffset);
345
346 BufferChunkSize = (UINTN)MIN (RemainingBufferSize, ChunkLength);
347
348 switch (Chunk->Type) {
351 {
352 ZeroMem (BufferCurrent, BufferChunkSize);
353 break;
354 }
355
357 {
358 Result = OcAppleRamDiskRead (
359 Context->ExtentTable,
360 (UINTN)(Chunk->CompressedOffset + ChunkOffset),
361 BufferChunkSize,
362 BufferCurrent
363 );
364 if (!Result) {
365 return FALSE;
366 }
367
368 break;
369 }
370
372 {
373 ChunkData = AllocatePool ((UINTN)(ChunkTotalLength + Chunk->CompressedLength));
374 if (ChunkData == NULL) {
375 return FALSE;
376 }
377
378 ChunkDataCompressed = (ChunkData + (UINTN)ChunkTotalLength);
379 Result = OcAppleRamDiskRead (
380 Context->ExtentTable,
381 (UINTN)Chunk->CompressedOffset,
382 (UINTN)Chunk->CompressedLength,
383 ChunkDataCompressed
384 );
385 if (!Result) {
386 FreePool (ChunkData);
387 return FALSE;
388 }
389
390 OutSize = DecompressZLIB (
391 ChunkData,
392 (UINTN)ChunkTotalLength,
393 ChunkDataCompressed,
394 (UINTN)Chunk->CompressedLength
395 );
396 if (OutSize != (UINTN)ChunkTotalLength) {
397 FreePool (ChunkData);
398 return FALSE;
399 }
400
401 CopyMem (BufferCurrent, (ChunkData + ChunkOffset), BufferChunkSize);
402 FreePool (ChunkData);
403 break;
404 }
405
406 default:
407 {
408 DEBUG ((
409 DEBUG_ERROR,
410 "OCDI: Compression type %x unsupported\n",
411 Chunk->Type
412 ));
413 return FALSE;
414 }
415 }
416
417 RemainingBufferSize -= BufferChunkSize;
418 BufferCurrent += BufferChunkSize;
419 LbaCurrent += LbaLength;
420 }
421
422 return TRUE;
423}
APPLE_RAM_DISK_EXTENT_TABLE ExtentTable
PACKED struct @54 APPLE_RAM_DISK_EXTENT_TABLE
#define APPLE_DISK_IMAGE_CHUNK_TYPE_ZLIB
#define APPLE_DISK_IMAGE_CHUNK_TYPE_IGNORE
#define APPLE_DISK_IMAGE_MAGIC
#define APPLE_DISK_IMAGE_SECTOR_SIZE
#define APPLE_DISK_IMAGE_CHUNK_TYPE_ZERO
#define APPLE_DISK_IMAGE_CHUNK_TYPE_RAW
BOOLEAN OcAppleChunklistVerifyData(IN OUT OC_APPLE_CHUNKLIST_CONTEXT *Context, IN CONST APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable)
BOOLEAN OcAppleDiskImageRead(IN OC_APPLE_DISK_IMAGE_CONTEXT *Context, IN UINTN Lba, IN UINTN BufferSize, OUT VOID *Buffer)
BOOLEAN OcAppleDiskImageVerifyData(IN OUT OC_APPLE_DISK_IMAGE_CONTEXT *Context, IN OUT OC_APPLE_CHUNKLIST_CONTEXT *ChunklistContext)
BOOLEAN OcAppleDiskImageInitializeContext(OUT OC_APPLE_DISK_IMAGE_CONTEXT *Context, IN CONST APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, IN UINTN FileSize)
BOOLEAN OcAppleDiskImageInitializeFromFile(OUT OC_APPLE_DISK_IMAGE_CONTEXT *Context, IN EFI_FILE_PROTOCOL *File)
VOID OcAppleDiskImageFreeContext(IN OC_APPLE_DISK_IMAGE_CONTEXT *Context)
VOID OcAppleDiskImageFreeFile(IN OC_APPLE_DISK_IMAGE_CONTEXT *Context)
BOOLEAN InternalParsePlist(IN CHAR8 *Plist, IN UINT32 PlistSize, IN UINTN SectorCount, IN UINTN DataForkOffset, IN UINTN DataForkSize, OUT UINT32 *BlockCount, OUT APPLE_DISK_IMAGE_BLOCK_DATA ***Blocks)
BOOLEAN InternalGetBlockChunk(IN OC_APPLE_DISK_IMAGE_CONTEXT *Context, IN UINTN Lba, OUT APPLE_DISK_IMAGE_BLOCK_DATA **Data, OUT APPLE_DISK_IMAGE_CHUNK **Chunk)
#define DMG_SECTOR_START_ABS(b, c)
VOID OcAppleRamDiskFree(IN CONST APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable)
CONST APPLE_RAM_DISK_EXTENT_TABLE * OcAppleRamDiskAllocate(IN UINTN Size, IN EFI_MEMORY_TYPE MemoryType)
BOOLEAN OcAppleRamDiskRead(IN CONST APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, IN UINTN Offset, IN UINTN Size, OUT VOID *Buffer)
BOOLEAN OcAppleRamDiskLoadFile(IN OUT CONST APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, IN EFI_FILE_PROTOCOL *File, IN UINTN FileSize)
UINTN DecompressZLIB(OUT UINT8 *Dst, IN UINTN DstLen, IN CONST UINT8 *Src, IN UINTN SrcLen)
Definition zlib_uefi.c:59
EFI_STATUS OcGetFileSize(IN EFI_FILE_PROTOCOL *File, OUT UINT32 *Size)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 SwapBytes64(UINT64 Operand)
Definition UserMath.c:125
#define ASSERT(x)
Definition coder.h:55
#define MIN(a, b)
Definition deflate.c:1673
UINT32 Data[APPLE_DISK_IMAGE_CHECKSUM_SIZE]
APPLE_DISK_IMAGE_CHECKSUM DataForkChecksum