Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/boot.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License").You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25/*
26 * Mach Operating System
27 * Copyright (c) 1990 Carnegie-Mellon University
28 * Copyright (c) 1989 Carnegie-Mellon University
29 * All rights reserved. The CMU software License Agreement specifies
30 * the terms and conditions for use and redistribution.
31 *
32 * INTEL CORPORATION PROPRIETARY INFORMATION
33 *
34 * This software is supplied under the terms of a license agreement or
35 * nondisclosure agreement with Intel Corporation and may not be copied
36 * nor disclosed except in accordance with the terms of that agreement.
37 *
38 *Copyright 1988, 1989 by Intel Corporation
39 *
40 *
41 * Copyright 1993 NeXT Computer, Inc.
42 * All rights reserved.
43 *
44 * Completely reworked by Sam Streeper (sam_s@NeXT.com)
45 * Reworked again by Curtis Galloway (galloway@NeXT.com)
46 */
47
48#include "config.h"
49#include "boot.h"
50#include "bootstruct.h"
51#include "fake_efi.h"
52#include "sl.h"
53#include "libsa.h"
54#include "ramdisk.h"
55#include "gui.h"
56#include "platform.h"
57#include "modules.h"
58#include "device_tree.h"
59
60
61#if DEBUG_BOOT2
62#define DBG(x...)printf(x)
63#else
64#define DBG(x...)msglog(x)
65#endif
66
67/*
68 * How long to wait (in seconds) to load the
69 * kernel after displaying the "boot:" prompt.
70 */
71#define kBootErrorTimeout 5
72
73boolgOverrideKernel;
74boolgEnableCDROMRescan;
75boolgScanSingleDrive;
76booluseGUI;
77
78/* recovery or installer ? */
79bool isInstaller;
80bool isRecoveryHD;
81bool isMacOSXUpgrade;
82bool isOSXUpgrade;
83
84#if DEBUG_INTERRUPTS
85static intinterruptsAvailable = 0;
86#endif
87
88static boolgUnloadPXEOnExit = false;
89
90static chargCacheNameAdler[64 + 256];
91char*gPlatformName = gCacheNameAdler;
92
93chargRootDevice[ROOT_DEVICE_SIZE];
94chargMKextName[512];
95intbvCount = 0;
96intgDeviceCount = 0;
97//intmenucount = 0;
98longgBootMode; /* defaults to 0 == kBootModeNormal */
99
100BVRefbvr;
101BVRefmenuBVR;
102BVRefbvChain;
103
104static unsigned longAdler32(unsigned char *buffer, long length);
105//static voidselectBiosDevice(void);
106
107/** options.c **/
108extern char *msgbuf;
109void showTextBuffer(char *buf, int size);
110
111//==========================================================================
112// Zero the BSS.
113
114static void zeroBSS(void)
115{
116extern char bss_start __asm("section$start$__DATA$__bss");
117extern char bss_end __asm("section$end$__DATA$__bss");
118extern char common_start __asm("section$start$__DATA$__common");
119extern char common_end __asm("section$end$__DATA$__common");
120
121bzero(&bss_start, (&bss_end - &bss_start));
122bzero(&common_start, (&common_end - &common_start));
123}
124
125//==========================================================================
126// Malloc error function
127
128static void malloc_error(char *addr, size_t size, const char *file, int line)
129{
130stop("\nMemory allocation error! Addr: 0x%x, Size: 0x%x, File: %s, Line: %d\n",
131 (unsigned)addr, (unsigned)size, file, line);
132}
133
134//==========================================================================
135//Initializes the runtime. Right now this means zeroing the BSS and initializing malloc.
136//
137void initialize_runtime(void)
138{
139zeroBSS();
140malloc_init(0, 0, 0, malloc_error);
141}
142
143// =========================================================================
144
145
146
147//==========================================================================
148// ExecKernel - Load the kernel image (mach-o) and jump to its entry point.
149
150static int ExecKernel(void *binary)
151{
152intret;
153entry_tkernelEntry;
154
155bootArgs->kaddr = bootArgs->ksize = 0;
156
157// ===============================================================================
158
159gMacOSVersion[0] = 0;
160verbose("Booting on %s %s (%s)\n", (MacOSVerCurrent < MacOSVer2Int("10.8")) ? "Mac OS X" : (MacOSVerCurrent < MacOSVer2Int("10.12")) ? "OS X" : "macOS", gBootVolume->OSFullVer, gBootVolume->OSBuildVer );
161
162setupBooterArgs();
163
164// ===============================================================================
165
166execute_hook("ExecKernel", (void *)binary, NULL, NULL, NULL);
167
168ret = DecodeKernel(binary,
169 &kernelEntry,
170 (char **) &bootArgs->kaddr,
171 (int *)&bootArgs->ksize);
172
173if ( ret != 0 )
174{
175printf("Decoding kernel failed.\n");
176pause();
177return ret;
178}
179
180// Reserve space for boot args
181reserveKernBootStruct();
182
183// Notify modules that the kernel has been decoded
184execute_hook("DecodedKernel", (void *)binary, (void *)bootArgs->kaddr, (void *)bootArgs->ksize, NULL);
185
186setupFakeEfi();
187
188// Load boot drivers from the specifed root path.
189//if (!gHaveKernelCache)
190{
191LoadDrivers("/");
192}
193
194execute_hook("DriversLoaded", (void *)binary, NULL, NULL, NULL);
195
196clearActivityIndicator();
197
198if (gErrors)
199{
200printf("Errors encountered while starting up the computer.\n");
201printf("Pausing %d seconds...\n", kBootErrorTimeout);
202sleep(kBootErrorTimeout);
203}
204
205md0Ramdisk();
206
207// Cleanup the PXE base code.
208
209if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit )
210{
211if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
212{
213printf("nbpUnloadBaseCode error %d\n", (int)ret);
214sleep(2);
215}
216}
217
218bool dummyVal;
219if (getBoolForKey(kWaitForKeypressKey, &dummyVal, &bootInfo->chameleonConfig) && dummyVal)
220{
221showTextBuffer(msgbuf, strlen(msgbuf));
222}
223
224usb_loop();
225
226#if DEBUG
227if (interruptsAvailable) ShowInterruptCounters();
228#endif
229
230// If we were in text mode, switch to graphics mode.
231// This will draw the boot graphics unless we are in
232// verbose mode.
233if (gVerboseMode)
234{
235setVideoMode( GRAPHICS_MODE );
236}
237else
238{
239drawBootGraphics();
240}
241
242DBG("Starting Darwin/%s [%s]\n",( archCpuType == CPU_TYPE_I386 ) ? "x86" : "x86_64", gDarwinBuildVerStr);
243DBG("Boot Args: %s\n", bootArgs->CommandLine);
244
245setupBooterLog();
246
247finalizeBootStruct();
248
249// Jump to kernel's entry point. There's no going back now.
250if ( MacOSVerCurrent < MacOSVer2Int("10.7") )
251{
252// Notify modules that the kernel is about to be started
253execute_hook("Kernel Start", (void *)kernelEntry, (void *)bootArgsLegacy, NULL, NULL);
254
255startprog( kernelEntry, bootArgsLegacy );
256}
257else
258{
259// Notify modules that the kernel is about to be started
260execute_hook("Kernel Start", (void *)kernelEntry, (void *)bootArgs, NULL, NULL);
261
262// Masking out so that Lion doesn't doublefault
263outb(0x21, 0xff);/* Maskout all interrupts Pic1 */
264outb(0xa1, 0xff);/* Maskout all interrupts Pic2 */
265
266startprog( kernelEntry, bootArgs );
267}
268
269// Not reached
270__builtin_unreachable();
271}
272
273//==========================================================================
274// LoadKernelCache - Try to load Kernel Cache.
275// return the length of the loaded cache file or -1 on error
276long LoadKernelCache(const char *cacheFile, void **binary)
277{
278charkernelCacheFile[512];
279charkernelCachePath[512];
280longflags, ret=-1;
281unsigned longadler32 = 0;
282u_int32_t time, cachetime, kerneltime, exttime;
283
284if((gBootMode & kBootModeSafe) != 0)
285{
286DBG("Kernel Cache ignored.\n");
287return -1;
288}
289
290// Use specify kernel cache file if not empty
291if (cacheFile[0] != 0)
292{
293strlcpy(kernelCacheFile, cacheFile, sizeof(kernelCacheFile));
294verbose("Specified kernel cache file path: %s\n", cacheFile);
295}
296else
297{
298// Leopard prelink kernel cache file
299if ( MacOSVerCurrent >= MacOSVer2Int("10.4") && MacOSVerCurrent <= MacOSVer2Int("10.5") ) // OSX is 10.4 or 10.5
300{
301// Reset cache name.
302bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
303snprintf(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64, "%s,%s", gRootDevice, bootInfo->bootFile);
304adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
305snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%s.%08lX", kDefaultCachePathLeo, adler32);
306verbose("Reseted kernel cache file path: %s\n", kernelCacheFile);
307
308}
309// Snow Leopard prelink kernel cache file
310else if ( MacOSVerCurrent >= MacOSVer2Int("10.6") && MacOSVerCurrent < MacOSVer2Int("10.7") )
311{
312snprintf(kernelCacheFile, sizeof(kernelCacheFile), "kernelcache_%s",
313(archCpuType == CPU_TYPE_I386) ? "i386" : "x86_64");
314
315intlnam = strlen(kernelCacheFile) + 9; //with adler32
316char*name;
317u_int32_tprev_time = 0;
318
319struct dirstuff *cacheDir = opendir(kDefaultCachePathSnow);
320
321/* TODO: handle error? */
322if (cacheDir)
323{
324while(readdir(cacheDir, (const char**)&name, &flags, &time) >= 0)
325{
326if (((flags & kFileTypeMask) != kFileTypeDirectory) && time > prev_time
327&& strstr(name, kernelCacheFile) && (name[lnam] != '.'))
328{
329snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%s%s", kDefaultCachePathSnow, name);
330prev_time = time;
331}
332}
333verbose("Kernel Cache file path (Mac OS X 10.6): %s\n", kernelCacheFile);
334}
335closedir(cacheDir);
336}
337else if ( MacOSVerCurrent >= MacOSVer2Int("10.7") && MacOSVerCurrent < MacOSVer2Int("10.9") )
338{
339// Lion, Mountain Lion
340// for 10.7 10.8
341if (isMacOSXUpgrade)
342{
343snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", "/Mac OS X Install Data/");
344}
345else if (isInstaller)
346{
347if (MacOSVerCurrent >= MacOSVer2Int("10.7") && MacOSVerCurrent < MacOSVer2Int("10.8") )
348{
349snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kLionInstallerDataFolder);
350}
351else if ( MacOSVerCurrent >= MacOSVer2Int("10.8") && MacOSVerCurrent < MacOSVer2Int("10.9") )
352{
353snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kMLionInstallerDataFolder);
354}
355
356}
357else if (isRecoveryHD)
358{
359snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCacheRecoveryHD);
360}
361else
362{
363snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCachePathSnow);
364}
365
366verbose("Kernel Cache file path (Mac OS X 10.7 and newer): %s\n", kernelCacheFile);
367
368}
369else if ( MacOSVerCurrent >= MacOSVer2Int("10.9") && MacOSVerCurrent < MacOSVer2Int("10.10") )
370{
371// Mavericks prelinked cache file
372// for 10.9
373if (isOSXUpgrade)
374{
375snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", "/OS X Install Data/");
376}
377else if (isInstaller)
378{
379snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCacheInstallerNew);
380}
381else if (isRecoveryHD)
382{
383snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCacheRecoveryHD);
384}
385else
386{
387snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCachePathSnow);
388}
389
390verbose("Kernel Cache file path (OS X 10.9): %s\n", kernelCacheFile);
391
392}
393else if ( MacOSVerCurrent >= MacOSVer2Int("10.10") && MacOSVerCurrent < MacOSVer2Int("10.11") )
394{
395// Yosemite prelink kernel cache file
396// for 10.10 and 10.11
397if (isOSXUpgrade)
398{
399snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", "/OS X Install Data/");
400}
401else if (isInstaller)
402{
403snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCacheInstallerNew);
404}
405else if (isRecoveryHD)
406{
407snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kDefaultCacheRecoveryHD);
408}
409else
410{
411snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCachePathYosemite);
412}
413
414verbose("Kernel Cache file path (OS X 10.10): %s\n", kernelCacheFile);
415}
416else if ( MacOSVerCurrent >= MacOSVer2Int("10.11") )
417{
418// El Capitan on prelinked kernel cache file
419// for 10.10 and 10.11
420if (isOSXUpgrade)
421{
422if ( MacOSVerCurrent >= MacOSVer2Int("10.13") )
423{
424snprintf(kernelCacheFile, sizeof(kernelCacheFile),
425 "%sprelinkedkernel",
426"/macOS Install Data/Locked Files/Boot Files/");
427}
428else
429{
430snprintf(kernelCacheFile,
431sizeof(kernelCacheFile),
432"%sprelinkedkernel",
433"/OS X Install Data/");
434}
435
436}
437else if (isInstaller)
438{
439snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCacheInstallerNew);
440}
441else if (isRecoveryHD)
442{
443snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCacheRecoveryHD);
444}
445else
446{
447snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCachePathYosemite);
448}
449
450verbose("Kernel Cache file path (OS X 10.11 and newer): %s\n", kernelCacheFile);
451}
452}
453
454// Check if the kernel cache file exists
455ret = -1;
456
457if (gBootVolume->flags & kBVFlagBooter)
458{
459if (isRecoveryHD)
460{
461strncpy(kernelCachePath, "/com.apple.recovery.boot/prelinkedkernel", sizeof(kernelCachePath) );
462ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
463
464if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
465{
466strncpy(kernelCachePath, "/com.apple.recovery.boot/kernelcache", sizeof(kernelCachePath) );
467ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
468
469if ((flags & kFileTypeMask) != kFileTypeFlat)
470{
471ret = -1;
472}
473}
474}
475else if (isInstaller)
476{
477strncpy(kernelCachePath, "/.IABootFiles/prelinkedkernel", sizeof(kernelCachePath) );
478ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
479
480if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
481{
482strncpy(kernelCachePath, "/.IABootFiles/kernelcache", sizeof(kernelCachePath) );
483ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
484
485if ((flags & kFileTypeMask) != kFileTypeFlat)
486{
487ret = -1;
488}
489}
490}
491else if (isMacOSXUpgrade)
492{
493strncpy(kernelCachePath, "/Mac OS X Install Data/kernelcache", sizeof(kernelCachePath) );
494ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
495
496if ((flags & kFileTypeMask) != kFileTypeFlat)
497{
498ret = -1;
499}
500}
501else if (isOSXUpgrade)
502{
503strncpy(kernelCachePath,
504"/macOS Install Data/Locked Files/Boot Files/prelinkedkernel",
505sizeof(kernelCachePath) );
506ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
507
508if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
509{
510strncpy(kernelCachePath, "/OS X Install Data/prelinkedkernel", sizeof(kernelCachePath) );
511ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
512
513if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
514{
515strncpy(kernelCachePath, "/OS X Install Data/kernelcache", sizeof(kernelCachePath) );
516ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
517
518if ((flags & kFileTypeMask) != kFileTypeFlat)
519{
520ret = -1;
521}
522}
523}
524}
525else
526{
527snprintf(kernelCachePath, sizeof(kernelCachePath), "/com.apple.boot.P/%s", kernelCacheFile);
528ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
529if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
530{
531snprintf(kernelCachePath, sizeof(kernelCachePath), "/com.apple.boot.R/%s", kernelCacheFile);
532ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
533
534if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
535{
536snprintf(kernelCachePath, sizeof(kernelCachePath), "/com.apple.boot.S/%s", kernelCacheFile);
537ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
538
539if ((flags & kFileTypeMask) != kFileTypeFlat)
540{
541ret = -1;
542}
543}
544}
545}
546}
547
548// If not found, use the original kernel cache path.
549if (ret == -1)
550{
551strlcpy(kernelCachePath, kernelCacheFile, sizeof(kernelCachePath));
552ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
553
554if ((flags & kFileTypeMask) != kFileTypeFlat)
555{
556ret = -1;
557}
558}
559
560// Exit if kernel cache file wasn't found
561if (ret == -1)
562{
563DBG("No Kernel Cache File '%s' found\n", kernelCacheFile);
564return -1;
565}
566
567if ( !isInstaller && !isRecoveryHD && !isMacOSXUpgrade && !isOSXUpgrade )
568{
569// Check if the kernel cache file is more recent (mtime)
570// than the kernel file or the S/L/E directory
571ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
572
573// Check if the kernel file is more recent than the cache file
574if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat) && (kerneltime > cachetime))
575{
576DBG("Kernel file '%s' is more recent than Kernel Cache '%s'! Ignoring Kernel Cache.\n", bootInfo->bootFile, kernelCacheFile);
577return -1;
578}
579
580ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
581
582// Check if the S/L/E directory time is more recent than the cache file
583if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory) && (exttime > cachetime))
584{
585DBG("Folder '/System/Library/Extensions' is more recent than Kernel Cache file '%s'! Ignoring Kernel Cache.\n", kernelCacheFile);
586return -1;
587}
588}
589
590// Since the kernel cache file exists and is the most recent try to load it
591DBG("Loading Kernel Cache from: '%s%s' (%s)\n", gBootVolume->label, gBootVolume->altlabel, gBootVolume->type_name);
592
593ret = LoadThinFatFile(kernelCachePath, binary);
594return ret; // ret contain the length of the binary
595}
596
597//==========================================================================
598// This is the entrypoint from real-mode which functions exactly as it did
599// before. Multiboot does its own runtime initialization, does some of its
600// own things, and then calls common_boot.
601void boot(int biosdev)
602{
603// Enable A20 gate before accessing memory above 1Mb.
604// Note: malloc_init(), called via initialize_runtime() writes
605// memory >= 1Mb, so A20 must be enabled before calling it. - zenith432
606zeroBSS();
607enableA20();
608malloc_init(0, 0, 0, malloc_error);
609common_boot(biosdev);
610}
611
612//==========================================================================
613// The 'main' function for the booter. Called by boot0 when booting
614// from a block device, or by the network booter.
615//
616// arguments:
617// biosdev - Value passed from boot1/NBP to specify the device
618// that the booter was loaded from.
619//
620// If biosdev is kBIOSDevNetwork, then this function will return if
621// booting was unsuccessful. This allows the PXE firmware to try the
622// next boot device on its list.
623void common_boot(int biosdev)
624{
625bool quiet;
626bool firstRun = true;
627bool instantMenu;
628bool rescanPrompt;
629intstatus;
630unsigned intallowBVFlags = kBVFlagSystemVolume | kBVFlagForeignBoot;
631unsigned intdenyBVFlags = kBVFlagEFISystem;
632
633// Set reminder to unload the PXE base code. Neglect to unload
634// the base code will result in a hang or kernel panic.
635gUnloadPXEOnExit = true;
636
637// Record the device that the booter was loaded from.
638gBIOSDev = biosdev & kBIOSDevMask;
639
640// Initialize boot-log
641initBooterLog();
642
643#if DEBUG_INTERRUPTS
644// Enable interrupts
645interruptsAvailable = SetupInterrupts();
646if (interruptsAvailable)
647{
648EnableInterrupts();
649}
650#endif
651
652// Initialize boot info structure.
653initKernBootStruct();
654
655// Setup VGA text mode.
656// Not sure if it is safe to call setVideoMode() before the
657// config table has been loaded. Call video_mode() instead.
658#if DEBUG
659printf("before video_mode\n");
660#endif
661video_mode( 2 ); // 80x25 mono text mode.
662#if DEBUG
663printf("after video_mode\n");
664#endif
665
666// Scan and record the system's hardware information.
667scan_platform();
668
669// First get info for boot volume.
670scanBootVolumes(gBIOSDev, 0);
671bvChain = getBVChainForBIOSDev(gBIOSDev);
672setBootGlobals(bvChain);
673
674// Load boot.plist config file
675status = loadChameleonConfig(&bootInfo->chameleonConfig, bvChain);
676
677if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->chameleonConfig) && quiet)
678{
679gBootMode |= kBootModeQuiet;
680}
681
682// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
683if (getBoolForKey(kInstantMenuKey, &instantMenu, &bootInfo->chameleonConfig) && instantMenu)
684{
685firstRun = false;
686}
687
688// Loading preboot ramdisk if exists.
689loadPrebootRAMDisk();
690
691// Disable rescan option by default
692gEnableCDROMRescan = false;
693
694// Enable it with Rescan=y in system config
695if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->chameleonConfig)&& gEnableCDROMRescan)
696{
697gEnableCDROMRescan = true;
698}
699
700// Disable rescanPrompt option by default
701rescanPrompt = false;
702
703// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
704if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->chameleonConfig) && rescanPrompt && biosDevIsCDROM(gBIOSDev))
705{
706gEnableCDROMRescan = promptForRescanOption();
707}
708
709// Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
710if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->chameleonConfig) && gScanSingleDrive)
711{
712gScanSingleDrive = true;
713}
714
715// Create a list of partitions on device(s).
716if (gScanSingleDrive)
717{
718scanBootVolumes(gBIOSDev, &bvCount);
719}
720else
721{
722scanDisks(gBIOSDev, &bvCount);
723}
724
725// Create a separated bvr chain using the specified filters.
726bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
727
728gBootVolume = selectBootVolume(bvChain);
729
730// Intialize module system
731init_module_system();
732
733#if DEBUG
734printf("Default: %d, ->biosdev: %d, ->part_no: %d ->flags: 0x%08X\n",
735gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
736printf("bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: 0x%08X\n",
737gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
738getchar();
739#endif
740
741useGUI = true;
742// Override useGUI default
743getBoolForKey(kGUIKey, &useGUI, &bootInfo->chameleonConfig);
744if (useGUI && initGUI())
745{
746// initGUI() returned with an error, disabling GUI.
747useGUI = false;
748}
749
750setBootGlobals(bvChain);
751
752// Parse args, load and start kernel.
753while (1)
754{
755booltryresume, tryresumedefault, forceresume;
756booluseKernelCache = true; // by default try to use the prelinked kernel
757const char*val;
758intlen, ret = -1;
759longflags;
760u_int32_tsleeptime, time;
761void*binary = (void *)kLoadAddr;
762
763charbootFile[sizeof(bootInfo->bootFile)];
764charbootFilePath[512];
765charkernelCacheFile[512];
766
767// Initialize globals.
768sysConfigValid = false;
769gErrors = false;
770
771status = getBootOptions(firstRun);
772firstRun = false;
773if (status == -1) continue;
774
775status = processBootOptions();
776// Status == 1 means to chainboot
777if ( status ==1 ) break;
778// Status == -1 means that the config file couldn't be loaded or that gBootVolume is NULL
779if ( status == -1 )
780{
781// gBootVolume == NULL usually means the user hit escape.
782if (gBootVolume == NULL)
783{
784freeFilteredBVChain(bvChain);
785
786if (gEnableCDROMRescan)
787{
788rescanBIOSDevice(gBIOSDev);
789}
790
791bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
792setBootGlobals(bvChain);
793setupDeviceList(&bootInfo->themeConfig);
794}
795continue;
796}
797
798// Other status (e.g. 0) means that we should proceed with boot.
799
800// Turn off any GUI elements
801if ( bootArgs->Video.v_display == GRAPHICS_MODE )
802{
803gui.devicelist.draw = false;
804gui.bootprompt.draw = false;
805gui.menu.draw = false;
806gui.infobox.draw = false;
807gui.logo.draw = false;
808drawBackground();
809updateVRAM();
810}
811
812if (platformCPUFeature(CPU_FEATURE_EM64T))
813{
814archCpuType = CPU_TYPE_X86_64;
815}
816else
817{
818archCpuType = CPU_TYPE_I386;
819}
820
821if (getValueForKey(karch, &val, &len, &bootInfo->chameleonConfig))
822{
823if (strncmp(val, "x86_64", sizeof("x86_64") ) == 0)
824{
825archCpuType = CPU_TYPE_X86_64;
826}
827else if (strncmp(val, "i386", sizeof("i386") ) == 0)
828{
829archCpuType = CPU_TYPE_I386;
830}
831else
832{
833DBG("Incorrect parameter for option 'arch =' , please use x86_64 or i386\n");
834}
835}
836
837if (getValueForKey(kKernelArchKey, &val, &len, &bootInfo->chameleonConfig))
838{
839if (strncmp(val, "i386", sizeof("i386") ) == 0)
840{
841archCpuType = CPU_TYPE_I386;
842}
843}
844
845// Notify modules that we are attempting to boot
846execute_hook("PreBoot", NULL, NULL, NULL, NULL);
847
848if (gBootVolume->OSisInstaller)
849{
850isInstaller = true;
851}
852
853if (gBootVolume->OSisMacOSXUpgrade)
854{
855isMacOSXUpgrade = true;
856}
857
858if (gBootVolume->OSisOSXUpgrade)
859{
860isOSXUpgrade = true;
861}
862
863if (gBootVolume->OSisRecovery)
864{
865isRecoveryHD = true;
866}
867
868if ( !isRecoveryHD && !isInstaller && !isMacOSXUpgrade && !isOSXUpgrade )
869{
870if (!getBoolForKey (kWake, &tryresume, &bootInfo->chameleonConfig))
871{
872tryresume = true;
873tryresumedefault = true;
874}
875else
876{
877tryresumedefault = false;
878}
879
880if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->chameleonConfig))
881{
882forceresume = false;
883}
884
885if (forceresume)
886{
887tryresume = true;
888tryresumedefault = false;
889}
890
891while (tryresume)
892{
893const char *tmp;
894BVRef bvr;
895if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->chameleonConfig))
896val = "/private/var/vm/sleepimage";
897
898// Do this first to be sure that root volume is mounted
899ret = GetFileInfo(0, val, &flags, &sleeptime);
900
901if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
902break;
903
904// Can't check if it was hibernation Wake=y is required
905if (bvr->modTime == 0 && tryresumedefault)
906break;
907
908if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
909break;
910
911if (!forceresume && ((sleeptime+3)<bvr->modTime))
912{
913#if DEBUG
914printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",
915bvr->modTime-sleeptime);
916#endif
917break;
918}
919
920HibernateBoot((char *)val);
921break;
922}
923}
924
925if (!isRecoveryHD && !isInstaller && !isMacOSXUpgrade && !isOSXUpgrade )
926{
927getBoolForKey(kUseKernelCache, &useKernelCache, &bootInfo->chameleonConfig);
928}
929
930if (useKernelCache)
931{
932do
933{
934// Determine the name of the Kernel Cache
935if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig))
936{
937if (val[0] == '\\')
938{
939len--;
940val++;
941}
942/* FIXME: check len vs sizeof(kernelCacheFile) */
943strlcpy(kernelCacheFile, val, len + 1);
944}
945else
946{
947kernelCacheFile[0] = 0; // Use default kernel cache file
948}
949
950if (gOverrideKernel && kernelCacheFile[0] == 0)
951{
952DBG("Using a non default kernel (%s) without specifying 'Kernel Cache' path, KernelCache will not be used\n", bootInfo->bootFile);
953useKernelCache = false;
954break;
955}
956
957if (gMKextName[0] != 0)
958{
959DBG("Using a specific MKext Cache (%s), KernelCache will not be used\n", gMKextName);
960useKernelCache = false;
961break;
962}
963
964if (gBootFileType != kBlockDeviceType)
965{
966useKernelCache = false;
967}
968
969} while(0);
970}
971else
972{
973DBG("Kernel Cache using disabled by user.\n");
974}
975
976do
977{
978if (useKernelCache)
979{
980ret = LoadKernelCache(kernelCacheFile, &binary);
981if (ret >= 0)
982{
983break;
984}
985}
986
987bool bootFileWithDevice = false;
988// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel
989if (strncmp(bootInfo->bootFile, "bt(", sizeof("bt(") ) == 0 ||
990strncmp(bootInfo->bootFile, "hd(", sizeof("hd(") ) == 0 ||
991strncmp(bootInfo->bootFile, "rd(", sizeof("rd(") ) == 0)
992{
993bootFileWithDevice = true;
994}
995
996// bootFile must start with a / if it not start with a device name
997if (!bootFileWithDevice && (bootInfo->bootFile)[0] != '/')
998{
999if ( MacOSVerCurrent < MacOSVer2Int("10.10") ) // Mavericks and older
1000{
1001snprintf(bootFile, sizeof(bootFile), "/%s", bootInfo->bootFile); // append a leading /
1002}
1003else
1004{
1005// Yosemite and newer
1006snprintf(bootFile, sizeof(bootFile), kDefaultKernelPathForYos"%s", bootInfo->bootFile); // Yosemite or El Capitan
1007}
1008}
1009else
1010{
1011strlcpy(bootFile, bootInfo->bootFile, sizeof(bootFile));
1012}
1013
1014// Try to load kernel image from alternate locations on boot helper partitions.
1015ret = -1;
1016if ((gBootVolume->flags & kBVFlagBooter) && !bootFileWithDevice)
1017{
1018snprintf(bootFilePath, sizeof(bootFilePath), "com.apple.boot.P%s", bootFile);
1019ret = GetFileInfo(NULL, bootFilePath, &flags, &time);
1020if (ret == -1)
1021{
1022snprintf(bootFilePath, sizeof(bootFilePath), "com.apple.boot.R%s", bootFile);
1023ret = GetFileInfo(NULL, bootFilePath, &flags, &time);
1024if (ret == -1)
1025{
1026snprintf(bootFilePath, sizeof(bootFilePath), "com.apple.boot.S%s", bootFile);
1027ret = GetFileInfo(NULL, bootFilePath, &flags, &time);
1028}
1029}
1030}
1031if (ret == -1)
1032{
1033// No alternate location found, using the original kernel image path.
1034strlcpy(bootFilePath, bootFile, sizeof(bootFilePath));
1035}
1036
1037DBG("Loading kernel from: '%s' (%s)\n", gBootVolume->label, gBootVolume->type_name);
1038ret = LoadThinFatFile(bootFilePath, &binary);
1039if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
1040{
1041archCpuType = CPU_TYPE_I386;
1042ret = LoadThinFatFile(bootFilePath, &binary);
1043}
1044} while (0);
1045
1046clearActivityIndicator();
1047
1048#if DEBUG
1049printf("Pausing...");
1050sleep(8);
1051#endif
1052
1053if (ret <= 0)
1054{
1055printf("Can't find boot file: '%s'\n", bootFile);
1056sleep(1);
1057
1058if (gBootFileType == kNetworkDeviceType)
1059{
1060// Return control back to PXE. Don't unload PXE base code.
1061gUnloadPXEOnExit = false;
1062break;
1063}
1064pause();
1065
1066}
1067else
1068{
1069/* Won't return if successful. */
1070ret = ExecKernel(binary);
1071}
1072}
1073
1074// chainboot
1075if (status == 1)
1076{
1077// if we are already in graphics-mode,
1078if (getVideoMode() == GRAPHICS_MODE)
1079{
1080setVideoMode( VGA_TEXT_MODE ); // switch back to text mode.
1081}
1082}
1083
1084if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit)
1085{
1086nbpUnloadBaseCode();
1087}
1088
1089#if DEBUG_INTERRUPTS
1090if (interruptsAvailable)
1091{
1092DisableInterrupts();
1093}
1094#endif
1095
1096}
1097
1098// =========================================================================
1099//
1100void setupBooterArgs()
1101{
1102bool KPRebootOption= false; // I don't want this by default ( It makes me angry because I do not see the reason for the panic)+
1103//bool HiDPIOption= false; // (Disabled by default) 10.8+
1104//bool FlagBlackOption= false; // (Disabled by default) 10.10+
1105
1106// OS X Lion 10.7
1107if ( MacOSVerCurrent >= MacOSVer2Int("10.7") ) // Lion and Up!
1108{
1109// Pike R. Alpha: Adding a 16 KB log space.
1110bootArgs->performanceDataSize= 0;
1111bootArgs->performanceDataStart= 0;
1112
1113// Pike R. Alpha: AppleKeyStore.kext
1114bootArgs->keyStoreDataSize= 0;
1115bootArgs->keyStoreDataStart= 0;
1116
1117bootArgs->bootMemSize= 0;
1118bootArgs->bootMemStart= 0;
1119}
1120
1121// OS X Mountain Lion 10.8
1122if ( MacOSVerCurrent >= MacOSVer2Int("10.8") ) // Mountain Lion and Up!
1123{
1124// cparm
1125getBoolForKey(kRebootOnPanic, &KPRebootOption, &bootInfo->chameleonConfig);
1126if ( KPRebootOption )
1127{
1128bootArgs->flags |= kBootArgsFlagRebootOnPanic;
1129}
1130
1131// cparm
1132getBoolForKey(kEnableHiDPI, &HiDPIOption, &bootInfo->chameleonConfig);
1133
1134if ( HiDPIOption )
1135{
1136bootArgs->flags |= kBootArgsFlagHiDPI;
1137}
1138}
1139
1140// OS X Yosemite 10.10
1141if ( MacOSVerCurrent >= MacOSVer2Int("10.10") ) // Yosemite and Up!
1142{
1143// Pike R. Alpha
1144getBoolForKey(kBlackMode, &FlagBlackOption, &bootInfo->chameleonConfig);
1145if ( FlagBlackOption )
1146{
1147// bootArgs->flags |= kBootArgsFlagBlack;
1148bootArgs->flags |= kBootArgsFlagBlackBg; // Micky1979
1149}
1150}
1151
1152// OS X El Capitan 10.11
1153if ( MacOSVerCurrent >= MacOSVer2Int("10.11") ) // El Capitan, Sierra and High Sierra!
1154{
1155// ErmaC
1156verbose("\n");
1157intcsrValue;
1158
1159/*
1160 * A special BootArgs flag "kBootArgsFlagCSRBoot"
1161 * is set in the Recovery or Installation environment.
1162 * This flag is kind of overkill by turning off all the protections
1163 */
1164
1165if (isRecoveryHD || isInstaller || isOSXUpgrade || isMacOSXUpgrade)
1166{
1167// SIP can be controlled with or without FileNVRAM.kext (Pike R. Alpha)
1168bootArgs->flags|=(kBootArgsFlagCSRActiveConfig + kBootArgsFlagCSRConfigMode + kBootArgsFlagCSRBoot + kBootArgsFlagInstallUI);
1169}
1170else
1171{
1172bootArgs->flags|= kBootArgsFlagCSRActiveConfig;
1173}
1174
1175// Set limit to 8bit
1176if ( getIntForKey(kCsrActiveConfig, &csrValue, &bootInfo->chameleonConfig) && (csrValue >= 0 && csrValue <= 255) )
1177{
1178bootArgs->csrActiveConfig= csrValue;
1179csrInfo(csrValue, 1);
1180}
1181else
1182{
1183// zenith432
1184bootArgs->csrActiveConfig= 0x67;
1185csrInfo(0x67, 0);
1186
1187}
1188
1189
1190// ===============================================================================
1191
1192bootArgs->csrCapabilities= CSR_VALID_FLAGS;
1193bootArgs->boot_SMC_plimit= 0;
1194}
1195}
1196
1197// =========================================================================
1198// ErmaC
1199void csrInfo(int csrValue, bool custom)
1200{
1201#define CSR_BITS 0x080
1202
1203int mask = CSR_BITS;
1204verbose("System Integrity Protection status: %s ", (csrValue == 0) ? "enabled":"disabled");
1205verbose("(%s Configuration).\nCsrActiveConfig = 0x%02X (", custom ? "Custom":"Default", csrValue);
1206
1207// Display integer number into binary using bitwise operator
1208((csrValue & 0x020) == 0) ? verbose("0"): verbose("1");
1209while (mask != 0)
1210{
1211( ((csrValue & mask) == 0) ? verbose("0"): verbose("1") );
1212mask = mask >> 1; // Right Shift
1213}
1214verbose(")\n");
1215if (csrValue != 0)
1216{
1217verbose("\nConfiguration:\n");
1218verbose("Kext Signing: %s\n", ((csrValue & 0x001) == 0) ? "enabled":"disabled"); /* (1 << 0) Allow untrusted kexts */
1219verbose("Filesystem Protections: %s\n", ((csrValue & 0x002) == 0) ? "enabled":"disabled"); /* (1 << 1) Allow unrestricted file system. */
1220verbose("Task for PID: %s\n", ((csrValue & 0x004) == 0) ? "enabled":"disabled"); /* (1 << 2) */
1221verbose("Debugging Restrictions: %s\n", ((csrValue & 0x008) == 0) ? "enabled":"disabled"); /* (1 << 3) */
1222verbose("Apple Internal: %s\n", ((csrValue & 0x010) == 0) ? "enabled":"disabled"); /* (1 << 4) */
1223verbose("DTrace Restrictions: %s\n", ((csrValue & 0x020) == 0) ? "enabled":"disabled"); /* (1 << 5) Allow unrestricted dtrace */
1224verbose("NVRAM Protections: %s\n", ((csrValue & 0x040) == 0) ? "enabled":"disabled"); /* (1 << 6) Allow unrestricted NVRAM */
1225verbose("Device configuration: %s\n", ((csrValue & 0x080) == 0) ? "enabled":"disabled"); /* (1 << 7) Allow device configuration */
1226verbose("BaseSystem Verification: %s\n", ((csrValue & 0x100) == 0) ? "enabled":"disabled"); /* (1 << 8) Allow any Recovery OS */
1227}
1228verbose("\n");
1229}
1230
1231// =========================================================================
1232
1233/*!
1234Selects a new BIOS device, taking care to update the global state appropriately.
1235 */
1236/*
1237static void selectBiosDevice(void)
1238{
1239struct DiskBVMap *oldMap = diskResetBootVolumes(gBIOSDev);
1240CacheReset();
1241diskFreeMap(oldMap);
1242oldMap = NULL;
1243
1244int dev = selectAlternateBootDevice(gBIOSDev);
1245
1246BVRef bvchain = scanBootVolumes(dev, 0);
1247BVRef bootVol = selectBootVolume(bvchain);
1248gBootVolume = bootVol;
1249setRootVolume(bootVol);
1250gBIOSDev = dev;
1251}
1252*/
1253
1254// =========================================================================
1255bool checkOSVersion(const char *version)
1256{
1257if ( '\0' != version[4] )
1258{
1259return !memcmp(&gMacOSVersion[0], &version[0], 5);
1260}
1261else
1262{
1263return !memcmp(&gMacOSVersion[0], &version[0], 4);
1264}
1265}
1266
1267uint32_t getMacOSVerCurrent()
1268{
1269MacOSVerCurrent = MacOSVer2Int(gBootVolume->OSVersion);
1270return MacOSVerCurrent;
1271}
1272
1273// =========================================================================
1274unsigned long Adler32(unsigned char *buf, long len)
1275{
1276#define BASE 65521L /* largest prime smaller than 65536 */
1277#define NMAX 5000
1278// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
1279
1280#define DO1(buf, i){s1 += buf[i]; s2 += s1;}
1281#define DO2(buf, i)DO1(buf, i); DO1(buf, i + 1);
1282#define DO4(buf, i)DO2(buf, i); DO2(buf, i + 2);
1283#define DO8(buf, i)DO4(buf, i); DO4(buf, i + 4);
1284#define DO16(buf)DO8(buf, 0); DO8(buf, 8);
1285
1286int k;
1287
1288unsigned long s1 = 1; // adler & 0xffff;
1289unsigned long s2 = 0; // (adler >> 16) & 0xffff;
1290unsigned long result;
1291
1292while (len > 0)
1293{
1294k = len < NMAX ? len : NMAX;
1295len -= k;
1296while (k >= 16)
1297{
1298DO16(buf);
1299buf += 16;
1300k -= 16;
1301}
1302
1303if (k != 0)
1304{
1305do
1306{
1307s1 += *buf++;
1308s2 += s1;
1309} while (--k);
1310}
1311
1312s1 %= BASE;
1313s2 %= BASE;
1314}
1315
1316result = (s2 << 16) | s1;
1317
1318return OSSwapHostToBigInt32(result);
1319}
1320

Archive Download this file

Revision: 2899