Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 33