1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2013 (c) Joyent, Inc. All rights reserved. 14 * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> 15 */ 16 17 #include <sys/asm_linkage.h> 18 #include <sys/machparam.h> 19 #include <sys/cpu_asm.h> 20 21 #include "assym.h" 22 23 /* 24 * Every story needs a beginning. This is ours. 25 */ 26 27 /* 28 * Each of the different machines has its own locore.s to take care of getting 29 * the machine specific setup done. Just before jumping into fakebop the 30 * first time, we call this machine specific code. 31 */ 32 33 /* 34 * We are in a primordial world here. The loader is going to come along and 35 * boot us at _start. As we've started the world, we also need to set up a 36 * few things about us, for example our stack pointer. To help us out, it's 37 * useful to remember what the loader set up for us: 38 * 39 * - unaligned access are allowed (A = 0, U = 1) 40 * - virtual memory is enabled 41 * - we (unix) are mapped right were we want to be 42 * - a UART has been enabled & any memory mapped registers have been 1:1 43 * mapped 44 * - ATAGs have been updated to tell us what the mappings are 45 * - I/D L1 caches have may be disabled 46 */ 47 48 /* 49 * External globals 50 */ 51 .globl _locore_start 52 .globl mlsetup 53 .globl sysp 54 .globl bootops 55 .globl bootopsp 56 .globl t0 57 58 .data 59 .comm t0stack, DEFAULTSTKSZ, 32 60 .comm t0, 4094, 32 61 62 63 /* 64 * Recall that _start is the traditional entry point for an ELF binary. 65 */ 66 ENTRY(_start) 67 ldr sp, =t0stack 68 ldr r4, =DEFAULTSTKSZ 69 add sp, r4 70 bic sp, sp, #0xff 71 72 /* 73 * establish bogus stacks for exceptional CPU states, our exception 74 * code should never make use of these, and we want loud and violent 75 * failure should we accidentally try. 76 */ 77 cps #(CPU_MODE_UND) 78 mov sp, #-1 79 cps #(CPU_MODE_ABT) 80 mov sp, #-1 81 cps #(CPU_MODE_FIQ) 82 mov sp, #-1 83 cps #(CPU_MODE_IRQ) 84 mov sp, #-1 85 cps #(CPU_MODE_SVC) 86 87 /* Enable highvecs (moves the base of the exception vector) */ 88 mrc p15, 0, r3, c1, c0, 0 89 orr r3, r3, #(1 << 13) 90 mcr p15, 0, r3, c1, c0, 0 91 92 /* 93 * Go ahead now and enable the L1 I/D caches. (Involves 94 * invalidating the caches and the TLB.) 95 */ 96 mov r4, #0 97 mov r5, #0 98 mcr p15, 0, r4, c7, c7, 0 /* invalidate caches */ 99 mcr p15, 0, r4, c8, c7, 0 /* invalidate tlb */ 100 mcr p15, 0, r5, c7, c10, 4 /* DSB */ 101 mrc p15, 0, r4, c1, c0, 0 102 orr r4, #0x04 /* D-cache */ 103 orr r4, #0x1000 /* I-cache */ 104 mcr p15, 0, r4, c1, c0, 0 105 106 /* invoke machine specific setup */ 107 bl _mach_start 108 109 bl _fakebop_start 110 SET_SIZE(_start) 111 112 113 #if defined(__lint) 114 115 /* ARGSUSED */ 116 void 117 _locore_start(struct boot_syscalls *sysp, struct bootops *bop) 118 {} 119 120 #else /* __lint */ 121 122 /* 123 * We got here from _kobj_init() via exitto(). We have a few different 124 * tasks that we need to take care of before we hop into mlsetup and 125 * then main. We're never going back so we shouldn't feel compelled to 126 * preserve any registers. 127 * 128 * o Save the boot syscalls and bootops for later 129 * o Set up our stack to be the real stack of t0stack. 130 * o Save t0 as curthread 131 * o Set up a struct REGS for mlsetup 132 * o Make sure that we're 8 byte aligned for the call 133 */ 134 135 ENTRY(_locore_start) 136 137 138 /* 139 * We've been running in t0stack anyway, up to this point, but 140 * _locore_start represents what is in effect a fresh start in the 141 * real kernel -- We'll never return back through here. 142 * 143 * So reclaim those few bytes 144 */ 145 ldr sp, =t0stack 146 ldr r4, =(DEFAULTSTKSZ - REGSIZE) 147 add sp, r4 148 bic sp, sp, #0xff 149 150 /* 151 * Save flags and arguments for potential debugging 152 */ 153 str r0, [sp, #REGOFF_R0] 154 str r1, [sp, #REGOFF_R1] 155 str r2, [sp, #REGOFF_R2] 156 str r3, [sp, #REGOFF_R3] 157 mrs r4, CPSR 158 str r4, [sp, #REGOFF_CPSR] 159 160 /* 161 * Save back the bootops and boot_syscalls. 162 */ 163 ldr r2, =sysp 164 str r0, [r2] 165 ldr r2, =bootops 166 str r1, [r2] 167 ldr r2, =bootopsp 168 ldr r2, [r2] 169 str r1, [r2] 170 171 /* 172 * Set up our curthread pointer 173 */ 174 ldr r0, =t0 175 mcr p15, 0, r0, c13, c0, 4 176 177 /* 178 * mlsetup() takes the struct regs as an argument. main doesn't take 179 * any and should never return. Currently, we have an 8-byte aligned 180 * stack. We want to push a zero frame pointer to terminate any 181 * stack walking, but that would cause us to end up with only a 182 * 4-byte aligned stack. So, to keep things nice and correct, we 183 * push a zero value twice - it's similar to a typical function 184 * entry: 185 * push { r9, lr } 186 */ 187 mov r9,#0 188 push { r9 } /* link register */ 189 push { r9 } /* frame pointer */ 190 mov r0, sp 191 bl mlsetup 192 bl main 193 /* NOTREACHED */ 194 ldr r0,=__return_from_main 195 ldr r0,[r0] 196 bl panic 197 SET_SIZE(_locore_start) 198 199 __return_from_main: 200 .string "main() returned" 201 #endif /* __lint */ 202 203 ENTRY(arm_reg_read) 204 ldr r0, [r0] 205 bx lr 206 SET_SIZE(arm_reg_read) 207 208 ENTRY(arm_reg_write) 209 str r1, [r0] 210 bx lr 211 SET_SIZE(arm_reg_write)