Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Test/i386/boot2/boot.c

Source at commit 157 created 13 years 9 months ago.
By scrax, Made a new layout for the installer. Added advanced Options subfolder with some options to test. Added No chameleon base installation option. Updated localizable.string in IT and EN folders. New background by iFabio added
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 "ramdisk.h"
59#include "gui.h"
60#include "platform.h"
61
62long gBootMode; /* defaults to 0 == kBootModeNormal */
63bool gOverrideKernel;
64static char gBootKernelCacheFile[512];
65static char gCacheNameAdler[64 + 256];
66char *gPlatformName = gCacheNameAdler;
67char gRootDevice[512];
68char gMKextName[512];
69char gMacOSVersion[8];
70bool gEnableCDROMRescan;
71bool gScanSingleDrive;
72
73int bvCount = 0;
74//intmenucount = 0;
75int gDeviceCount = 0;
76
77BVRef bvr;
78BVRef menuBVR;
79BVRef bvChain;
80bool useGUI;
81
82//static void selectBiosDevice(void);
83static unsigned long Adler32(unsigned char *buffer, long length);
84static bool getOSVersion(char *str);
85
86static bool gUnloadPXEOnExit = false;
87
88/*
89 * How long to wait (in seconds) to load the
90 * kernel after displaying the "boot:" prompt.
91 */
92#define kBootErrorTimeout 5
93
94/*
95 * Default path to kernel cache file
96 */
97#define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache"
98
99//==========================================================================
100// Zero the BSS.
101
102static void zeroBSS(void)
103{
104extern char _DATA__bss__begin, _DATA__bss__end;
105extern char _DATA__common__begin, _DATA__common__end;
106
107bzero(&_DATA__bss__begin, (&_DATA__bss__end - &_DATA__bss__begin));
108bzero(&_DATA__common__begin, (&_DATA__common__end - &_DATA__common__begin));
109}
110
111//==========================================================================
112// Malloc error function
113
114static void malloc_error(char *addr, size_t size, const char *file, int line)
115{
116stop("\nMemory allocation error! Addr=0x%x, Size=0x%x, File=%s, Line=%d\n", (unsigned)addr, (unsigned)size, file, line);
117}
118
119//==========================================================================
120//Initializes the runtime. Right now this means zeroing the BSS and initializing malloc.
121//
122void initialize_runtime(void)
123{
124zeroBSS();
125malloc_init(0, 0, 0, malloc_error);
126}
127
128//==========================================================================
129// execKernel - Load the kernel image (mach-o) and jump to its entry point.
130
131static int ExecKernel(void *binary)
132{
133 entry_t kernelEntry;
134 int ret;
135
136 bootArgs->kaddr = bootArgs->ksize = 0;
137
138 ret = DecodeKernel(binary,
139 &kernelEntry,
140 (char **) &bootArgs->kaddr,
141 (int *)&bootArgs->ksize );
142
143 if ( ret != 0 )
144 return ret;
145
146 // Reserve space for boot args
147 reserveKernBootStruct();
148
149 // Load boot drivers from the specifed root path.
150
151 if (!gHaveKernelCache) {
152 LoadDrivers("/");
153 }
154
155 clearActivityIndicator();
156
157 if (gErrors) {
158 printf("Errors encountered while starting up the computer.\n");
159 printf("Pausing %d seconds...\n", kBootErrorTimeout);
160 sleep(kBootErrorTimeout);
161 }
162
163 setupFakeEfi();
164
165 md0Ramdisk();
166
167 verbose("Starting Darwin %s\n",( archCpuType == CPU_TYPE_I386 ) ? "x86" : "x86_64");
168
169 // Cleanup the PXE base code.
170
171 if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) {
172if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
173 {
174 printf("nbpUnloadBaseCode error %d\n", (int) ret);
175 sleep(2);
176 }
177 }
178
179 bool dummyVal;
180if (getBoolForKey(kWaitForKeypressKey, &dummyVal, &bootInfo->bootConfig) && dummyVal) {
181printf("Press any key to continue...");
182getc();
183}
184
185usb_loop();
186
187 // If we were in text mode, switch to graphics mode.
188 // This will draw the boot graphics unless we are in
189 // verbose mode.
190
191 if(gVerboseMode)
192 setVideoMode( GRAPHICS_MODE, 0 );
193 else
194 drawBootGraphics();
195
196setupBooterLog();
197
198 finalizeBootStruct();
199
200 // Jump to kernel's entry point. There's no going back now.
201
202 startprog( kernelEntry, bootArgs );
203
204 // Not reached
205
206 return 0;
207}
208
209//==========================================================================
210// This is the entrypoint from real-mode which functions exactly as it did
211// before. Multiboot does its own runtime initialization, does some of its
212// own things, and then calls common_boot.
213void boot(int biosdev)
214{
215initialize_runtime();
216// Enable A20 gate before accessing memory above 1Mb.
217enableA20();
218common_boot(biosdev);
219}
220
221//==========================================================================
222// The 'main' function for the booter. Called by boot0 when booting
223// from a block device, or by the network booter.
224//
225// arguments:
226// biosdev - Value passed from boot1/NBP to specify the device
227// that the booter was loaded from.
228//
229// If biosdev is kBIOSDevNetwork, then this function will return if
230// booting was unsuccessful. This allows the PXE firmware to try the
231// next boot device on its list.
232void common_boot(int biosdev)
233{
234 int status;
235 char *bootFile;
236 unsigned long adler32;
237 bool quiet;
238 bool firstRun = true;
239 bool instantMenu;
240 bool rescanPrompt;
241 unsigned int allowBVFlags = kBVFlagSystemVolume|kBVFlagForeignBoot;
242 unsigned int denyBVFlags = kBVFlagEFISystem;
243
244 // Set reminder to unload the PXE base code. Neglect to unload
245 // the base code will result in a hang or kernel panic.
246 gUnloadPXEOnExit = true;
247
248 // Record the device that the booter was loaded from.
249 gBIOSDev = biosdev & kBIOSDevMask;
250
251 // Initialize boot info structure.
252 initKernBootStruct();
253
254initBooterLog();
255
256 // Setup VGA text mode.
257 // Not sure if it is safe to call setVideoMode() before the
258 // config table has been loaded. Call video_mode() instead.
259#if DEBUG
260 printf("before video_mode\n");
261#endif
262 video_mode( 2 ); // 80x25 mono text mode.
263#if DEBUG
264 printf("after video_mode\n");
265#endif
266
267 // Scan and record the system's hardware information.
268 scan_platform();
269
270 // First get info for boot volume.
271 scanBootVolumes(gBIOSDev, 0);
272 bvChain = getBVChainForBIOSDev(gBIOSDev);
273 setBootGlobals(bvChain);
274
275 // Load boot.plist config file
276 status = loadSystemConfig(&bootInfo->bootConfig);
277
278 if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->bootConfig) && quiet) {
279 gBootMode |= kBootModeQuiet;
280 }
281
282 // Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
283 if (getBoolForKey(kInsantMenuKey, &instantMenu, &bootInfo->bootConfig) && instantMenu) {
284 firstRun = false;
285 }
286
287 // Loading preboot ramdisk if exists.
288 loadPrebootRAMDisk();
289
290 // Disable rescan option by default
291 gEnableCDROMRescan = false;
292
293 // Enable it with Rescan=y in system config
294 if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->bootConfig) && gEnableCDROMRescan) {
295 gEnableCDROMRescan = true;
296 }
297
298 // Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
299 rescanPrompt = false;
300 if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->bootConfig) && rescanPrompt && biosDevIsCDROM(gBIOSDev)) {
301 gEnableCDROMRescan = promptForRescanOption();
302 }
303
304 // Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
305 if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->bootConfig) && gScanSingleDrive) {
306 gScanSingleDrive = true;
307 }
308
309 // Create a list of partitions on device(s).
310 if (gScanSingleDrive) {
311 scanBootVolumes(gBIOSDev, &bvCount);
312 } else {
313 scanDisks(gBIOSDev, &bvCount);
314 }
315
316 // Create a separated bvr chain using the specified filters.
317 bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
318
319 gBootVolume = selectBootVolume(bvChain);
320
321#if DEBUG
322 printf(" Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
323 printf(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
324 getc();
325#endif
326
327useGUI = true;
328// Override useGUI default
329getBoolForKey(kGUIKey, &useGUI, &bootInfo->bootConfig);
330if (useGUI && initGUI())
331{
332// initGUI() returned with an error, disabling GUI.
333useGUI = false;
334}
335
336 setBootGlobals(bvChain);
337
338 // Parse args, load and start kernel.
339 while (1) {
340 const char *val;
341 int len;
342 int trycache;
343 long flags, cachetime, kerneltime, exttime, sleeptime, time;
344 int ret = -1;
345 void *binary = (void *)kLoadAddr;
346 bool tryresume;
347 bool tryresumedefault;
348 bool forceresume;
349
350 // additional variable for testing alternate kernel image locations on boot helper partitions.
351 char bootFileSpec[512];
352
353 // Initialize globals.
354
355 sysConfigValid = false;
356 gErrors = false;
357
358 status = getBootOptions(firstRun);
359 firstRun = false;
360 if (status == -1) continue;
361
362 status = processBootOptions();
363 // Status==1 means to chainboot
364 if ( status == 1 ) break;
365 // Status==-1 means that the config file couldn't be loaded or that gBootVolume is NULL
366 if ( status == -1 )
367 {
368 // gBootVolume == NULL usually means the user hit escape.
369 if(gBootVolume == NULL)
370 {
371 freeFilteredBVChain(bvChain);
372
373 if (gEnableCDROMRescan)
374 rescanBIOSDevice(gBIOSDev);
375
376 bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
377 setBootGlobals(bvChain);
378 setupDeviceList(&bootInfo->themeConfig);
379 }
380 continue;
381 }
382
383 // Other status (e.g. 0) means that we should proceed with boot.
384
385// Turn off any GUI elements
386if( bootArgs->Video.v_display == GRAPHICS_MODE )
387{
388gui.devicelist.draw = false;
389gui.bootprompt.draw = false;
390gui.menu.draw = false;
391gui.infobox.draw = false;
392gui.logo.draw = false;
393drawBackground();
394updateVRAM();
395}
396
397// Find out which version mac os we're booting.
398getOSVersion(gMacOSVersion);
399
400if (platformCPUFeature(CPU_FEATURE_EM64T)) {
401archCpuType = CPU_TYPE_X86_64;
402} else {
403archCpuType = CPU_TYPE_I386;
404}
405if (getValueForKey(karch, &val, &len, &bootInfo->bootConfig)) {
406if (strncmp(val, "i386", 4) == 0) {
407archCpuType = CPU_TYPE_I386;
408}
409}
410
411if (!getBoolForKey (kWake, &tryresume, &bootInfo->bootConfig)) {
412tryresume = true;
413tryresumedefault = true;
414} else {
415tryresumedefault = false;
416}
417
418if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->bootConfig)) {
419forceresume = false;
420}
421
422if (forceresume) {
423tryresume = true;
424tryresumedefault = false;
425}
426
427while (tryresume) {
428const char *tmp;
429BVRef bvr;
430if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->bootConfig))
431val="/private/var/vm/sleepimage";
432
433// Do this first to be sure that root volume is mounted
434ret = GetFileInfo(0, val, &flags, &sleeptime);
435
436if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
437break;
438
439// Can't check if it was hibernation Wake=y is required
440if (bvr->modTime == 0 && tryresumedefault)
441break;
442
443if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
444break;
445
446if (!forceresume && ((sleeptime+3)<bvr->modTime)) {
447printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",bvr->modTime-sleeptime);
448break;
449}
450
451HibernateBoot((char *)val);
452break;
453}
454
455 // Reset cache name.
456 bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
457
458 sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);
459
460 adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
461
462 if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig)) {
463 strlcpy(gBootKernelCacheFile, val, len+1);
464 } else {
465 sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePath, adler32);
466 }
467
468 // Check for cache file.
469 trycache = (((gBootMode & kBootModeSafe) == 0) &&
470 !gOverrideKernel &&
471 (gBootFileType == kBlockDeviceType) &&
472 (gMKextName[0] == '\0') &&
473 (gBootKernelCacheFile[0] != '\0'));
474
475verbose("Loading Darwin %s\n", gMacOSVersion);
476
477 if (trycache) do {
478
479 // if we haven't found the kernel yet, don't use the cache
480 ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
481 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
482 trycache = 0;
483 break;
484 }
485 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
486 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
487 || (cachetime < kerneltime)) {
488 trycache = 0;
489 break;
490 }
491 ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
492 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
493 && (cachetime < exttime)) {
494 trycache = 0;
495 break;
496 }
497 if (kerneltime > exttime) {
498 exttime = kerneltime;
499 }
500 if (cachetime != (exttime + 1)) {
501 trycache = 0;
502 break;
503 }
504 } while (0);
505
506 do {
507 if (trycache) {
508 bootFile = gBootKernelCacheFile;
509 verbose("Loading kernel cache %s\n", bootFile);
510 ret = LoadFile(bootFile);
511 binary = (void *)kLoadAddr;
512 if (ret >= 0) {
513 break;
514 }
515 }
516 bootFile = bootInfo->bootFile;
517
518 // Try to load kernel image from alternate locations on boot helper partitions.
519 sprintf(bootFileSpec, "com.apple.boot.P/%s", bootFile);
520 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
521 if (ret == -1)
522 {
523 sprintf(bootFileSpec, "com.apple.boot.R/%s", bootFile);
524 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
525 if (ret == -1)
526 {
527 sprintf(bootFileSpec, "com.apple.boot.S/%s", bootFile);
528 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
529 if (ret == -1)
530 {
531 // Not found any alternate locations, using the original kernel image path.
532 strcpy(bootFileSpec, bootFile);
533 }
534 }
535 }
536
537 verbose("Loading kernel %s\n", bootFileSpec);
538 ret = LoadThinFatFile(bootFileSpec, &binary);
539 if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
540 {
541 archCpuType = CPU_TYPE_I386;
542 ret = LoadThinFatFile(bootFileSpec, &binary);
543 }
544
545 } while (0);
546
547 clearActivityIndicator();
548#if DEBUG
549 printf("Pausing...");
550 sleep(8);
551#endif
552
553 if (ret <= 0) {
554printf("Can't find %s\n", bootFile);
555
556sleep(1);
557
558 if (gBootFileType == kNetworkDeviceType) {
559 // Return control back to PXE. Don't unload PXE base code.
560 gUnloadPXEOnExit = false;
561 break;
562 }
563 } else {
564 /* Won't return if successful. */
565 ret = ExecKernel(binary);
566 }
567 }
568
569 // chainboot
570 if (status==1) {
571if (getVideoMode() == GRAPHICS_MODE) {// if we are already in graphics-mode,
572setVideoMode(VGA_TEXT_MODE, 0);// switch back to text mode
573}
574 }
575
576 if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
577nbpUnloadBaseCode();
578 }
579}
580
581/*!
582 Selects a new BIOS device, taking care to update the global state appropriately.
583 */
584/*
585static void selectBiosDevice(void)
586{
587 struct DiskBVMap *oldMap = diskResetBootVolumes(gBIOSDev);
588 CacheReset();
589 diskFreeMap(oldMap);
590 oldMap = NULL;
591
592 int dev = selectAlternateBootDevice(gBIOSDev);
593
594 BVRef bvchain = scanBootVolumes(dev, 0);
595 BVRef bootVol = selectBootVolume(bvchain);
596 gBootVolume = bootVol;
597 setRootVolume(bootVol);
598 gBIOSDev = dev;
599}
600*/
601
602static bool getOSVersion(char *str)
603{
604bool valid = false;
605config_file_t systemVersion;
606const char *val;
607int len;
608
609if (!loadConfigFile("System/Library/CoreServices/SystemVersion.plist", &systemVersion))
610{
611valid = true;
612}
613else if (!loadConfigFile("System/Library/CoreServices/ServerVersion.plist", &systemVersion))
614{
615valid = true;
616}
617
618if (valid)
619{
620if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
621{
622// getValueForKey uses const char for val
623// so copy it and trim
624*str = '\0';
625strncat(str, val, MIN(len, 4));
626}
627else
628valid = false;
629}
630
631return valid;
632}
633
634#define BASE 65521L /* largest prime smaller than 65536 */
635#define NMAX 5000
636// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
637
638#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
639#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
640#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
641#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
642#define DO16(buf) DO8(buf,0); DO8(buf,8);
643
644unsigned long Adler32(unsigned char *buf, long len)
645{
646 unsigned long s1 = 1; // adler & 0xffff;
647 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
648 unsigned long result;
649 int k;
650
651 while (len > 0) {
652 k = len < NMAX ? len : NMAX;
653 len -= k;
654 while (k >= 16) {
655 DO16(buf);
656 buf += 16;
657 k -= 16;
658 }
659 if (k != 0) do {
660 s1 += *buf++;
661 s2 += s1;
662 } while (--k);
663 s1 %= BASE;
664 s2 %= BASE;
665 }
666 result = (s2 << 16) | s1;
667 return OSSwapHostToBigInt32(result);
668}
669

Archive Download this file

Revision: 157