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

Archive Download this file

Revision: 2858