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);
93static void init_pic(void);
94void getKernelCachePath(void);
95#ifdef NBP_SUPPORT
96static bool gUnloadPXEOnExit = false;
97#endif
98
99
100/*
101 * How long to wait (in seconds) to load the
102 * kernel after displaying the "boot:" prompt.
103 */
104#define kBootErrorTimeout 5
105
106/*
107 * Default path to kernel cache file
108 */
109#define kDefaultCachePath "/System/Library/Caches/com.apple.kext.caches/Startup/kernelcache"
110
111//==========================================================================
112// Zero the BSS.
113
114static void zeroBSS(void)
115{
116extern char _DATA__bss__begin, _DATA__bss__end;
117extern char _DATA__common__begin, _DATA__common__end;
118
119bzero(&_DATA__bss__begin, (&_DATA__bss__end - &_DATA__bss__begin));
120bzero(&_DATA__common__begin, (&_DATA__common__end - &_DATA__common__begin));
121}
122
123//==========================================================================
124// Malloc error function
125
126#ifdef SAFE_MALLOC
127static inline void malloc_error(char *addr, size_t size, const char *file, int line)
128{
129 stop("\nMemory allocation error! Addr=0x%x, Size=0x%x, File=%s, Line=%d\n", (unsigned)addr, (unsigned)size, file, line);
130}
131#else
132static inline void malloc_error(char *addr, size_t size)
133{
134 printf("\nMemory allocation error (0x%x, 0x%x)\n", (unsigned)addr, (unsigned)size);
135 asm volatile ("hlt");
136}
137#endif
138
139BVRef getBvChain(void)
140{
141return bvChain;
142}
143
144
145//==========================================================================
146//Initializes the runtime. Right now this means zeroing the BSS and initializing malloc.
147//
148void initialize_runtime(void)
149{
150zeroBSS();
151malloc_init(0, 0, 0, malloc_error);
152}
153
154static void init_pic(void)
155{
156 /* Remap IRQ's */
157/*
158 outb(0x20, 0x11);
159 outb(0xA0, 0x11);
160 outb(0x21, 0x20);
161 outb(0xA1, 0x28);
162 outb(0x21, 0x04);
163 outb(0xA1, 0x02);
164 outb(0x21, 0x01);
165 outb(0xA1, 0x01);
166 */
167//outb(0x70, inb(0x70)|0x80); /* Disable NMI */
168
169outb(0x21, 0xff); /* Maskout all interrupts Pic1 */
170outb(0xa1, 0xff); /* Maskout all interrupts Pic2 */
171}
172
173//==========================================================================
174// execKernel - Load the kernel image (mach-o) and jump to its entry point.
175
176static int ExecKernel(void *binary)
177{
178 entry_t kernelEntry;
179 int ret;
180
181 bootArgs->kaddr = bootArgs->ksize = 0;
182
183if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
184{
185bootArgs->Header.Version = kBootArgsVersion1;
186bootArgs->Header.Revision = ((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3];
187}
188else
189{
190#if kBootArgsVersion > 1
191
192bootArgs->Header.Version = kBootArgsVersion;
193bootArgs->Header.Revision = kBootArgsRevision;
194#else
195if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] >= '7')
196{
197bootArgs->Header.Version = 2;
198bootArgs->Header.Revision = 0;
199}
200#endif
201}
202
203execute_hook("ExecKernel", (void*)binary, NULL, NULL, NULL, NULL, NULL);
204
205 ret = DecodeKernel(binary,
206 &kernelEntry,
207 (char **) &bootArgs->kaddr,
208 (int *)&bootArgs->ksize );
209
210 if ( ret != 0 )
211 return ret;
212
213 // Load boot drivers from the specifed root path.
214
215 if (!get_env(envgHaveKernelCache))
216{
217LoadDrivers("/");
218 }
219
220 showError();
221
222execute_hook("md0Ramdisk", NULL, NULL, NULL, NULL, NULL, NULL);
223
224 setupFakeEfi();
225
226 verbose("Starting Darwin %s\n",( get_env(envarchCpuType) == CPU_TYPE_I386 ) ? "x86" : "x86_64");
227#ifdef NBP_SUPPORT
228 // Cleanup the PXE base code.
229
230 if ( (get_env(envgBootFileType) == kNetworkDeviceType) && gUnloadPXEOnExit )
231{
232if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
233 {
234 printf("nbpUnloadBaseCode error %d\n", (int) ret);
235 sleep(2);
236 }
237 }
238#endif
239{
240bool wait = false;
241const char *strval = 0;
242int dummysize /*= 0*/;
243
244getBoolForKey(kWaitForKeypressKey, &wait, DEFAULT_BOOT_CONFIG);
245
246if (getValueForBootKey(bootArgs->CommandLine, "-wait", &strval, &dummysize))
247{
248wait = true;
249
250if (strval && ((strcmp(strval, "no") == 0) || (strcmp(strval, "No") == 0)))
251{
252wait = false;
253}
254}
255
256if (wait == true)
257{
258pause();
259}
260}
261
262 //debug_platform_env();
263
264if ((execute_hook("GUI_ExecKernel", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS)) // (bootArgs->Video.v_display == VGA_TEXT_MODE)
265{
266 __setVideoMode( GRAPHICS_MODE );
267
268
269if(!get_env(envgVerboseMode))
270{
271__drawColorRectangle(0, 0, DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 0x01);
272
273uint8_t *appleBootPict;
274uint16_t bootImageWidth = kAppleBootWidth;
275uint16_t bootImageHeight = kAppleBootHeight;
276uint8_t *bootImageData = NULL;
277uint16_t x, y;
278
279unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};// here we store the used screen resolution
280// Prepare the data for the default Apple boot image.
281appleBootPict = (uint8_t *) __decodeRLE(gAppleBootPictRLE, kAppleBootRLEBlocks, bootImageWidth * bootImageHeight);
282if (appleBootPict)
283{
284if(__convertImage(bootImageWidth, bootImageHeight, appleBootPict, &bootImageData) == 0)
285 {
286 if (bootImageData)
287 {
288 x = (screen_params[0] - MIN(kAppleBootWidth, screen_params[0])) / 2;
289 y = (screen_params[1] - MIN(kAppleBootHeight, screen_params[1])) / 2;
290 __drawDataRectangle(x, y, kAppleBootWidth, kAppleBootHeight, bootImageData);
291 free(bootImageData);
292 }
293 }
294
295free(appleBootPict);
296}
297
298}
299}
300
301 finalizeEFIConfigTable();
302
303setupBooterLog();
304
305 finalizeBootStruct();
306
307execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgs, NULL, NULL, NULL, NULL);// Notify modules that the kernel is about to be started
308
309 switch (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3]) {
310case '4':
311case '5':
312case '6':
313reserveKernLegacyBootStruct();
314break;
315case '7':
316reserveKern107BootStruct();
317break;
318case '8':
319reserveKern108BootStruct();
320break;
321default:
322break;
323}
324
325#if UNUSED
326turnOffFloppy();
327#endif
328#if BETA
329#include "smp-imps.h"
330#include "apic.h"
331IMPS_LAPIC_WRITE(LAPIC_LVT1, LAPIC_ICR_DM_NMI);
332#endif
333
334switch (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3]) {
335case '4':
336case '5':
337case '6':
338// Jump to kernel's entry point. There's no going back now. XXX LEGACY OS XXX
339startprog( kernelEntry, bootArgsLegacy );
340break;
341case '7':
342init_pic();
343// Jump to kernel's entry point. There's no going back now. XXX LION XXX
344startprog( kernelEntry, bootArgs107 );
345break;
346case '8':
347init_pic();
348// Jump to kernel's entry point. There's no going back now. XXX MOUNTAIN LION XXX
349startprog( kernelEntry, bootArgs108 );
350break;
351default:
352printf("Error: Unsupported Darwin version\n");
353getc();
354break;
355}
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
415init_ut_fnc();
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// 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); // 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: %d, ->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): %d, ->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 (strcmp(bootInfo->bootFile, 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 = 0;
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 = 0;
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 = 0;
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 = 0;
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)
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 sprintf(bootFileSpec, "com.apple.boot.P/%s", bootFile);
734 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
735 if (ret == -1)
736 {
737sprintf(bootFileSpec, "com.apple.boot.R/%s", bootFile);
738ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
739if (ret == -1)
740{
741sprintf(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{
822if (cpu_mode_is64bit())
823{
824safe_set_env(envarchCpuType, CPU_TYPE_X86_64);
825
826}
827else
828{
829safe_set_env(envarchCpuType, CPU_TYPE_I386);
830}
831}
832
833void getKernelCachePath(void)
834{
835{
836// If there is an extra kext/mkext, we return immediatly and we skip the kernelCache
837// since kexts/mkexts are not loaded properly when the kernelCache is used.
838// Another method would be to re-build the kernelCache one the fly
839if (found_extra_kext() == true) return;
840}
841
842{
843const char *val;
844int len;
845unsigned long Adler32 = 0;
846
847if (getValueForKey(kKernelCacheKey, &val, &len, DEFAULT_BOOT_CONFIG))
848{
849 char * buffer = newString(val);
850
851if (val[0] == '\\')
852{
853// Flip the back slash's to slash's .
854 len = 0;
855 while (buffer[len] != '\0') {
856 if (buffer[len] == '\\')
857 {
858 buffer[len] = '/';
859 }
860 len++;
861 }
862}
863strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile));
864 forcecache = true;
865}
866else
867{
868if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
869{
870sprintf(gBootKernelCacheFile, "%s", kDefaultCachePath);
871}
872else if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
873{
874
875PlatformInfo *platformInfo = malloc(sizeof(PlatformInfo));
876if (platformInfo)
877{
878
879bzero(platformInfo, sizeof(PlatformInfo));
880
881if (GetgPlatformName())
882strlcpy(platformInfo->platformName,GetgPlatformName(), sizeof(platformInfo->platformName)+1);
883
884if (GetgRootDevice())
885{
886char *rootPath_p = platformInfo->rootPath;
887len = strlen(GetgRootDevice()) + 1;
888if ((unsigned)len > sizeof(platformInfo->rootPath))
889{
890len = sizeof(platformInfo->rootPath);
891}
892memcpy(rootPath_p, GetgRootDevice(),len);
893
894rootPath_p += len;
895
896len = strlen(bootInfo->bootFile);
897
898if ((unsigned)(rootPath_p - platformInfo->rootPath + len) >=
899sizeof(platformInfo->rootPath))
900{
901
902len = sizeof(platformInfo->rootPath) -
903(rootPath_p - platformInfo->rootPath);
904}
905memcpy(rootPath_p, bootInfo->bootFile, len);
906
907}
908
909if (!platformInfo->platformName[0] || !platformInfo->rootPath[0])
910{
911platformInfo->platformName[0] = platformInfo->rootPath[0] = 0;
912}
913#ifdef rootpath
914 SetgRootPath(platformInfo->rootPath);
915#endif
916
917Adler32 = OSSwapHostToBigInt32(adler32((unsigned char *)platformInfo, sizeof(*platformInfo)));
918safe_set_env(envAdler32, Adler32);
919
920free(platformInfo);
921}
922
923DBG("Adler32: %08lX\n",Adler32);
924
925if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] < '6')
926{
927long flags, cachetime;
928int ret = -1;
929
930if (Adler32) {
931sprintf(gBootKernelCacheFile, "%s.%08lX", "/System/Library/Caches/com.apple.kernelcaches/kernelcache",Adler32);
932ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
933}
934
935if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
936{
937safe_set_env(envAdler32, 0);
938sprintf(gBootKernelCacheFile, "%s", "/System/Library/Caches/com.apple.kernelcaches/kernelcache");
939}
940
941} else if (Adler32)
942sprintf(gBootKernelCacheFile, "%s_%s.%08lX", kDefaultCachePath, (get_env(envarchCpuType) == CPU_TYPE_I386) ? "i386" : "x86_64", Adler32); //Snow Leopard
943
944}
945}
946}
947}
948
949static void getRootDevice()
950{
951// Maximum config table value size
952#define VALUE_SIZE 2048
953bool uuidSet = false;
954const char *val = 0;
955 int cnt = 0;
956
957if (getValueForKey(kBootUUIDKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
958{
959uuidSet = true;
960}
961else
962{
963if (getValueForBootKey(bootArgs->CommandLine, kRootDeviceKey, &val, &cnt))
964{
965if (*val == '*' && *(val + 1) != '/' && *(val + 1) != 'u')
966{
967val += 1; //skip the *
968uuidSet = true;
969
970}
971else if (*val == '*' && *(val + 1) == 'u')
972{
973
974if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
975uuidSet = true;
976
977}
978}
979else
980{
981#ifdef BOOT_HELPER_SUPPORT
982//
983// Try an alternate method for getting the root UUID on boot helper partitions.
984//
985if (((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagBooter)
986{
987if((loadHelperConfig() == 0)
988 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
989{
990getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
991uuidSet = true;
992goto out;
993}
994}
995#endif
996if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
997{
998int ArgCntRemaining = (int)get_env(envArgCntRemaining);
999uuidSet = false;
1000char * valueBuffer;
1001valueBuffer = malloc(VALUE_SIZE);
1002 if (!valueBuffer) {
1003 return;
1004 }
1005char * argP = bootArgs->CommandLine;
1006valueBuffer[0] = '*';
1007if (cnt > VALUE_SIZE)
1008{
1009cnt = VALUE_SIZE;
1010}
1011strlcpy(valueBuffer + 1, val, cnt+1);
1012if (!copyArgument( kRootDeviceKey, valueBuffer, cnt, &argP, &ArgCntRemaining))
1013{
1014free(valueBuffer);
1015printf("Error: boot arguments too long, unable to set root device !!");
1016getc();
1017return;
1018}
1019 safe_set_env(envArgCntRemaining,ArgCntRemaining);
1020free(valueBuffer);
1021goto out;
1022}
1023
1024if (((BVRef)(uint32_t)get_env(envgBootVolume))->fs_getuuid && (((BVRef)(uint32_t)get_env(envgBootVolume))->fs_getuuid (((BVRef)(uint32_t)get_env(envgBootVolume)), bootInfo->uuidStr) == 0))
1025{
1026verbose("Setting boot-uuid to: %s\n", bootInfo->uuidStr);
1027//uuidSet = true;
1028SetgRootDevice(bootInfo->uuidStr);
1029return;
1030}
1031
1032}
1033}
1034
1035out:
1036verbose("Setting %s to: %s\n", uuidSet ? kBootUUIDKey : "root device", (char* )val);
1037 SetgRootDevice(val);
1038}
1039
1040static bool find_file_with_ext(const char* dir, const char *ext, const char * name_to_compare, size_t ext_size)
1041{
1042 long ret, length, flags, time;
1043 long long index;
1044 const char * name;
1045
1046DBG("FileLoadBundles in %s\n",dirSpec);
1047
1048 index = 0;
1049 while (1) {
1050 ret = GetDirEntry(dir, &index, &name, &flags, &time);
1051 if (ret == -1) break;
1052
1053 // Make sure this is not a directory.
1054 if ((flags & kFileTypeMask) != kFileTypeFlat) continue;
1055
1056 // Make sure this is a kext or mkext.
1057 length = strlen(name);
1058 if (strcmp(name + length - ext_size, ext)) continue;
1059
1060 if (name_to_compare)
1061 {
1062 if (strcmp(name, name_to_compare) == 0)
1063 {
1064 DBG("found : %s\n", name);
1065 return true;
1066 }
1067 }
1068 else
1069 {
1070 DBG("found : %s\n", name);
1071 return true;
1072 }
1073
1074 }
1075return false;
1076}
1077
1078// If a kext is found in /Extra/Extentions return true
1079// If a mkext is found in /Extra return true
1080// Otherwise return false
1081// Tips (if you still want to use extra kext(s)/mkext(s) ):
1082// 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),
1083// so it's recommended to create a system mkext by yourself to decrease boot time (see the kextcache commandline)
1084static bool found_extra_kext(void)
1085{
1086#define EXTENSIONS "Extensions"
1087#define MKEXT_EXT ".mkext"
1088#define MKEXT_EXT_SIZE strlen(MKEXT_EXT)
1089#define KEXT_EXT ".kext"
1090#define KEXT_EXT_SIZE strlen(KEXT_EXT)
1091
1092long flags;
1093long exttime;
1094int ret = -1;
1095
1096ret = GetFileInfo("rd(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1097if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
1098{
1099if (((flags & kFileTypeMask) == kFileTypeFlat))
1100{
1101if (find_file_with_ext("rd(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1102{
1103return true;
1104}
1105}
1106else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1107{
1108if (find_file_with_ext("rd(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1109{
1110return true;
1111}
1112}
1113}
1114ret = GetFileInfo("/Extra/", EXTENSIONS, &flags, &exttime);
1115if (ret == 0)
1116{
1117if (((flags & kFileTypeMask) == kFileTypeFlat))
1118{
1119if (find_file_with_ext("/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1120{
1121return true;
1122}
1123}
1124else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1125{
1126if (find_file_with_ext("/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1127{
1128return true;
1129}
1130}
1131}
1132ret = GetFileInfo("bt(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1133if (ret == 0)
1134{
1135if (((flags & kFileTypeMask) == kFileTypeFlat))
1136{
1137if (find_file_with_ext("bt(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1138{
1139return true;
1140}
1141}
1142else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1143{
1144if (find_file_with_ext("bt(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1145{
1146return true;
1147}
1148}
1149}
1150DBG("NO Extra Mkext/Kext found\n");
1151
1152// nothing found
1153return false;
1154}
1155
1156#if 0
1157static char *FIXED_BOOTFILE_PATH(char * str)
1158{
1159char bootfile[128];
1160
1161bool bootFileWithDevice = false;
1162// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel
1163if (strncmp(str,"bt(",3) == 0 ||
1164strncmp(str,"hd(",3) == 0 ||
1165strncmp(str,"rd(",3) == 0)
1166{
1167bootFileWithDevice = true;
1168}
1169
1170// bootFile must start with a / if it not start with a device name
1171if (!bootFileWithDevice && (str)[0] != '/')
1172sprintf(bootFile, "/%s", str); // append a leading /
1173else
1174strlcpy(bootFile, bootInfo->bootFile, sizeof(bootInfo->bootFile));
1175
1176return bootfile;
1177}
1178#endif
1179

Archive Download this file

Revision: 1977