Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1146