OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
ProcessKernel.c
Go to the documentation of this file.
1
16#include <Library/DebugLib.h>
17#include <Library/MemoryAllocationLib.h>
20#include <Library/OcMiscLib.h>
22
24#include <Library/OcMainLib.h>
25
26#include <UserFile.h>
27
28#define OC_USER_FULL_PATH_MAX_SIZE 256
29
31STATIC UINTN mRootPathLen = 0;
32
33STATIC
34BOOLEAN
36 IN CONST CHAR8 *RootPath
37 )
38{
39 UINTN RootPathLen;
40
41 RootPathLen = AsciiStrLen (RootPath);
42 //
43 // Preserve 2 bytes for '/' and '\0'.
44 //
45 if (RootPathLen > OC_USER_FULL_PATH_MAX_SIZE - 2) {
46 DEBUG ((DEBUG_ERROR, "RootPath is too long!\n"));
47 return FALSE;
48 }
49
50 AsciiStrCpyS (mFullPath, sizeof (mFullPath) - 1, RootPath);
51 //
52 // If passed without '/' in the end, append it.
53 //
54 if (mFullPath[RootPathLen - 1] != '/') {
55 mFullPath[RootPathLen] = '/';
56 mFullPath[RootPathLen + 1] = '\0';
57 mRootPathLen = RootPathLen + 1;
58 } else {
59 mRootPathLen = RootPathLen;
60 }
61
62 DEBUG ((DEBUG_ERROR, "Root Path: %a\n", mFullPath));
63 return TRUE;
64}
65
66STATIC
67UINT8 *
69 IN CONST CHAR8 *FileName,
70 OUT UINT32 *Size
71 )
72{
73 AsciiStrCpyS (&mFullPath[mRootPathLen], sizeof (mFullPath) - mRootPathLen - 1, FileName);
74 DEBUG ((DEBUG_ERROR, "Full path: %a\n", mFullPath));
75 return UserReadFile (mFullPath, Size);
76}
77
78STATIC BOOLEAN FailedToProcess = FALSE;
79STATIC UINT32 KernelVersion = 0;
80
81STATIC EFI_FILE_PROTOCOL NilFileProtocol;
82
83STATIC UINT8 *mPrelinked = NULL;
84STATIC UINT32 mPrelinkedSize = 0;
85
86//
87// TODO: Windows portability.
88//
89STATIC
90VOID
92 IN OUT CHAR8 *String
93 )
94{
95 CHAR8 *Needle;
96
97 Needle = String;
98 while ((Needle = AsciiStrStr (Needle, "\\")) != NULL) {
99 *Needle++ = '/';
100 }
101}
102
103STATIC
104EFI_STATUS
106 IN OC_KERNEL_ADD_ENTRY *Kext,
107 IN UINT32 Index,
108 IN OC_GLOBAL_CONFIG *Config,
109 IN BOOLEAN Is32Bit,
110 IN OUT UINT32 *ReservedExeSize,
111 IN OUT UINT32 *ReservedInfoSize,
112 IN OUT UINT32 *NumReservedKexts
113 )
114{
115 EFI_STATUS Status;
116 CHAR8 *BundlePath;
117 CHAR8 *Comment;
118 CONST CHAR8 *Arch;
119 CHAR8 *PlistPath;
120 CHAR8 *ExecutablePath;
121 CHAR8 FullPath[OC_STORAGE_SAFE_PATH_MAX];
122
123 if (!Kext->Enabled) {
124 return EFI_SUCCESS;
125 }
126
127 BundlePath = OC_BLOB_GET (&Kext->BundlePath);
128 Comment = OC_BLOB_GET (&Kext->Comment);
129 Arch = OC_BLOB_GET (&Kext->Arch);
130 PlistPath = OC_BLOB_GET (&Kext->PlistPath);
131 if ((BundlePath[0] == '\0') || (PlistPath[0] == '\0')) {
132 DEBUG ((
133 DEBUG_ERROR,
134 "OC: Injected kext %u (%a) has invalid info\n",
135 Index,
136 Comment
137 ));
138 Kext->Enabled = FALSE;
139 return EFI_INVALID_PARAMETER;
140 }
141
142 if (AsciiStrCmp (Arch, Is32Bit ? "x86_64" : "i386") == 0) {
143 DEBUG ((
144 DEBUG_INFO,
145 "OC: Injected kext %a (%a) at %u skipped due to arch %a != %a\n",
146 BundlePath,
147 Comment,
148 Index,
149 Arch,
150 Is32Bit ? "i386" : "x86_64"
151 ));
152 return EFI_SUCCESS;
153 }
154
155 //
156 // Required for possible cacheless force injection later on.
157 //
158 AsciiHostSlashes (BundlePath);
159
160 //
161 // Get plist path and data.
162 //
163 Status = OcAsciiSafeSPrint (
164 FullPath,
165 sizeof (FullPath),
166 "%s%a\\%a",
168 BundlePath,
169 PlistPath
170 );
171 if (EFI_ERROR (Status)) {
172 DEBUG ((
173 DEBUG_WARN,
174 "OC: Failed to fit injected kext path %s%a\\%a",
176 BundlePath,
177 PlistPath
178 ));
179 Kext->Enabled = FALSE;
180 return Status;
181 }
182
183 AsciiHostSlashes (FullPath);
184
185 Kext->PlistData = (CHAR8 *)UserReadFileFromRoot (
186 FullPath,
187 &Kext->PlistDataSize
188 );
189 if (Kext->PlistData == NULL) {
190 DEBUG ((
191 DEBUG_ERROR,
192 "OC: Plist injected is missing for %s kext %a (%a)\n",
193 FullPath,
194 BundlePath,
195 Comment
196 ));
197 Kext->Enabled = FALSE;
198 return EFI_UNSUPPORTED;
199 }
200
201 //
202 // Get executable path and data, if present.
203 //
204 ExecutablePath = OC_BLOB_GET (&Kext->ExecutablePath);
205 if (ExecutablePath[0] != '\0') {
206 Status = OcAsciiSafeSPrint (
207 FullPath,
208 sizeof (FullPath),
209 "%s%a\\%a",
211 BundlePath,
212 ExecutablePath
213 );
214 if (EFI_ERROR (Status)) {
215 DEBUG ((
216 DEBUG_WARN,
217 "OC: Failed to fit injected kext path %s%a\\%a",
219 BundlePath,
220 ExecutablePath
221 ));
222 Kext->Enabled = FALSE;
223 FreePool (Kext->PlistData);
224 Kext->PlistData = NULL;
225 return Status;
226 }
227
228 AsciiHostSlashes (FullPath);
229
230 Kext->ImageData = UserReadFileFromRoot (
231 FullPath,
232 &Kext->ImageDataSize
233 );
234 if (Kext->ImageData == NULL) {
235 DEBUG ((
236 DEBUG_ERROR,
237 "OC: Image injected is missing for %a kext %a (%a)\n",
238 FullPath,
239 BundlePath,
240 Comment
241 ));
242 Kext->Enabled = FALSE;
243 FreePool (Kext->PlistData);
244 Kext->PlistData = NULL;
245 return EFI_UNSUPPORTED;
246 }
247 }
248
249 Status = PrelinkedReserveKextSize (
250 ReservedInfoSize,
251 ReservedExeSize,
252 Kext->PlistDataSize,
253 Kext->ImageData,
254 Kext->ImageDataSize,
255 Is32Bit
256 );
257 if (EFI_ERROR (Status)) {
258 DEBUG ((
259 DEBUG_INFO,
260 "OC: Failed to fit %s kext %a (%a) - %r\n",
261 Is32Bit ? L"32-bit" : L"64-bit",
262 BundlePath,
263 Comment,
264 Status
265 ));
266 if (Kext->ImageData != NULL) {
267 FreePool (Kext->ImageData);
268 Kext->ImageData = NULL;
269 }
270
271 FreePool (Kext->PlistData);
272 Kext->PlistData = NULL;
273 return Status;
274 }
275
276 (*NumReservedKexts)++;
277
278 return EFI_SUCCESS;
279}
280
281EFI_STATUS
283 IN EFI_FILE_PROTOCOL *File,
284 IN UINT32 Position,
285 IN UINT32 Size,
286 OUT UINT8 *Buffer
287 )
288{
289 ASSERT (File == &NilFileProtocol);
290
291 if ((UINT64)Position + Size > mPrelinkedSize) {
292 return EFI_INVALID_PARAMETER;
293 }
294
295 CopyMem (&Buffer[0], &mPrelinked[Position], Size);
296 return EFI_SUCCESS;
297}
298
299EFI_STATUS
301 IN EFI_FILE_PROTOCOL *File,
302 OUT UINT32 *Size
303 )
304{
305 ASSERT (File == &NilFileProtocol);
306
308 return EFI_SUCCESS;
309}
310
311int
313 int argc,
314 char *argv[]
315 )
316{
317 UINT8 *ConfigFileBuffer;
318 UINT32 ConfigFileSize;
319 OC_GLOBAL_CONFIG Config;
320 EFI_STATUS Status;
321 UINT32 ErrorCount;
322 UINT32 Index;
323 UINT32 AllocSize;
324 EFI_STATUS PrelinkedStatus;
325
326 CONST CHAR8 *FileName;
327
328 BOOLEAN mUse32BitKernel;
329 UINT32 ReservedInfoSize;
330 UINT32 ReservedExeSize;
331 UINT32 NumReservedKexts;
332 UINT32 LinkedExpansion;
333 UINT8 *NewPrelinked;
334 UINT32 NewPrelinkedSize;
335 UINT8 Sha384[48];
336 BOOLEAN Is32Bit;
337
338 OC_CPU_INFO DummyCpuInfo;
339
340 OC_KERNEL_ADD_ENTRY *Kext;
341
342 if (argc < 2) {
343 DEBUG ((DEBUG_ERROR, "Usage: %a <path/to/OC/folder/> [path/to/kernel]\n\n", argv[0]));
344 return -1;
345 }
346
347 FileName = argc > 2 ? argv[2] : "/System/Library/PrelinkedKernels/prelinkedkernel";
348 if ((mPrelinked = UserReadFile (FileName, &mPrelinkedSize)) == NULL) {
349 DEBUG ((DEBUG_ERROR, "Read fail %a\n", FileName));
350 return -1;
351 }
352
353 if (!UserSetRootPath (argv[1])) {
354 return -1;
355 }
356
357 //
358 // Read config file (Only one single config is supported).
359 //
360 CHAR8 AsciiOcConfig[16];
361
362 UnicodeStrToAsciiStrS (OPEN_CORE_CONFIG_PATH, AsciiOcConfig, L_STR_SIZE (OPEN_CORE_CONFIG_PATH));
363 ConfigFileBuffer = UserReadFileFromRoot (AsciiOcConfig, &ConfigFileSize);
364 if (ConfigFileBuffer == NULL) {
365 DEBUG ((DEBUG_ERROR, "Failed to read %s\n", OPEN_CORE_CONFIG_PATH));
366 return -1;
367 }
368
369 //
370 // Initialise config structure to be checked, and exit on error.
371 //
372 ErrorCount = 0;
373 Status = OcConfigurationInit (&Config, ConfigFileBuffer, ConfigFileSize, &ErrorCount);
374 if (EFI_ERROR (Status)) {
375 DEBUG ((DEBUG_ERROR, "Invalid config\n"));
376 return -1;
377 }
378
379 if (ErrorCount > 0) {
380 DEBUG ((DEBUG_ERROR, "Serialisation returns %u %a!\n", ErrorCount, ErrorCount > 1 ? "errors" : "error"));
381 }
382
383 PcdGet32 (PcdFixedDebugPrintErrorLevel) |= DEBUG_INFO;
384 PcdGet32 (PcdDebugPrintErrorLevel) |= DEBUG_INFO;
385 PcdGet8 (PcdDebugPropertyMask) |= DEBUG_PROPERTY_DEBUG_CODE_ENABLED;
386
387 mUse32BitKernel = FALSE;
388 ReservedInfoSize = PRELINK_INFO_RESERVE_SIZE;
389 ReservedExeSize = 0;
390 NumReservedKexts = 0;
391 //
392 // Process kexts to be injected.
393 //
394 for (Index = 0; Index < Config.Kernel.Add.Count; ++Index) {
395 Kext = Config.Kernel.Add.Values[Index];
396
398 Kext,
399 Index,
400 &Config,
402 &ReservedExeSize,
403 &ReservedInfoSize,
404 &NumReservedKexts
405 );
406 if (EFI_ERROR (Status)) {
407 DEBUG ((DEBUG_WARN, "[FAIL] Kernel load and reserve - %r\n", Status));
408 FailedToProcess = TRUE;
409 return -1;
410 }
411 }
412
413 LinkedExpansion = KcGetSegmentFixupChainsSize (ReservedExeSize);
414 if (LinkedExpansion == 0) {
415 FailedToProcess = TRUE;
416 return -1;
417 }
418
419 Status = ReadAppleKernel (
421 FALSE,
422 &Is32Bit,
423 &NewPrelinked,
424 &NewPrelinkedSize,
425 &AllocSize,
426 ReservedInfoSize + ReservedExeSize + LinkedExpansion,
427 Sha384
428 );
429 if (!EFI_ERROR (Status)) {
430 FreePool (mPrelinked);
431 mPrelinked = NewPrelinked;
432 mPrelinkedSize = NewPrelinkedSize;
433 DEBUG ((DEBUG_WARN, "[OK] Sha384 is %02X%02X%02X%02X\n", Sha384[0], Sha384[1], Sha384[2], Sha384[3]));
434 } else {
435 DEBUG ((DEBUG_WARN, "[FAIL] Kernel unpack failure - %r\n", Status));
436 FailedToProcess = TRUE;
437 return -1;
438 }
439
441 if (KernelVersion != 0) {
442 DEBUG ((DEBUG_WARN, "[OK] Got version %u\n", KernelVersion));
443 } else {
444 DEBUG ((DEBUG_WARN, "[FAIL] Failed to detect version\n"));
445 FailedToProcess = TRUE;
446 }
447
448 ZeroMem (&DummyCpuInfo, sizeof (DummyCpuInfo));
449 //
450 // Disable ProvideCurrentCpuInfo patch, as there is no CpuInfo available on userspace.
451 //
452 Config.Kernel.Quirks.ProvideCurrentCpuInfo = FALSE;
453 ASSERT (Config.Kernel.Quirks.ProvideCurrentCpuInfo == FALSE);
454
455 ZeroMem (Config.Kernel.Emulate.Cpuid1Data, sizeof (Config.Kernel.Emulate.Cpuid1Data));
456 Config.Kernel.Emulate.Cpuid1Data[0] = 0x000306A9;
457 ZeroMem (Config.Kernel.Emulate.Cpuid1Mask, sizeof (Config.Kernel.Emulate.Cpuid1Mask));
458 Config.Kernel.Emulate.Cpuid1Mask[0] = 0xFFFFFFFF;
459
460 ASSERT (Config.Kernel.Force.Count == 0);
461
462 //
463 // Apply patches to kernel itself, and then process prelinked.
464 //
466 &Config,
467 &DummyCpuInfo,
469 FALSE,
471 NULL,
472 NewPrelinked,
473 NewPrelinkedSize
474 );
475 PrelinkedStatus = OcKernelProcessPrelinked (
476 &Config,
478 FALSE,
479 NewPrelinked,
480 &NewPrelinkedSize,
481 AllocSize,
482 LinkedExpansion,
483 ReservedExeSize
484 );
485 if (EFI_ERROR (PrelinkedStatus)) {
486 DEBUG ((DEBUG_WARN, "[FAIL] Kernel process - %r\n", PrelinkedStatus));
487 FailedToProcess = TRUE;
488 return -1;
489 }
490
491 DEBUG ((DEBUG_INFO, "OC: Prelinked status - %r\n", PrelinkedStatus));
492
493 UserWriteFile ("out.bin", NewPrelinked, NewPrelinkedSize);
494
495 FreePool (mPrelinked);
496
497 return 0;
498}
499
500int
502 int argc,
503 char *argv[]
504 )
505{
506 int code;
507
508 code = WrapMain (argc, argv);
509 if (FailedToProcess) {
510 code = -1;
511 }
512
513 return code;
514}
DMG_SIZE_DEVICE_PATH Size
EFI_STATUS ReadAppleKernel(IN EFI_FILE_PROTOCOL *File, IN BOOLEAN Prefer32Bit, OUT BOOLEAN *Is32Bit, OUT UINT8 **Kernel, OUT UINT32 *KernelSize, OUT UINT32 *AllocatedSize, IN UINT32 ReservedSize, OUT UINT8 *Digest OPTIONAL)
#define PRELINK_INFO_RESERVE_SIZE
EFI_STATUS PrelinkedReserveKextSize(IN OUT UINT32 *ReservedInfoSize, IN OUT UINT32 *ReservedExeSize, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, IN BOOLEAN Is32Bit)
@ CacheTypeNone
UINT32 OcKernelReadDarwinVersion(IN CONST UINT8 *Kernel, IN UINT32 KernelSize)
UINT32 KcGetSegmentFixupChainsSize(IN UINT32 SegmentSize)
EFI_STATUS OcConfigurationInit(OUT OC_GLOBAL_CONFIG *Config, IN VOID *Buffer, IN UINT32 Size, IN OUT UINT32 *ErrorCount OPTIONAL)
VOID Sha384(UINT8 *Hash, CONST UINT8 *Data, UINTN Len)
VOID OcKernelApplyPatches(IN OC_GLOBAL_CONFIG *Config, IN OC_CPU_INFO *CpuInfo, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN KERNEL_CACHE_TYPE CacheType, IN VOID *Context, IN OUT UINT8 *Kernel, IN UINT32 Size)
#define OPEN_CORE_CONFIG_PATH
Definition OcMainLib.h:52
EFI_STATUS OcKernelProcessPrelinked(IN OC_GLOBAL_CONFIG *Config, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN OUT UINT8 *Kernel, IN UINT32 *KernelSize, IN UINT32 AllocatedSize, IN UINT32 LinkedExpansion, IN UINT32 ReservedExeSize)
#define OPEN_CORE_KEXT_PATH
Definition OcMainLib.h:60
#define OC_STORAGE_SAFE_PATH_MAX
EFI_STATUS EFIAPI OcAsciiSafeSPrint(OUT CHAR8 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition OcAsciiLib.c:190
#define L_STR_SIZE(String)
Definition OcStringLib.h:35
#define OC_BLOB_GET(Blob)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
STATIC BOOLEAN mUse32BitKernel
STATIC VOID AsciiHostSlashes(IN OUT CHAR8 *String)
#define OC_USER_FULL_PATH_MAX_SIZE
STATIC UINTN mRootPathLen
STATIC EFI_STATUS UserOcKernelLoadAndReserveKext(IN OC_KERNEL_ADD_ENTRY *Kext, IN UINT32 Index, IN OC_GLOBAL_CONFIG *Config, IN BOOLEAN Is32Bit, IN OUT UINT32 *ReservedExeSize, IN OUT UINT32 *ReservedInfoSize, IN OUT UINT32 *NumReservedKexts)
EFI_STATUS OcGetFileSize(IN EFI_FILE_PROTOCOL *File, OUT UINT32 *Size)
STATIC CHAR8 mFullPath[OC_USER_FULL_PATH_MAX_SIZE]
STATIC UINT32 KernelVersion
STATIC EFI_FILE_PROTOCOL NilFileProtocol
STATIC UINT32 mPrelinkedSize
int WrapMain(int argc, char *argv[])
STATIC UINT8 * mPrelinked
STATIC UINT8 * UserReadFileFromRoot(IN CONST CHAR8 *FileName, OUT UINT32 *Size)
EFI_STATUS OcGetFileData(IN EFI_FILE_PROTOCOL *File, IN UINT32 Position, IN UINT32 Size, OUT UINT8 *Buffer)
STATIC BOOLEAN UserSetRootPath(IN CONST CHAR8 *RootPath)
STATIC BOOLEAN FailedToProcess
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT8 * UserReadFile(IN CONST CHAR8 *FileName, OUT UINT32 *Size)
Definition UserFile.c:62
VOID UserWriteFile(IN CONST CHAR8 *FileName, IN CONST VOID *Data, IN UINT32 Size)
Definition UserFile.c:116
int main()
Definition acdtinfo.c:181
#define ASSERT(x)
Definition coder.h:55