Chameleon

Chameleon Svn Source Tree

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

Source at commit 429 created 13 years 8 months ago.
By meklort, Updated module system. Hooks can now be used within modules when cetaion functions are called in chameleon. Note that onle two hooks currently exist, more need to be added. I also updated the HelloWorld module to use a hook instead of print out right away.
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
202execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgs, NULL, NULL);// Notify modules that the kernel is about to be started
203
204// Jump to kernel's entry point. There's no going back now.
205 startprog( kernelEntry, bootArgs );
206
207 // Not reached
208
209 return 0;
210}
211
212//==========================================================================
213// This is the entrypoint from real-mode which functions exactly as it did
214// before. Multiboot does its own runtime initialization, does some of its
215// own things, and then calls common_boot.
216void boot(int biosdev)
217{
218initialize_runtime();
219// Enable A20 gate before accessing memory above 1Mb.
220enableA20();
221common_boot(biosdev);
222}
223
224//==========================================================================
225// The 'main' function for the booter. Called by boot0 when booting
226// from a block device, or by the network booter.
227//
228// arguments:
229// biosdev - Value passed from boot1/NBP to specify the device
230// that the booter was loaded from.
231//
232// If biosdev is kBIOSDevNetwork, then this function will return if
233// booting was unsuccessful. This allows the PXE firmware to try the
234// next boot device on its list.
235void common_boot(int biosdev)
236{
237 int status;
238 char *bootFile;
239 unsigned long adler32;
240 bool quiet;
241 bool firstRun = true;
242 bool instantMenu;
243 bool rescanPrompt;
244 unsigned int allowBVFlags = kBVFlagSystemVolume|kBVFlagForeignBoot;
245 unsigned int denyBVFlags = kBVFlagEFISystem;
246
247 // Set reminder to unload the PXE base code. Neglect to unload
248 // the base code will result in a hang or kernel panic.
249 gUnloadPXEOnExit = true;
250
251 // Record the device that the booter was loaded from.
252 gBIOSDev = biosdev & kBIOSDevMask;
253
254 // Initialize boot info structure.
255 initKernBootStruct();
256
257 // Setup VGA text mode.
258 // Not sure if it is safe to call setVideoMode() before the
259 // config table has been loaded. Call video_mode() instead.
260#if DEBUG
261 printf("before video_mode\n");
262#endif
263 video_mode( 2 ); // 80x25 mono text mode.
264#if DEBUG
265 printf("after video_mode\n");
266#endif
267
268 // Scan and record the system's hardware information.
269 scan_platform();
270
271 // First get info for boot volume.
272 scanBootVolumes(gBIOSDev, 0);
273 bvChain = getBVChainForBIOSDev(gBIOSDev);
274 setBootGlobals(bvChain);
275
276 // Load boot.plist config file
277 status = loadSystemConfig(&bootInfo->bootConfig);
278
279 if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->bootConfig) && quiet) {
280 gBootMode |= kBootModeQuiet;
281 }
282
283 // Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
284 if (getBoolForKey(kInsantMenuKey, &instantMenu, &bootInfo->bootConfig) && instantMenu) {
285 firstRun = false;
286 }
287
288// Intialize module system
289if(init_module_system())
290{
291load_all_modules();
292}
293
294
295
296 // Loading preboot ramdisk if exists.
297 loadPrebootRAMDisk();
298
299 // Disable rescan option by default
300 gEnableCDROMRescan = false;
301
302 // Enable it with Rescan=y in system config
303 if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->bootConfig) && gEnableCDROMRescan) {
304 gEnableCDROMRescan = true;
305 }
306
307 // Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
308 rescanPrompt = false;
309 if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->bootConfig) && rescanPrompt && biosDevIsCDROM(gBIOSDev)) {
310 gEnableCDROMRescan = promptForRescanOption();
311 }
312
313 // Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
314 if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->bootConfig) && gScanSingleDrive) {
315 gScanSingleDrive = true;
316 }
317
318 // Create a list of partitions on device(s).
319 if (gScanSingleDrive) {
320 scanBootVolumes(gBIOSDev, &bvCount);
321 } else {
322 scanDisks(gBIOSDev, &bvCount);
323 }
324
325 // Create a separated bvr chain using the specified filters.
326 bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
327
328 gBootVolume = selectBootVolume(bvChain);
329
330#if DEBUG
331 printf(" Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
332 printf(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
333 getc();
334#endif
335
336 useGUI = true;
337 // Override useGUI default
338 getBoolForKey(kGUIKey, &useGUI, &bootInfo->bootConfig);
339 if (useGUI) {
340patchVideoBios();
341 /* XXX AsereBLN handle error */
342initGUI();
343 }
344
345 setBootGlobals(bvChain);
346
347 // Parse args, load and start kernel.
348 while (1) {
349 const char *val;
350 int len;
351 int trycache;
352 long flags, cachetime, kerneltime, exttime, sleeptime, time;
353 int ret = -1;
354 void *binary = (void *)kLoadAddr;
355 bool tryresume;
356 bool tryresumedefault;
357 bool forceresume;
358
359 config_file_t systemVersion;// system.plist of booting partition
360
361 // additional variable for testing alternate kernel image locations on boot helper partitions.
362 char bootFileSpec[512];
363
364 // Initialize globals.
365
366 sysConfigValid = false;
367 gErrors = false;
368
369 status = getBootOptions(firstRun);
370 firstRun = false;
371 if (status == -1) continue;
372
373 status = processBootOptions();
374 // Status==1 means to chainboot
375 if ( status == 1 ) break;
376 // Status==-1 means that the config file couldn't be loaded or that gBootVolume is NULL
377 if ( status == -1 )
378 {
379 // gBootVolume == NULL usually means the user hit escape.
380 if(gBootVolume == NULL)
381 {
382 freeFilteredBVChain(bvChain);
383
384 if (gEnableCDROMRescan)
385 rescanBIOSDevice(gBIOSDev);
386
387 bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
388 setBootGlobals(bvChain);
389 }
390 continue;
391 }
392
393 // Other status (e.g. 0) means that we should proceed with boot.
394
395if( bootArgs->Video.v_display == GRAPHICS_MODE )
396drawBackground();
397
398 // Found and loaded a config file. Proceed with boot.
399
400// Turn off any GUI elements
401if( bootArgs->Video.v_display == GRAPHICS_MODE )
402{
403gui.devicelist.draw = false;
404gui.bootprompt.draw = false;
405gui.menu.draw = false;
406gui.infobox.draw = false;
407drawBackground();
408updateVRAM();
409}
410
411// Find out which version mac os we're booting.
412if (!loadConfigFile("System/Library/CoreServices/SystemVersion.plist", &systemVersion)) {
413if (getValueForKey(kProductVersion, &val, &len, &systemVersion)) {
414// getValueForKey uses const char for val
415// so copy it and trim
416strncpy(gMacOSVersion, val, MIN(len, 4));
417gMacOSVersion[MIN(len, 4)] = '\0';
418}
419}
420
421if (platformCPUFeature(CPU_FEATURE_EM64T)) {
422archCpuType = CPU_TYPE_X86_64;
423} else {
424archCpuType = CPU_TYPE_I386;
425}
426if (getValueForKey(karch, &val, &len, &bootInfo->bootConfig)) {
427if (strncmp(val, "i386", 4) == 0) {
428archCpuType = CPU_TYPE_I386;
429}
430}
431if (getValueForKey(k32BitModeFlag, &val, &len, &bootInfo->bootConfig)) {
432archCpuType = CPU_TYPE_I386;
433}
434
435if (!getBoolForKey (kWake, &tryresume, &bootInfo->bootConfig)) {
436tryresume = true;
437tryresumedefault = true;
438} else {
439tryresumedefault = false;
440}
441
442if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->bootConfig)) {
443forceresume = false;
444}
445
446if (forceresume) {
447tryresume = true;
448tryresumedefault = false;
449}
450
451while (tryresume) {
452const char *tmp;
453BVRef bvr;
454if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->bootConfig))
455val="/private/var/vm/sleepimage";
456
457// Do this first to be sure that root volume is mounted
458ret = GetFileInfo(0, val, &flags, &sleeptime);
459
460if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
461break;
462
463// Can't check if it was hibernation Wake=y is required
464if (bvr->modTime == 0 && tryresumedefault)
465break;
466
467if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
468break;
469
470if (!forceresume && ((sleeptime+3)<bvr->modTime)) {
471printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",bvr->modTime-sleeptime);
472break;
473}
474
475HibernateBoot((char *)val);
476break;
477}
478
479 // Reset cache name.
480 bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
481
482 sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);
483
484 adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
485
486 if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig)) {
487 strlcpy(gBootKernelCacheFile, val, len+1);
488 } else {
489 sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePath, adler32);
490 }
491
492 // Check for cache file.
493 trycache = (((gBootMode & kBootModeSafe) == 0) &&
494 !gOverrideKernel &&
495 (gBootFileType == kBlockDeviceType) &&
496 (gMKextName[0] == '\0') &&
497 (gBootKernelCacheFile[0] != '\0'));
498
499verbose("Loading Darwin %s\n", gMacOSVersion);
500
501 if (trycache) do {
502
503 // if we haven't found the kernel yet, don't use the cache
504 ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
505 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
506 trycache = 0;
507 break;
508 }
509 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
510 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
511 || (cachetime < kerneltime)) {
512 trycache = 0;
513 break;
514 }
515 ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
516 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
517 && (cachetime < exttime)) {
518 trycache = 0;
519 break;
520 }
521 if (kerneltime > exttime) {
522 exttime = kerneltime;
523 }
524 if (cachetime != (exttime + 1)) {
525 trycache = 0;
526 break;
527 }
528 } while (0);
529
530 do {
531 if (trycache) {
532 bootFile = gBootKernelCacheFile;
533 verbose("Loading kernel cache %s\n", bootFile);
534 ret = LoadFile(bootFile);
535 binary = (void *)kLoadAddr;
536 if (ret >= 0) {
537 break;
538 }
539 }
540 bootFile = bootInfo->bootFile;
541
542 // Try to load kernel image from alternate locations on boot helper partitions.
543 sprintf(bootFileSpec, "com.apple.boot.P/%s", bootFile);
544 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
545 if (ret == -1)
546 {
547 sprintf(bootFileSpec, "com.apple.boot.R/%s", bootFile);
548 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
549 if (ret == -1)
550 {
551 sprintf(bootFileSpec, "com.apple.boot.S/%s", bootFile);
552 ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
553 if (ret == -1)
554 {
555 // Not found any alternate locations, using the original kernel image path.
556 strcpy(bootFileSpec, bootFile);
557 }
558 }
559 }
560
561 verbose("Loading kernel %s\n", bootFileSpec);
562 ret = LoadThinFatFile(bootFileSpec, &binary);
563 if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
564 {
565 archCpuType = CPU_TYPE_I386;
566 ret = LoadThinFatFile(bootFileSpec, &binary);
567 }
568
569 } while (0);
570
571 clearActivityIndicator();
572#if DEBUG
573 printf("Pausing...");
574 sleep(8);
575#endif
576
577 if (ret <= 0) {
578printf("Can't find %s\n", bootFile);
579
580if(gui.initialised) {
581sleep(1);
582drawBackground();
583gui.devicelist.draw = true;
584gui.redraw = true;
585}
586 if (gBootFileType == kNetworkDeviceType) {
587 // Return control back to PXE. Don't unload PXE base code.
588 gUnloadPXEOnExit = false;
589 break;
590 }
591 } else {
592 /* Won't return if successful. */
593// Notify modules that ExecKernel is about to be called
594execute_hook("ExecKernel", binary, NULL, NULL, NULL);
595 ret = ExecKernel(binary);
596 }
597 }
598
599 // chainboot
600 if (status==1) {
601if (getVideoMode() == GRAPHICS_MODE) {// if we are already in graphics-mode,
602setVideoMode(VGA_TEXT_MODE, 0);// switch back to text mode
603}
604 }
605
606 if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
607nbpUnloadBaseCode();
608 }
609}
610
611/*!
612 Selects a new BIOS device, taking care to update the global state appropriately.
613 */
614/*
615static void selectBiosDevice(void)
616{
617 struct DiskBVMap *oldMap = diskResetBootVolumes(gBIOSDev);
618 CacheReset();
619 diskFreeMap(oldMap);
620 oldMap = NULL;
621
622 int dev = selectAlternateBootDevice(gBIOSDev);
623
624 BVRef bvchain = scanBootVolumes(dev, 0);
625 BVRef bootVol = selectBootVolume(bvchain);
626 gBootVolume = bootVol;
627 setRootVolume(bootVol);
628 gBIOSDev = dev;
629}
630*/
631
632#define BASE 65521L /* largest prime smaller than 65536 */
633#define NMAX 5000
634// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
635
636#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
637#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
638#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
639#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
640#define DO16(buf) DO8(buf,0); DO8(buf,8);
641
642unsigned long Adler32(unsigned char *buf, long len)
643{
644 unsigned long s1 = 1; // adler & 0xffff;
645 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
646 unsigned long result;
647 int k;
648
649 while (len > 0) {
650 k = len < NMAX ? len : NMAX;
651 len -= k;
652 while (k >= 16) {
653 DO16(buf);
654 buf += 16;
655 k -= 16;
656 }
657 if (k != 0) do {
658 s1 += *buf++;
659 s2 += s1;
660 } while (--k);
661 s1 %= BASE;
662 s2 %= BASE;
663 }
664 result = (s2 << 16) | s1;
665 return OSSwapHostToBigInt32(result);
666}
667

Archive Download this file

Revision: 429