Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2849