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

Archive Download this file

Revision: 2043