Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/boot.c

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

Archive Download this file

Revision: 284