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

Archive Download this file

Revision: 2052