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 * ARM processor init
31 */
32
33#include <mach/mach_types.h>
34#include <arm/pmap.h>
35#include <arm/cpu_data.h>
36#include <pexpert/arm/boot.h>
37#include <pexpert/arm/protos.h>
38#include <arm/armops.h>
39#include <arm/misc_protos.h>
40#include <kern/startup.h>
41#include "proc_reg.h"
42
43int debug_task;
44
45extern uint8_t *irqstack;
46
47extern int disableConsoleOutput, serialmode;
48
49/**
50 * arm_processor_identify
51 *
52 * Print out information about the currently executing processor.
53 */
54void arm_processor_identify(void)
55{
56    get_cachetype_cp15();
57    identify_arm_cpu();
58}
59
60/**
61 * arm_init
62 *
63 * Initialize the core ARM subsystems, this routine is called from the
64 * boot loader. A basic identity mapping is created in __start, however,
65 * arm_vm_init will create new mappings.
66 */
67void arm_init(boot_args * args)
68{
69    cpu_data_t *bootProcessorData;
70    processor_t bootProcessor;
71    uint32_t baMaxMem;
72    uint64_t maxMem;
73    thread_t thread;
74
75    /*
76     * We are in.
77     */
78    PE_early_puts("arm_init: starting up\n");
79
80    /*
81     * arm_init is only called on processor #0, the others will enter using arm_slave_init.
82     */
83    bootProcessor = cpu_processor_alloc(TRUE);
84    if (!bootProcessor) {
85        panic("cpu_processor_alloc failed\n");
86    }
87
88    /*
89     * Pin the processor information to CPU #0.
90     */
91    PE_early_puts("arm_init: calling cpu_bootstrap\n");
92    cpu_bootstrap();
93
94    /*
95     * Initialize core processor data.
96     */
97    bootProcessorData = current_cpu_datap();
98
99    bootProcessorData->cpu_number = 0;
100    bootProcessorData->cpu_active_stack = (vm_offset_t)&irqstack;
101    bootProcessorData->cpu_phys_number = 0;
102    bootProcessorData->cpu_preemption_level = 1;
103    bootProcessorData->cpu_interrupt_level = 0;
104    bootProcessorData->cpu_running = 1;
105    bootProcessorData->cpu_pending_ast = AST_NONE;
106
107    /*
108     * Initialize the core thread subsystem (This sets up a template
109     * which will then be used to initialize the rest of the thread
110     * system later.)
111     *
112     * Additionally, this also sets the current kernel thread register
113     * to our bootstrap thread.
114     */
115    PE_early_puts("arm_init: calling thread_bootstrap\n");
116    thread_bootstrap();
117
118    /*
119     * CPU initialization.
120     */
121    PE_early_puts("arm_init: calling cpu_init\n");
122    cpu_init();
123
124    /*
125     * Mach processor bootstrap.
126     */
127    PE_early_puts("arm_init: calling processor_bootstrap\n");
128    processor_bootstrap();
129
130    /*
131     * Initialize the ARM platform expert.
132     */
133    PE_early_puts("arm_init: calling PE_init_platform\n");
134    PE_init_platform(FALSE, (void *) args);
135
136    /*
137     * Initialize kprintf, but no VM is running yet.
138     */
139    PE_init_kprintf(FALSE);
140
141    /*
142     * Set maximum memory size based on boot-args.
143     */
144    if (!PE_parse_boot_argn("maxmem", &baMaxMem, sizeof(baMaxMem)))
145        maxMem = 0;
146    else
147        maxMem = (uint64_t) baMaxMem *(1024 * 1024);
148
149    /*
150     * After this, we'll no longer be using physical mappings created by the bootloader.
151     */
152    arm_vm_init(maxMem, args);
153
154    /*
155     * Kernel early bootstrap.
156     */
157    kernel_early_bootstrap();
158
159    /*
160     * PE platform init.
161     */
162    PE_init_platform(TRUE, (void *) args);
163
164    /*
165     * Enable I+D cache.
166     */
167    char tempbuf[16];
168
169    if (PE_parse_boot_argn("-no-cache", tempbuf, sizeof(tempbuf))) {
170        kprintf("cache: No caching enabled (I+D).\n");
171    } else {
172        kprintf("cache: initializing i+dcache ... ");
173        cache_initialize();
174        kprintf("done\n");
175    }
176
177    /*
178     * Specify serial mode.
179     */
180    serialmode = 0;
181    if (PE_parse_boot_argn("serial", &serialmode, sizeof(serialmode))) {
182        /*
183         * We want a serial keyboard and/or console
184         */
185        kprintf("Serial mode specified: %08X\n", serialmode);
186    }
187
188    if (serialmode & 1) {
189        (void) switch_to_serial_console();
190        disableConsoleOutput = FALSE;   /* Allow printfs to happen */
191    }
192
193    /*
194     * Start system timers.
195     */
196    thread = current_thread();
197    thread->machine.preempt_count = 1;
198    thread->machine.cpu_data = cpu_datap(cpu_number());
199    thread->kernel_stack = irqstack;
200    timer_start(&thread->system_timer, mach_absolute_time());
201
202    /*
203     * Processor identification.
204     */
205    arm_processor_identify();
206
207    /*
208     * VFP/float initialization.
209     */
210    init_vfp();
211
212    /*
213     * Machine startup.
214     */
215    machine_startup();
216
217    /*
218     * If we return, something very bad is happening.
219     */
220    panic("20:02:14 <DHowett> wwwwwwwat is HAAAAAAAPPENING\n");
221
222    /*
223     * Last chance.
224     */
225    while (1) ;
226}
227