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 SECURITY_READ_ONLY_LATE(uint32_t) PE_esdm_fuses = 0;
57 SECURITY_READ_ONLY_LATE(uint32_t) PE_vmm_present = 0;
58
59 /* Clock Frequency Info */
60 clock_frequency_info_t gPEClockFrequencyInfo;
61
62 void *gPEEFISystemTable;
63 void *gPEEFIRuntimeServices;
64
65 static boot_icon_element* norootIcon_lzss;
66 static const uint8_t* norootClut_lzss;
67
68 int
PE_initialize_console(PE_Video * info,int op)69 PE_initialize_console( PE_Video * info, int op )
70 {
71 static int last_console = -1;
72
73 if (info) {
74 info->v_offset = 0;
75 info->v_length = 0;
76 info->v_display = GRAPHICS_MODE;
77 }
78
79 switch (op) {
80 case kPEDisableScreen:
81 initialize_screen(info, op);
82 kprintf("kPEDisableScreen %d\n", last_console);
83 if (!console_is_serial()) {
84 last_console = switch_to_serial_console();
85 }
86 break;
87
88 case kPEEnableScreen:
89 initialize_screen(info, op);
90 if (info) {
91 PE_state.video = *info;
92 }
93 kprintf("kPEEnableScreen %d\n", last_console);
94 if (last_console != -1) {
95 switch_to_old_console( last_console);
96 }
97 break;
98
99 case kPEBaseAddressChange:
100 if (info) {
101 PE_state.video = *info;
102 }
103 OS_FALLTHROUGH;
104
105 default:
106 initialize_screen(info, op);
107 break;
108 }
109
110 return 0;
111 }
112
113 void
PE_init_iokit(void)114 PE_init_iokit(void)
115 {
116 enum { kMaxBootVar = 128 };
117
118 boolean_t bootClutInitialized = FALSE;
119 boolean_t noroot_rle_Initialized = FALSE;
120
121 DTEntry entry;
122 unsigned int size;
123 uint32_t const *map;
124 boot_progress_element *bootPict;
125
126 norootIcon_lzss = NULL;
127 norootClut_lzss = NULL;
128
129 PE_init_printf(TRUE);
130
131 kprintf("Kernel boot args: '%s'\n", PE_boot_args());
132
133 /*
134 * Fetch the CLUT and the noroot image.
135 */
136
137 if (kSuccess == SecureDTLookupEntry(NULL, "/chosen/memory-map", &entry)) {
138 if (kSuccess == SecureDTGetProperty(entry, "BootCLUT", (void const **) &map, &size)) {
139 if (sizeof(appleClut8) <= map[1]) {
140 bcopy((void *)ml_static_ptovirt(map[0]), appleClut8, sizeof(appleClut8));
141 bootClutInitialized = TRUE;
142 }
143 }
144
145 if (kSuccess == SecureDTGetProperty(entry, "Pict-FailedBoot", (void const **) &map, &size)) {
146 bootPict = (boot_progress_element *) ml_static_ptovirt(map[0]);
147 default_noroot.width = bootPict->width;
148 default_noroot.height = bootPict->height;
149 default_noroot.dx = 0;
150 default_noroot.dy = bootPict->yOffset;
151 default_noroot_data = &bootPict->data[0];
152 noroot_rle_Initialized = TRUE;
153 }
154
155 if (kSuccess == SecureDTGetProperty(entry, "FailedCLUT", (void const **) &map, &size)) {
156 norootClut_lzss = (uint8_t*) ml_static_ptovirt(map[0]);
157 }
158
159 if (kSuccess == SecureDTGetProperty(entry, "FailedImage", (void const **) &map, &size)) {
160 norootIcon_lzss = (boot_icon_element *) ml_static_ptovirt(map[0]);
161 if (norootClut_lzss == NULL) {
162 printf("ERROR: No FailedCLUT provided for noroot icon!\n");
163 }
164 }
165 }
166
167 if (!bootClutInitialized) {
168 bcopy((void *) (uintptr_t) bootClut, (void *) appleClut8, sizeof(appleClut8));
169 }
170
171 if (!noroot_rle_Initialized) {
172 default_noroot.width = kFailedBootWidth;
173 default_noroot.height = kFailedBootHeight;
174 default_noroot.dx = 0;
175 default_noroot.dy = kFailedBootOffset;
176 default_noroot_data = failedBootPict;
177 }
178
179 /*
180 * Initialize the spinning wheel (progress indicator).
181 */
182 vc_progress_initialize(&default_progress,
183 default_progress_data1x,
184 default_progress_data2x,
185 default_progress_data3x,
186 (unsigned char *) appleClut8);
187
188 /*
189 * x86 only minimally enforces lockdown in hardware. Additionally, some pre-lockdown functionality
190 * such as commpage initialization requires IOKit enumeration of CPUs, which is heavily entangled
191 * with the ACPI stack. Therefore, we start the IOKit matching process immediately on x86.
192 */
193 InitIOKit(PE_state.deviceTreeHead);
194 zalloc_iokit_lockdown();
195 StartIOKitMatching();
196 }
197
198 void
PE_lockdown_iokit(void)199 PE_lockdown_iokit(void)
200 {
201 /* Ensure that at least the CPUs have been enumerated before moving forward. */
202 ml_wait_max_cpus();
203 }
204
205 void
PE_init_platform(boolean_t vm_initialized,void * _args)206 PE_init_platform(boolean_t vm_initialized, void * _args)
207 {
208 boot_args *args = (boot_args *)_args;
209
210 if (PE_state.initialized == FALSE) {
211 PE_state.initialized = TRUE;
212
213 // New EFI-style
214 PE_state.bootArgs = _args;
215 PE_state.deviceTreeHead = (void *) ml_static_ptovirt(args->deviceTreeP);
216 PE_state.deviceTreeSize = args->deviceTreeLength;
217 if (args->Video.v_baseAddr) {
218 PE_state.video.v_baseAddr = args->Video.v_baseAddr;// remains physical address
219 PE_state.video.v_rowBytes = args->Video.v_rowBytes;
220 PE_state.video.v_depth = args->Video.v_depth;
221 PE_state.video.v_display = args->Video.v_display;
222 PE_state.video.v_rotate = args->Video.v_rotate;
223
224 /* EFI doesn't have a good way of describing rotation internally,
225 * so it flips width and height in portrait mode. We flip it back. */
226 if (PE_state.video.v_rotate == kDataRotate90 ||
227 PE_state.video.v_rotate == kDataRotate270) {
228 PE_state.video.v_width = args->Video.v_height;
229 PE_state.video.v_height = args->Video.v_width;
230 } else {
231 PE_state.video.v_width = args->Video.v_width;
232 PE_state.video.v_height = args->Video.v_height;
233 }
234
235 strlcpy(PE_state.video.v_pixelFormat, "PPPPPPPP",
236 sizeof(PE_state.video.v_pixelFormat));
237 } else {
238 PE_state.video.v_baseAddr = args->VideoV1.v_baseAddr;// remains physical address
239 PE_state.video.v_rowBytes = args->VideoV1.v_rowBytes;
240 PE_state.video.v_width = args->VideoV1.v_width;
241 PE_state.video.v_height = args->VideoV1.v_height;
242 PE_state.video.v_depth = args->VideoV1.v_depth;
243 PE_state.video.v_display = args->VideoV1.v_display;
244 PE_state.video.v_rotate = kDataRotate0; /* no room for rotation info */
245 strlcpy(PE_state.video.v_pixelFormat, "PPPPPPPP",
246 sizeof(PE_state.video.v_pixelFormat));
247 }
248
249 #ifdef kBootArgsFlagHiDPI
250 if (args->flags & kBootArgsFlagHiDPI) {
251 PE_state.video.v_scale = kPEScaleFactor2x;
252 } else {
253 PE_state.video.v_scale = kPEScaleFactor1x;
254 }
255 #else
256 PE_state.video.v_scale = kPEScaleFactor1x;
257 #endif
258 }
259
260 if (!vm_initialized) {
261 if (PE_state.deviceTreeHead) {
262 SecureDTInit(PE_state.deviceTreeHead, PE_state.deviceTreeSize);
263 }
264
265 pe_identify_machine(args);
266 pe_init_debug();
267 }
268 }
269
270 void
PE_create_console(void)271 PE_create_console( void )
272 {
273 if (PE_state.video.v_display == GRAPHICS_MODE) {
274 PE_initialize_console( &PE_state.video, kPEGraphicsMode );
275 } else {
276 PE_initialize_console( &PE_state.video, kPETextMode );
277 }
278 }
279
280 int
PE_current_console(PE_Video * info)281 PE_current_console( PE_Video * info )
282 {
283 *info = PE_state.video;
284
285 return 0;
286 }
287
288 void
PE_display_icon(__unused unsigned int flags,__unused const char * name)289 PE_display_icon( __unused unsigned int flags, __unused const char * name )
290 {
291 if (norootIcon_lzss && norootClut_lzss) {
292 uint32_t width = norootIcon_lzss->width;
293 uint32_t height = norootIcon_lzss->height;
294 uint32_t x = ((PE_state.video.v_width - width) / 2);
295 uint32_t y = ((PE_state.video.v_height - height) / 2) + norootIcon_lzss->y_offset_from_center;
296
297 vc_display_lzss_icon(x, y, width, height,
298 &norootIcon_lzss->data[0],
299 norootIcon_lzss->data_size,
300 norootClut_lzss);
301 } else if (default_noroot_data) {
302 vc_display_icon( &default_noroot, default_noroot_data );
303 } else {
304 printf("ERROR: No data found for noroot icon!\n");
305 }
306 }
307
308 boolean_t
PE_get_hotkey(__unused unsigned char key)309 PE_get_hotkey(__unused unsigned char key)
310 {
311 return FALSE;
312 }
313
314 static timebase_callback_func gTimebaseCallback;
315
316 void
PE_register_timebase_callback(timebase_callback_func callback)317 PE_register_timebase_callback(timebase_callback_func callback)
318 {
319 gTimebaseCallback = callback;
320
321 PE_call_timebase_callback();
322 }
323
324 void
PE_call_timebase_callback(void)325 PE_call_timebase_callback(void)
326 {
327 struct timebase_freq_t timebase_freq;
328 unsigned long num, den, cnt;
329
330 num = gPEClockFrequencyInfo.bus_clock_rate_num * gPEClockFrequencyInfo.bus_to_dec_rate_num;
331 den = gPEClockFrequencyInfo.bus_clock_rate_den * gPEClockFrequencyInfo.bus_to_dec_rate_den;
332
333 cnt = 2;
334 while (cnt <= den) {
335 if ((num % cnt) || (den % cnt)) {
336 cnt++;
337 continue;
338 }
339
340 num /= cnt;
341 den /= cnt;
342 }
343
344 timebase_freq.timebase_num = num;
345 timebase_freq.timebase_den = den;
346
347 if (gTimebaseCallback) {
348 gTimebaseCallback(&timebase_freq);
349 }
350 }
351
352 /*
353 * The default (non-functional) PE_poll_input handler.
354 */
355 int
PE_stub_poll_input(__unused unsigned int options,char * c)356 PE_stub_poll_input(__unused unsigned int options, char * c)
357 {
358 *c = 0xff;
359 return 1; /* 0 for success, 1 for unsupported */
360 }
361
362 boolean_t
PE_reboot_on_panic(void)363 PE_reboot_on_panic(void)
364 {
365 boot_args *args = (boot_args *)PE_state.bootArgs;
366
367 if (args->flags & kBootArgsFlagRebootOnPanic) {
368 return TRUE;
369 } else {
370 return FALSE;
371 }
372 }
373
374 void
PE_sync_panic_buffers(void)375 PE_sync_panic_buffers(void)
376 {
377 }
378
379 /* rdar://problem/21244753 */
380 uint32_t
PE_i_can_has_debugger(uint32_t * debug_flags)381 PE_i_can_has_debugger(uint32_t *debug_flags)
382 {
383 #if DEVELOPMENT || DEBUG
384 if (debug_flags) {
385 assert(startup_phase >= STARTUP_SUB_TUNABLES);
386 }
387 #endif
388
389 #if CONFIG_CSR
390 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) != 0) {
391 if (debug_flags) {
392 *debug_flags = 0;
393 }
394 return FALSE;
395 }
396 #endif
397 if (debug_flags) {
398 *debug_flags = debug_boot_arg;
399 }
400 return TRUE;
401 }
402
403 uint32_t
PE_get_offset_into_panic_region(char * location)404 PE_get_offset_into_panic_region(char *location)
405 {
406 assert(panic_info != NULL);
407 assert(location > (char *) panic_info);
408
409 return (uint32_t) (location - (char *) panic_info);
410 }
411
412 void
PE_init_panicheader()413 PE_init_panicheader()
414 {
415 bzero(panic_info, offsetof(struct macos_panic_header, mph_data));
416 panic_info->mph_panic_log_offset = PE_get_offset_into_panic_region(debug_buf_base);
417
418 panic_info->mph_magic = MACOS_PANIC_MAGIC;
419 panic_info->mph_version = MACOS_PANIC_HEADER_CURRENT_VERSION;
420
421 return;
422 }
423
424 /*
425 * Tries to update the panic header to keep it consistent on nested panics.
426 *
427 * NOTE: The purpose of this function is NOT to detect/correct corruption in the panic region,
428 * it is to update the panic header to make it consistent when we nest panics.
429 *
430 * We try to avoid nested panics/asserts on x86 because they are difficult to debug, so log any
431 * inconsistencies we find.
432 */
433 void
PE_update_panicheader_nestedpanic()434 PE_update_panicheader_nestedpanic()
435 {
436 /*
437 * if the panic header pointer is bogus (e.g. someone stomped on it) then bail.
438 */
439 if (!panic_info) {
440 /* if this happens in development then blow up bigly */
441 assert(panic_info);
442 return;
443 }
444
445 /* If the panic log offset is not set, re-init the panic header */
446 if (panic_info->mph_panic_log_offset == 0) {
447 PE_init_panicheader();
448 panic_info->mph_panic_flags |= MACOS_PANIC_HEADER_FLAG_NESTED_PANIC;
449 return;
450 }
451
452 panic_info->mph_panic_flags |= MACOS_PANIC_HEADER_FLAG_NESTED_PANIC;
453
454 /* Usually indicative of corruption in the panic region */
455 if (!(((panic_info->mph_stackshot_offset == 0) && (panic_info->mph_stackshot_len == 0)) ||
456 ((panic_info->mph_stackshot_offset != 0) && (panic_info->mph_stackshot_len != 0)))) {
457 kdb_printf("panic_info contains invalid stackshot metadata: mph_stackshot_offset 0x%x mph_stackshot_len 0x%x\n",
458 panic_info->mph_stackshot_offset, panic_info->mph_stackshot_len);
459
460 panic_info->mph_panic_flags |= MACOS_PANIC_HEADER_FLAG_INCOHERENT_PANICLOG;
461 }
462
463 /*
464 * macOS panic logs contain nested panic data, if we've already closed the panic log,
465 * begin the other log.
466 */
467 if ((panic_info->mph_panic_log_len != 0) && (panic_info->mph_other_log_offset == 0)) {
468 panic_info->mph_other_log_offset = PE_get_offset_into_panic_region(debug_buf_ptr);
469
470 /* Usually indicative of corruption in the panic region */
471 if (panic_info->mph_other_log_len != 0) {
472 kdb_printf("panic_info contains invalid other log metadata (zero offset but non-zero length), length was 0x%x, zeroing value\n",
473 panic_info->mph_other_log_len);
474
475 panic_info->mph_other_log_len = 0;
476
477 panic_info->mph_panic_flags |= MACOS_PANIC_HEADER_FLAG_INCOHERENT_PANICLOG;
478 }
479 }
480
481 return;
482 }
483
484 vm_size_t
PE_init_socd_client(void)485 PE_init_socd_client(void)
486 {
487 /* not implemented */
488 return 0;
489 }
490
491 void
PE_read_socd_client_buffer(__unused vm_offset_t offset,__unused void * out_buff,__unused vm_size_t size)492 PE_read_socd_client_buffer(__unused vm_offset_t offset, __unused void *out_buff, __unused vm_size_t size)
493 {
494 /* not implemented */
495 }
496
497 void
PE_write_socd_client_buffer(__unused vm_offset_t offset,__unused const void * buff,__unused vm_size_t size)498 PE_write_socd_client_buffer(__unused vm_offset_t offset, __unused const void *buff, __unused vm_size_t size)
499 {
500 /* not implemented */
501 }
502