1/*
2 * Copyright 2013, winocm. <winocm@icloud.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 *   Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 *
11 *   Redistributions in binary form must reproduce the above copyright notice, this
12 *   list of conditions and the following disclaimer in the documentation and/or
13 *   other materials provided with the distribution.
14 *
15 *   If you are going to use this software in any form that does not involve
16 *   releasing the source to this project or improving it, let me know beforehand.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * Platform expert initialization module.
31 */
32
33#include <sys/types.h>
34#include <mach/vm_param.h>
35#include <machine/machine_routines.h>
36#include <pexpert/protos.h>
37#include <pexpert/pexpert.h>
38#include <pexpert/boot.h>
39#include <pexpert/device_tree.h>
40#include <pexpert/pe_images.h>
41#include <kern/sched_prim.h>
42#include <kern/debug.h>
43#include "boot_images.h"
44
45/* private globals */
46PE_state_t PE_state;
47
48char firmware_version[32];
49int pe_initialized = 0;
50
51extern uint32_t debug_enabled;
52extern void pe_identify_machine(void *args);
53
54boot_args *BootArgs;
55
56int PE_initialize_console( PE_Video * info, int op )
57{
58    static int   last_console = -1;
59
60    if (info) {
61    info->v_offset  = 0;
62    info->v_length  = 0;
63    info->v_display = GRAPHICS_MODE;
64    }
65
66    switch ( op ) {
67
68        case kPEDisableScreen:
69            initialize_screen(info, op);
70            kprintf("kPEDisableScreen %d\n", last_console);
71        if (!console_is_serial())
72        last_console = switch_to_serial_console();
73            break;
74
75        case kPEEnableScreen:
76            initialize_screen(info, op);
77            if (info) PE_state.video = *info;
78            kprintf("kPEEnableScreen %d\n", last_console);
79            if( last_console != -1)
80                switch_to_old_console( last_console);
81            break;
82
83        case kPEBaseAddressChange:
84            if (info) PE_state.video = *info;
85            /* fall thru */
86
87        default:
88            initialize_screen(info, op);
89            break;
90    }
91
92    return 0;
93}
94
95static void null_putc(int c)
96{
97    return;
98}
99
100/**
101 * PE_init_platform
102 *
103 * Initialize the platform expert for ARM.
104 */
105void PE_init_platform(boolean_t vm_initialized, void *_args)
106{
107    boot_args *args = (boot_args *) _args;
108
109    if (PE_state.initialized == FALSE) {
110        PE_early_puts("PE_init_platform: My name is Macintosh.\n");
111        PE_early_puts("PE_init_platform: Initializing for the first time.\n");
112
113        PE_state.initialized = TRUE;
114        PE_state.bootArgs = _args;
115        PE_state.deviceTreeHead = args->deviceTreeP;
116
117        PE_state.video.v_baseAddr = args->Video.v_baseAddr;
118        PE_state.video.v_rowBytes = args->Video.v_rowBytes;
119        PE_state.video.v_width = args->Video.v_width;
120        PE_state.video.v_height = args->Video.v_height;
121        PE_state.video.v_depth = args->Video.v_depth;
122        PE_state.video.v_display = args->Video.v_display;
123
124        strncpy(PE_state.video.v_pixelFormat, "PPPPPPPP", 8);
125
126        BootArgs = args;
127    }
128
129    if (!vm_initialized) {
130        /*
131         * Initialize the device tree crap.
132         */
133        PE_early_puts("PE_init_platform: Initializing device tree\n");
134        DTInit(PE_state.deviceTreeHead);
135
136        PE_early_puts("PE_init_platform: Calling pe_identify_machine\n");
137        pe_identify_machine(NULL);
138    } else {
139        DTEntry entry;
140        char *fversion, map;
141        unsigned int size;
142
143        pe_initialized = 1;
144
145        kprintf("PE_init_platform: It sure is great to get out of that bag.\n");
146        PE_init_SocSupport();
147
148        /*
149         * Reset kputc.
150         */
151        PE_kputc = gPESocDispatch.uart_putc;
152        unsigned int boot_arg;
153
154        if (PE_parse_boot_argn("kprintf", &boot_arg, sizeof(boot_arg)))
155            PE_kputc = cnputc;
156
157        if (PE_parse_boot_argn("silence_kprintf", &boot_arg, sizeof(boot_arg)))
158            PE_kputc = null_putc;
159
160        /*
161         * XXX: Real iOS kernel does iBoot/debug-enabled init after the DTInit call.
162         */
163        if (kSuccess == DTLookupEntry(NULL, "/chosen", &entry)) {
164            /*
165             * What's the iBoot version on this bad boy?
166             */
167            if (kSuccess == DTGetProperty(entry, "firmware-version", (void **) &fversion, &size)) {
168                if (fversion && (strlen(fversion) <= 32)) {
169                    ovbcopy((void *) fversion, (void *) firmware_version, strlen(fversion));
170                }
171            }
172            /*
173             * Is the SoC debug-enabled?
174             */
175            if (kSuccess == DTGetProperty(entry, "debug-enabled", (void **) &map, &size)) {
176                debug_enabled = 1;
177            }
178        }
179
180        pe_arm_init_interrupts(NULL);
181    }
182}
183
184/**
185 * PE_init_iokit
186 *
187 * Start IOKit and also set up the video console.
188 */
189void PE_init_iokit(void)
190{
191    enum { kMaxBootVar = 128 };
192
193    typedef struct {
194        char name[32];
195        unsigned long length;
196        unsigned long value[2];
197    } DriversPackageProp;
198
199    boolean_t bootClutInitialized = FALSE;
200    boolean_t norootInitialized = FALSE;
201
202    DTEntry entry;
203    unsigned int size;
204    uint32_t *map;
205    boot_progress_element *bootPict;
206
207    kprintf("Kernel boot args: '%s'\n", PE_boot_args());
208
209    /*
210     * Fetch the CLUT and the noroot image.
211     */
212    if (kSuccess == DTLookupEntry(NULL, "/chosen/memory-map", &entry)) {
213        if (kSuccess == DTGetProperty(entry, "BootCLUT", (void **) &map, &size)) {
214            if (sizeof(appleClut8) <= map[1]) {
215                bcopy((void *) (map[0]), appleClut8, sizeof(appleClut8));
216                bootClutInitialized = TRUE;
217            }
218        }
219    }
220
221    if (!bootClutInitialized) {
222        bcopy((void *) (uintptr_t) bootClut, (void *) appleClut8, sizeof(appleClut8));
223    }
224
225    if (!norootInitialized) {
226        default_noroot.width = kFailedBootWidth;
227        default_noroot.height = kFailedBootHeight;
228        default_noroot.dx = 0;
229        default_noroot.dy = kFailedBootOffset;
230        default_noroot_data = failedBootPict;
231    }
232
233    /*
234     * Initialize the panic UI
235     */
236    panic_ui_initialize((unsigned char *) appleClut8);
237
238    /*
239     * Initialize the spinning wheel (progress indicator).
240     */
241    vc_progress_initialize(&default_progress, default_progress_data1x, default_progress_data2x, (unsigned char *) appleClut8);
242
243    printf("iBoot version: %s\n", firmware_version);
244
245    kprintf("PE_init_iokit: starting IOKit now!\n");
246
247    PE_init_printf(TRUE);
248
249    StartIOKit(PE_state.deviceTreeHead, PE_state.bootArgs, (void *) 0, (void *) 0);
250}
251
252/**
253 * PE_current_console
254 *
255 * Get video console information
256 */
257int PE_current_console(PE_Video * info)
258{
259    *info = PE_state.video;
260
261    return 0;
262}
263
264/* Stub. */
265void PE_display_icon(__unused unsigned int flags, __unused const char *name)
266{
267    if (default_noroot_data)
268        vc_display_icon(&default_noroot, default_noroot_data);
269}
270
271boolean_t PE_reboot_on_panic(void)
272{
273    /*
274     * Enable reboot-on-panic
275     */
276    char tempbuf[16];
277
278    if (PE_parse_boot_argn("-panic-reboot", tempbuf, sizeof(tempbuf))) {
279        return TRUE;
280    } else {
281        return FALSE;
282    }
283}
284