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

Archive Download this file

Revision: 2157