xref: /xnu-8019.80.24/pexpert/i386/pe_init.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * file: pe_init.c
30  *    i386 platform expert initialization.
31  */
32 
33 #include <console/video_console.h>
34 #include <sys/types.h>
35 #include <mach/vm_param.h>
36 #include <machine/machine_routines.h>
37 #include <pexpert/protos.h>
38 #include <pexpert/pexpert.h>
39 #include <pexpert/boot.h>
40 #include <pexpert/device_tree.h>
41 #include <pexpert/pe_images.h>
42 #include <kern/sched_prim.h>
43 #include <kern/debug.h>
44 
45 #if CONFIG_CSR
46 #include <sys/csr.h>
47 #endif
48 
49 #include "boot_images.h"
50 
51 /* extern references */
52 extern void pe_identify_machine(void * args);
53 extern int kdb_printf(const char *format, ...) __printflike(1, 2);
54 /* private globals */
55 PE_state_t  PE_state;
56 
57 /* Clock Frequency Info */
58 clock_frequency_info_t gPEClockFrequencyInfo;
59 
60 void *gPEEFISystemTable;
61 void *gPEEFIRuntimeServices;
62 
63 static boot_icon_element* norootIcon_lzss;
64 static const uint8_t*     norootClut_lzss;
65 
66 int
PE_initialize_console(PE_Video * info,int op)67 PE_initialize_console( PE_Video * info, int op )
68 {
69 	static int   last_console = -1;
70 
71 	if (info) {
72 		info->v_offset  = 0;
73 		info->v_length  = 0;
74 		info->v_display = GRAPHICS_MODE;
75 	}
76 
77 	switch (op) {
78 	case kPEDisableScreen:
79 		initialize_screen(info, op);
80 		kprintf("kPEDisableScreen %d\n", last_console);
81 		if (!console_is_serial()) {
82 			last_console = switch_to_serial_console();
83 		}
84 		break;
85 
86 	case kPEEnableScreen:
87 		initialize_screen(info, op);
88 		if (info) {
89 			PE_state.video = *info;
90 		}
91 		kprintf("kPEEnableScreen %d\n", last_console);
92 		if (last_console != -1) {
93 			switch_to_old_console( last_console);
94 		}
95 		break;
96 
97 	case kPEBaseAddressChange:
98 		if (info) {
99 			PE_state.video = *info;
100 		}
101 		OS_FALLTHROUGH;
102 
103 	default:
104 		initialize_screen(info, op);
105 		break;
106 	}
107 
108 	return 0;
109 }
110 
111 void
PE_init_iokit(void)112 PE_init_iokit(void)
113 {
114 	enum { kMaxBootVar = 128 };
115 
116 	boolean_t bootClutInitialized = FALSE;
117 	boolean_t noroot_rle_Initialized = FALSE;
118 
119 	DTEntry             entry;
120 	unsigned int        size;
121 	uint32_t const      *map;
122 	boot_progress_element *bootPict;
123 
124 	norootIcon_lzss = NULL;
125 	norootClut_lzss = NULL;
126 
127 	PE_init_printf(TRUE);
128 
129 	kprintf("Kernel boot args: '%s'\n", PE_boot_args());
130 
131 	/*
132 	 * Fetch the CLUT and the noroot image.
133 	 */
134 
135 	if (kSuccess == SecureDTLookupEntry(NULL, "/chosen/memory-map", &entry)) {
136 		if (kSuccess == SecureDTGetProperty(entry, "BootCLUT", (void const **) &map, &size)) {
137 			if (sizeof(appleClut8) <= map[1]) {
138 				bcopy((void *)ml_static_ptovirt(map[0]), appleClut8, sizeof(appleClut8));
139 				bootClutInitialized = TRUE;
140 			}
141 		}
142 
143 		if (kSuccess == SecureDTGetProperty(entry, "Pict-FailedBoot", (void const **) &map, &size)) {
144 			bootPict = (boot_progress_element *) ml_static_ptovirt(map[0]);
145 			default_noroot.width  = bootPict->width;
146 			default_noroot.height = bootPict->height;
147 			default_noroot.dx     = 0;
148 			default_noroot.dy     = bootPict->yOffset;
149 			default_noroot_data   = &bootPict->data[0];
150 			noroot_rle_Initialized = TRUE;
151 		}
152 
153 		if (kSuccess == SecureDTGetProperty(entry, "FailedCLUT", (void const **) &map, &size)) {
154 			norootClut_lzss = (uint8_t*) ml_static_ptovirt(map[0]);
155 		}
156 
157 		if (kSuccess == SecureDTGetProperty(entry, "FailedImage", (void const **) &map, &size)) {
158 			norootIcon_lzss = (boot_icon_element *) ml_static_ptovirt(map[0]);
159 			if (norootClut_lzss == NULL) {
160 				printf("ERROR: No FailedCLUT provided for noroot icon!\n");
161 			}
162 		}
163 	}
164 
165 	if (!bootClutInitialized) {
166 		bcopy((void *) (uintptr_t) bootClut, (void *) appleClut8, sizeof(appleClut8));
167 	}
168 
169 	if (!noroot_rle_Initialized) {
170 		default_noroot.width  = kFailedBootWidth;
171 		default_noroot.height = kFailedBootHeight;
172 		default_noroot.dx     = 0;
173 		default_noroot.dy     = kFailedBootOffset;
174 		default_noroot_data   = failedBootPict;
175 	}
176 
177 	/*
178 	 * Initialize the spinning wheel (progress indicator).
179 	 */
180 	vc_progress_initialize(&default_progress,
181 	    default_progress_data1x,
182 	    default_progress_data2x,
183 	    default_progress_data3x,
184 	    (unsigned char *) appleClut8);
185 
186 	/*
187 	 * x86 only minimally enforces lockdown in hardware.  Additionally, some pre-lockdown functionality
188 	 * such as commpage initialization requires IOKit enumeration of CPUs, which is heavily entangled
189 	 * with the ACPI stack.  Therefore, we start the IOKit matching process immediately on x86.
190 	 */
191 	InitIOKit(PE_state.deviceTreeHead);
192 	StartIOKitMatching();
193 }
194 
195 void
PE_lockdown_iokit(void)196 PE_lockdown_iokit(void)
197 {
198 	/* Ensure that at least the CPUs have been enumerated before moving forward. */
199 	ml_wait_max_cpus();
200 }
201 
202 void
PE_init_platform(boolean_t vm_initialized,void * _args)203 PE_init_platform(boolean_t vm_initialized, void * _args)
204 {
205 	boot_args *args = (boot_args *)_args;
206 
207 	if (PE_state.initialized == FALSE) {
208 		PE_state.initialized        = TRUE;
209 
210 		// New EFI-style
211 		PE_state.bootArgs           = _args;
212 		PE_state.deviceTreeHead     = (void *) ml_static_ptovirt(args->deviceTreeP);
213 		PE_state.deviceTreeSize     = args->deviceTreeLength;
214 		if (args->Video.v_baseAddr) {
215 			PE_state.video.v_baseAddr   = args->Video.v_baseAddr;// remains physical address
216 			PE_state.video.v_rowBytes   = args->Video.v_rowBytes;
217 			PE_state.video.v_depth      = args->Video.v_depth;
218 			PE_state.video.v_display    = args->Video.v_display;
219 			PE_state.video.v_rotate     = args->Video.v_rotate;
220 
221 			/* EFI doesn't have a good way of describing rotation internally,
222 			 * so it flips width and height in portrait mode. We flip it back. */
223 			if (PE_state.video.v_rotate == kDataRotate90 ||
224 			    PE_state.video.v_rotate == kDataRotate270) {
225 				PE_state.video.v_width  = args->Video.v_height;
226 				PE_state.video.v_height = args->Video.v_width;
227 			} else {
228 				PE_state.video.v_width  = args->Video.v_width;
229 				PE_state.video.v_height = args->Video.v_height;
230 			}
231 
232 			strlcpy(PE_state.video.v_pixelFormat, "PPPPPPPP",
233 			    sizeof(PE_state.video.v_pixelFormat));
234 		} else {
235 			PE_state.video.v_baseAddr   = args->VideoV1.v_baseAddr;// remains physical address
236 			PE_state.video.v_rowBytes   = args->VideoV1.v_rowBytes;
237 			PE_state.video.v_width      = args->VideoV1.v_width;
238 			PE_state.video.v_height     = args->VideoV1.v_height;
239 			PE_state.video.v_depth      = args->VideoV1.v_depth;
240 			PE_state.video.v_display    = args->VideoV1.v_display;
241 			PE_state.video.v_rotate     = kDataRotate0; /* no room for rotation info */
242 			strlcpy(PE_state.video.v_pixelFormat, "PPPPPPPP",
243 			    sizeof(PE_state.video.v_pixelFormat));
244 		}
245 
246 #ifdef  kBootArgsFlagHiDPI
247 		if (args->flags & kBootArgsFlagHiDPI) {
248 			PE_state.video.v_scale = kPEScaleFactor2x;
249 		} else {
250 			PE_state.video.v_scale = kPEScaleFactor1x;
251 		}
252 #else
253 		PE_state.video.v_scale = kPEScaleFactor1x;
254 #endif
255 	}
256 
257 	if (!vm_initialized) {
258 		if (PE_state.deviceTreeHead) {
259 			SecureDTInit(PE_state.deviceTreeHead, PE_state.deviceTreeSize);
260 		}
261 
262 		pe_identify_machine(args);
263 		pe_init_debug();
264 	}
265 }
266 
267 void
PE_create_console(void)268 PE_create_console( void )
269 {
270 	if (PE_state.video.v_display == GRAPHICS_MODE) {
271 		PE_initialize_console( &PE_state.video, kPEGraphicsMode );
272 	} else {
273 		PE_initialize_console( &PE_state.video, kPETextMode );
274 	}
275 }
276 
277 int
PE_current_console(PE_Video * info)278 PE_current_console( PE_Video * info )
279 {
280 	*info = PE_state.video;
281 
282 	return 0;
283 }
284 
285 void
PE_display_icon(__unused unsigned int flags,__unused const char * name)286 PE_display_icon( __unused unsigned int flags, __unused const char * name )
287 {
288 	if (norootIcon_lzss && norootClut_lzss) {
289 		uint32_t width  = norootIcon_lzss->width;
290 		uint32_t height = norootIcon_lzss->height;
291 		uint32_t x = ((PE_state.video.v_width  - width) / 2);
292 		uint32_t y = ((PE_state.video.v_height - height) / 2) + norootIcon_lzss->y_offset_from_center;
293 
294 		vc_display_lzss_icon(x, y, width, height,
295 		    &norootIcon_lzss->data[0],
296 		    norootIcon_lzss->data_size,
297 		    norootClut_lzss);
298 	} else if (default_noroot_data) {
299 		vc_display_icon( &default_noroot, default_noroot_data );
300 	} else {
301 		printf("ERROR: No data found for noroot icon!\n");
302 	}
303 }
304 
305 boolean_t
PE_get_hotkey(__unused unsigned char key)306 PE_get_hotkey(__unused unsigned char key)
307 {
308 	return FALSE;
309 }
310 
311 static timebase_callback_func gTimebaseCallback;
312 
313 void
PE_register_timebase_callback(timebase_callback_func callback)314 PE_register_timebase_callback(timebase_callback_func callback)
315 {
316 	gTimebaseCallback = callback;
317 
318 	PE_call_timebase_callback();
319 }
320 
321 void
PE_call_timebase_callback(void)322 PE_call_timebase_callback(void)
323 {
324 	struct timebase_freq_t timebase_freq;
325 	unsigned long          num, den, cnt;
326 
327 	num = gPEClockFrequencyInfo.bus_clock_rate_num * gPEClockFrequencyInfo.bus_to_dec_rate_num;
328 	den = gPEClockFrequencyInfo.bus_clock_rate_den * gPEClockFrequencyInfo.bus_to_dec_rate_den;
329 
330 	cnt = 2;
331 	while (cnt <= den) {
332 		if ((num % cnt) || (den % cnt)) {
333 			cnt++;
334 			continue;
335 		}
336 
337 		num /= cnt;
338 		den /= cnt;
339 	}
340 
341 	timebase_freq.timebase_num = num;
342 	timebase_freq.timebase_den = den;
343 
344 	if (gTimebaseCallback) {
345 		gTimebaseCallback(&timebase_freq);
346 	}
347 }
348 
349 /*
350  * The default (non-functional) PE_poll_input handler.
351  */
352 int
PE_stub_poll_input(__unused unsigned int options,char * c)353 PE_stub_poll_input(__unused unsigned int options, char * c)
354 {
355 	*c = 0xff;
356 	return 1; /* 0 for success, 1 for unsupported */
357 }
358 
359 boolean_t
PE_reboot_on_panic(void)360 PE_reboot_on_panic(void)
361 {
362 	boot_args *args = (boot_args *)PE_state.bootArgs;
363 
364 	if (args->flags & kBootArgsFlagRebootOnPanic) {
365 		return TRUE;
366 	} else {
367 		return FALSE;
368 	}
369 }
370 
371 void
PE_sync_panic_buffers(void)372 PE_sync_panic_buffers(void)
373 {
374 }
375 
376 /* rdar://problem/21244753 */
377 uint32_t
PE_i_can_has_debugger(uint32_t * debug_flags)378 PE_i_can_has_debugger(uint32_t *debug_flags)
379 {
380 #if DEVELOPMENT || DEBUG
381 	if (debug_flags) {
382 		assert(startup_phase >= STARTUP_SUB_TUNABLES);
383 	}
384 #endif
385 
386 #if CONFIG_CSR
387 	if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) != 0) {
388 		if (debug_flags) {
389 			*debug_flags = 0;
390 		}
391 		return FALSE;
392 	}
393 #endif
394 	if (debug_flags) {
395 		*debug_flags = debug_boot_arg;
396 	}
397 	return TRUE;
398 }
399 
400 uint32_t
PE_get_offset_into_panic_region(char * location)401 PE_get_offset_into_panic_region(char *location)
402 {
403 	assert(panic_info != NULL);
404 	assert(location > (char *) panic_info);
405 
406 	return (uint32_t) (location - (char *) panic_info);
407 }
408 
409 void
PE_init_panicheader()410 PE_init_panicheader()
411 {
412 	bzero(panic_info, offsetof(struct macos_panic_header, mph_data));
413 	panic_info->mph_panic_log_offset = PE_get_offset_into_panic_region(debug_buf_base);
414 
415 	panic_info->mph_magic = MACOS_PANIC_MAGIC;
416 	panic_info->mph_version = MACOS_PANIC_HEADER_CURRENT_VERSION;
417 
418 	return;
419 }
420 
421 /*
422  * Tries to update the panic header to keep it consistent on nested panics.
423  *
424  * NOTE: The purpose of this function is NOT to detect/correct corruption in the panic region,
425  *       it is to update the panic header to make it consistent when we nest panics.
426  *
427  * We try to avoid nested panics/asserts on x86 because they are difficult to debug, so log any
428  * inconsistencies we find.
429  */
430 void
PE_update_panicheader_nestedpanic()431 PE_update_panicheader_nestedpanic()
432 {
433 	/* If the panic log offset is not set, re-init the panic header */
434 	if (panic_info->mph_panic_log_offset == 0) {
435 		PE_init_panicheader();
436 		panic_info->mph_panic_flags |= MACOS_PANIC_HEADER_FLAG_NESTED_PANIC;
437 		return;
438 	}
439 
440 	panic_info->mph_panic_flags |= MACOS_PANIC_HEADER_FLAG_NESTED_PANIC;
441 
442 	/* Usually indicative of corruption in the panic region */
443 	if (!(((panic_info->mph_stackshot_offset == 0) && (panic_info->mph_stackshot_len == 0)) ||
444 	    ((panic_info->mph_stackshot_offset != 0) && (panic_info->mph_stackshot_len != 0)))) {
445 		kdb_printf("panic_info contains invalid stackshot metadata: mph_stackshot_offset 0x%x mph_stackshot_len 0x%x\n",
446 		    panic_info->mph_stackshot_offset, panic_info->mph_stackshot_len);
447 	}
448 
449 	/*
450 	 * macOS panic logs contain nested panic data, if we've already closed the panic log,
451 	 * begin the other log.
452 	 */
453 	if ((panic_info->mph_panic_log_len != 0) && (panic_info->mph_other_log_offset == 0)) {
454 		panic_info->mph_other_log_offset = PE_get_offset_into_panic_region(debug_buf_ptr);
455 
456 		/* Usually indicative of corruption in the panic region */
457 		if (panic_info->mph_other_log_len != 0) {
458 			kdb_printf("panic_info contains invalid other log metadata (zero offset but non-zero length), length was 0x%x, zeroing value\n",
459 			    panic_info->mph_other_log_len);
460 			panic_info->mph_other_log_len = 0;
461 		}
462 	}
463 
464 	return;
465 }
466 
467 vm_size_t
PE_init_socd_client(void)468 PE_init_socd_client(void)
469 {
470 	/* not implemented */
471 	return 0;
472 }
473 
474 void
PE_write_socd_client_buffer(__unused vm_offset_t offset,__unused const void * buff,__unused vm_size_t size)475 PE_write_socd_client_buffer(__unused vm_offset_t offset, __unused const void *buff, __unused vm_size_t size)
476 {
477 	/* not implemented */
478 }
479