Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 96