2b0ae7ea17e59bcedae06db235f991851f09f03d
[barrelfish] / kernel / arch / armv7-m / init.c
1 /*
2  * Copyright (c) 2009-2013, ETH Zurich. All rights reserved.
3  *
4  * This file is distributed under the terms in the attached LICENSE file.
5  * If you do not find this file, copies can be found by writing to:
6  * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
7  * Attn: Systems Group.
8  */
9
10 /**
11  * \file
12  * \brief cortex-m3 CPU driver init code for the OMAP44xx series SoCs.
13  */
14
15 #include <kernel.h>
16 #include <string.h>
17 #include <init.h>
18 #include <exceptions.h>
19 #include <exec.h>
20 #include <offsets.h>
21 #include <paging_kernel_arch.h>
22 #include <phys_mmap.h>
23 #include <serial.h>
24 #include <spinlock.h>
25 #include <stdio.h>
26 #include <arm_hal.h>
27 #include <getopt/getopt.h>
28 #include <elf/elf.h>
29 #include <barrelfish_kpi/arm_core_data.h>
30 #include <startup_arch.h>
31 #include <kernel_multiboot.h>
32 #include <global.h>
33 #include <start_aps.h> // AP_WAIT_*, AUX_CORE_BOOT_*  and friends
34
35 #include <omap44xx_map.h>
36 #include <dev/omap/omap44xx_id_dev.h>
37 #include <dev/omap/omap44xx_gpio_dev.h>
38
39 /// Round up n to the next multiple of size
40 #define ROUND_UP(n, size)           ((((n) + (size) - 1)) & (~((size) - 1)))
41
42 /**
43  * Used to store the address of global struct passed during boot across kernel
44  * relocations.
45  */
46 //static uint32_t addr_global;
47
48 /**
49  * \brief Kernel stack.
50  *
51  * This is the one and only kernel stack for a kernel instance.
52  */
53 uintptr_t kernel_stack[KERNEL_STACK_SIZE/sizeof(uintptr_t)]
54 __attribute__ ((aligned(8)));
55
56 #define MIN(a,b) ((a) < (b) ? (a) : (b))
57 #define MAX(a,b) ((a) > (b) ? (a) : (b))
58 #define CONSTRAIN(x, a, b) MIN(MAX(x, a), b)
59
60 //
61 // Kernel command line variables and binding options
62 //
63 //XXX: SysTick actually counts cycles, so time can at most be estimated
64 static int timeslice  = 5; //interval in ms in which the scheduler gets called
65
66 static struct cmdarg cmdargs[] = {
67     { "consolePort",    ArgType_UInt, { .uinteger = &serial_console_port}},
68     { "debugPort",      ArgType_UInt, { .uinteger = &serial_debug_port}},
69     { "loglevel",       ArgType_Int, { .integer = &kernel_loglevel }},
70     { "logmask",        ArgType_Int, { .integer = &kernel_log_subsystem_mask }},
71     { "timeslice",      ArgType_Int, { .integer = &timeslice }},
72     {NULL, 0, {NULL}}
73 };
74
75 static inline void __attribute__ ((always_inline))
76 relocate_stack(lvaddr_t offset)
77 {
78     __asm volatile (
79                     "add        sp, sp, %[offset]\n\t" ::[offset] "r" (offset)
80                     );
81 }
82
83 static inline void __attribute__ ((always_inline))
84 relocate_got_base(lvaddr_t offset)
85 {
86     __asm volatile (
87                     "add        r10, r10, %[offset]\n\t" ::[offset] "r" (offset)
88                     );
89 }
90
91
92 void kernel_startup_early(void)
93 {
94     const char *cmdline;
95     assert(glbl_core_data != NULL);
96     cmdline = MBADDR_ASSTRING(glbl_core_data->cmdline);
97     parse_commandline(cmdline, cmdargs);
98     timeslice = CONSTRAIN(timeslice, 1, 20);
99 }
100
101 /**
102  * \brief Continue kernel initialization in kernel address space.
103  *
104  * This function resets paging to map out low memory and map in physical
105  * address space, relocating all remaining data structures. It sets up exception handling,
106  * initializes devices and transitions into handler mode.
107  */
108 static void  __attribute__ ((noinline,noreturn)) text_init(void)
109 {
110     errval_t errval;
111
112     if ((glbl_core_data->multiboot_flags & MULTIBOOT_INFO_FLAG_HAS_MMAP)) {
113         // BSP core: set final page tables
114         struct arm_coredata_mmap *mmap = (struct arm_coredata_mmap *)
115             local_phys_to_mem(glbl_core_data->mmap_addr);
116         paging_arm_reset(mmap->base_addr, mmap->length);
117         //printf("paging_arm_reset: base: 0x%"PRIx64", length: 0x%"PRIx64".\n", mmap->base_addr, mmap->length);
118     } else {
119         // AP core
120         //  FIXME: Not sure what to do, so map the whole memory for now
121         paging_arm_reset(PHYS_MEMORY_START, 0x40000000);
122     }
123
124
125     //printf("startup_early\n");
126     kernel_startup_early();
127     //printf("kernel_startup_early done!\n");
128
129     //initialize console
130     serial_init(serial_console_port);
131     spinlock_init();
132
133     printf("Barrelfish CPU driver starting on ARMv7-M OMAP44xx"
134            " Board id 0x%08"PRIx32"\n", hal_get_board_id());
135     printf("The address of paging_map_kernel_section is %p\n",
136            paging_map_kernel_section);
137
138     errval = serial_debug_init();
139     if (err_is_fail(errval)) {
140             printf("Failed to initialize debug port: %d", serial_debug_port);
141     }
142
143     if (my_core_id != hal_get_cpu_id()) {
144         printf("** setting my_core_id (="PRIuCOREID") to match hal_get_cpu_id() (=%u)\n");
145         my_core_id = hal_get_cpu_id();
146     }
147
148     // Test MMU by remapping the device identifier and reading it using a
149     // virtual address
150     lpaddr_t id_code_section = OMAP44XX_MAP_L4_CFG_SYSCTRL_GENERAL_CORE & ~ARM_L1_SECTION_MASK;
151     lvaddr_t id_code_remapped = paging_map_device(id_code_section,
152                                                   ARM_L1_SECTION_BYTES);
153     omap44xx_id_t id;
154     omap44xx_id_initialize(&id, (mackerel_addr_t)(id_code_remapped +
155              (OMAP44XX_MAP_L4_CFG_SYSCTRL_GENERAL_CORE & ARM_L1_SECTION_MASK)));
156
157     char buf[200];
158     omap44xx_id_code_pr(buf,200,&id);
159     printf("Using MMU, %s", buf);
160
161     
162     nvic_init();
163     printf("nvic_init done\n");
164     //XXX: cachemarker: these counts are intended for no caching, adjust if we have caching
165     //systick_init(0xFFFFFF);//maximum value
166     //systick_init(0x0AC000);//absolute minimum for -O2: very little progress and much thrashing
167     systick_init(0x0C0000);//reasonable: many interrupts, no thrashing (with -O2)
168     printf("systick_init done\n");
169     
170
171     //transition into handler mode, will call text_init_continued
172     exceptions_early_init();
173     panic("exceptions_early_init has returned. this should never happen!");
174 }
175
176 /*
177  * \brief last bit of initialization before calling arm_kernel_startup()
178  *  called by a special exception handler -> we are now in handler mode
179  *  properly set up exceptions here
180  */
181 void  __attribute__ ((noinline,noreturn)) text_init_continued(void){
182     printf("entered text_init_continued - we are now in handler mode\n");
183     
184     //now all devices should have been mapped -> release the lock on their TLB entries
185     set_tlb_lock_basevalue(0);
186     
187     //now is probably the time to set up the vectortable?
188     printf("overwriting TLB mapping for page 0 (vectortable).\n");
189     printf("physical address of vectortable: 0x%x\n", (uint32_t) &vectortable);
190     add_tlb_mapping(0, (lpaddr_t) &vectortable, 1, 2);
191     printf("mapped vectortable page to address 0 in TLB.\n");
192     set_tlb_lock_basevalue(2);//XXX: hack, to make sure the already preserved entry in there stays preserved
193     //(entry 1 is a preserved mapping of the section containing the TLB flush code)
194     //XXX: cachemarker: as soon as caching is up, we can flush the TLB safely
195     // -> remove the preserved-bit for the entry with the flushing code on
196     
197     
198     exceptions_init();//set up proper exception handlers in the relocated vectortable
199     
200     printf("starting SysTick timer\n");
201     systick_start();
202     arm_kernel_startup();
203 }
204
205
206 /*
207  * Doesn't work yet on the second LED for some reason...
208  */
209 static void set_leds(void)
210 {
211     uint32_t r, nr;
212     omap44xx_gpio_t g;
213     //char buf[8001];
214
215     omap44xx_gpio_initialize(&g, (mackerel_addr_t)OMAP44XX_MAP_L4_WKUP_GPIO1);
216     // Output enable
217     r = omap44xx_gpio_oe_rd(&g) & (~(1<<8));
218     omap44xx_gpio_oe_wr(&g,r);
219     // Write data out
220     r = omap44xx_gpio_dataout_rd(&g);
221     nr = r  |(1<<8); 
222     for(int i = 0; i < 5; i++) {
223         omap44xx_gpio_dataout_wr(&g,r);
224         for(int j = 0; j < 2000; j++) { 
225             printf(".");
226         }
227         omap44xx_gpio_dataout_wr(&g,nr);
228         for(int j = 0; j < 2000; j++) { 
229             printf(".");
230         }
231     }
232     return;
233
234     omap44xx_gpio_initialize(&g, (mackerel_addr_t)OMAP44XX_MAP_L4_PER_GPIO4);
235
236     // Output enable
237     r = omap44xx_gpio_oe_rd(&g) & (~(1<<14));
238     omap44xx_gpio_oe_wr(&g,r);
239     // Write data out
240     r = omap44xx_gpio_dataout_rd(&g);
241     nr = r  |(1<<14); 
242     for(int i = 0; i < 100; i++) {
243         omap44xx_gpio_dataout_wr(&g,r);
244         for(int j = 0; j < 2000; j++) { 
245             printf(".");
246         }
247         omap44xx_gpio_dataout_wr(&g,nr);
248         for(int j = 0; j < 2000; j++) { 
249             printf(".");
250         }
251     }
252 }
253
254 /**
255  * Entry point called from boot.S for bootstrap processor.
256  * if is_bsp == true, then pointer points to multiboot_info
257  * else pointer points to a global struct
258  */
259 void arch_init(void *pointer)
260 {
261
262     serial_early_init(serial_console_port);
263     spinlock_early_init();//from here on we can safely use printf
264
265 #if 0 //XXX: HACK: we currently are seperate from the other cores, so we can not use
266         // either of the "normal" cases
267     if (hal_cpu_is_bsp()) {
268         struct multiboot_info *mb = pointer;
269
270         memset(glbl_core_data, 0, sizeof(struct arm_core_data));
271
272         size_t max_addr = max(multiboot_end_addr(mb), (uintptr_t)&kernel_final_byte);
273         glbl_core_data->start_free_ram = ROUND_UP(max_addr, BASE_PAGE_SIZE);
274         glbl_core_data->mods_addr = mb->mods_addr;
275         glbl_core_data->mods_count = mb->mods_count;
276         glbl_core_data->cmdline = mb->cmdline;
277         glbl_core_data->mmap_length = mb->mmap_length;
278         glbl_core_data->mmap_addr = mb->mmap_addr;
279         glbl_core_data->multiboot_flags = mb->flags;
280
281         memset(&global->locks, 0, sizeof(global->locks));
282     } else {
283         global = (struct global *)GLOBAL_VBASE;
284         // zeroing locks for the app core seems bogus to me --AKK
285         //memset(&global->locks, 0, sizeof(global->locks));
286
287         // our core data (struct arm_core_data) is placed one page before the
288         // first byte of the kernel image
289         glbl_core_data = (struct arm_core_data *)
290                             ((lpaddr_t)&kernel_first_byte - BASE_PAGE_SIZE);
291         glbl_core_data->cmdline = (lpaddr_t)&glbl_core_data->kernel_cmdline;
292         my_core_id = glbl_core_data->dst_core_id;
293
294         // tell BSP that we are started up
295         // See Section 27.4.4 in the OMAP44xx manual for how this should work.
296         // we do this early, to avoid having to map the registers
297         lpaddr_t aux_core_boot_0 = AUX_CORE_BOOT_0;
298         lpaddr_t ap_wait = AP_WAIT_PHYS;
299
300         *((volatile lvaddr_t *)aux_core_boot_0) = 2<<2;
301         //__sync_synchronize();
302         *((volatile lvaddr_t *)ap_wait) = AP_STARTED;
303
304     }
305 #else    
306     //XXX: HACK
307     //since the M3 currently thinks it is a bsp core, we do most of the bsp stuff
308     //exept for truly global variables
309     
310     //not sure what address to use for our core_data
311     glbl_core_data = (struct arm_core_data*)((lvaddr_t)&kernel_first_byte - BASE_PAGE_SIZE);
312     
313     memset(glbl_core_data, 0, sizeof(struct arm_core_data));
314        
315     struct multiboot_info *mb = (struct multiboot_info *)pointer;
316     
317         glbl_core_data->start_free_ram =
318                         ROUND_UP(max(multiboot_end_addr(mb), (uintptr_t)&kernel_final_byte),
319                                  BASE_PAGE_SIZE);
320
321     glbl_core_data->mods_addr = mb->mods_addr;
322     glbl_core_data->mods_count = mb->mods_count;
323     glbl_core_data->cmdline = mb->cmdline;
324     glbl_core_data->mmap_length = mb->mmap_length;
325     glbl_core_data->mmap_addr = mb->mmap_addr;
326     glbl_core_data->multiboot_flags = mb->flags;
327     
328 //    global = (struct global *)GLOBAL_VBASE;//we currently do not need global
329 #endif //0
330
331
332     // XXX: print kernel address for debugging with gdb
333     printf("Barrelfish OMAP44xx cortex-m3 CPU driver starting at addr 0x%"PRIxLVADDR"\n", 
334            local_phys_to_mem((uint32_t)&kernel_first_byte));
335
336
337     if (1) {
338         set_leds();
339     }
340
341     //we already are in a virtual address space, so we do not have to do MMU stuff already
342     text_init();
343 }