Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 426