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.
184
185static int ExecKernel(void *binary)
186{
187 entry_t kernelEntry;
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 (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
334reserveKernLegacyBootStruct();
335
336#if UNUSED
337turnOffFloppy();
338#endif
339#if BETA
340#include "smp-imps.h"
341#include "apic.h"
342IMPS_LAPIC_WRITE(LAPIC_LVT1, LAPIC_ICR_DM_NMI);
343#endif
344
345if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6') {
346
347// Jump to kernel's entry point. There's no going back now. XXX LEGACY OS XXX
348startprog( kernelEntry, bootArgsLegacy );
349}
350
351outb(0x21, 0xff); /* Maskout all interrupts Pic1 */
352outb(0xa1, 0xff); /* Maskout all interrupts Pic2 */
353
354// Jump to kernel's entry point. There's no going back now. XXX LION XXX
355 startprog( kernelEntry, bootArgs );
356
357 // Should not be reached
358
359 return 0;
360}
361
362//==========================================================================
363// This is the entrypoint from real-mode which functions exactly as it did
364// before. Multiboot does its own runtime initialization, does some of its
365// own things, and then calls common_boot.
366void boot(int biosdev)
367{
368initialize_runtime();
369// Enable A20 gate before accessing memory above 1Mb.
370enableA20();
371common_boot(biosdev);
372}
373
374//==========================================================================
375// The 'main' function for the booter. Called by boot0 when booting
376// from a block device, or by the network booter.
377//
378// arguments:
379// biosdev - Value passed from boot1/NBP to specify the device
380// that the booter was loaded from.
381//
382// If biosdev is kBIOSDevNetwork, then this function will return if
383// booting was unsuccessful. This allows the PXE firmware to try the
384// next boot device on its list.
385void common_boot(int biosdev)
386{
387 int status;
388 bool firstRun = true;
389 int devcnt = 0;
390 int bvCount = 0;
391int BIOSDev = 0;
392 long gBootMode = kBootModeNormal; /* defaults to 0 == kBootModeNormal */
393
394 unsigned int allowBVFlags = kBVFlagSystemVolume|kBVFlagForeignBoot;
395 unsigned int denyBVFlags = kBVFlagEFISystem;
396
397#ifdef NBP_SUPPORT
398 // Set reminder to unload the PXE base code. Neglect to unload
399 // the base code will result in a hang or kernel panic.
400 gUnloadPXEOnExit = true;
401#endif
402
403 // Setup VGA text mode.
404 // It's unsafe to call setVideoMode() before the
405 // bootargs is initialized, we call video_mode() instead.
406#if DEBUG
407 printf("before video_mode\n");
408#endif
409 video_mode( 2 ); // 80x25 mono text mode.
410#if DEBUG
411 printf("after video_mode\n");
412#endif
413printf("Starting Chameleon ...\n");
414
415Install_Default_Handler();
416
417init_ut_fnc();
418
419initBooterLog();
420
421// Initialize boot info structure.
422 initKernBootStruct();
423
424 // Scan and record the system's hardware information.
425 scan_platform();
426
427
428// Pseudo-random generator initialization.
429 // arc4_init();
430
431 set_env(envgBIOSDev, (BIOSDev = biosdev & kBIOSDevMask));
432 set_env(envShouldboot, false);
433 set_env(envkCacheFile, (uint32_t)gBootKernelCacheFile);
434 set_env(envMKextName, (uint32_t)gMKextName);
435set_env(envHFSLoadVerbose, 1);
436set_env(envarchCpuType, CPU_TYPE_I386);
437set_env(envgHaveKernelCache, false);
438
439 InitBootPrompt();
440
441 // First get info for boot volume.
442 scanBootVolumes(BIOSDev, 0);
443
444 bvChain = getBVChainForBIOSDev(BIOSDev);
445
446 setBootGlobals(bvChain);
447
448 // Load Booter boot.plist config file
449 loadBooterConfig();
450
451 {
452 bool isServer = false;
453 getBoolForKey(kIsServer, &isServer, DEFAULT_BOOT_CONFIG); // we must set this as soon as possible
454 set_env(envIsServer , isServer);
455 }
456
457
458{
459bool quiet = false;
460if (getBoolForKey(kQuietBootKey, &quiet, DEFAULT_BOOT_CONFIG) && quiet)
461{
462gBootMode |= kBootModeQuiet;
463}
464}
465
466 set_env(envgBootMode, gBootMode);
467
468{
469bool instantMenu = false;
470// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
471if (getBoolForKey(kInsantMenuKey, &instantMenu, DEFAULT_BOOT_CONFIG) && instantMenu)
472{
473firstRun = false;
474}
475}
476
477 {
478 bool ScanSingleDrive = false;
479 // Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
480 if (getBoolForKey(kScanSingleDriveKey, &ScanSingleDrive, DEFAULT_BOOT_CONFIG) && ScanSingleDrive)
481 {
482 ScanSingleDrive = true;
483 }
484 safe_set_env(envgScanSingleDrive, ScanSingleDrive);
485 // Create a list of partitions on device(s).
486 if (ScanSingleDrive)
487 {
488 scanBootVolumes(BIOSDev, &bvCount);
489 }
490 else
491 {
492 scanDisks();
493 }
494
495}
496
497 // Create a separated bvr chain using the specified filters.
498 bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &devcnt);
499 safe_set_env(envgDeviceCount,devcnt);
500
501safe_set_env(envgBootVolume, (uint32_t)selectBootVolume(bvChain));
502
503
504LoadBundles("/Extra/");
505
506 // Loading preboot ramdisk if exists.
507execute_hook("loadPrebootRAMDisk", NULL, NULL, NULL, NULL, NULL, NULL);
508
509 {
510 // Disable rescan option by default
511 bool CDROMRescan = false;
512
513 // Enable it with Rescan=y in system config
514 if (getBoolForKey(kRescanKey, &CDROMRescan, DEFAULT_BOOT_CONFIG) && CDROMRescan)
515 {
516 CDROMRescan = true;
517
518 }
519 safe_set_env(envgEnableCDROMRescan, CDROMRescan);
520
521 }
522
523
524{
525bool rescanPrompt = false;
526// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
527if (getBoolForKey(kRescanPromptKey, &rescanPrompt , DEFAULT_BOOT_CONFIG) && rescanPrompt && biosDevIsCDROM((int)get_env(envgBIOSDev)))
528{
529 safe_set_env(envgEnableCDROMRescan, promptForRescanOption());
530}
531}
532
533#if DEBUG
534 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);
535 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);
536 getc();
537#endif
538
539 setBootGlobals(bvChain);
540
541// Display the GUI
542execute_hook("GUI_Display", NULL, NULL, NULL, NULL, NULL, NULL);
543
544 // Parse args, load and start kernel.
545 while (1) {
546 const char *val;
547 int len;
548char *bootFile;
549bool trycache = true; // Always try to catch the kernelcache first
550
551 long flags;
552#ifdef BOOT_HELPER_SUPPORT
553long time;
554#endif
555 int ret = -1;
556 void *binary = (void *)kLoadAddr;
557
558 // additional variable for testing alternate kernel image locations on boot helper partitions.
559 char bootFileSpec[512];
560
561 // Initialize globals.
562 safe_set_env(envSysConfigValid, false);
563
564 status = getBootOptions(firstRun);
565 firstRun = false;
566 if (status == -1) continue;
567
568 status = processBootOptions();
569#ifndef NO_MULTIBOOT_SUPPORT
570 // Status==1 means to chainboot
571 if ( status == 1 ) break;
572#endif
573 // Status==-1 means that the config file couldn't be loaded or that gBootVolume is NULL
574 if ( status == -1 )
575 {
576// gBootVolume == NULL usually means the user hit escape.
577if(((BVRef)(uint32_t)get_env(envgBootVolume)) == NULL)
578{
579freeFilteredBVChain(bvChain);
580
581if (get_env(envgEnableCDROMRescan))
582rescanBIOSDevice((int)get_env(envgBIOSDev));
583
584bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &devcnt);
585 safe_set_env(envgDeviceCount,devcnt);
586
587setBootGlobals(bvChain);
588}
589continue;
590 }
591
592 // Other status (e.g. 0) means that we should proceed with boot.
593execute_hook("GUI_PreBoot", NULL, NULL, NULL, NULL, NULL, NULL);
594
595if (getValueForKey(karch, &val, &len, DEFAULT_BOOT_CONFIG) && val)
596{
597if (strncmp(val, "x86_64", 4) == 0)
598{
599safe_set_env(envarchCpuType, CPU_TYPE_X86_64);
600
601}
602else if (strncmp(val, "i386", 4) == 0)
603{
604safe_set_env(envarchCpuType, CPU_TYPE_I386);
605
606}
607else
608{
609DBG("Incorrect parameter for option 'arch =' , please use x86_64 or i386\n");
610determineCpuArch();
611}
612
613}
614else determineCpuArch();
615
616
617getRootDevice();
618
619// Notify to all modules that we are attempting to boot
620execute_hook("PreBoot", NULL, NULL, NULL, NULL, NULL, NULL);
621
622if (execute_hook("getProductNamePatched", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
623readSMBIOS(thePlatformName); // read smbios Platform Name
624
625
626if (((get_env(envgBootMode) & kBootModeSafe) == 0) &&
627!get_env(envgOverrideKernel) &&
628(get_env(envgBootFileType) == kBlockDeviceType) &&
629(gMKextName[0] == '\0') &&
630!getValueForBootKey(bootArgs->CommandLine, kIgnorePrelinkKern, &val, &len))
631{
632getBoolForKey(kUseKernelCache, &trycache, DEFAULT_BOOT_CONFIG);
633if (trycache == true)
634{
635// try to find the cache and fill the gBootKernelCacheFile string
636getKernelCachePath();
637
638// Check for cache file
639trycache = (gBootKernelCacheFile[0] != '\0') ? true : false; // if gBootKernelCacheFile is filled et bla bla bla.... :-)
640}
641
642}
643else
644{
645trycache = false;
646}
647
648verbose("Loading Darwin %s\n", ((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion);
649{
650long cachetime, kerneltime = 0, exttime;
651if (trycache && !forcecache) do {
652
653 if (strncmp(bootInfo->bootFile, kDefaultKernel,sizeof(kDefaultKernel)) != 0) {
654 // if we haven't found the kernel yet, don't use the cache
655 ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
656 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
657 {
658 trycache = false;
659 safe_set_env(envAdler32, 0);
660 DBG("No kernel found, kernelcache disabled !!!\n");
661 break;
662 }
663 }
664 else if (((BVRef)(uint32_t)get_env(envgBootVolume))->kernelfound != true) // Should never happen.
665 {
666 bootFile = kDefaultKernel;
667 goto out;
668 }
669
670ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
671if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
672|| (cachetime < kerneltime))
673{
674trycache = false;
675safe_set_env(envAdler32, 0);
676DBG("Warning: No kernelcache found or kernelcache too old (timestamp of the kernel > timestamp of the cache), kernelcache disabled !!!\n");
677
678break;
679}
680ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
681if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
682&& (cachetime < exttime))
683{
684trycache = false;
685safe_set_env(envAdler32, 0);
686DBG("Warning: kernelcache too old, timestamp of S/L/E > timestamp of the cache, kernelcache disabled !!! \n");
687
688break;
689}
690if (kerneltime > exttime)
691{
692exttime = kerneltime;
693}
694if (cachetime != (exttime + 1))
695{
696trycache = false;
697safe_set_env(envAdler32, 0);
698DBG("Warning: invalid timestamp, kernelcache disabled !!!\n");
699
700break;
701}
702} while (0);
703}
704
705 do {
706 if (trycache == true || forcecache == true)
707{
708 bootFile = gBootKernelCacheFile;
709 verbose("Loading kernel cache %s\n", bootFile);
710if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
711{
712ret = LoadThinFatFile(bootFile, &binary);
713if ((ret <= 0) && (get_env(envarchCpuType) == CPU_TYPE_X86_64))
714{
715safe_set_env(envarchCpuType, CPU_TYPE_I386);
716ret = LoadThinFatFile(bootFile, &binary);
717}
718}
719else
720{
721ret = LoadFile(bootFile);
722binary = (void *)kLoadAddr;
723}
724
725 if (ret >= 0)
726{
727 break;
728 }
729
730 }
731safe_set_env(envAdler32, 0);
732 bootFile = bootInfo->bootFile;
733#ifdef BOOT_HELPER_SUPPORT
734
735 // Try to load kernel image from alternate locations on boot helper partitions.
736 snprintf(bootFileSpec, sizeof(bootFileSpec),"com.apple.boot.P/%s", bootFile);
737 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
738 if (ret == -1)
739 {
740snprintf(bootFileSpec, sizeof(bootFileSpec), "com.apple.boot.R/%s", bootFile);
741ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
742if (ret == -1)
743{
744snprintf(bootFileSpec, sizeof(bootFileSpec), "com.apple.boot.S/%s", bootFile);
745ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
746if (ret == -1)
747{
748// Not found any alternate locations, using the original kernel image path.
749strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
750}
751}
752 }
753#else
754strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
755#endif
756
757 verbose("Loading kernel %s\n", bootFileSpec);
758 ret = LoadThinFatFile(bootFileSpec, &binary);
759 if ((ret <= 0) && (get_env(envarchCpuType) == CPU_TYPE_X86_64))
760 {
761safe_set_env(envarchCpuType, CPU_TYPE_I386);
762ret = LoadThinFatFile(bootFileSpec, &binary);
763 }
764
765 } while (0);
766
767#if DEBUG
768 printf("Pausing...");
769 sleep(8);
770#endif
771
772 if (ret <= 0)
773{
774 out:
775printf("Can't find %s\n", bootFile);
776
777sleep(1);
778#ifdef NBP_SUPPORT
779 if (get_env(envgBootFileType) == kNetworkDeviceType)
780{
781 // Return control back to PXE. Don't unload PXE base code.
782 gUnloadPXEOnExit = false;
783 break;
784 }
785#endif
786 }
787else
788{
789 /* Won't return if successful. */
790 if ( ExecKernel(binary))
791 {
792 firstRun = true;
793 continue;
794 }
795 }
796 }
797
798#ifndef NO_MULTIBOOT_SUPPORT
799 // chainboot
800 if (status==1)
801{
802if (getVideoMode() == GRAPHICS_MODE)
803{// if we are already in graphics-mode,
804
805__setVideoMode(VGA_TEXT_MODE);// switch back to text mode
806
807}
808 }
809#else
810printf("No proper Darwin Partition found, reseting ... \n");
811pause();
812common_boot(biosdev);
813#endif
814
815#ifdef NBP_SUPPORT
816 if ((get_env(envgBootFileType) == kNetworkDeviceType) && gUnloadPXEOnExit)
817{
818nbpUnloadBaseCode();
819 }
820#endif
821}
822
823static void determineCpuArch(void)
824{
825if (cpu_mode_is64bit())
826{
827safe_set_env(envarchCpuType, CPU_TYPE_X86_64);
828
829}
830else
831{
832safe_set_env(envarchCpuType, CPU_TYPE_I386);
833}
834}
835
836void getKernelCachePath(void)
837{
838{
839// If there is an extra kext/mkext, we return immediatly and we skip the kernelCache
840// since kexts/mkexts are not loaded properly when the kernelCache is used.
841// Another method would be to re-build the kernelCache one the fly
842if (found_extra_kext() == true) return;
843}
844
845{
846const char *val;
847int len;
848unsigned long Adler32 = 0;
849
850if (getValueForKey(kKernelCacheKey, &val, &len, DEFAULT_BOOT_CONFIG))
851{
852 char * buffer = newString(val);
853
854if (val[0] == '\\')
855{
856// Flip the back slash's to slash's .
857 len = 0;
858 while (buffer[len] != '\0') {
859 if (buffer[len] == '\\')
860 {
861 buffer[len] = '/';
862 }
863 len++;
864 }
865}
866strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile));
867 forcecache = true;
868}
869else
870{
871if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
872{
873snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s", kDefaultCachePath);
874}
875else if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
876{
877
878PlatformInfo *platformInfo = malloc(sizeof(PlatformInfo));
879if (platformInfo)
880{
881
882bzero(platformInfo, sizeof(PlatformInfo));
883
884if (GetgPlatformName())
885strlcpy(platformInfo->platformName,GetgPlatformName(), sizeof(platformInfo->platformName)+1);
886
887if (GetgRootDevice())
888{
889char *rootPath_p = platformInfo->rootPath;
890len = strlen(GetgRootDevice()) + 1;
891if ((unsigned)len > sizeof(platformInfo->rootPath))
892{
893len = sizeof(platformInfo->rootPath);
894}
895memcpy(rootPath_p, GetgRootDevice(),len);
896
897rootPath_p += len;
898
899len = strlen(bootInfo->bootFile);
900
901if ((unsigned)(rootPath_p - platformInfo->rootPath + len) >=
902sizeof(platformInfo->rootPath))
903{
904
905len = sizeof(platformInfo->rootPath) -
906(rootPath_p - platformInfo->rootPath);
907}
908memcpy(rootPath_p, bootInfo->bootFile, len);
909
910}
911
912if (!platformInfo->platformName[0] || !platformInfo->rootPath[0])
913{
914platformInfo->platformName[0] = platformInfo->rootPath[0] = 0;
915}
916#ifdef rootpath
917 SetgRootPath(platformInfo->rootPath);
918#endif
919
920Adler32 = OSSwapHostToBigInt32(local_adler32((unsigned char *)platformInfo, sizeof(PlatformInfo)));
921safe_set_env(envAdler32, Adler32);
922
923free(platformInfo);
924}
925
926DBG("Adler32: %08lX\n",Adler32);
927
928if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] < '6')
929{
930long flags, cachetime;
931int ret = -1;
932
933if (Adler32) {
934snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s.%08lX", "/System/Library/Caches/com.apple.kernelcaches/kernelcache",Adler32);
935ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
936}
937
938if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
939{
940safe_set_env(envAdler32, 0);
941snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s", "/System/Library/Caches/com.apple.kernelcaches/kernelcache");
942}
943
944} else if (Adler32)
945snprintf(gBootKernelCacheFile, sizeof(gBootKernelCacheFile), "%s_%s.%08lX", kDefaultCachePath, (get_env(envarchCpuType) == CPU_TYPE_I386) ? "i386" : "x86_64", Adler32); //Snow Leopard
946
947}
948}
949}
950}
951
952static void getRootDevice(void)
953{
954// Maximum config table value size
955#define VALUE_SIZE 2048
956bool uuidSet = false;
957const char *val = 0;
958 int cnt = 0;
959
960if (getValueForKey(kBootUUIDKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
961{
962uuidSet = true;
963}
964else
965{
966if (getValueForBootKey(bootArgs->CommandLine, kRootDeviceKey, &val, &cnt))
967{
968if (*val == '*' && *(val + 1) != '/' && *(val + 1) != 'u')
969{
970val += 1; //skip the *
971uuidSet = true;
972
973}
974else if (*val == '*' && *(val + 1) == 'u')
975{
976
977if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
978uuidSet = true;
979
980}
981}
982else
983{
984#ifdef BOOT_HELPER_SUPPORT
985//
986// Try an alternate method for getting the root UUID on boot helper partitions.
987//
988if (((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagBooter)
989{
990if((loadHelperConfig() == 0)
991 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
992{
993getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
994uuidSet = true;
995goto out;
996}
997}
998#endif
999if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
1000{
1001int ArgCntRemaining = (int)get_env(envArgCntRemaining);
1002uuidSet = false;
1003char * valueBuffer;
1004valueBuffer = malloc(VALUE_SIZE);
1005 if (!valueBuffer) {
1006 return;
1007 }
1008char * argP = bootArgs->CommandLine;
1009valueBuffer[0] = '*';
1010if (cnt > VALUE_SIZE)
1011{
1012cnt = VALUE_SIZE;
1013}
1014strlcpy(valueBuffer + 1, val, cnt+1);
1015if (!copyArgument( kRootDeviceKey, valueBuffer, cnt, &argP, &ArgCntRemaining))
1016{
1017free(valueBuffer);
1018printf("Error: boot arguments too long, unable to set root device !!");
1019getc();
1020return;
1021}
1022 safe_set_env(envArgCntRemaining,ArgCntRemaining);
1023free(valueBuffer);
1024goto out;
1025}
1026
1027if (((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))
1028{
1029verbose("Setting boot-uuid to: %s\n", bootInfo->uuidStr);
1030//uuidSet = true;
1031SetgRootDevice(bootInfo->uuidStr);
1032return;
1033}
1034
1035}
1036}
1037
1038out:
1039verbose("Setting %s to: %s\n", uuidSet ? kBootUUIDKey : "root device", (char* )val);
1040 SetgRootDevice(val);
1041}
1042
1043static bool find_file_with_ext(const char* dir, const char *ext, const char * name_to_compare, size_t ext_size)
1044{
1045 long ret, length, flags, time;
1046 long long index;
1047 const char * name;
1048
1049DBG("FileLoadBundles in %s\n",dirSpec);
1050
1051 index = 0;
1052 while (1) {
1053 ret = GetDirEntry(dir, &index, &name, &flags, &time);
1054 if (ret == -1) break;
1055
1056 // Make sure this is not a directory.
1057 if ((flags & kFileTypeMask) != kFileTypeFlat) continue;
1058
1059 // Make sure this is a kext or mkext.
1060 length = strlen(name);
1061 if (strncmp(name + length - ext_size, ext, ext_size)) continue;
1062
1063 if (name_to_compare)
1064 {
1065 if (strcmp(name, name_to_compare) == 0)
1066 {
1067 DBG("found : %s\n", name);
1068 return true;
1069 }
1070 }
1071 else
1072 {
1073 DBG("found : %s\n", name);
1074 return true;
1075 }
1076
1077 }
1078return false;
1079}
1080
1081// If a kext is found in /Extra/Extentions return true
1082// If a mkext is found in /Extra return true
1083// Otherwise return false
1084// Tips (if you still want to use extra kext(s)/mkext(s) ):
1085// 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),
1086// so it's recommended to create a system mkext by yourself to decrease boot time (see the kextcache commandline)
1087static bool found_extra_kext(void)
1088{
1089#define EXTENSIONS "Extensions"
1090#define MKEXT_EXT ".mkext"
1091#define MKEXT_EXT_SIZE strlen(MKEXT_EXT)
1092#define KEXT_EXT ".kext"
1093#define KEXT_EXT_SIZE strlen(KEXT_EXT)
1094
1095long flags;
1096long exttime;
1097int ret = -1;
1098
1099ret = GetFileInfo("rd(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1100if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
1101{
1102if (((flags & kFileTypeMask) == kFileTypeFlat))
1103{
1104if (find_file_with_ext("rd(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1105{
1106return true;
1107}
1108}
1109else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1110{
1111if (find_file_with_ext("rd(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1112{
1113return true;
1114}
1115}
1116}
1117ret = GetFileInfo("/Extra/", EXTENSIONS, &flags, &exttime);
1118if (ret == 0)
1119{
1120if (((flags & kFileTypeMask) == kFileTypeFlat))
1121{
1122if (find_file_with_ext("/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1123{
1124return true;
1125}
1126}
1127else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1128{
1129if (find_file_with_ext("/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1130{
1131return true;
1132}
1133}
1134}
1135ret = GetFileInfo("bt(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1136if (ret == 0)
1137{
1138if (((flags & kFileTypeMask) == kFileTypeFlat))
1139{
1140if (find_file_with_ext("bt(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1141{
1142return true;
1143}
1144}
1145else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1146{
1147if (find_file_with_ext("bt(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1148{
1149return true;
1150}
1151}
1152}
1153DBG("NO Extra Mkext/Kext found\n");
1154
1155// nothing found
1156return false;
1157}
1158
1159#if 0
1160static char *FIXED_BOOTFILE_PATH(char * str)
1161{
1162char bootfile[128];
1163
1164bool bootFileWithDevice = false;
1165// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel
1166if (strncmp(str,"bt(",3) == 0 ||
1167strncmp(str,"hd(",3) == 0 ||
1168strncmp(str,"rd(",3) == 0)
1169{
1170bootFileWithDevice = true;
1171}
1172
1173// bootFile must start with a / if it not start with a device name
1174if (!bootFileWithDevice && (str)[0] != '/')
1175snprintf(bootFile, sizeof(bootfile), "/%s", str); // append a leading /
1176else
1177strlcpy(bootFile, bootInfo->bootFile, sizeof(bootFile));
1178
1179return bootfile;
1180}
1181#endif
1182

Archive Download this file

Revision: 2154