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 been enabled
  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         mov     r4, #1
  90         lsl     r4, r4, #13
  91         orr     r3, r3, r4
  92         mcr     p15, 0, r3, c1, c0, 0
  93 
  94         /* invoke machine specific setup */
  95         bl      _mach_start
  96 
  97         bl      _fakebop_start
  98         SET_SIZE(_start)
  99 
 100 
 101 #if defined(__lint)
 102 
 103 /* ARGSUSED */
 104 void
 105 _locore_start(struct boot_syscalls *sysp, struct bootops *bop)
 106 {}
 107 
 108 #else   /* __lint */
 109 
 110         /*
 111          * We got here from _kobj_init() via exitto().  We have a few different
 112          * tasks that we need to take care of before we hop into mlsetup and
 113          * then main. We're never going back so we shouldn't feel compelled to
 114          * preserve any registers.
 115          *
 116          *  o Enable our I/D-caches
 117          *  o Save the boot syscalls and bootops for later
 118          *  o Set up our stack to be the real stack of t0stack.
 119          *  o Save t0 as curthread
 120          *  o Set up a struct REGS for mlsetup
 121          *  o Make sure that we're 8 byte aligned for the call
 122          */
 123 
 124         ENTRY(_locore_start)
 125 
 126 
 127         /*
 128          * We've been running in t0stack anyway, up to this point, but
 129          * _locore_start represents what is in effect a fresh start in the
 130          * real kernel -- We'll never return back through here.
 131          *
 132          * So reclaim those few bytes
 133          */
 134         ldr     sp, =t0stack
 135         ldr     r4, =(DEFAULTSTKSZ - REGSIZE)
 136         add     sp, r4
 137         bic     sp, sp, #0xff
 138 
 139         /*
 140          * Save flags and arguments for potential debugging
 141          */
 142         str     r0, [sp, #REGOFF_R0]
 143         str     r1, [sp, #REGOFF_R1]
 144         str     r2, [sp, #REGOFF_R2]
 145         str     r3, [sp, #REGOFF_R3]
 146         mrs     r4, CPSR
 147         str     r4, [sp, #REGOFF_CPSR]
 148 
 149         /*
 150          * Save back the bootops and boot_syscalls.
 151          */
 152         ldr     r2, =sysp
 153         str     r0, [r2]
 154         ldr     r2, =bootops
 155         str     r1, [r2]
 156         ldr     r2, =bootopsp
 157         ldr     r2, [r2]
 158         str     r1, [r2]
 159 
 160         /*
 161          * Set up our curthread pointer
 162          */
 163         ldr     r0, =t0
 164         mcr     p15, 0, r0, c13, c0, 4
 165 
 166         /*
 167          * Go ahead now and enable the L1 I/D caches.  
 168          */
 169         mrc     p15, 0, r0, c1, c0, 0
 170         orr     r0, #0x04       /* D-cache */
 171         orr     r0, #0x1000     /* I-cache */
 172         mcr     p15, 0, r0, c1, c0, 0
 173 
 174         /*
 175          * mlsetup() takes the struct regs as an argument. main doesn't take
 176          * any and should never return. Currently, we have an 8-byte aligned
 177          * stack.  We want to push a zero frame pointer to terminate any
 178          * stack walking, but that would cause us to end up with only a
 179          * 4-byte aligned stack.  So, to keep things nice and correct, we
 180          * push a zero value twice - it's similar to a typical function
 181          * entry:
 182          *      push { r9, lr }
 183          */
 184         mov     r9,#0
 185         push    { r9 }          /* link register */
 186         push    { r9 }          /* frame pointer */
 187         mov     r0, sp
 188         bl      mlsetup
 189         bl      main
 190         /* NOTREACHED */
 191         ldr     r0,=__return_from_main
 192         ldr     r0,[r0]
 193         bl      panic
 194         SET_SIZE(_locore_start)
 195 
 196 __return_from_main:
 197         .string "main() returned"
 198 #endif  /* __lint */
 199 
 200         ENTRY(arm_reg_read)
 201         ldr r0, [r0]
 202         bx lr
 203         SET_SIZE(arm_reg_read)
 204 
 205         ENTRY(arm_reg_write)
 206         str r1, [r0]
 207         bx lr
 208         SET_SIZE(arm_reg_write)