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}
355else if ( MacOSVerCurrent > MacOSVer2Int("10.12") && MacOSVerCurrent < MacOSVer2Int("10.14") )
356{
357snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%skernelcache", kHSierraInstallerDataFolder);
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{
425if ( MacOSVerCurrent >= MacOSVer2Int("10.13") )
426{
427snprintf(kernelCacheFile, sizeof(kernelCacheFile),
428 "%sprelinkedkernel",
429"/macOS Install Data/Locked Files/Boot Files/");
430}
431else
432{
433snprintf(kernelCacheFile,
434sizeof(kernelCacheFile),
435"%sprelinkedkernel",
436"/OS X Install Data/");
437}
438
439}
440else if (isInstaller)
441{
442snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCacheInstallerNew);
443}
444else if (isRecoveryHD)
445{
446snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCacheRecoveryHD);
447}
448else
449{
450snprintf(kernelCacheFile, sizeof(kernelCacheFile), "%sprelinkedkernel", kDefaultCachePathYosemite);
451}
452
453verbose("Kernel Cache file path (OS X 10.11 and newer): %s\n", kernelCacheFile);
454}
455}
456
457// Check if the kernel cache file exists
458ret = -1;
459
460if (gBootVolume->flags & kBVFlagBooter)
461{
462if (isRecoveryHD)
463{
464strncpy(kernelCachePath, "/com.apple.recovery.boot/prelinkedkernel", sizeof(kernelCachePath) );
465ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
466
467if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
468{
469strncpy(kernelCachePath, "/com.apple.recovery.boot/kernelcache", sizeof(kernelCachePath) );
470ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
471
472if ((flags & kFileTypeMask) != kFileTypeFlat)
473{
474ret = -1;
475}
476}
477}
478else if (isInstaller)
479{
480strncpy(kernelCachePath, "/.IABootFiles/prelinkedkernel", sizeof(kernelCachePath) );
481ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
482
483if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
484{
485strncpy(kernelCachePath, "/.IABootFiles/kernelcache", sizeof(kernelCachePath) );
486ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
487
488if ((flags & kFileTypeMask) != kFileTypeFlat)
489{
490ret = -1;
491}
492}
493}
494else if (isMacOSXUpgrade)
495{
496strncpy(kernelCachePath, "/Mac OS X Install Data/kernelcache", sizeof(kernelCachePath) );
497ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
498
499if ((flags & kFileTypeMask) != kFileTypeFlat)
500{
501ret = -1;
502}
503}
504else if (isOSXUpgrade)
505{
506strncpy(kernelCachePath,
507"/macOS Install Data/Locked Files/Boot Files/prelinkedkernel",
508sizeof(kernelCachePath) );
509ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
510
511if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
512{
513strncpy(kernelCachePath, "/OS X Install Data/prelinkedkernel", sizeof(kernelCachePath) );
514ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
515
516if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
517{
518strncpy(kernelCachePath, "/OS X Install Data/kernelcache", sizeof(kernelCachePath) );
519ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
520
521if ((flags & kFileTypeMask) != kFileTypeFlat)
522{
523ret = -1;
524}
525}
526}
527}
528else
529{
530snprintf(kernelCachePath, sizeof(kernelCachePath), "/com.apple.boot.P/%s", kernelCacheFile);
531ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
532if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
533{
534snprintf(kernelCachePath, sizeof(kernelCachePath), "/com.apple.boot.R/%s", kernelCacheFile);
535ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
536
537if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
538{
539snprintf(kernelCachePath, sizeof(kernelCachePath), "/com.apple.boot.S/%s", kernelCacheFile);
540ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
541
542if ((flags & kFileTypeMask) != kFileTypeFlat)
543{
544ret = -1;
545}
546}
547}
548}
549}
550
551// If not found, use the original kernel cache path.
552if (ret == -1)
553{
554strlcpy(kernelCachePath, kernelCacheFile, sizeof(kernelCachePath));
555ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
556
557if ((flags & kFileTypeMask) != kFileTypeFlat)
558{
559ret = -1;
560}
561}
562
563// Exit if kernel cache file wasn't found
564if (ret == -1)
565{
566DBG("No Kernel Cache File '%s' found\n", kernelCacheFile);
567return -1;
568}
569
570if ( !isInstaller && !isRecoveryHD && !isMacOSXUpgrade && !isOSXUpgrade )
571{
572// Check if the kernel cache file is more recent (mtime)
573// than the kernel file or the S/L/E directory
574ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
575
576// Check if the kernel file is more recent than the cache file
577if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat) && (kerneltime > cachetime))
578{
579DBG("Kernel file '%s' is more recent than Kernel Cache '%s'! Ignoring Kernel Cache.\n", bootInfo->bootFile, kernelCacheFile);
580return -1;
581}
582
583ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
584
585// Check if the S/L/E directory time is more recent than the cache file
586if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory) && (exttime > cachetime))
587{
588DBG("Folder '/System/Library/Extensions' is more recent than Kernel Cache file '%s'! Ignoring Kernel Cache.\n", kernelCacheFile);
589return -1;
590}
591}
592
593// Since the kernel cache file exists and is the most recent try to load it
594DBG("Loading Kernel Cache from: '%s%s' (%s)\n", gBootVolume->label, gBootVolume->altlabel, gBootVolume->type_name);
595
596ret = LoadThinFatFile(kernelCachePath, binary);
597return ret; // ret contain the length of the binary
598}
599
600//==========================================================================
601// This is the entrypoint from real-mode which functions exactly as it did
602// before. Multiboot does its own runtime initialization, does some of its
603// own things, and then calls common_boot.
604void boot(int biosdev)
605{
606// Enable A20 gate before accessing memory above 1Mb.
607// Note: malloc_init(), called via initialize_runtime() writes
608// memory >= 1Mb, so A20 must be enabled before calling it. - zenith432
609zeroBSS();
610enableA20();
611malloc_init(0, 0, 0, malloc_error);
612common_boot(biosdev);
613}
614
615//==========================================================================
616// The 'main' function for the booter. Called by boot0 when booting
617// from a block device, or by the network booter.
618//
619// arguments:
620// biosdev - Value passed from boot1/NBP to specify the device
621// that the booter was loaded from.
622//
623// If biosdev is kBIOSDevNetwork, then this function will return if
624// booting was unsuccessful. This allows the PXE firmware to try the
625// next boot device on its list.
626void common_boot(int biosdev)
627{
628bool quiet;
629bool firstRun = true;
630bool instantMenu;
631bool rescanPrompt;
632intstatus;
633unsigned intallowBVFlags = kBVFlagSystemVolume | kBVFlagForeignBoot;
634unsigned intdenyBVFlags = kBVFlagEFISystem;
635
636// Set reminder to unload the PXE base code. Neglect to unload
637// the base code will result in a hang or kernel panic.
638gUnloadPXEOnExit = true;
639
640// Record the device that the booter was loaded from.
641gBIOSDev = biosdev & kBIOSDevMask;
642
643// Initialize boot-log
644initBooterLog();
645
646#if DEBUG_INTERRUPTS
647// Enable interrupts
648interruptsAvailable = SetupInterrupts();
649if (interruptsAvailable)
650{
651EnableInterrupts();
652}
653#endif
654
655// Initialize boot info structure.
656initKernBootStruct();
657
658// Setup VGA text mode.
659// Not sure if it is safe to call setVideoMode() before the
660// config table has been loaded. Call video_mode() instead.
661#if DEBUG
662printf("before video_mode\n");
663#endif
664video_mode( 2 ); // 80x25 mono text mode.
665#if DEBUG
666printf("after video_mode\n");
667#endif
668
669// Scan and record the system's hardware information.
670scan_platform();
671
672// First get info for boot volume.
673scanBootVolumes(gBIOSDev, 0);
674bvChain = getBVChainForBIOSDev(gBIOSDev);
675setBootGlobals(bvChain);
676
677// Load boot.plist config file
678status = loadChameleonConfig(&bootInfo->chameleonConfig, bvChain);
679
680if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->chameleonConfig) && quiet)
681{
682gBootMode |= kBootModeQuiet;
683}
684
685// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
686if (getBoolForKey(kInstantMenuKey, &instantMenu, &bootInfo->chameleonConfig) && instantMenu)
687{
688firstRun = false;
689}
690
691// Loading preboot ramdisk if exists.
692loadPrebootRAMDisk();
693
694// Disable rescan option by default
695gEnableCDROMRescan = false;
696
697// Enable it with Rescan=y in system config
698if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->chameleonConfig)&& gEnableCDROMRescan)
699{
700gEnableCDROMRescan = true;
701}
702
703// Disable rescanPrompt option by default
704rescanPrompt = false;
705
706// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
707if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->chameleonConfig) && rescanPrompt && biosDevIsCDROM(gBIOSDev))
708{
709gEnableCDROMRescan = promptForRescanOption();
710}
711
712// Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
713if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->chameleonConfig) && gScanSingleDrive)
714{
715gScanSingleDrive = true;
716}
717
718// Create a list of partitions on device(s).
719if (gScanSingleDrive)
720{
721scanBootVolumes(gBIOSDev, &bvCount);
722}
723else
724{
725scanDisks(gBIOSDev, &bvCount);
726}
727
728// Create a separated bvr chain using the specified filters.
729bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
730
731gBootVolume = selectBootVolume(bvChain);
732
733// Intialize module system
734init_module_system();
735
736#if DEBUG
737printf("Default: %d, ->biosdev: %d, ->part_no: %d ->flags: 0x%08X\n",
738gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
739printf("bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: 0x%08X\n",
740gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
741getchar();
742#endif
743
744useGUI = true;
745// Override useGUI default
746getBoolForKey(kGUIKey, &useGUI, &bootInfo->chameleonConfig);
747if (useGUI && initGUI())
748{
749// initGUI() returned with an error, disabling GUI.
750useGUI = false;
751}
752
753setBootGlobals(bvChain);
754
755// Parse args, load and start kernel.
756while (1)
757{
758booltryresume, tryresumedefault, forceresume;
759booluseKernelCache = true; // by default try to use the prelinked kernel
760const char*val;
761intlen, ret = -1;
762longflags;
763u_int32_tsleeptime, time;
764void*binary = (void *)kLoadAddr;
765
766charbootFile[sizeof(bootInfo->bootFile)];
767charbootFilePath[512];
768charkernelCacheFile[512];
769
770// Initialize globals.
771sysConfigValid = false;
772gErrors = false;
773
774status = getBootOptions(firstRun);
775firstRun = false;
776if (status == -1) continue;
777
778status = processBootOptions();
779// Status == 1 means to chainboot
780if ( status ==1 ) break;
781// Status == -1 means that the config file couldn't be loaded or that gBootVolume is NULL
782if ( status == -1 )
783{
784// gBootVolume == NULL usually means the user hit escape.
785if (gBootVolume == NULL)
786{
787freeFilteredBVChain(bvChain);
788
789if (gEnableCDROMRescan)
790{
791rescanBIOSDevice(gBIOSDev);
792}
793
794bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
795setBootGlobals(bvChain);
796setupDeviceList(&bootInfo->themeConfig);
797}
798continue;
799}
800
801// Other status (e.g. 0) means that we should proceed with boot.
802
803// Turn off any GUI elements
804if ( bootArgs->Video.v_display == GRAPHICS_MODE )
805{
806gui.devicelist.draw = false;
807gui.bootprompt.draw = false;
808gui.menu.draw = false;
809gui.infobox.draw = false;
810gui.logo.draw = false;
811drawBackground();
812updateVRAM();
813}
814
815if (platformCPUFeature(CPU_FEATURE_EM64T))
816{
817archCpuType = CPU_TYPE_X86_64;
818}
819else
820{
821archCpuType = CPU_TYPE_I386;
822}
823
824if (getValueForKey(karch, &val, &len, &bootInfo->chameleonConfig))
825{
826if (strncmp(val, "x86_64", sizeof("x86_64") ) == 0)
827{
828archCpuType = CPU_TYPE_X86_64;
829}
830else if (strncmp(val, "i386", sizeof("i386") ) == 0)
831{
832archCpuType = CPU_TYPE_I386;
833}
834else
835{
836DBG("Incorrect parameter for option 'arch =' , please use x86_64 or i386\n");
837}
838}
839
840if (getValueForKey(kKernelArchKey, &val, &len, &bootInfo->chameleonConfig))
841{
842if (strncmp(val, "i386", sizeof("i386") ) == 0)
843{
844archCpuType = CPU_TYPE_I386;
845}
846}
847
848// Notify modules that we are attempting to boot
849execute_hook("PreBoot", NULL, NULL, NULL, NULL);
850
851if (gBootVolume->OSisInstaller)
852{
853isInstaller = true;
854}
855
856if (gBootVolume->OSisMacOSXUpgrade)
857{
858isMacOSXUpgrade = true;
859}
860
861if (gBootVolume->OSisOSXUpgrade)
862{
863isOSXUpgrade = true;
864}
865
866if (gBootVolume->OSisRecovery)
867{
868isRecoveryHD = true;
869}
870
871if ( !isRecoveryHD && !isInstaller && !isMacOSXUpgrade && !isOSXUpgrade )
872{
873if (!getBoolForKey (kWake, &tryresume, &bootInfo->chameleonConfig))
874{
875tryresume = true;
876tryresumedefault = true;
877}
878else
879{
880tryresumedefault = false;
881}
882
883if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->chameleonConfig))
884{
885forceresume = false;
886}
887
888if (forceresume)
889{
890tryresume = true;
891tryresumedefault = false;
892}
893
894while (tryresume)
895{
896const char *tmp;
897BVRef bvr;
898if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->chameleonConfig))
899val = "/private/var/vm/sleepimage";
900
901// Do this first to be sure that root volume is mounted
902ret = GetFileInfo(0, val, &flags, &sleeptime);
903
904if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
905break;
906
907// Can't check if it was hibernation Wake=y is required
908if (bvr->modTime == 0 && tryresumedefault)
909break;
910
911if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
912break;
913
914if (!forceresume && ((sleeptime+3)<bvr->modTime))
915{
916#if DEBUG
917printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",
918bvr->modTime-sleeptime);
919#endif
920break;
921}
922
923HibernateBoot((char *)val);
924break;
925}
926}
927
928if (!isRecoveryHD && !isInstaller && !isMacOSXUpgrade && !isOSXUpgrade )
929{
930getBoolForKey(kUseKernelCache, &useKernelCache, &bootInfo->chameleonConfig);
931}
932
933if (useKernelCache)
934{
935do
936{
937// Determine the name of the Kernel Cache
938if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig))
939{
940if (val[0] == '\\')
941{
942len--;
943val++;
944}
945/* FIXME: check len vs sizeof(kernelCacheFile) */
946strlcpy(kernelCacheFile, val, len + 1);
947}
948else
949{
950kernelCacheFile[0] = 0; // Use default kernel cache file
951}
952
953if (gOverrideKernel && kernelCacheFile[0] == 0)
954{
955DBG("Using a non default kernel (%s) without specifying 'Kernel Cache' path, KernelCache will not be used\n", bootInfo->bootFile);
956useKernelCache = false;
957break;
958}
959
960if (gMKextName[0] != 0)
961{
962DBG("Using a specific MKext Cache (%s), KernelCache will not be used\n", gMKextName);
963useKernelCache = false;
964break;
965}
966
967if (gBootFileType != kBlockDeviceType)
968{
969useKernelCache = false;
970}
971
972} while(0);
973}
974else
975{
976DBG("Kernel Cache using disabled by user.\n");
977}
978
979do
980{
981if (useKernelCache)
982{
983ret = LoadKernelCache(kernelCacheFile, &binary);
984if (ret >= 0)
985{
986break;
987}
988}
989
990bool bootFileWithDevice = false;
991// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel
992if (strncmp(bootInfo->bootFile, "bt(", sizeof("bt(") ) == 0 ||
993strncmp(bootInfo->bootFile, "hd(", sizeof("hd(") ) == 0 ||
994strncmp(bootInfo->bootFile, "rd(", sizeof("rd(") ) == 0)
995{
996bootFileWithDevice = true;
997}
998
999// bootFile must start with a / if it not start with a device name
1000if (!bootFileWithDevice && (bootInfo->bootFile)[0] != '/')
1001{
1002if ( MacOSVerCurrent < MacOSVer2Int("10.10") ) // Mavericks and older
1003{
1004snprintf(bootFile, sizeof(bootFile), "/%s", bootInfo->bootFile); // append a leading /
1005}
1006else
1007{
1008// Yosemite and newer
1009snprintf(bootFile, sizeof(bootFile), kDefaultKernelPathForYos"%s", bootInfo->bootFile); // Yosemite or El Capitan
1010}
1011}
1012else
1013{
1014strlcpy(bootFile, bootInfo->bootFile, sizeof(bootFile));
1015}
1016
1017// Try to load kernel image from alternate locations on boot helper partitions.
1018ret = -1;
1019if ((gBootVolume->flags & kBVFlagBooter) && !bootFileWithDevice)
1020{
1021snprintf(bootFilePath, sizeof(bootFilePath), "com.apple.boot.P%s", bootFile);
1022ret = GetFileInfo(NULL, bootFilePath, &flags, &time);
1023if (ret == -1)
1024{
1025snprintf(bootFilePath, sizeof(bootFilePath), "com.apple.boot.R%s", bootFile);
1026ret = GetFileInfo(NULL, bootFilePath, &flags, &time);
1027if (ret == -1)
1028{
1029snprintf(bootFilePath, sizeof(bootFilePath), "com.apple.boot.S%s", bootFile);
1030ret = GetFileInfo(NULL, bootFilePath, &flags, &time);
1031}
1032}
1033}
1034if (ret == -1)
1035{
1036// No alternate location found, using the original kernel image path.
1037strlcpy(bootFilePath, bootFile, sizeof(bootFilePath));
1038}
1039
1040DBG("Loading kernel from: '%s' (%s)\n", gBootVolume->label, gBootVolume->type_name);
1041ret = LoadThinFatFile(bootFilePath, &binary);
1042if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
1043{
1044archCpuType = CPU_TYPE_I386;
1045ret = LoadThinFatFile(bootFilePath, &binary);
1046}
1047} while (0);
1048
1049clearActivityIndicator();
1050
1051#if DEBUG
1052printf("Pausing...");
1053sleep(8);
1054#endif
1055
1056if (ret <= 0)
1057{
1058printf("Can't find boot file: '%s'\n", bootFile);
1059sleep(1);
1060
1061if (gBootFileType == kNetworkDeviceType)
1062{
1063// Return control back to PXE. Don't unload PXE base code.
1064gUnloadPXEOnExit = false;
1065break;
1066}
1067pause();
1068
1069}
1070else
1071{
1072/* Won't return if successful. */
1073ret = ExecKernel(binary);
1074}
1075}
1076
1077// chainboot
1078if (status == 1)
1079{
1080// if we are already in graphics-mode,
1081if (getVideoMode() == GRAPHICS_MODE)
1082{
1083setVideoMode( VGA_TEXT_MODE ); // switch back to text mode.
1084}
1085}
1086
1087if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit)
1088{
1089nbpUnloadBaseCode();
1090}
1091
1092#if DEBUG_INTERRUPTS
1093if (interruptsAvailable)
1094{
1095DisableInterrupts();
1096}
1097#endif
1098
1099}
1100
1101// =========================================================================
1102//
1103void setupBooterArgs()
1104{
1105bool KPRebootOption= false; // I don't want this by default ( It makes me angry because I do not see the reason for the panic)+
1106//bool HiDPIOption= false; // (Disabled by default) 10.8+
1107//bool FlagBlackOption= false; // (Disabled by default) 10.10+
1108
1109// OS X Lion 10.7
1110if ( MacOSVerCurrent >= MacOSVer2Int("10.7") ) // Lion and Up!
1111{
1112// Pike R. Alpha: Adding a 16 KB log space.
1113bootArgs->performanceDataSize= 0;
1114bootArgs->performanceDataStart= 0;
1115
1116// Pike R. Alpha: AppleKeyStore.kext
1117bootArgs->keyStoreDataSize= 0;
1118bootArgs->keyStoreDataStart= 0;
1119
1120bootArgs->bootMemSize= 0;
1121bootArgs->bootMemStart= 0;
1122}
1123
1124// OS X Mountain Lion 10.8
1125if ( MacOSVerCurrent >= MacOSVer2Int("10.8") ) // Mountain Lion and Up!
1126{
1127// cparm
1128getBoolForKey(kRebootOnPanic, &KPRebootOption, &bootInfo->chameleonConfig);
1129if ( KPRebootOption )
1130{
1131bootArgs->flags |= kBootArgsFlagRebootOnPanic;
1132}
1133
1134// cparm
1135getBoolForKey(kEnableHiDPI, &HiDPIOption, &bootInfo->chameleonConfig);
1136
1137if ( HiDPIOption )
1138{
1139bootArgs->flags |= kBootArgsFlagHiDPI;
1140}
1141}
1142
1143// OS X Yosemite 10.10
1144if ( MacOSVerCurrent >= MacOSVer2Int("10.10") ) // Yosemite and Up!
1145{
1146// Pike R. Alpha
1147getBoolForKey(kBlackMode, &FlagBlackOption, &bootInfo->chameleonConfig);
1148if ( FlagBlackOption )
1149{
1150// bootArgs->flags |= kBootArgsFlagBlack;
1151bootArgs->flags |= kBootArgsFlagBlackBg; // Micky1979
1152}
1153}
1154
1155// OS X El Capitan 10.11
1156if ( MacOSVerCurrent >= MacOSVer2Int("10.11") ) // El Capitan, Sierra and High Sierra!
1157{
1158// ErmaC
1159verbose("\n");
1160intcsrValue;
1161
1162/*
1163 * A special BootArgs flag "kBootArgsFlagCSRBoot"
1164 * is set in the Recovery or Installation environment.
1165 * This flag is kind of overkill by turning off all the protections
1166 */
1167
1168if (isRecoveryHD || isInstaller || isOSXUpgrade || isMacOSXUpgrade)
1169{
1170// SIP can be controlled with or without FileNVRAM.kext (Pike R. Alpha)
1171bootArgs->flags|=(kBootArgsFlagCSRActiveConfig + kBootArgsFlagCSRConfigMode + kBootArgsFlagCSRBoot + kBootArgsFlagInstallUI);
1172}
1173else
1174{
1175bootArgs->flags|= kBootArgsFlagCSRActiveConfig;
1176}
1177
1178// Set limit to 8bit
1179if ( getIntForKey(kCsrActiveConfig, &csrValue, &bootInfo->chameleonConfig) && (csrValue >= 0 && csrValue <= 255) )
1180{
1181bootArgs->csrActiveConfig= csrValue;
1182csrInfo(csrValue, 1);
1183}
1184else
1185{
1186// zenith432
1187bootArgs->csrActiveConfig= 0x67;
1188csrInfo(0x67, 0);
1189
1190}
1191
1192
1193// ===============================================================================
1194
1195bootArgs->csrCapabilities= CSR_VALID_CAPABILITIES; // CSR_VALID_FLAGS
1196bootArgs->boot_SMC_plimit= 0;
1197bootArgs->bootProgressMeterStart= 0;
1198bootArgs->bootProgressMeterEnd= 0;
1199}
1200}
1201
1202// =========================================================================
1203// ErmaC
1204void csrInfo(int csrValue, bool custom)
1205{
1206#define CSR_BITS 0x080
1207
1208int mask = CSR_BITS;
1209verbose("System Integrity Protection status: %s ", (csrValue == 0) ? "enabled":"disabled");
1210verbose("(%s Configuration).\nCsrActiveConfig = 0x%02X (", custom ? "Custom":"Default", csrValue);
1211
1212// Display integer number into binary using bitwise operator
1213((csrValue & 0x020) == 0) ? verbose("0"): verbose("1");
1214while (mask != 0)
1215{
1216( ((csrValue & mask) == 0) ? verbose("0"): verbose("1") );
1217mask = mask >> 1; // Right Shift
1218}
1219verbose(")\n");
1220if (csrValue != 0)
1221{
1222verbose("\nConfiguration:\n");
1223verbose("\tKext Signing: %s\n", ((csrValue & 0x001) == 0) ? "enabled" : "disabled"); /* (1 << 0) Allow untrusted kexts */
1224verbose("\tFilesystem Protections: %s\n", ((csrValue & 0x002) == 0) ? "enabled" : "disabled"); /* (1 << 1) Allow unrestricted file system. */
1225verbose("\tTask for PID: %s\n", ((csrValue & 0x004) == 0) ? "enabled" : "disabled"); /* (1 << 2) */
1226verbose("\tDebugging Restrictions: %s\n", ((csrValue & 0x008) == 0) ? "enabled" : "disabled"); /* (1 << 3) */
1227verbose("\tApple Internal: %s\n", ((csrValue & 0x010) == 0) ? "enabled" : "disabled"); /* (1 << 4) */
1228verbose("\tDTrace Restrictions: %s\n", ((csrValue & 0x020) == 0) ? "enabled" : "disabled"); /* (1 << 5) Allow unrestricted dtrace */
1229verbose("\tNVRAM Protections: %s\n", ((csrValue & 0x040) == 0) ? "enabled" : "disabled"); /* (1 << 6) Allow unrestricted NVRAM */
1230verbose("\tDevice configuration: %s\n", ((csrValue & 0x080) == 0) ? "enabled" : "disabled"); /* (1 << 7) Allow device configuration */
1231verbose("\tBaseSystem Verification: %s\n", ((csrValue & 0x100) == 0) ? "enabled" : "disabled"); /* (1 << 8) Allow any Recovery OS */
1232//verbose("\tApple Internal HS: %s\n", ((csrValue & 0x200) == 0) ? "enabled" : "disabled"); /* (1 << 9) Allow Apple Internal HS */
1233}
1234verbose("\n");
1235}
1236
1237// =========================================================================
1238
1239/*!
1240Selects a new BIOS device, taking care to update the global state appropriately.
1241 */
1242/*
1243static void selectBiosDevice(void)
1244{
1245struct DiskBVMap *oldMap = diskResetBootVolumes(gBIOSDev);
1246CacheReset();
1247diskFreeMap(oldMap);
1248oldMap = NULL;
1249
1250int dev = selectAlternateBootDevice(gBIOSDev);
1251
1252BVRef bvchain = scanBootVolumes(dev, 0);
1253BVRef bootVol = selectBootVolume(bvchain);
1254gBootVolume = bootVol;
1255setRootVolume(bootVol);
1256gBIOSDev = dev;
1257}
1258*/
1259
1260// =========================================================================
1261bool checkOSVersion(const char *version)
1262{
1263if ( '\0' != version[4] )
1264{
1265return !memcmp(&gMacOSVersion[0], &version[0], 5);
1266}
1267else
1268{
1269return !memcmp(&gMacOSVersion[0], &version[0], 4);
1270}
1271}
1272
1273uint32_t getMacOSVerCurrent()
1274{
1275MacOSVerCurrent = MacOSVer2Int(gBootVolume->OSVersion);
1276return MacOSVerCurrent;
1277}
1278
1279// =========================================================================
1280unsigned long Adler32(unsigned char *buf, long len)
1281{
1282#define BASE 65521L /* largest prime smaller than 65536 */
1283#define NMAX 5000
1284// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
1285
1286#define DO1(buf, i){s1 += buf[i]; s2 += s1;}
1287#define DO2(buf, i)DO1(buf, i); DO1(buf, i + 1);
1288#define DO4(buf, i)DO2(buf, i); DO2(buf, i + 2);
1289#define DO8(buf, i)DO4(buf, i); DO4(buf, i + 4);
1290#define DO16(buf)DO8(buf, 0); DO8(buf, 8);
1291
1292int k;
1293
1294unsigned long s1 = 1; // adler & 0xffff;
1295unsigned long s2 = 0; // (adler >> 16) & 0xffff;
1296unsigned long result;
1297
1298while (len > 0)
1299{
1300k = len < NMAX ? len : NMAX;
1301len -= k;
1302while (k >= 16)
1303{
1304DO16(buf);
1305buf += 16;
1306k -= 16;
1307}
1308
1309if (k != 0)
1310{
1311do
1312{
1313s1 += *buf++;
1314s2 += s1;
1315} while (--k);
1316}
1317
1318s1 %= BASE;
1319s2 %= BASE;
1320}
1321
1322result = (s2 << 16) | s1;
1323
1324return OSSwapHostToBigInt32(result);
1325}
1326

Archive Download this file

Revision: HEAD