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
498//gBootVolume = selectBootVolume(bvChain);
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: %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);
533 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);
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 // Status==1 means to chainboot
568 if ( status == 1 ) break;
569 // Status==-1 means that the config file couldn't be loaded or that gBootVolume is NULL
570 if ( status == -1 )
571 {
572// gBootVolume == NULL usually means the user hit escape.
573if(((BVRef)(uint32_t)get_env(envgBootVolume)) == NULL)
574{
575freeFilteredBVChain(bvChain);
576
577if (get_env(envgEnableCDROMRescan))
578rescanBIOSDevice((int)get_env(envgBIOSDev));
579
580bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &devcnt);
581 safe_set_env(envgDeviceCount,devcnt);
582
583setBootGlobals(bvChain);
584}
585continue;
586 }
587
588 // Other status (e.g. 0) means that we should proceed with boot.
589execute_hook("GUI_PreBoot", NULL, NULL, NULL, NULL, NULL, NULL);
590
591if (getValueForKey(karch, &val, &len, DEFAULT_BOOT_CONFIG) && val)
592{
593if (strncmp(val, "x86_64", 4) == 0)
594{
595safe_set_env(envarchCpuType, CPU_TYPE_X86_64);
596
597}
598else if (strncmp(val, "i386", 4) == 0)
599{
600safe_set_env(envarchCpuType, CPU_TYPE_I386);
601
602}
603else
604{
605DBG("Incorrect parameter for option 'arch =' , please use x86_64 or i386\n");
606determineCpuArch();
607}
608
609}
610else determineCpuArch();
611
612
613getRootDevice();
614
615// Notify to all modules that we are attempting to boot
616execute_hook("PreBoot", NULL, NULL, NULL, NULL, NULL, NULL);
617
618if (execute_hook("getProductNamePatched", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
619readSMBIOS(thePlatformName); // read smbios Platform Name
620
621
622if (((get_env(envgBootMode) & kBootModeSafe) == 0) &&
623!get_env(envgOverrideKernel) &&
624(get_env(envgBootFileType) == kBlockDeviceType) &&
625(gMKextName[0] == '\0') &&
626!getValueForBootKey(bootArgs->CommandLine, kIgnorePrelinkKern, &val, &len))
627{
628getBoolForKey(kUseKernelCache, &trycache, DEFAULT_BOOT_CONFIG);
629if (trycache == true)
630{
631// try to find the cache and fill the gBootKernelCacheFile string
632getKernelCachePath();
633
634// Check for cache file
635trycache = (gBootKernelCacheFile[0] != '\0') ? true : false; // if gBootKernelCacheFile is filled et bla bla bla.... :-)
636}
637
638}
639else
640{
641trycache = false;
642}
643
644verbose("Loading Darwin %s\n", ((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion);
645{
646long cachetime, kerneltime = 0, exttime;
647if (trycache && !forcecache) do {
648
649 if (strcmp(bootInfo->bootFile, kDefaultKernel) != 0) {
650 // if we haven't found the kernel yet, don't use the cache
651 ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
652 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
653 {
654 trycache = 0;
655 safe_set_env(envAdler32, 0);
656 DBG("No kernel found, kernelcache disabled !!!\n");
657 break;
658 }
659 }
660 else if (((BVRef)(uint32_t)get_env(envgBootVolume))->kernelfound != true) // Should never happen.
661 {
662 bootFile = kDefaultKernel;
663 goto out;
664 }
665
666ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
667if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
668|| (cachetime < kerneltime))
669{
670trycache = 0;
671safe_set_env(envAdler32, 0);
672DBG("Warning: No kernelcache found or kernelcache too old (timestamp of the kernel > timestamp of the cache), kernelcache disabled !!!\n");
673
674break;
675}
676ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
677if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
678&& (cachetime < exttime))
679{
680trycache = 0;
681safe_set_env(envAdler32, 0);
682DBG("Warning: kernelcache too old, timestamp of S/L/E > timestamp of the cache, kernelcache disabled !!! \n");
683
684break;
685}
686if (kerneltime > exttime)
687{
688exttime = kerneltime;
689}
690if (cachetime != (exttime + 1))
691{
692trycache = 0;
693safe_set_env(envAdler32, 0);
694DBG("Warning: invalid timestamp, kernelcache disabled !!!\n");
695
696break;
697}
698} while (0);
699}
700
701 do {
702 if (trycache)
703{
704 bootFile = gBootKernelCacheFile;
705 verbose("Loading kernel cache %s\n", bootFile);
706if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
707{
708ret = LoadThinFatFile(bootFile, &binary);
709if ((ret <= 0) && (get_env(envarchCpuType) == CPU_TYPE_X86_64))
710{
711safe_set_env(envarchCpuType, CPU_TYPE_I386);
712ret = LoadThinFatFile(bootFile, &binary);
713}
714}
715else
716{
717ret = LoadFile(bootFile);
718binary = (void *)kLoadAddr;
719}
720
721 if (ret >= 0)
722{
723 break;
724 }
725
726 }
727safe_set_env(envAdler32, 0);
728 bootFile = bootInfo->bootFile;
729#ifdef BOOT_HELPER_SUPPORT
730
731 // Try to load kernel image from alternate locations on boot helper partitions.
732 sprintf(bootFileSpec, "com.apple.boot.P/%s", bootFile);
733 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
734 if (ret == -1)
735 {
736sprintf(bootFileSpec, "com.apple.boot.R/%s", bootFile);
737ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
738if (ret == -1)
739{
740sprintf(bootFileSpec, "com.apple.boot.S/%s", bootFile);
741ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
742if (ret == -1)
743{
744// Not found any alternate locations, using the original kernel image path.
745strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
746}
747}
748 }
749#else
750strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
751#endif
752
753 verbose("Loading kernel %s\n", bootFileSpec);
754 ret = LoadThinFatFile(bootFileSpec, &binary);
755 if ((ret <= 0) && (get_env(envarchCpuType) == CPU_TYPE_X86_64))
756 {
757safe_set_env(envarchCpuType, CPU_TYPE_I386);
758ret = LoadThinFatFile(bootFileSpec, &binary);
759 }
760
761 } while (0);
762
763#if DEBUG
764 printf("Pausing...");
765 sleep(8);
766#endif
767
768 if (ret <= 0)
769{
770 out:
771printf("Can't find %s\n", bootFile);
772
773sleep(1);
774#ifdef NBP_SUPPORT
775 if (get_env(envgBootFileType) == kNetworkDeviceType)
776{
777 // Return control back to PXE. Don't unload PXE base code.
778 gUnloadPXEOnExit = false;
779 break;
780 }
781#endif
782 }
783else
784{
785 /* Won't return if successful. */
786 if ( ExecKernel(binary))
787 {
788 firstRun = true;
789 continue;
790 }
791 }
792 }
793
794 // chainboot
795 if (status==1)
796{
797if (getVideoMode() == GRAPHICS_MODE)
798{// if we are already in graphics-mode,
799
800__setVideoMode(VGA_TEXT_MODE);// switch back to text mode
801
802}
803 }
804#ifdef NBP_SUPPORT
805 if ((get_env(envgBootFileType) == kNetworkDeviceType) && gUnloadPXEOnExit)
806{
807nbpUnloadBaseCode();
808 }
809#endif
810}
811
812static void determineCpuArch(void)
813{
814if (cpu_mode_is64bit())
815{
816safe_set_env(envarchCpuType, CPU_TYPE_X86_64);
817
818}
819else
820{
821safe_set_env(envarchCpuType, CPU_TYPE_I386);
822}
823}
824
825void getKernelCachePath(void)
826{
827{
828// If there is an extra kext/mkext, we return immediatly and we skip the kernelCache
829// since kexts/mkexts are not loaded properly when the kernelCache is used.
830// Another method would be to re-build the kernelCache one the fly
831if (found_extra_kext() == true) return;
832}
833
834{
835const char *val;
836int len;
837unsigned long Adler32 = 0;
838
839if (getValueForKey(kKernelCacheKey, &val, &len, DEFAULT_BOOT_CONFIG))
840{
841 char * buffer = newString(val);
842
843if (val[0] == '\\')
844{
845// Flip the back slash's to slash's .
846 len = 0;
847 while (buffer[len] != '\0') {
848 if (buffer[len] == '\\')
849 {
850 buffer[len] = '/';
851 }
852 len++;
853 }
854}
855strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile));
856 forcecache = true;
857}
858else
859{
860if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] > '6')
861{
862sprintf(gBootKernelCacheFile, "%s", kDefaultCachePath);
863}
864else if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] <= '6')
865{
866
867PlatformInfo *platformInfo = malloc(sizeof(PlatformInfo));
868if (platformInfo)
869{
870
871bzero(platformInfo, sizeof(PlatformInfo));
872
873if (GetgPlatformName())
874strlcpy(platformInfo->platformName,GetgPlatformName(), sizeof(platformInfo->platformName)+1);
875
876if (GetgRootDevice())
877{
878char *rootPath_p = platformInfo->rootPath;
879len = strlen(GetgRootDevice()) + 1;
880if ((unsigned)len > sizeof(platformInfo->rootPath))
881{
882len = sizeof(platformInfo->rootPath);
883}
884memcpy(rootPath_p, GetgRootDevice(),len);
885
886rootPath_p += len;
887
888len = strlen(bootInfo->bootFile);
889
890if ((unsigned)(rootPath_p - platformInfo->rootPath + len) >=
891sizeof(platformInfo->rootPath))
892{
893
894len = sizeof(platformInfo->rootPath) -
895(rootPath_p - platformInfo->rootPath);
896}
897memcpy(rootPath_p, bootInfo->bootFile, len);
898
899}
900
901if (!platformInfo->platformName[0] || !platformInfo->rootPath[0])
902{
903platformInfo->platformName[0] = platformInfo->rootPath[0] = 0;
904}
905#ifdef rootpath
906 SetgRootPath(platformInfo->rootPath);
907#endif
908
909Adler32 = OSSwapHostToBigInt32(adler32((unsigned char *)platformInfo, sizeof(*platformInfo)));
910safe_set_env(envAdler32, Adler32);
911
912free(platformInfo);
913}
914
915DBG("Adler32: %08lX\n",Adler32);
916
917if (((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] < '6')
918{
919long flags, cachetime;
920int ret = -1;
921
922if (Adler32) {
923sprintf(gBootKernelCacheFile, "%s.%08lX", "/System/Library/Caches/com.apple.kernelcaches/kernelcache",Adler32);
924ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
925}
926
927if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
928{
929safe_set_env(envAdler32, 0);
930sprintf(gBootKernelCacheFile, "%s", "/System/Library/Caches/com.apple.kernelcaches/kernelcache");
931}
932
933} else if (Adler32)
934sprintf(gBootKernelCacheFile, "%s_%s.%08lX", kDefaultCachePath, (get_env(envarchCpuType) == CPU_TYPE_I386) ? "i386" : "x86_64", Adler32); //Snow Leopard
935
936}
937}
938}
939}
940
941static void getRootDevice()
942{
943// Maximum config table value size
944#define VALUE_SIZE 2048
945bool uuidSet = false;
946const char *val = 0;
947 int cnt = 0;
948
949if (getValueForKey(kBootUUIDKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
950{
951uuidSet = true;
952}
953else
954{
955if (getValueForBootKey(bootArgs->CommandLine, kRootDeviceKey, &val, &cnt))
956{
957if (*val == '*' && *(val + 1) != '/' && *(val + 1) != 'u')
958{
959val += 1; //skip the *
960uuidSet = true;
961
962}
963else if (*val == '*' && *(val + 1) == 'u')
964{
965
966if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
967uuidSet = true;
968
969}
970}
971else
972{
973#ifdef BOOT_HELPER_SUPPORT
974//
975// Try an alternate method for getting the root UUID on boot helper partitions.
976//
977if (((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagBooter)
978{
979if((loadHelperConfig() == 0)
980 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
981{
982getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
983uuidSet = true;
984goto out;
985}
986}
987#endif
988if ( getValueForKey( kBootDeviceKey, &val, &cnt, DEFAULT_BOOT_CONFIG))
989{
990int ArgCntRemaining = (int)get_env(envArgCntRemaining);
991uuidSet = false;
992char * valueBuffer;
993valueBuffer = malloc(VALUE_SIZE);
994 if (!valueBuffer) {
995 return;
996 }
997char * argP = bootArgs->CommandLine;
998valueBuffer[0] = '*';
999if (cnt > VALUE_SIZE)
1000{
1001cnt = VALUE_SIZE;
1002}
1003strlcpy(valueBuffer + 1, val, cnt+1);
1004if (!copyArgument( kRootDeviceKey, valueBuffer, cnt, &argP, &ArgCntRemaining))
1005{
1006free(valueBuffer);
1007printf("Error: boot arguments too long, unable to set root device !!");
1008getc();
1009return;
1010}
1011 safe_set_env(envArgCntRemaining,ArgCntRemaining);
1012free(valueBuffer);
1013goto out;
1014}
1015
1016if (((BVRef)(uint32_t)get_env(envgBootVolume))->fs_getuuid && (((BVRef)(uint32_t)get_env(envgBootVolume))->fs_getuuid (((BVRef)(uint32_t)get_env(envgBootVolume)), bootInfo->uuidStr) == 0))
1017{
1018verbose("Setting boot-uuid to: %s\n", bootInfo->uuidStr);
1019//uuidSet = true;
1020SetgRootDevice(bootInfo->uuidStr);
1021return;
1022}
1023
1024}
1025}
1026
1027out:
1028verbose("Setting %s to: %s\n", uuidSet ? kBootUUIDKey : "root device", (char* )val);
1029 SetgRootDevice(val);
1030}
1031
1032static bool find_file_with_ext(const char* dir, const char *ext, const char * name_to_compare, size_t ext_size)
1033{
1034 long ret, length, flags, time;
1035 long long index;
1036 const char * name;
1037
1038DBG("FileLoadBundles in %s\n",dirSpec);
1039
1040 index = 0;
1041 while (1) {
1042 ret = GetDirEntry(dir, &index, &name, &flags, &time);
1043 if (ret == -1) break;
1044
1045 // Make sure this is not a directory.
1046 if ((flags & kFileTypeMask) != kFileTypeFlat) continue;
1047
1048 // Make sure this is a kext or mkext.
1049 length = strlen(name);
1050 if (strcmp(name + length - ext_size, ext)) continue;
1051
1052 if (name_to_compare)
1053 {
1054 if (strcmp(name, name_to_compare) == 0)
1055 {
1056 DBG("found : %s\n", name);
1057 return true;
1058 }
1059 }
1060 else
1061 {
1062 DBG("found : %s\n", name);
1063 return true;
1064 }
1065
1066 }
1067return false;
1068}
1069
1070// If a kext is found in /Extra/Extentions return true
1071// If a mkext is found in /Extra return true
1072// Otherwise return false
1073// Tips (if you still want to use extra kext(s)/mkext(s) ):
1074// With Lion and earlier, the default boot cache is a kernelcache, no mkext is created anymore by kextd automaticaly (kextd still update the existing mkexts),
1075// so it's recommended to create a system mkext by yourself to decrease boot time (see the kextcache commandline)
1076static bool found_extra_kext(void)
1077{
1078#define EXTENSIONS "Extensions"
1079#define MKEXT_EXT ".mkext"
1080#define MKEXT_EXT_SIZE strlen(MKEXT_EXT)
1081#define KEXT_EXT ".kext"
1082#define KEXT_EXT_SIZE strlen(KEXT_EXT)
1083
1084long flags;
1085long exttime;
1086int ret = -1;
1087
1088ret = GetFileInfo("rd(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1089if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
1090{
1091if (((flags & kFileTypeMask) == kFileTypeFlat))
1092{
1093if (find_file_with_ext("rd(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1094{
1095return true;
1096}
1097}
1098else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1099{
1100if (find_file_with_ext("rd(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1101{
1102return true;
1103}
1104}
1105}
1106ret = GetFileInfo("/Extra/", EXTENSIONS, &flags, &exttime);
1107if (ret == 0)
1108{
1109if (((flags & kFileTypeMask) == kFileTypeFlat))
1110{
1111if (find_file_with_ext("/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1112{
1113return true;
1114}
1115}
1116else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1117{
1118if (find_file_with_ext("/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1119{
1120return true;
1121}
1122}
1123}
1124ret = GetFileInfo("bt(0,0)/Extra/", EXTENSIONS, &flags, &exttime);
1125if (ret == 0)
1126{
1127if (((flags & kFileTypeMask) == kFileTypeFlat))
1128{
1129if (find_file_with_ext("bt(0,0)/Extra/", MKEXT_EXT, EXTENSIONS, MKEXT_EXT_SIZE))
1130{
1131return true;
1132}
1133}
1134else if (((flags & kFileTypeMask) == kFileTypeDirectory))
1135{
1136if (find_file_with_ext("bt(0,0)/Extra/Extensions/", KEXT_EXT, NULL, KEXT_EXT_SIZE))
1137{
1138return true;
1139}
1140}
1141}
1142DBG("NO Extra Mkext/Kext found\n");
1143
1144// nothing found
1145return false;
1146}
1147
1148#if 0
1149static char *FIXED_BOOTFILE_PATH(char * str)
1150{
1151char bootfile[128];
1152
1153bool bootFileWithDevice = false;
1154// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel
1155if (strncmp(str,"bt(",3) == 0 ||
1156strncmp(str,"hd(",3) == 0 ||
1157strncmp(str,"rd(",3) == 0)
1158{
1159bootFileWithDevice = true;
1160}
1161
1162// bootFile must start with a / if it not start with a device name
1163if (!bootFileWithDevice && (str)[0] != '/')
1164sprintf(bootFile, "/%s", str); // append a leading /
1165else
1166strlcpy(bootFile, bootInfo->bootFile, sizeof(bootInfo->bootFile));
1167
1168return bootfile;
1169}
1170#endif
1171

Archive Download this file

Revision: 1972