Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/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 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
30 */
31
32/*
33 * INTEL CORPORATION PROPRIETARY INFORMATION
34 *
35 * This software is supplied under the terms of a license agreement or
36 * nondisclosure agreement with Intel Corporation and may not be copied
37 * nor disclosed except in accordance with the terms of that agreement.
38 *
39 * Copyright 1988, 1989 by Intel Corporation
40 */
41
42/*
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
45 */
46
47/*
48 * Completely reworked by Sam Streeper (sam_s@NeXT.com)
49 * Reworked again by Curtis Galloway (galloway@NeXT.com)
50 */
51
52
53#include "boot.h"
54#include "bootstruct.h"
55#include "fake_efi.h"
56#include "sl.h"
57#include "libsa.h"
58#include "platform.h"
59#include "graphics.h"
60#include "appleboot.h"
61#include "modules.h"
62#include "xml.h"
63#include "options.h"
64#include "drivers.h"
65
66#ifndef DEBUG_BOOT
67#define DEBUG_BOOT 0
68#endif
69
70#if DEBUG_BOOT
71#define DBG(x...)printf(x)
72#else
73#define DBG(x...)
74#endif
75
76
77typedef struct platform_info {
78char platformName[PLATFORM_NAME_LEN];
79char rootPath[ROOT_PATH_LEN];
80} PlatformInfo;
81
82static BVRef bvChain;
83static bool forcecache = false;
84
85static char gBootKernelCacheFile[Cache_len_name];
86static char gMKextName[Cache_len_name];
87static void zeroBSS(void);
88static int ExecKernel(void *binary);
89static void getRootDevice();
90static bool find_file_with_ext(const char* dir, const char *ext, const char * name_compare, size_t ext_size);
91static bool found_extra_kext(void);
92static void determineCpuArch(void);
93void getKernelCachePath(void);
94#ifdef NBP_SUPPORT
95static bool gUnloadPXEOnExit = false;
96#endif
97static void getRootDevice(void);
98
99/*
100 * How long to wait (in seconds) to load the
101 * kernel after displaying the "boot:" prompt.
102 */
103#define kBootErrorTimeout 5
104
105/*
106 * Default path to kernel cache file
107 */
108#define kDefaultCachePath "/System/Library/Caches/com.apple.kext.caches/Startup/kernelcache"
109
110//==========================================================================
111// Zero the BSS.
112
113static void zeroBSS(void)
114{
115#if (defined(__clang__)) && (defined(__XCODE45_HACK__))/* WARNING : must be first, __GNUC__ seems to be also defined */
116
117extern int bss_start __asm("section$start$__DATA$__bss");
118 extern int bss_end __asm("section$end$__DATA$__bss");
119 extern int common_start __asm("section$start$__DATA$__common");
120 extern int common_end __asm("section$end$__DATA$__common");
121
122bzero(&bss_start, (&bss_end - &bss_start));
123bzero(&common_start, (&common_end - &common_start));
124
125#elif (defined(__GNUC__)) || (defined(__llvm__))
126
127extern char _DATA__bss__begin, _DATA__bss__end;
128extern char _DATA__common__begin, _DATA__common__end;
129
130bzero(&_DATA__bss__begin, (&_DATA__bss__end - &_DATA__bss__begin));
131bzero(&_DATA__common__begin, (&_DATA__common__end - &_DATA__common__begin));
132
133#endif
134}
135
136#ifdef ZALLOC
137//==========================================================================
138// Malloc error function
139
140#ifdef SAFE_MALLOC
141static inline void malloc_error(char *addr, size_t size, const char *file, int line)
142{
143 stop("\nMemory allocation error! Addr=0x%x, Size=0x%x, File=%s, Line=%d\n", (unsigned)addr, (unsigned)size, file, line);
144}
145#else
146static inline void malloc_error(char *addr, size_t size)
147{
148 printf("\nMemory allocation error (0x%x, 0x%x)\n", (unsigned)addr, (unsigned)size);
149 asm volatile ("hlt");
150}
151#endif
152
153#else
154
155static inline void print_callback(char *s)
156{
157 printf("%s", s);
158}
159
160#endif
161
162BVRef getBvChain(void)
163{
164return bvChain;
165}
166
167
168//==========================================================================
169//Initializes the runtime. Right now this means zeroing the BSS and initializing malloc.
170//
171void initialize_runtime(void)
172{
173zeroBSS();
174#ifdef ZALLOC
175malloc_init(0, 0, 0, malloc_error);
176#else
177__printf_init(print_callback);
178
179#endif
180}
181
182//==========================================================================
183// execKernel - Load the kernel image (mach-o) and jump to its entry point.
184static entry_t kernelEntry;
185
186static int ExecKernel(void *binary)
187{
188 int ret;
189
190 bootArgs->kaddr = bootArgs->ksize = 0;
191
192{
193bool KPRebootOption = false;
194bool HiDPIOption = false;
195
196getBoolForKey(kRebootOnPanic, &KPRebootOption, DEFAULT_BOOT_CONFIG);
197if (KPRebootOption == true) bootArgs->flags |= kBootArgsFlagRebootOnPanic;
198
199getBoolForKey(kEnableHiDPI, &HiDPIOption, DEFAULT_BOOT_CONFIG);
200if (HiDPIOption == true) bootArgs->flags |= kBootArgsFlagHiDPI;
201}
202
203if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
204{
205bootArgs->Version = kBootArgsVersion1;
206bootArgs->Revision = ((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3];
207}
208else
209{
210#if kBootArgsVersion > 1
211
212bootArgs->Version = kBootArgsVersion;
213bootArgs->Revision = kBootArgsRevision;
214#else
215if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] >= '7')
216{
217bootArgs->Version = 2;
218bootArgs->Revision = 0;
219}
220#endif
221}
222
223execute_hook("ExecKernel", (void*)binary, NULL, NULL, NULL, NULL, NULL);
224
225 ret = DecodeKernel(binary,
226 &kernelEntry,
227 (char **) &bootArgs->kaddr,
228 (int *)&bootArgs->ksize );
229
230 if ( ret != 0 )
231 return ret;
232
233 // Reserve space for boot args for 10.7 only (for 10.6 and earlier, we will convert (to legacy) the structure and reserve kernel memory for it later.)
234if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] >= '7')
235 reserveKernBootStruct();
236
237 // Load boot drivers from the specifed root path.
238
239 if (!get_env(envgHaveKernelCache))
240{
241LoadDrivers("/");
242 }
243
244 showError();
245
246execute_hook("md0Ramdisk", NULL, NULL, NULL, NULL, NULL, NULL);
247
248 setupFakeEfi();
249
250 verbose("Starting Darwin %s\n",( get_env(envarchCpuType) == CPU_TYPE_I386 ) ? "x86" : "x86_64");
251#ifdef NBP_SUPPORT
252 // Cleanup the PXE base code.
253
254 if ( (get_env(envgBootFileType) == kNetworkDeviceType) && gUnloadPXEOnExit )
255{
256if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
257 {
258 printf("nbpUnloadBaseCode error %d\n", (int) ret);
259 sleep(2);
260 }
261 }
262#endif
263{
264bool wait = false;
265const char *strval = 0;
266int dummysize /*= 0*/;
267
268getBoolForKey(kWaitForKeypressKey, &wait, DEFAULT_BOOT_CONFIG);
269
270if (getValueForBootKey(bootArgs->CommandLine, "-wait", &strval, &dummysize))
271{
272wait = true;
273
274if (strval && ((strncmp(strval, "no", sizeof("no")) == 0) || (strncmp(strval, "No", sizeof("No")) == 0)))
275{
276wait = false;
277}
278}
279
280if (wait == true)
281{
282pause();
283}
284}
285
286 //debug_platform_env();
287
288if ((execute_hook("GUI_ExecKernel", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS)) // (bootArgs->Video.v_display == VGA_TEXT_MODE)
289{
290 __setVideoMode( GRAPHICS_MODE );
291
292
293if(!get_env(envgVerboseMode))
294{
295__drawColorRectangle(0, 0, DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 0x01);
296
297uint8_t *appleBootPict;
298uint16_t bootImageWidth = kAppleBootWidth;
299uint16_t bootImageHeight = kAppleBootHeight;
300uint8_t *bootImageData = NULL;
301uint16_t x, y;
302
303unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};// here we store the used screen resolution
304// Prepare the data for the default Apple boot image.
305appleBootPict = (uint8_t *) __decodeRLE(gAppleBootPictRLE, kAppleBootRLEBlocks, bootImageWidth * bootImageHeight);
306if (appleBootPict)
307{
308if(__convertImage(bootImageWidth, bootImageHeight, appleBootPict, &bootImageData) == 0)
309 {
310 if (bootImageData)
311 {
312 x = (screen_params[0] - MIN(kAppleBootWidth, screen_params[0])) / 2;
313 y = (screen_params[1] - MIN(kAppleBootHeight, screen_params[1])) / 2;
314 __drawDataRectangle(x, y, kAppleBootWidth, kAppleBootHeight, bootImageData);
315 free(bootImageData);
316 }
317 }
318
319free(appleBootPict);
320}
321
322}
323}
324
325 finalizeEFIConfigTable();
326
327setupBooterLog();
328
329 finalizeBootStruct();
330
331execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgs, NULL, NULL, NULL, NULL);// Notify modules that the kernel is about to be started
332
333#if UNUSED
334turnOffFloppy();
335#endif
336#if BETA
337#include "smp-imps.h"
338#include "apic.h"
339IMPS_LAPIC_WRITE(LAPIC_LVT1, LAPIC_ICR_DM_NMI);
340#endif
341
342if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6') {
343
344 reserveKernLegacyBootStruct();
345
346// Jump to kernel's entry point. There's no going back now. XXX LEGACY OS XXX
347startprog( kernelEntry, bootArgsLegacy );
348}
349
350outb(0x21, 0xff); /* Maskout all interrupts Pic1 */
351outb(0xa1, 0xff); /* Maskout all interrupts Pic2 */
352
353// Jump to kernel's entry point. There's no going back now. XXX LION XXX
354 startprog( kernelEntry, bootArgs );
355
356 // Should not be reached
357
358 return 0;
359}
360
361//==========================================================================
362// This is the entrypoint from real-mode which functions exactly as it did
363// before. Multiboot does its own runtime initialization, does some of its
364// own things, and then calls common_boot.
365void boot(int biosdev)
366{
367initialize_runtime();
368// Enable A20 gate before accessing memory above 1Mb.
369enableA20();
370common_boot(biosdev);
371}
372
373//==========================================================================
374// The 'main' function for the booter. Called by boot0 when booting
375// from a block device, or by the network booter.
376//
377// arguments:
378// biosdev - Value passed from boot1/NBP to specify the device
379// that the booter was loaded from.
380//
381// If biosdev is kBIOSDevNetwork, then this function will return if
382// booting was unsuccessful. This allows the PXE firmware to try the
383// next boot device on its list.
384void common_boot(int biosdev)
385{
386 int status;
387 bool firstRun = true;
388 int devcnt = 0;
389 int bvCount = 0;
390int BIOSDev = 0;
391 long gBootMode = kBootModeNormal; /* defaults to 0 == kBootModeNormal */
392
393 unsigned int allowBVFlags = kBVFlagSystemVolume|kBVFlagForeignBoot;
394 unsigned int denyBVFlags = kBVFlagEFISystem;
395
396#ifdef NBP_SUPPORT
397 // Set reminder to unload the PXE base code. Neglect to unload
398 // the base code will result in a hang or kernel panic.
399 gUnloadPXEOnExit = true;
400#endif
401
402 // Setup VGA text mode.
403 // It's unsafe to call setVideoMode() before the
404 // bootargs is initialized, we call video_mode() instead.
405#if DEBUG
406 printf("before video_mode\n");
407#endif
408 video_mode( 2 ); // 80x25 mono text mode.
409#if DEBUG
410 printf("after video_mode\n");
411#endif
412printf("Starting Chameleon ...\n");
413
414Install_Default_Handler();
415
416initBooterLog();
417
418// Initialize boot info structure.
419 initKernBootStruct();
420
421 // Scan and record the system's hardware information.
422 scan_platform();
423
424
425// Pseudo-random generator initialization.
426 // arc4_init();
427
428 set_env(envgBIOSDev, (BIOSDev = biosdev & kBIOSDevMask));
429 set_env(envShouldboot, false);
430 set_env(envkCacheFile, (uint32_t)gBootKernelCacheFile);
431 set_env(envMKextName, (uint32_t)gMKextName);
432set_env(envHFSLoadVerbose, 1);
433set_env(envarchCpuType, CPU_TYPE_I386);
434set_env(envgHaveKernelCache, false);
435
436 InitBootPrompt();
437
438 // First get info for boot volume.
439 scanBootVolumes(BIOSDev, 0);
440
441 bvChain = getBVChainForBIOSDev(BIOSDev);
442
443 setBootGlobals(bvChain);
444
445 // Load Booter boot.plist config file
446 loadBooterConfig();
447
448 {
449 bool isServer = false;
450 getBoolForKey(kIsServer, &isServer, DEFAULT_BOOT_CONFIG); // we must set this as soon as possible
451 set_env(envIsServer , isServer);
452 }
453
454
455{
456bool quiet = false;
457if (getBoolForKey(kQuietBootKey, &quiet, DEFAULT_BOOT_CONFIG) && quiet)
458{
459gBootMode |= kBootModeQuiet;
460}
461}
462
463 set_env(envgBootMode, gBootMode);
464
465{
466bool instantMenu = false;
467// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
468if (getBoolForKey(kInsantMenuKey, &instantMenu, DEFAULT_BOOT_CONFIG) && instantMenu)
469{
470firstRun = false;
471}
472}
473
474 {
475 bool ScanSingleDrive = false;
476 // Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
477 if (getBoolForKey(kScanSingleDriveKey, &ScanSingleDrive, DEFAULT_BOOT_CONFIG) && ScanSingleDrive)
478 {
479 ScanSingleDrive = true;
480 }
481 safe_set_env(envgScanSingleDrive, ScanSingleDrive);
482 // Create a list of partitions on device(s).
483 if (ScanSingleDrive)
484 {
485 scanBootVolumes(BIOSDev, &bvCount);
486 }
487 else
488 {
489 scanDisks();
490 }
491
492}
493
494 // Create a separated bvr chain using the specified filters.
495 bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &devcnt);
496 safe_set_env(envgDeviceCount,devcnt);
497
498safe_set_env(envgBootVolume, (uint32_t)selectBootVolume(bvChain));
499
500
501LoadBundles("/Extra/");
502
503 // Loading preboot ramdisk if exists.
504execute_hook("loadPrebootRAMDisk", NULL, NULL, NULL, NULL, NULL, NULL);
505
506 {
507 // Disable rescan option by default
508 bool CDROMRescan = false;
509
510 // Enable it with Rescan=y in system config
511 if (getBoolForKey(kRescanKey, &CDROMRescan, DEFAULT_BOOT_CONFIG) && CDROMRescan)
512 {
513 CDROMRescan = true;
514
515 }
516 safe_set_env(envgEnableCDROMRescan, CDROMRescan);
517
518 }
519
520
521{
522bool rescanPrompt = false;
523// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
524if (getBoolForKey(kRescanPromptKey, &rescanPrompt , DEFAULT_BOOT_CONFIG) && rescanPrompt && biosDevIsCDROM((int)get_env(envgBIOSDev)))
525{
526 safe_set_env(envgEnableCDROMRescan, promptForRescanOption());
527}
528}
529
530#if DEBUG
531 printf(" Default: %p, ->biosdev: %d, ->part_no: %d ->flags: %d\n", ((BVRef)(uint32_t)get_env(envgBootVolume)), ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev, ((BVRef)(uint32_t)get_env(envgBootVolume))->part_no, ((BVRef)(uint32_t)get_env(envgBootVolume))->flags);
532 printf(" bt(0,0): %p, ->biosdev: %d, ->part_no: %d ->flags: %d\n", ((BVRef)(uint32_t)get_env(envgBIOSBootVolume)), ((BVRef)(uint32_t)get_env(envgBIOSBootVolume))->biosdev, ((BVRef)(uint32_t)get_env(envgBIOSBootVolume))->part_no, ((BVRef)(uint32_t)get_env(envgBIOSBootVolume))->flags);
533 getc();
534#endif
535
536 setBootGlobals(bvChain);
537
538// Display the GUI
539execute_hook("GUI_Display", NULL, NULL, NULL, NULL, NULL, NULL);
540
541 // Parse args, load and start kernel.
542 while (1) {
543 const char *val;
544 int len;
545char *bootFile;
546bool trycache = true; // Always try to catch the kernelcache first
547
548 long flags;
549#ifdef BOOT_HELPER_SUPPORT
550long time;
551#endif
552 int ret = -1;
553 void *binary = (void *)kLoadAddr;
554
555 // additional variable for testing alternate kernel image locations on boot helper partitions.
556 char bootFileSpec[512];
557
558 // Initialize globals.
559 safe_set_env(envSysConfigValid, false);
560
561 status = getBootOptions(firstRun);
562 firstRun = false;
563 if (status == -1) continue;
564
565 status = processBootOptions();
566#ifndef NO_MULTIBOOT_SUPPORT
567 // Status==1 means to chainboot
568 if ( status == 1 ) break;
569#endif
570 // Status==-1 means that the config file couldn't be loaded or that gBootVolume is NULL
571 if ( status == -1 )
572 {
573// gBootVolume == NULL usually means the user hit escape.
574if(((BVRef)(uint32_t)get_env(envgBootVolume)) == NULL)
575{
576freeFilteredBVChain(bvChain);
577
578if (get_env(envgEnableCDROMRescan))
579rescanBIOSDevice((int)get_env(envgBIOSDev));
580
581bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &devcnt);
582 safe_set_env(envgDeviceCount,devcnt);
583
584setBootGlobals(bvChain);
585}
586continue;
587 }
588
589 // Other status (e.g. 0) means that we should proceed with boot.
590execute_hook("GUI_PreBoot", NULL, NULL, NULL, NULL, NULL, NULL);
591
592if (getValueForKey(karch, &val, &len, DEFAULT_BOOT_CONFIG) && val)
593{
594if (strncmp(val, "x86_64", 4) == 0)
595{
596safe_set_env(envarchCpuType, CPU_TYPE_X86_64);
597
598}
599else if (strncmp(val, "i386", 4) == 0)
600{
601safe_set_env(envarchCpuType, CPU_TYPE_I386);
602
603}
604else
605{
606DBG("Incorrect parameter for option 'arch =' , please use x86_64 or i386\n");
607determineCpuArch();
608}
609
610}
611else determineCpuArch();
612
613
614getRootDevice();
615
616// Notify to all modules that we are attempting to boot
617execute_hook("PreBoot", NULL, NULL, NULL, NULL, NULL, NULL);
618
619if (execute_hook("getProductNamePatched", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
620readSMBIOS(thePlatformName); // read smbios Platform Name
621
622
623if (((get_env(envgBootMode) & kBootModeSafe) == 0) &&
624!get_env(envgOverrideKernel) &&
625(get_env(envgBootFileType) == kBlockDeviceType) &&
626(gMKextName[0] == '\0') &&
627!getValueForBootKey(bootArgs->CommandLine, kIgnorePrelinkKern, &val, &len))
628{
629getBoolForKey(kUseKernelCache, &trycache, DEFAULT_BOOT_CONFIG);
630if (trycache == true)
631{
632// try to find the cache and fill the gBootKernelCacheFile string
633getKernelCachePath();
634
635// Check for cache file
636trycache = (gBootKernelCacheFile[0] != '\0') ? true : false; // if gBootKernelCacheFile is filled et bla bla bla.... :-)
637}
638
639}
640else
641{
642trycache = false;
643}
644
645verbose("Loading Darwin %s\n", ((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion);
646{
647long cachetime, kerneltime = 0, exttime;
648if (trycache && !forcecache) do {
649
650 if (strncmp(bootInfo->bootFile, kDefaultKernel,sizeof(kDefaultKernel)) != 0) {
651 // if we haven't found the kernel yet, don't use the cache
652 ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
653 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
654 {
655 trycache = false;
656 safe_set_env(envAdler32, 0);
657 DBG("No kernel found, kernelcache disabled !!!\n");
658 break;
659 }
660 }
661 else if (((BVRef)(uint32_t)get_env(envgBootVolume))->kernelfound != true) // Should never happen.
662 {
663 bootFile = kDefaultKernel;
664 goto out;
665 }
666
667ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
668if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
669|| (cachetime < kerneltime))
670{
671trycache = false;
672safe_set_env(envAdler32, 0);
673DBG("Warning: No kernelcache found or kernelcache too old (timestamp of the kernel > timestamp of the cache), kernelcache disabled !!!\n");
674
675break;
676}
677ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
678if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
679&& (cachetime < exttime))
680{
681trycache = false;
682safe_set_env(envAdler32, 0);
683DBG("Warning: kernelcache too old, timestamp of S/L/E > timestamp of the cache, kernelcache disabled !!! \n");
684
685break;
686}
687if (kerneltime > exttime)
688{
689exttime = kerneltime;
690}
691if (cachetime != (exttime + 1))
692{
693trycache = false;
694safe_set_env(envAdler32, 0);
695DBG("Warning: invalid timestamp, kernelcache disabled !!!\n");
696
697break;
698}
699} while (0);
700}
701
702 do {
703 if (trycache == true || forcecache == true)
704{
705 bootFile = gBootKernelCacheFile;
706 verbose("Loading kernel cache %s\n", bootFile);
707if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
708{
709ret = LoadThinFatFile(bootFile, &binary);
710if ((ret <= 0) && (get_env(envarchCpuType) == CPU_TYPE_X86_64))
711{
712safe_set_env(envarchCpuType, CPU_TYPE_I386);
713ret = LoadThinFatFile(bootFile, &binary);
714}
715}
716else
717{
718ret = LoadFile(bootFile);
719binary = (void *)kLoadAddr;
720}
721
722 if (ret >= 0)
723{
724 break;
725 }
726
727 }
728safe_set_env(envAdler32, 0);
729 bootFile = bootInfo->bootFile;
730#ifdef BOOT_HELPER_SUPPORT
731
732 // Try to load kernel image from alternate locations on boot helper partitions.
733 snprintf(bootFileSpec, sizeof(bootFileSpec),"com.apple.boot.P/%s", bootFile);
734 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
735 if (ret == -1)
736 {
737snprintf(bootFileSpec, sizeof(bootFileSpec), "com.apple.boot.R/%s", bootFile);
738ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
739if (ret == -1)
740{
741snprintf(bootFileSpec, sizeof(bootFileSpec), "com.apple.boot.S/%s", bootFile);
742ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
743if (ret == -1)
744{
745// Not found any alternate locations, using the original kernel image path.
746strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
747}
748}
749 }
750#else
751strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
752#endif
753
754 verbose("Loading kernel %s\n", bootFileSpec);
755 ret = LoadThinFatFile(bootFileSpec, &binary);
756 if ((ret <= 0) && (get_env(envarchCpuType) == CPU_TYPE_X86_64))
757 {
758safe_set_env(envarchCpuType, CPU_TYPE_I386);
759ret = LoadThinFatFile(bootFileSpec, &binary);
760 }
761
762 } while (0);
763
764#if DEBUG
765 printf("Pausing...");
766 sleep(8);
767#endif
768
769 if (ret <= 0)
770{
771 out:
772printf("Can't find %s\n", bootFile);
773
774sleep(1);
775#ifdef NBP_SUPPORT
776 if (get_env(envgBootFileType) == kNetworkDeviceType)
777{
778 // Return control back to PXE. Don't unload PXE base code.
779 gUnloadPXEOnExit = false;
780 break;
781 }
782#endif
783 }
784else
785{
786 /* Won't return if successful. */
787 if ( ExecKernel(binary))
788 {
789 firstRun = true;
790 continue;
791 }
792 }
793 }
794
795#ifndef NO_MULTIBOOT_SUPPORT
796 // chainboot
797 if (status==1)
798{
799if (getVideoMode() == GRAPHICS_MODE)
800{// if we are already in graphics-mode,
801
802__setVideoMode(VGA_TEXT_MODE);// switch back to text mode
803
804}
805 }
806#else
807printf("No proper Darwin Partition found, reseting ... \n");
808pause();
809common_boot(biosdev);
810#endif
811
812#ifdef NBP_SUPPORT
813 if ((get_env(envgBootFileType) == kNetworkDeviceType) && gUnloadPXEOnExit)
814{
815nbpUnloadBaseCode();
816 }
817#endif
818}
819
820static void determineCpuArch(void)
821{
822safe_set_env(envarchCpuType, cpu_mode_is64bit() ? CPU_TYPE_X86_64 : CPU_TYPE_I386);
823}
824
825void getKernelCachePath(void)
826{
827{
828// If there is an extra kext/mkext, we return immediatly and we skip the kernelCache
829// since kexts/mkexts are not loaded properly when the kernelCache is used.
830// Another method would be to re-build the kernelCache one the fly
831if (found_extra_kext() == true) return;
832}
833
834{
835const char *val;
836int len;
837unsigned long Adler32 = 0;
838
839if (getValueForKey(kKernelCacheKey, &val, &len, DEFAULT_BOOT_CONFIG))
840{
841 char * buffer = newString(val);
842
843if (val[0] == '\\')
844{
845// Flip the back slash's to slash's .
846 len = 0;
847 while (buffer[len] != '\0') {
848 if (buffer[len] == '\\')
849 {
850 buffer[len] = '/';
851 }
852 len++;
853 }
854}
855strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile));
856 forcecache = true;
857}
858else
859{
860if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
861{
862snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s", kDefaultCachePath);
863}
864else if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
865{
866
867PlatformInfo *platformInfo = malloc(sizeof(PlatformInfo));
868if (platformInfo)
869{
870
871bzero(platformInfo, sizeof(PlatformInfo));
872
873if (GetgPlatformName())
874strlcpy(platformInfo->platformName,GetgPlatformName(), sizeof(platformInfo->platformName)+1);
875
876if (GetgRootDevice())
877{
878char *rootPath_p = platformInfo->rootPath;
879len = strlen(GetgRootDevice()) + 1;
880if ((unsigned)len > sizeof(platformInfo->rootPath))
881{
882len = sizeof(platformInfo->rootPath);
883}
884memcpy(rootPath_p, GetgRootDevice(),len);
885
886rootPath_p += len;
887
888len = strlen(bootInfo->bootFile);
889
890if ((unsigned)(rootPath_p - platformInfo->rootPath + len) >=
891sizeof(platformInfo->rootPath))
892{
893
894len = sizeof(platformInfo->rootPath) -
895(rootPath_p - platformInfo->rootPath);
896}
897memcpy(rootPath_p, bootInfo->bootFile, len);
898
899}
900
901if (!platformInfo->platformName[0] || !platformInfo->rootPath[0])
902{
903platformInfo->platformName[0] = platformInfo->rootPath[0] = 0;
904}
905#ifdef rootpath
906 SetgRootPath(platformInfo->rootPath);
907#endif
908
909Adler32 = OSSwapHostToBigInt32(local_adler32((unsigned char *)platformInfo, sizeof(PlatformInfo)));
910safe_set_env(envAdler32, Adler32);
911
912free(platformInfo);
913}
914
915DBG("Adler32: %08lX\n",Adler32);
916
917if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] < '6')
918{
919long flags, cachetime;
920int ret = -1;
921
922if (Adler32) {
923snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s.%08lX", "/System/Library/Caches/com.apple.kernelcaches/kernelcache",Adler32);
924ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
925}
926
927if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
928{
929safe_set_env(envAdler32, 0);
930snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s", "/System/Library/Caches/com.apple.kernelcaches/kernelcache");
931}
932
933} else if (Adler32)
934snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s_%s.%08lX", kDefaultCachePath, (get_env(envarchCpuType) == CPU_TYPE_I386) ? "i386" : "x86_64", Adler32); //Snow Leopard
935
936}
937}
938}
939}
940
941static void getRootDevice(void)
942{
943// Maximum config table value size
944#define VALUE_SIZE 2048
945bool uuidSet = false;
946const char *val = 0;
947 int cnt = 0;
948
949if (getValueForKey(kBootUUIDKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
950{
951uuidSet = true;
952}
953else
954{
955if (getValueForBootKey(bootArgs->CommandLine, kRootDeviceKey, &val, &cnt))
956{
957if (*val == '*' && *(val + 1) != '/' && *(val + 1) != 'u')
958{
959val += 1; //skip the *
960uuidSet = true;
961
962}
963else if (*val == '*' && *(val + 1) == 'u')
964{
965
966if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
967uuidSet = true;
968
969}
970}
971else
972{
973#ifdef BOOT_HELPER_SUPPORT
974//
975// Try an alternate method for getting the root UUID on boot helper partitions.
976//
977if (((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagBooter)
978{
979if((loadHelperConfig() == 0)
980 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
981{
982getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
983uuidSet = true;
984goto out;
985}
986}
987#endif
988if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
989{
990int ArgCntRemaining = (int)get_env(envArgCntRemaining);
991uuidSet = false;
992char * valueBuffer;
993valueBuffer = calloc(VALUE_SIZE,sizeof(char));
994 if (!valueBuffer) {
995 return;
996 }
997char * argP = bootArgs->CommandLine;
998valueBuffer[0] = '*';
999if (cnt > VALUE_SIZE)
1000{
1001cnt = VALUE_SIZE;
1002}
1003strlcpy(valueBuffer + 1, val, cnt+1);
1004if (!copyArgument( kRootDeviceKey, valueBuffer, cnt, &argP, &ArgCntRemaining))
1005{
1006free(valueBuffer);
1007printf("Error: boot arguments too long, unable to set root device !!");
1008getc();
1009return;
1010}
1011 safe_set_env(envArgCntRemaining,ArgCntRemaining);
1012free(valueBuffer);
1013goto out;
1014}
1015
1016if (((BVRef)(uint32_t)get_env(envgBootVolume))->fs_getuuid && (((BVRef)(uint32_t)get_env(envgBootVolume))->fs_getuuid (((BVRef)(uint32_t)get_env(envgBootVolume)), bootInfo->uuidStr, sizeof(bootInfo->uuidStr)) == 0))
1017{
1018verbose("Setting boot-uuid to: %s\n", bootInfo->uuidStr);
1019//uuidSet = true;
1020SetgRootDevice(bootInfo->uuidStr);
1021return;
1022}
1023
1024}
1025}
1026
1027out:
1028verbose("Setting %s to: %s\n", uuidSet ? kBootUUIDKey : "root device", (char* )val);
1029 SetgRootDevice(val);
1030}
1031
1032static bool find_file_with_ext(const char* dir, const char *ext, const char * name_to_compare, size_t ext_size)
1033{
1034 long ret, length, flags, time;
1035 long long index;
1036 const char * name;
1037
1038DBG("FileLoadBundles in %s\n",dirSpec);
1039
1040 index = 0;
1041 while (1) {
1042 ret = GetDirEntry(dir, &index, &name, &flags, &time);
1043 if (ret == -1) break;
1044
1045 // Make sure this is not a directory.
1046 if ((flags & kFileTypeMask) != kFileTypeFlat) continue;
1047
1048 // Make sure this is a kext or mkext.
1049 length = strlen(name);
1050 if (strncmp(name + length - ext_size, ext, ext_size)) continue;
1051
1052 if (name_to_compare)
1053 {
1054 if (strcmp(name, name_to_compare) == 0)
1055 {
1056 DBG("found : %s\n", name);
1057 return true;
1058 }
1059 }
1060 else
1061 {
1062 DBG("found : %s\n", name);
1063 return true;
1064 }
1065
1066 }
1067return false;
1068}
1069
1070// If a kext is found in /Extra/Extentions return true
1071// If a mkext is found in /Extra return true
1072// Otherwise return false
1073// Tips (if you still want to use extra kext(s)/mkext(s) ):
1074// With Lion and earlier, the default boot cache is a kernelcache, no mkext is created anymore by kextd automaticaly (kextd still update the existing mkexts),
1075// so it's recommended to create a system mkext by yourself to decrease boot time (see the kextcache commandline)
1076static bool found_extra_kext(void)
1077{
1078#define EXTENSIONS "Extensions"
1079#define MKEXT_EXT ".mkext"
1080#define MKEXT_EXT_SIZE strlen(MKEXT_EXT)
1081#define KEXT_EXT ".kext"
1082#define KEXT_EXT_SIZE strlen(KEXT_EXT)
1083
1084long flags;
1085long exttime;
1086int ret = -1;
1087
1088ret = GetFileInfo("rd(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1089if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
1090{
1091if (((flags & kFileTypeMask) == kFileTypeFlat))
1092{
1093if (find_file_with_ext("rd(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1094{
1095return true;
1096}
1097}
1098else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1099{
1100if (find_file_with_ext("rd(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1101{
1102return true;
1103}
1104}
1105}
1106ret = GetFileInfo("/Extra/", EXTENSIONS, &flags, &exttime);
1107if (ret == 0)
1108{
1109if (((flags & kFileTypeMask) == kFileTypeFlat))
1110{
1111if (find_file_with_ext("/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1112{
1113return true;
1114}
1115}
1116else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1117{
1118if (find_file_with_ext("/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1119{
1120return true;
1121}
1122}
1123}
1124ret = GetFileInfo("bt(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1125if (ret == 0)
1126{
1127if (((flags & kFileTypeMask) == kFileTypeFlat))
1128{
1129if (find_file_with_ext("bt(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1130{
1131return true;
1132}
1133}
1134else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1135{
1136if (find_file_with_ext("bt(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1137{
1138return true;
1139}
1140}
1141}
1142DBG("NO Extra Mkext/Kext found\n");
1143
1144// nothing found
1145return false;
1146}
1147
1148#if 0
1149static char *FIXED_BOOTFILE_PATH(char * str)
1150{
1151char bootfile[128];
1152
1153bool bootFileWithDevice = false;
1154// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel
1155if (strncmp(str,"bt(",3) == 0 ||
1156strncmp(str,"hd(",3) == 0 ||
1157strncmp(str,"rd(",3) == 0)
1158{
1159bootFileWithDevice = true;
1160}
1161
1162// bootFile must start with a / if it not start with a device name
1163if (!bootFileWithDevice && (str)[0] != '/')
1164snprintf(bootFile, sizeof(bootfile), "/%s", str); // append a leading /
1165else
1166strlcpy(bootFile, bootInfo->bootFile, sizeof(bootFile));
1167
1168return bootfile;
1169}
1170#endif
1171

Archive Download this file

Revision: HEAD