Root/
Source at commit 2381 created 10 years 21 days ago. By ifabio, Apply patch: (Credits to Thomas Jansen aka tja) - Reading options from all devices during boot. The options for the boot menu are only read from the devices rd(0,0) or bt(0,0). Consequently, boot menu options (e.g. "Quiet Boot", "Timeout", etc.) in plists on other devices (like most users have) are ignored. This patch extends the list of paths to search for the options plist on all devices that can be found. | |
---|---|
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 | /* ␊ |
26 | * Mach Operating System␊ |
27 | * Copyright (c) 1990 Carnegie-Mellon University␊ |
28 | * Copyright (c) 1989 Carnegie-Mellon University␊ |
29 | * All rights reserved.␉ The CMU software License Agreement specifies␊ |
30 | * the terms and conditions for use and redistribution.␊ |
31 | */␊ |
32 | ␊ |
33 | /*␊ |
34 | *␉␉␉INTEL CORPORATION PROPRIETARY INFORMATION␊ |
35 | *␊ |
36 | *␉This software is supplied under the terms of a license␉agreement or ␊ |
37 | *␉nondisclosure agreement with Intel Corporation and may not be copied ␊ |
38 | *␉nor disclosed except in accordance with the terms of that agreement.␊ |
39 | *␊ |
40 | *␉Copyright 1988, 1989 by Intel Corporation␊ |
41 | */␊ |
42 | ␊ |
43 | /*␊ |
44 | * Copyright 1993 NeXT Computer, Inc.␊ |
45 | * All rights reserved.␊ |
46 | */␊ |
47 | ␊ |
48 | /*␊ |
49 | * Completely reworked by Sam Streeper (sam_s@NeXT.com)␊ |
50 | * Reworked again by Curtis Galloway (galloway@NeXT.com)␊ |
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 "modules.h"␊ |
62 | ␊ |
63 | /*␊ |
64 | * How long to wait (in seconds) to load the␊ |
65 | * kernel after displaying the "boot:" prompt.␊ |
66 | */␊ |
67 | #define kBootErrorTimeout 5␊ |
68 | ␊ |
69 | bool␉␉gOverrideKernel, gEnableCDROMRescan, gScanSingleDrive, useGUI;␊ |
70 | static bool␉gUnloadPXEOnExit = false;␊ |
71 | ␊ |
72 | static char␉gCacheNameAdler[64 + 256];␊ |
73 | char␉␉*gPlatformName = gCacheNameAdler;␊ |
74 | ␊ |
75 | char␉␉gRootDevice[ROOT_DEVICE_SIZE];␊ |
76 | char␉␉gMKextName[512];␊ |
77 | char␉␉gMacOSVersion[8];␊ |
78 | int␉␉␉bvCount = 0, gDeviceCount = 0;␊ |
79 | //int␉␉menucount = 0;␊ |
80 | long␉␉gBootMode; /* defaults to 0 == kBootModeNormal */␊ |
81 | BVRef␉␉bvr, menuBVR, bvChain;␊ |
82 | ␊ |
83 | static bool␉␉␉␉checkOSVersion(const char * version);␊ |
84 | static void␉␉␉␉getOSVersion();␊ |
85 | static unsigned long␉Adler32(unsigned char *buffer, long length);␊ |
86 | //static void␉␉␉selectBiosDevice(void);␊ |
87 | ␊ |
88 | /** options.c **/␊ |
89 | extern char* msgbuf;␊ |
90 | void showTextBuffer(char *buf, int size);␊ |
91 | ␊ |
92 | ␊ |
93 | //==========================================================================␊ |
94 | // Zero the BSS.␊ |
95 | ␊ |
96 | static void zeroBSS(void)␊ |
97 | {␊ |
98 | ␉extern char bss_start __asm("section$start$__DATA$__bss");␊ |
99 | extern char bss_end __asm("section$end$__DATA$__bss");␊ |
100 | extern char common_start __asm("section$start$__DATA$__common");␊ |
101 | extern char common_end __asm("section$end$__DATA$__common");␊ |
102 | ␉␊ |
103 | ␉bzero(&bss_start, (&bss_end - &bss_start));␊ |
104 | ␉bzero(&common_start, (&common_end - &common_start));␊ |
105 | } ␊ |
106 | ␊ |
107 | //==========================================================================␊ |
108 | // Malloc error function␊ |
109 | ␊ |
110 | static void malloc_error(char *addr, size_t size, const char *file, int line)␊ |
111 | {␊ |
112 | ␉stop("\nMemory allocation error! Addr: 0x%x, Size: 0x%x, File: %s, Line: %d\n",␊ |
113 | ␉␉␉␉␉␉␉␉␉ (unsigned)addr, (unsigned)size, file, line);␊ |
114 | }␊ |
115 | ␊ |
116 | //==========================================================================␊ |
117 | //Initializes the runtime. Right now this means zeroing the BSS and initializing malloc.␊ |
118 | //␊ |
119 | void initialize_runtime(void)␊ |
120 | {␊ |
121 | ␉zeroBSS();␊ |
122 | ␉malloc_init(0, 0, 0, malloc_error);␊ |
123 | }␊ |
124 | ␊ |
125 | //==========================================================================␊ |
126 | // execKernel - Load the kernel image (mach-o) and jump to its entry point.␊ |
127 | ␊ |
128 | static int ExecKernel(void *binary)␊ |
129 | {␊ |
130 | ␉int␉␉␉ret;␊ |
131 | ␉entry_t␉␉kernelEntry;␊ |
132 | ␉␊ |
133 | ␉bootArgs->kaddr = bootArgs->ksize = 0;␊ |
134 | ␉execute_hook("ExecKernel", (void*)binary, NULL, NULL, NULL);␊ |
135 | ␉␊ |
136 | ␉ret = DecodeKernel(binary,␊ |
137 | ␉␉␉␉␉ &kernelEntry,␊ |
138 | ␉␉␉␉␉ (char **) &bootArgs->kaddr,␊ |
139 | ␉␉␉␉␉ (int *)&bootArgs->ksize );␊ |
140 | ␉␊ |
141 | ␉if ( ret != 0 )␊ |
142 | ␉␉return ret;␊ |
143 | ␉␊ |
144 | ␉// Reserve space for boot args␊ |
145 | ␉reserveKernBootStruct();␊ |
146 | ␉␊ |
147 | ␉// Notify modules that the kernel has been decoded␊ |
148 | ␉execute_hook("DecodedKernel", (void*)binary, NULL, NULL, NULL);␊ |
149 | ␉␊ |
150 | ␉setupFakeEfi();␊ |
151 | ␉␊ |
152 | ␉// Load boot drivers from the specifed root path.␊ |
153 | ␉//if (!gHaveKernelCache)␊ |
154 | ␉LoadDrivers("/");␊ |
155 | ␉␊ |
156 | ␉execute_hook("DriversLoaded", (void*)binary, NULL, NULL, NULL);␊ |
157 | ␉␊ |
158 | ␉clearActivityIndicator();␊ |
159 | ␉␊ |
160 | ␉if (gErrors) {␊ |
161 | ␉␉printf("Errors encountered while starting up the computer.\n");␊ |
162 | ␉␉printf("Pausing %d seconds...\n", kBootErrorTimeout);␊ |
163 | ␉␉sleep(kBootErrorTimeout);␊ |
164 | ␉}␊ |
165 | ␉␊ |
166 | ␉md0Ramdisk();␊ |
167 | ␉␊ |
168 | ␉verbose("Starting Darwin %s\n",( archCpuType == CPU_TYPE_I386 ) ? "x86" : "x86_64");␊ |
169 | ␉verbose("Boot Args: %s\n", bootArgs->CommandLine);␊ |
170 | ␊ |
171 | ␉// Cleanup the PXE base code.␊ |
172 | ␉␊ |
173 | ␉if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) {␊ |
174 | ␉␉if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )␊ |
175 | ␉␉{␊ |
176 | ␉␉␉printf("nbpUnloadBaseCode error %d\n", (int) ret);␊ |
177 | ␉␉␉sleep(2);␊ |
178 | ␉␉}␊ |
179 | ␉}␊ |
180 | ␉␊ |
181 | ␉bool dummyVal;␊ |
182 | ␉if (getBoolForKey(kWaitForKeypressKey, &dummyVal, &bootInfo->chameleonConfig) && dummyVal) {␊ |
183 | ␉␉showTextBuffer(msgbuf, strlen(msgbuf));␊ |
184 | ␉}␊ |
185 | ␉␊ |
186 | ␉usb_loop();␊ |
187 | ␊ |
188 | ␉// If we were in text mode, switch to graphics mode.␊ |
189 | ␉// This will draw the boot graphics unless we are in␊ |
190 | ␉// verbose mode.␊ |
191 | ␉if (gVerboseMode)␊ |
192 | ␉␉setVideoMode( GRAPHICS_MODE, 0 );␊ |
193 | ␉else␊ |
194 | ␉␉drawBootGraphics();␊ |
195 | ␉␊ |
196 | ␉setupBooterLog();␊ |
197 | ␉␊ |
198 | ␉finalizeBootStruct();␊ |
199 | ␉␊ |
200 | ␉// Jump to kernel's entry point. There's no going back now.␊ |
201 | ␉if ((checkOSVersion("10.7")) || (checkOSVersion("10.8"))) {␊ |
202 | ␉␉␊ |
203 | ␉␉// Notify modules that the kernel is about to be started␊ |
204 | ␉␉execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgs, NULL, NULL);␊ |
205 | ␊ |
206 | ␉␉// Masking out so that Lion doesn't doublefault␊ |
207 | ␉␉outb(0x21, 0xff);␉/* Maskout all interrupts Pic1 */␊ |
208 | ␉␉outb(0xa1, 0xff);␉/* Maskout all interrupts Pic2 */␊ |
209 | ␉␉␊ |
210 | ␉␉startprog( kernelEntry, bootArgs );␊ |
211 | ␉}␊ |
212 | ␉else {␊ |
213 | ␉␉// Notify modules that the kernel is about to be started␊ |
214 | ␉␉execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgsPreLion, NULL, NULL);␊ |
215 | ␊ |
216 | ␉␉startprog( kernelEntry, bootArgsPreLion );␊ |
217 | ␉}␊ |
218 | ␉␊ |
219 | ␉// Not reached␊ |
220 | ␉return 0;␊ |
221 | }␊ |
222 | ␊ |
223 | ␊ |
224 | //==========================================================================␊ |
225 | // LoadKernelCache - Try to load Kernel Cache.␊ |
226 | // return the length of the loaded cache file or -1 on error␊ |
227 | long LoadKernelCache(const char* cacheFile, void **binary) {␊ |
228 | ␉char␉␉kernelCacheFile[512];␊ |
229 | ␉char␉␉kernelCachePath[512];␊ |
230 | ␉long␉␉flags, time, cachetime, kerneltime, exttime, ret=-1;␊ |
231 | unsigned long adler32;␊ |
232 | ␊ |
233 | if((gBootMode & kBootModeSafe) != 0)␊ |
234 | {␊ |
235 | ␉␉verbose("Kernel Cache ignored.\n");␊ |
236 | ␉␉return -1;␊ |
237 | }␊ |
238 | ␊ |
239 | ␉// Use specify kernel cache file if not empty␊ |
240 | ␉if (cacheFile[0] != 0)␊ |
241 | ␉␉strlcpy(kernelCacheFile, cacheFile, sizeof(kernelCacheFile));␊ |
242 | ␉else {␊ |
243 | ␉␉// Lion and Mountain Lion prelink kernel cache file␊ |
244 | ␉␉if ((checkOSVersion("10.7")) || (checkOSVersion("10.8"))) {␊ |
245 | ␉␉␉sprintf(kernelCacheFile, "%skernelcache", kDefaultCachePathSnow);␊ |
246 | ␉␉}␊ |
247 | ␉␉// Snow Leopard prelink kernel cache file␊ |
248 | ␉␉else if (checkOSVersion("10.6")) {␊ |
249 | ␉␉␉sprintf(kernelCacheFile, "kernelcache_%s", (archCpuType == CPU_TYPE_I386)␊ |
250 | ␉␉␉␉␉? "i386" : "x86_64");␊ |
251 | ␉␉␉int lnam = strlen(kernelCacheFile) + 9; //with adler32␊ |
252 | ␊ |
253 | ␉␉␉char* name;␊ |
254 | ␉␉␉long prev_time = 0;␊ |
255 | ␊ |
256 | ␉␉␉struct dirstuff* cacheDir = opendir(kDefaultCachePathSnow);␊ |
257 | ␊ |
258 | ␉␉␉while(readdir(cacheDir, (const char**)&name, &flags, &time) >= 0)␊ |
259 | ␉␉␉{␊ |
260 | ␉␉␉␉if (((flags & kFileTypeMask) != kFileTypeDirectory) && time > prev_time␊ |
261 | ␉␉␉␉␉&& strstr(name, kernelCacheFile) && (name[lnam] != '.'))␊ |
262 | ␉␉␉␉{␊ |
263 | ␉␉␉␉␉sprintf(kernelCacheFile, "%s%s", kDefaultCachePathSnow, name);␊ |
264 | ␉␉␉␉␉prev_time = time;␊ |
265 | ␉␉␉␉}␊ |
266 | ␉␉␉}␊ |
267 | ␉␉}␊ |
268 | ␉␉else {␊ |
269 | ␉␉␉// Reset cache name.␊ |
270 | ␉␉␉bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);␊ |
271 | ␉␉␉sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);␊ |
272 | ␉␉␉adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));␊ |
273 | ␉␉␉sprintf(kernelCacheFile, "%s.%08lX", kDefaultCachePathLeo, adler32);␊ |
274 | ␉␉}␊ |
275 | ␉}␊ |
276 | ␊ |
277 | ␉// Check if the kernel cache file exists␊ |
278 | ␉ret = -1;␊ |
279 | ␊ |
280 | ␉// If boot from a boot helper partition check the kernel cache file on it␊ |
281 | ␉if (gBootVolume->flags & kBVFlagBooter) {␊ |
282 | ␉␉sprintf(kernelCachePath, "com.apple.boot.P%s", kernelCacheFile);␊ |
283 | ␉␉ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);␊ |
284 | ␉␉if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))␊ |
285 | ␉␉{␊ |
286 | ␉␉␉sprintf(kernelCachePath, "com.apple.boot.R%s", kernelCacheFile);␊ |
287 | ␉␉␉ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);␊ |
288 | ␉␉␉if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))␊ |
289 | ␉␉␉{␊ |
290 | ␉␉␉␉sprintf(kernelCachePath, "com.apple.boot.S%s", kernelCacheFile);␊ |
291 | ␉␉␉␉ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);␊ |
292 | ␉␉␉␉if ((flags & kFileTypeMask) != kFileTypeFlat)␊ |
293 | ␉␉␉␉␉ret = -1;␊ |
294 | ␉␉␉}␊ |
295 | ␉␉}␊ |
296 | ␉}␊ |
297 | ␉// If not found, use the original kernel cache path.␊ |
298 | ␉if (ret == -1) {␊ |
299 | ␉␉strcpy(kernelCachePath, kernelCacheFile);␊ |
300 | ␉␉ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);␊ |
301 | ␉␉if ((flags & kFileTypeMask) != kFileTypeFlat)␊ |
302 | ␉␉␉ret = -1;␊ |
303 | ␉}␊ |
304 | ␊ |
305 | ␉// Exit if kernel cache file wasn't found␊ |
306 | ␉if (ret == -1) {␊ |
307 | ␉␉verbose("No Kernel Cache File '%s' found\n", kernelCacheFile);␊ |
308 | ␉␉return -1;␊ |
309 | ␉}␊ |
310 | ␊ |
311 | ␉// Check if the kernel cache file is more recent (mtime)␊ |
312 | ␉// than the kernel file or the S/L/E directory␊ |
313 | ␉ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);␊ |
314 | ␉// Check if the kernel file is more recent than the cache file␊ |
315 | ␉if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat)␊ |
316 | ␉␉&& (kerneltime > cachetime)) {␊ |
317 | ␉␉verbose("Kernel file (%s) is more recent than KernelCache (%s), ignoring KernelCache\n",␊ |
318 | ␉␉␉␉bootInfo->bootFile, kernelCacheFile);␊ |
319 | ␉␉return -1;␊ |
320 | ␉}␊ |
321 | ␊ |
322 | ␉ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);␊ |
323 | ␉// Check if the S/L/E directory time is more recent than the cache file␊ |
324 | ␉if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)␊ |
325 | ␉␉&& (exttime > cachetime)) {␊ |
326 | ␉␉verbose("/System/Library/Extensions is more recent than KernelCache (%s), ignoring KernelCache\n",␊ |
327 | ␉␉␉␉kernelCacheFile);␊ |
328 | ␉␉return -1;␊ |
329 | ␉}␊ |
330 | ␊ |
331 | ␉// Since the kernel cache file exists and is the most recent try to load it␊ |
332 | ␉verbose("Loading kernel cache %s\n", kernelCachePath);␊ |
333 | ␊ |
334 | ␉ret = LoadThinFatFile(kernelCachePath, binary);␊ |
335 | ␉return ret; // ret contain the length of the binary␊ |
336 | }␊ |
337 | ␊ |
338 | //==========================================================================␊ |
339 | // This is the entrypoint from real-mode which functions exactly as it did␊ |
340 | // before. Multiboot does its own runtime initialization, does some of its␊ |
341 | // own things, and then calls common_boot.␊ |
342 | void boot(int biosdev)␊ |
343 | {␊ |
344 | ␉initialize_runtime();␊ |
345 | ␉// Enable A20 gate before accessing memory above 1Mb.␊ |
346 | ␉enableA20();␊ |
347 | ␉common_boot(biosdev);␊ |
348 | }␊ |
349 | ␊ |
350 | //==========================================================================␊ |
351 | // The 'main' function for the booter. Called by boot0 when booting␊ |
352 | // from a block device, or by the network booter.␊ |
353 | //␊ |
354 | // arguments:␊ |
355 | //␉ biosdev - Value passed from boot1/NBP to specify the device␊ |
356 | //␉␉␉ that the booter was loaded from.␊ |
357 | //␊ |
358 | // If biosdev is kBIOSDevNetwork, then this function will return if␊ |
359 | // booting was unsuccessful. This allows the PXE firmware to try the␊ |
360 | // next boot device on its list.␊ |
361 | void common_boot(int biosdev)␊ |
362 | {␊ |
363 | ␉bool␉ ␉␉quiet;␊ |
364 | ␉bool␉ ␉␉firstRun = true;␊ |
365 | ␉bool␉ ␉␉instantMenu;␊ |
366 | ␉bool␉ ␉␉rescanPrompt;␊ |
367 | ␉int␉␉␉␉status;␊ |
368 | ␉unsigned int␉allowBVFlags = kBVFlagSystemVolume | kBVFlagForeignBoot;␊ |
369 | ␉unsigned int␉denyBVFlags = kBVFlagEFISystem;␊ |
370 | ␉␊ |
371 | ␉// Set reminder to unload the PXE base code. Neglect to unload␊ |
372 | ␉// the base code will result in a hang or kernel panic.␊ |
373 | ␉gUnloadPXEOnExit = true;␊ |
374 | ␉␊ |
375 | ␉// Record the device that the booter was loaded from.␊ |
376 | ␉gBIOSDev = biosdev & kBIOSDevMask;␊ |
377 | ␉␊ |
378 | ␉// Initialize boot info structure.␊ |
379 | ␉initKernBootStruct();␊ |
380 | ␉␊ |
381 | ␉initBooterLog();␊ |
382 | ␉␊ |
383 | ␉// Setup VGA text mode.␊ |
384 | ␉// Not sure if it is safe to call setVideoMode() before the␊ |
385 | ␉// config table has been loaded. Call video_mode() instead.␊ |
386 | #if DEBUG␊ |
387 | ␉printf("before video_mode\n");␊ |
388 | #endif␊ |
389 | ␉video_mode( 2 ); // 80x25 mono text mode.␊ |
390 | #if DEBUG␊ |
391 | ␉printf("after video_mode\n");␊ |
392 | #endif␊ |
393 | ␉␊ |
394 | ␉// Scan and record the system's hardware information.␊ |
395 | ␉scan_platform();␊ |
396 | ␉␊ |
397 | ␉// First get info for boot volume.␊ |
398 | ␉scanBootVolumes(gBIOSDev, 0);␊ |
399 | ␉bvChain = getBVChainForBIOSDev(gBIOSDev);␊ |
400 | ␉setBootGlobals(bvChain);␊ |
401 | ␉␊ |
402 | ␉// Load boot.plist config file␊ |
403 | ␉status = loadChameleonConfig(&bootInfo->chameleonConfig);␊ |
404 | ␉␊ |
405 | ␉if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->chameleonConfig) && quiet) {␊ |
406 | ␉␉gBootMode |= kBootModeQuiet;␊ |
407 | ␉}␊ |
408 | ␉␊ |
409 | ␉// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config␊ |
410 | ␉if (getBoolForKey(kInstantMenuKey, &instantMenu, &bootInfo->chameleonConfig) && instantMenu) {␊ |
411 | ␉␉firstRun = false;␊ |
412 | ␉}␊ |
413 | ␉␊ |
414 | ␉// Loading preboot ramdisk if exists.␊ |
415 | ␉loadPrebootRAMDisk();␊ |
416 | ␉␊ |
417 | ␉// Disable rescan option by default␊ |
418 | ␉gEnableCDROMRescan = false;␊ |
419 | ␉␊ |
420 | ␉// Enable it with Rescan=y in system config␊ |
421 | ␉if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->chameleonConfig)␊ |
422 | ␉␉&& gEnableCDROMRescan) {␊ |
423 | ␉␉gEnableCDROMRescan = true;␊ |
424 | ␉}␊ |
425 | ␉␊ |
426 | ␉// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.␊ |
427 | ␉rescanPrompt = false;␊ |
428 | ␉if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->chameleonConfig)␊ |
429 | ␉␉&& rescanPrompt && biosDevIsCDROM(gBIOSDev))␊ |
430 | ␉{␊ |
431 | ␉␉gEnableCDROMRescan = promptForRescanOption();␊ |
432 | ␉}␊ |
433 | ␉␊ |
434 | ␉// Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.␊ |
435 | ␉if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->chameleonConfig)␊ |
436 | ␉␉&& gScanSingleDrive) {␊ |
437 | ␉␉gScanSingleDrive = true;␊ |
438 | ␉}␊ |
439 | ␉␊ |
440 | ␉// Create a list of partitions on device(s).␊ |
441 | ␉if (gScanSingleDrive) {␊ |
442 | ␉␉scanBootVolumes(gBIOSDev, &bvCount);␊ |
443 | ␉} else {␊ |
444 | ␉␉scanDisks(gBIOSDev, &bvCount);␊ |
445 | ␉}␊ |
446 | ␉␊ |
447 | ␉// Create a separated bvr chain using the specified filters.␊ |
448 | ␉bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);␊ |
449 | ␉␊ |
450 | ␉gBootVolume = selectBootVolume(bvChain);␊ |
451 | ␉␊ |
452 | ␉// Intialize module system ␊ |
453 | ␉init_module_system();␊ |
454 | ␉␉␊ |
455 | #if DEBUG␊ |
456 | ␉printf(" Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n",␊ |
457 | ␉␉␉ gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);␊ |
458 | ␉printf(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n",␊ |
459 | ␉␉␉ gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);␊ |
460 | ␉getchar();␊ |
461 | #endif␊ |
462 | ␉␊ |
463 | ␉useGUI = true;␊ |
464 | ␉// Override useGUI default␊ |
465 | ␉getBoolForKey(kGUIKey, &useGUI, &bootInfo->chameleonConfig);␊ |
466 | ␉if (useGUI && initGUI())␊ |
467 | ␉{␊ |
468 | ␉␉// initGUI() returned with an error, disabling GUI.␊ |
469 | ␉␉useGUI = false;␊ |
470 | ␉}␊ |
471 | ␉␊ |
472 | ␉setBootGlobals(bvChain);␊ |
473 | ␉␊ |
474 | ␉// Parse args, load and start kernel.␊ |
475 | ␉while (1)␊ |
476 | ␉{␊ |
477 | ␉␉bool␉␉tryresume, tryresumedefault, forceresume;␊ |
478 | ␉␉bool␉␉useKernelCache = true; // by default try to use the prelinked kernel␊ |
479 | ␉␉const char␉*val;␊ |
480 | ␉␉int␉␉␉len, ret = -1;␊ |
481 | ␉␉long␉␉flags, sleeptime, time;␊ |
482 | ␉␉void␉␉*binary = (void *)kLoadAddr;␊ |
483 | ␉␉␊ |
484 | ␉␉char bootFile[sizeof(bootInfo->bootFile)];␊ |
485 | ␉␉char␉␉bootFilePath[512];␊ |
486 | ␉␉char␉␉kernelCacheFile[512];␊ |
487 | ␊ |
488 | ␉␉// Initialize globals.␊ |
489 | ␉␉sysConfigValid = false;␊ |
490 | ␉␉gErrors␉␉ = false;␊ |
491 | ␉␉␊ |
492 | ␉␉status = getBootOptions(firstRun);␊ |
493 | ␉␉firstRun = false;␊ |
494 | ␉␉if (status == -1) continue;␊ |
495 | ␉␉ ␊ |
496 | ␉␉status = processBootOptions();␊ |
497 | ␉␉// Status == 1 means to chainboot␊ |
498 | ␉␉if ( status ==␉1 ) break;␊ |
499 | ␉␉// Status == -1 means that the config file couldn't be loaded or that gBootVolume is NULL␊ |
500 | ␉␉if ( status == -1 )␊ |
501 | ␉␉{␊ |
502 | ␉␉␉// gBootVolume == NULL usually means the user hit escape.␊ |
503 | ␉␉␉if (gBootVolume == NULL)␊ |
504 | ␉␉␉{␊ |
505 | ␉␉␉␉freeFilteredBVChain(bvChain);␊ |
506 | ␉␉␉␉␊ |
507 | ␉␉␉␉if (gEnableCDROMRescan)␊ |
508 | ␉␉␉␉␉rescanBIOSDevice(gBIOSDev);␊ |
509 | ␉␉␉␉␊ |
510 | ␉␉␉␉bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);␊ |
511 | ␉␉␉␉setBootGlobals(bvChain);␊ |
512 | ␉␉␉␉setupDeviceList(&bootInfo->themeConfig);␊ |
513 | ␉␉␉}␊ |
514 | ␉␉␉continue;␊ |
515 | ␉␉}␊ |
516 | ␉␉␊ |
517 | ␉␉// Other status (e.g. 0) means that we should proceed with boot.␊ |
518 | ␉␉␊ |
519 | ␉␉// Turn off any GUI elements␊ |
520 | ␉␉if ( bootArgs->Video.v_display == GRAPHICS_MODE )␊ |
521 | ␉␉{␊ |
522 | ␉␉␉gui.devicelist.draw = false;␊ |
523 | ␉␉␉gui.bootprompt.draw = false;␊ |
524 | ␉␉␉gui.menu.draw = false;␊ |
525 | ␉␉␉gui.infobox.draw = false;␊ |
526 | ␉␉␉gui.logo.draw = false;␊ |
527 | ␉␉␉drawBackground();␊ |
528 | ␉␉␉updateVRAM();␊ |
529 | ␉␉}␊ |
530 | ␉␉␊ |
531 | ␉␉// Find out which version mac os we're booting.␊ |
532 | ␉␉getOSVersion();␊ |
533 | ␉␉␊ |
534 | ␉␉if (platformCPUFeature(CPU_FEATURE_EM64T)) {␊ |
535 | ␉␉␉archCpuType = CPU_TYPE_X86_64;␊ |
536 | ␉␉} else {␊ |
537 | ␉␉␉archCpuType = CPU_TYPE_I386;␊ |
538 | ␉␉}␊ |
539 | ␉␉␊ |
540 | ␉␉if (getValueForKey(karch, &val, &len, &bootInfo->chameleonConfig)) {␊ |
541 | ␉␉␉if (strncmp(val, "i386", 4) == 0) {␊ |
542 | ␉␉␉␉archCpuType = CPU_TYPE_I386;␊ |
543 | ␉␉␉}␊ |
544 | ␉␉}␊ |
545 | ␉␉␊ |
546 | ␉␉if (getValueForKey(kKernelArchKey, &val, &len, &bootInfo->chameleonConfig)) {␊ |
547 | ␉␉␉if (strncmp(val, "i386", 4) == 0) {␊ |
548 | ␉␉␉␉archCpuType = CPU_TYPE_I386;␊ |
549 | ␉␉␉}␊ |
550 | ␉␉}␊ |
551 | ␉␉␊ |
552 | ␉␉// Notify modules that we are attempting to boot␊ |
553 | ␉␉execute_hook("PreBoot", NULL, NULL, NULL, NULL);␊ |
554 | ␉␉␊ |
555 | ␉␉if (!getBoolForKey (kWake, &tryresume, &bootInfo->chameleonConfig)) {␊ |
556 | ␉␉␉tryresume = true;␊ |
557 | ␉␉␉tryresumedefault = true;␊ |
558 | ␉␉} else {␊ |
559 | ␉␉␉tryresumedefault = false;␊ |
560 | ␉␉}␊ |
561 | ␉␉␊ |
562 | ␉␉if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->chameleonConfig)) {␊ |
563 | ␉␉␉forceresume = false;␊ |
564 | ␉␉}␊ |
565 | ␉␉␊ |
566 | ␉␉if (forceresume) {␊ |
567 | ␉␉␉tryresume = true;␊ |
568 | ␉␉␉tryresumedefault = false;␊ |
569 | ␉␉}␊ |
570 | ␉␉␊ |
571 | ␉␉while (tryresume) {␊ |
572 | ␉␉␉const char *tmp;␊ |
573 | ␉␉␉BVRef bvr;␊ |
574 | ␉␉␉if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->chameleonConfig))␊ |
575 | ␉␉␉␉val = "/private/var/vm/sleepimage";␊ |
576 | ␉␉␉␊ |
577 | ␉␉␉// Do this first to be sure that root volume is mounted␊ |
578 | ␉␉␉ret = GetFileInfo(0, val, &flags, &sleeptime);␊ |
579 | ␉␉␉␊ |
580 | ␉␉␉if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)␊ |
581 | ␉␉␉␉break;␊ |
582 | ␉␉␉␊ |
583 | ␉␉␉// Can't check if it was hibernation Wake=y is required␊ |
584 | ␉␉␉if (bvr->modTime == 0 && tryresumedefault)␊ |
585 | ␉␉␉␉break;␊ |
586 | ␉␉␉␊ |
587 | ␉␉␉if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))␊ |
588 | ␉␉␉␉break;␊ |
589 | ␉␉␉␊ |
590 | ␉␉␉if (!forceresume && ((sleeptime+3)<bvr->modTime)) {␊ |
591 | #if DEBUG␉␊ |
592 | ␉␉␉␉printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",␊ |
593 | ␉␉␉␉␉␉bvr->modTime-sleeptime);␊ |
594 | #endif␉␉␉␉ ␊ |
595 | ␉␉␉␉break;␊ |
596 | ␉␉␉}␊ |
597 | ␉␉␉␊ |
598 | ␉␉␉HibernateBoot((char *)val);␊ |
599 | ␉␉␉break;␊ |
600 | ␉␉}␊ |
601 | ␉␉␊ |
602 | ␉␉verbose("Loading Darwin %s\n", gMacOSVersion);␊ |
603 | ␊ |
604 | ␉␉getBoolForKey(kUseKernelCache, &useKernelCache, &bootInfo->chameleonConfig);␊ |
605 | ␉␉if (useKernelCache) do {␊ |
606 | ␊ |
607 | ␉␉␉// Determine the name of the Kernel Cache␊ |
608 | ␉␉␉if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig)) {␊ |
609 | ␉␉␉␉if (val[0] == '\\')␊ |
610 | ␉␉␉␉{␊ |
611 | ␉␉␉␉␉len--;␊ |
612 | ␉␉␉␉␉val++;␊ |
613 | ␉␉␉␉}␊ |
614 | ␉␉␉␉strlcpy(kernelCacheFile, val, len + 1);␊ |
615 | ␉␉␉} else {␊ |
616 | ␉␉␉␉kernelCacheFile[0] = 0; // Use default kernel cache file␊ |
617 | ␉␉␉}␊ |
618 | ␊ |
619 | ␉␉␉if (gOverrideKernel && kernelCacheFile[0] == 0) {␊ |
620 | ␉␉␉␉verbose("Using a non default kernel (%s) without specifying 'Kernel Cache' path, KernelCache will not be used\n",␊ |
621 | ␉␉␉␉␉␉bootInfo->bootFile);␊ |
622 | ␉␉␉␉useKernelCache = false;␊ |
623 | ␉␉␉␉break;␊ |
624 | ␉␉␉}␊ |
625 | ␉␉␉if (gMKextName[0] != 0) {␊ |
626 | ␉␉␉␉verbose("Using a specific MKext Cache (%s), KernelCache will not be used\n",␊ |
627 | ␉␉␉␉␉␉gMKextName);␊ |
628 | ␉␉␉␉useKernelCache = false;␊ |
629 | ␉␉␉␉break;␊ |
630 | ␉␉␉}␊ |
631 | ␉␉␉if (gBootFileType != kBlockDeviceType)␊ |
632 | ␉␉␉␉useKernelCache = false;␊ |
633 | ␊ |
634 | ␉␉} while(0);␊ |
635 | ␉␉␊ |
636 | ␉␉do {␊ |
637 | ␉␉␉if (useKernelCache) {␊ |
638 | ␉␉␉␉ret = LoadKernelCache(kernelCacheFile, &binary);␊ |
639 | ␉␉␉␉if (ret >= 0)␊ |
640 | ␉␉␉␉␉break;␊ |
641 | ␉␉␉}␊ |
642 | ␊ |
643 | ␉␉␉bool bootFileWithDevice = false;␊ |
644 | ␉␉␉// Check if bootFile start with a device ex: bt(0,0)/Extra/mach_kernel␊ |
645 | ␉␉␉if (strncmp(bootInfo->bootFile,"bt(",3) == 0 ||␊ |
646 | ␉␉␉␉strncmp(bootInfo->bootFile,"hd(",3) == 0 ||␊ |
647 | ␉␉␉␉strncmp(bootInfo->bootFile,"rd(",3) == 0)␊ |
648 | ␉␉␉␉bootFileWithDevice = true;␊ |
649 | ␊ |
650 | ␉␉␉// bootFile must start with a / if it not start with a device name␊ |
651 | ␉␉␉if (!bootFileWithDevice && (bootInfo->bootFile)[0] != '/')␊ |
652 | ␉␉␉␉sprintf(bootFile, "/%s", bootInfo->bootFile); // append a leading /␊ |
653 | ␉␉␉else␊ |
654 | ␉␉␉␉strlcpy(bootFile, bootInfo->bootFile, sizeof(bootFile));␊ |
655 | ␊ |
656 | ␉␉␉// Try to load kernel image from alternate locations on boot helper partitions.␊ |
657 | ␉␉␉ret = -1;␊ |
658 | ␉␉␉if ((gBootVolume->flags & kBVFlagBooter) && !bootFileWithDevice) {␊ |
659 | ␉␉␉␉sprintf(bootFilePath, "com.apple.boot.P%s", bootFile);␊ |
660 | ␉␉␉␉ret = GetFileInfo(NULL, bootFilePath, &flags, &time);␊ |
661 | ␉␉␉␉if (ret == -1)␊ |
662 | ␉␉␉␉{␊ |
663 | ␉␉␉␉␉sprintf(bootFilePath, "com.apple.boot.R%s", bootFile);␊ |
664 | ␉␉␉␉␉ret = GetFileInfo(NULL, bootFilePath, &flags, &time);␊ |
665 | ␉␉␉␉␉if (ret == -1)␊ |
666 | ␉␉␉␉␉{␊ |
667 | ␉␉␉␉␉␉sprintf(bootFilePath, "com.apple.boot.S%s", bootFile);␊ |
668 | ␉␉␉␉␉␉ret = GetFileInfo(NULL, bootFilePath, &flags, &time);␊ |
669 | ␉␉␉␉␉}␊ |
670 | ␉␉␉␉}␊ |
671 | ␉␉␉}␊ |
672 | ␉␉␉if (ret == -1) {␊ |
673 | ␉␉␉␉// No alternate location found, using the original kernel image path.␊ |
674 | ␉␉␉␉strlcpy(bootFilePath, bootFile,sizeof(bootFilePath));␊ |
675 | ␉␉␉}␊ |
676 | ␉␉␉␊ |
677 | ␉␉␉verbose("Loading kernel %s\n", bootFilePath);␊ |
678 | ␉␉␉ret = LoadThinFatFile(bootFilePath, &binary);␊ |
679 | ␉␉␉if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)␊ |
680 | ␉␉␉{␊ |
681 | ␉␉␉␉archCpuType = CPU_TYPE_I386;␊ |
682 | ␉␉␉␉ret = LoadThinFatFile(bootFilePath, &binary);␊ |
683 | ␉␉␉}␊ |
684 | ␉␉} while (0);␊ |
685 | ␉␉␊ |
686 | ␉␉clearActivityIndicator();␊ |
687 | ␉␉␊ |
688 | #if DEBUG␊ |
689 | ␉␉printf("Pausing...");␊ |
690 | ␉␉sleep(8);␊ |
691 | #endif␊ |
692 | ␉␉␊ |
693 | ␉␉if (ret <= 0) {␊ |
694 | ␉␉␉printf("Can't find %s\n", bootFile);␊ |
695 | ␉␉␉sleep(1);␊ |
696 | ␉␉␉␊ |
697 | ␉␉␉if (gBootFileType == kNetworkDeviceType) {␊ |
698 | ␉␉␉␉// Return control back to PXE. Don't unload PXE base code.␊ |
699 | ␉␉␉␉gUnloadPXEOnExit = false;␊ |
700 | ␉␉␉␉break;␊ |
701 | ␉␉␉}␊ |
702 | ␉␉␉pause();␊ |
703 | ␊ |
704 | ␉␉} else {␊ |
705 | ␉␉␉/* Won't return if successful. */␊ |
706 | ␉␉␉ret = ExecKernel(binary);␊ |
707 | ␉␉}␊ |
708 | ␉}␊ |
709 | ␉␊ |
710 | ␉// chainboot␊ |
711 | ␉if (status == 1) {␊ |
712 | ␉␉// if we are already in graphics-mode,␊ |
713 | ␉␉if (getVideoMode() == GRAPHICS_MODE) {␊ |
714 | ␉␉␉setVideoMode(VGA_TEXT_MODE, 0); // switch back to text mode.␊ |
715 | ␉␉}␊ |
716 | ␉}␊ |
717 | ␉␊ |
718 | ␉if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {␊ |
719 | ␉␉nbpUnloadBaseCode();␊ |
720 | ␉}␊ |
721 | }␊ |
722 | ␊ |
723 | /*!␊ |
724 | ␉Selects a new BIOS device, taking care to update the global state appropriately.␊ |
725 | */␊ |
726 | /*␊ |
727 | static void selectBiosDevice(void)␊ |
728 | {␊ |
729 | ␉struct DiskBVMap *oldMap = diskResetBootVolumes(gBIOSDev);␊ |
730 | ␉CacheReset();␊ |
731 | ␉diskFreeMap(oldMap);␊ |
732 | ␉oldMap = NULL;␊ |
733 | ␉␊ |
734 | ␉int dev = selectAlternateBootDevice(gBIOSDev);␊ |
735 | ␉␊ |
736 | ␉BVRef bvchain = scanBootVolumes(dev, 0);␊ |
737 | ␉BVRef bootVol = selectBootVolume(bvchain);␊ |
738 | ␉gBootVolume = bootVol;␊ |
739 | ␉setRootVolume(bootVol);␊ |
740 | ␉gBIOSDev = dev;␊ |
741 | }␊ |
742 | */␊ |
743 | ␊ |
744 | bool checkOSVersion(const char * version) ␊ |
745 | {␊ |
746 | ␉return ((gMacOSVersion[0] == version[0]) && (gMacOSVersion[1] == version[1])␊ |
747 | ␉␉␉&& (gMacOSVersion[2] == version[2]) && (gMacOSVersion[3] == version[3]));␊ |
748 | }␊ |
749 | ␊ |
750 | static void getOSVersion()␊ |
751 | {␊ |
752 | ␉strlcpy(gMacOSVersion, gBootVolume->OSVersion, sizeof(gMacOSVersion));␊ |
753 | }␊ |
754 | ␊ |
755 | #define BASE 65521L /* largest prime smaller than 65536 */␊ |
756 | #define NMAX 5000␊ |
757 | // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1␊ |
758 | ␊ |
759 | #define DO1(buf, i)␉{s1 += buf[i]; s2 += s1;}␊ |
760 | #define DO2(buf, i)␉DO1(buf, i); DO1(buf, i + 1);␊ |
761 | #define DO4(buf, i)␉DO2(buf, i); DO2(buf, i + 2);␊ |
762 | #define DO8(buf, i)␉DO4(buf, i); DO4(buf, i + 4);␊ |
763 | #define DO16(buf)␉DO8(buf, 0); DO8(buf, 8);␊ |
764 | ␊ |
765 | unsigned long Adler32(unsigned char *buf, long len)␊ |
766 | {␊ |
767 | ␉unsigned long s1 = 1; // adler & 0xffff;␊ |
768 | ␉unsigned long s2 = 0; // (adler >> 16) & 0xffff;␊ |
769 | ␉unsigned long result;␊ |
770 | ␉int k;␊ |
771 | ␉␊ |
772 | ␉while (len > 0) {␊ |
773 | ␉␉k = len < NMAX ? len : NMAX;␊ |
774 | ␉␉len -= k;␊ |
775 | ␉␉while (k >= 16) {␊ |
776 | ␉␉␉DO16(buf);␊ |
777 | ␉␉␉buf += 16;␊ |
778 | ␉␉␉k -= 16;␊ |
779 | ␉␉}␊ |
780 | ␉␉if (k != 0) do {␊ |
781 | ␉␉␉s1 += *buf++;␊ |
782 | ␉␉␉s2 += s1;␊ |
783 | ␉␉} while (--k);␊ |
784 | ␉␉s1 %= BASE;␊ |
785 | ␉␉s2 %= BASE;␊ |
786 | ␉}␊ |
787 | ␉result = (s2 << 16) | s1;␊ |
788 | ␉return OSSwapHostToBigInt32(result);␊ |
789 | }␊ |
790 |