1/* 2 * arch/ubicom32/kernel/head.S 3 * <TODO: Replace with short file description> 4 * 5 * (C) Copyright 2009, Ubicom, Inc. 6 * 7 * This file is part of the Ubicom32 Linux Kernel Port. 8 * 9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute 10 * it and/or modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation, either version 2 of the 12 * License, or (at your option) any later version. 13 * 14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it 15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied 16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with the Ubicom32 Linux Kernel Port. If not, 21 * see <http://www.gnu.org/licenses/>. 22 * 23 * Ubicom32 implementation derived from (with many thanks): 24 * arch/m68knommu 25 * arch/blackfin 26 * arch/parisc 27 */ 28#include <linux/sys.h> 29#include <linux/linkage.h> 30#include <asm/asm-offsets.h> 31#include <asm/page_offset.h> 32#define __ASM__ 33#include <asm/ip5000.h> 34 35 36#define SRC_AN A3 37#define DST_AN A4 38 39#define PARAM_DN D0 40#define TMP_DN D15 41#define TMP2_DN D14 42 43/* 44 * The following code is placed at the start of the Linux section of memory. 45 * This is the primary entry point for Linux. 46 * 47 * However, we also want the syscall entry/exit code to be at a fixed address. 48 * So we take the primary entry point and reserve 16 bytes. That address is 49 * where the system_call entry point exists. This 16 bytes basically allows 50 * us to jump around the system_call entry point code to the actual startup 51 * code. 52 * 53 * Linux Memory Map (see vlinux.lds.S): 54 * 0x40400000 - Primary Entry Point for Linux (jump around code below). 55 * 0x40400010 - Old syscall Entry Point. 56 */ 57 58 .sect .skip_syscall, "ax", @progbits 59 .global __skip_syscall_section 60__skip_syscall_section: 61 moveai A3, #%hi(_start) 62 lea.1 A3, %lo(_start)(A3) 63 ret A3 64/* 65 * __os_node_offset contains the offset from KERNELBASE to the os_node, it is 66 * not intended to be used by anything except the boot code. 67 */ 68__os_node_offset: 69.long (_os_node - KERNELSTART) 70 71.text 72.global _start 73 74/* 75 * start() 76 * This is the start of the Linux kernel. 77 */ 78_start: 79 move.4 SCRATCHPAD1, #0 80 81 82/* 83 * Setup the range registers... the loader has setup a few, but we will go ahead 84 * and correct them for our own limits. Note that once set these are never 85 * changed again. The ranges are as follows 86 * 87 * D_RANGE0 - io block (set up by loaded) 88 * 89 * I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top 90 * of ram typically 0x3ffc0000 - 0x440000000 91 * I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches) 92 * typically 0x3FFC0030 - ~0x3FFC0200 93 * I_RANGE2 / D_RANGE2 - slab area 94 * typically 0x40A00000 - ~0x44000000 95 * I_RANGE3 96 * old system call interface if enabled. 97 * 98 * D_RANGE3, D_RANGE4 - unused. 99 */ 100 moveai SRC_AN, #%hi(PAGE_OFFSET_RAW) 101 lea.4 SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN) 102 move.4 D_RANGE1_LO, SRC_AN 103 move.4 I_RANGE0_LO, SRC_AN 104 105; don't try to calculate I_RANGE_HI, see below 106; moveai SRC_AN, #%hi(___init_end-4) 107; lea.4 SRC_AN, %lo(___init_end-4)(SRC_AN) 108; move.4 I_RANGE0_HI, SRC_AN 109 110 moveai SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4) 111 lea.4 SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN) 112 move.4 D_RANGE1_HI, SRC_AN 113 114; for now allow the whole ram to be executable as well so we don't run into problems 115; once we load user more code. 116 move.4 I_RANGE0_HI, SRC_AN 117 118#ifdef CONFIG_PROTECT_KERNEL 119; when kernel protection is enabled, we only open up syscall and non kernel text 120; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace. 121 122 ;; syscall range 123 moveai SRC_AN, #%hi(__syscall_text_run_begin) 124 lea.4 SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN) 125 move.4 I_RANGE1_LO, SRC_AN 126 moveai SRC_AN, #%hi(__syscall_text_run_end) 127 lea.4 SRC_AN, %lo(__syscall_text_run_end)(SRC_AN) 128 move.4 I_RANGE1_HI, SRC_AN 129 130 ;; slab instructions 131 moveai SRC_AN, #%hi(_edata) 132 lea.4 SRC_AN, %lo(_edata)(SRC_AN) 133 move.4 I_RANGE2_LO, SRC_AN 134 ;; End of DDR is already in range0 hi so just copy it. 135 move.4 I_RANGE2_HI, I_RANGE0_HI 136 137#ifdef CONFIG_OLD_40400010_SYSTEM_CALL 138 ;; create a small hole for old syscall location 139 moveai SRC_AN, #%hi(0x40400000) 140 lea.4 I_RANGE3_LO, 0x10(SRC_AN) 141 lea.4 I_RANGE3_HI, 0x14(SRC_AN) 142#endif 143 ;; slab data (same as slab instructions but starting a little earlier). 144 moveai SRC_AN, #%hi(_data_protection_end) 145 lea.4 SRC_AN, %lo(_data_protection_end)(SRC_AN) 146 move.4 D_RANGE2_LO, SRC_AN 147 move.4 D_RANGE2_HI, I_RANGE0_HI 148 149;; enable ranges 150 ;; skip I_RANGE0_EN 151 move.4 I_RANGE1_EN, #-1 152 move.4 I_RANGE2_EN, #-1 153#ifdef CONFIG_OLD_40400010_SYSTEM_CALL 154 move.4 I_RANGE3_EN, #-1 155#else 156 move.4 I_RANGE3_EN, #0 157#endif 158 ;; skip D_RANGE0_EN or D_RANGE1_EN 159 move.4 D_RANGE2_EN, #-1 160 move.4 D_RANGE3_EN, #0 161 move.4 D_RANGE4_EN, #0 162#endif 163 164; 165; If __ocm_free_begin is smaller than __ocm_free_end the 166; setup OCM text and data ram banks properly 167; 168 moveai DST_AN, #%hi(__ocm_free_begin) 169 lea.4 TMP_DN, %lo(__ocm_free_begin)(DST_AN) 170 moveai DST_AN, #%hi(__ocm_free_end) 171 lea.4 TMP2_DN, %lo(__ocm_free_end)(DST_AN) 172 sub.4 #0, TMP2_DN, TMP_DN 173 jmple.f 2f 174 moveai DST_AN, #%hi(__data_begin) 175 lea.4 TMP_DN, %lo(__data_begin)(DST_AN) 176 moveai DST_AN, #%hi(OCMSTART) 177 lea.4 TMP2_DN, %lo(OCMSTART)(DST_AN) 178 sub.4 TMP_DN, TMP_DN, TMP2_DN 179 lsr.4 TMP_DN, TMP_DN, #15 180 lsl.4 TMP_DN, #1, TMP_DN 181 moveai DST_AN, #%hi(OCMC_BASE) 182 add.4 OCMC_BANK_MASK(DST_AN), #-1, TMP_DN 183 pipe_flush 0 1842: 185; 186; Load .ocm_text 187; 188 moveai DST_AN, #%hi(__ocm_text_run_end) 189 lea.4 TMP_DN, %lo(__ocm_text_run_end)(DST_AN) 190 moveai DST_AN, #%hi(__ocm_text_run_begin) 191 lea.4 DST_AN, %lo(__ocm_text_run_begin)(DST_AN) 192 moveai SRC_AN, #%hi(__ocm_text_load_begin) 193 lea.4 SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN) 194 jmpt.t 2f 195 1961: move.4 (DST_AN)4++, (SRC_AN)4++ 197 1982: sub.4 #0, DST_AN, TMP_DN 199 jmpne.t 1b 200; 201; Load .syscall_text 202; 203 moveai DST_AN, #%hi(__syscall_text_run_end) 204 lea.4 TMP_DN, %lo(__syscall_text_run_end)(DST_AN) 205 moveai DST_AN, #%hi(__syscall_text_run_begin) 206 lea.4 DST_AN, %lo(__syscall_text_run_begin)(DST_AN) 207 moveai SRC_AN, #%hi(__syscall_text_load_begin) 208 lea.4 SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN) 209 jmpt.t 2f 210 2111: move.4 (DST_AN)4++, (SRC_AN)4++ 212 2132: sub.4 #0, DST_AN, TMP_DN 214 jmpne.t 1b 215 216; 217; Load .ocm_data 218; 219 moveai DST_AN, #%hi(__ocm_data_run_end) 220 lea.4 TMP_DN, %lo(__ocm_data_run_end)(DST_AN) 221 moveai DST_AN, #%hi(__ocm_data_run_begin) 222 lea.4 DST_AN, %lo(__ocm_data_run_begin)(DST_AN) 223 moveai SRC_AN, #%hi(__ocm_data_load_begin) 224 lea.4 SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN) 225 jmpt.t 2f 226 2271: move.4 (DST_AN)4++, (SRC_AN)4++ 228 2292: sub.4 #0, DST_AN, TMP_DN 230 jmpne.t 1b 231 232; Clear .bss 233; 234 moveai SRC_AN, #%hi(_ebss) 235 lea.4 TMP_DN, %lo(_ebss)(SRC_AN) 236 moveai DST_AN, #%hi(_sbss) 237 lea.4 DST_AN, %lo(_sbss)(DST_AN) 238 jmpt.t 2f 239 2401: move.4 (DST_AN)4++, #0 241 2422: sub.4 #0, DST_AN, TMP_DN 243 jmpne.t 1b 244 245; save our parameter to devtree (after clearing .bss) 246 moveai DST_AN, #%hi(devtree) 247 lea.4 DST_AN, %lo(devtree)(DST_AN) 248 move.4 (DST_AN), PARAM_DN 249 250 moveai sp, #%hi(init_thread_union) 251 lea.4 sp, %lo(init_thread_union)(sp) 252 movei TMP_DN, #ASM_THREAD_SIZE 253 add.4 sp, sp, TMP_DN 254 move.4 -4(sp)++, #0 ; nesting level = 0 255 move.4 -4(sp)++, #1 ; KERNEL_THREAD 256 257;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue 258;; or single step commands are issued. scratchpad3 is set to 0 when the 259;; debugger detaches from the board. 260 move.4 TMP_DN, scratchpad3 261 lsl.4 TMP_DN, TMP_DN, #0x0 262 jmpeq.f _jump_to_start_kernel 263_ok_to_set_break_points_in_linux: 264;; THREAD_STALL 265 move.4 mt_dbg_active_clr,#-1 266;; stalling the threads isn't instantaneous.. need to flush the pipe. 267 pipe_flush 0 268 pipe_flush 0 269 270_jump_to_start_kernel: 271 moveai SRC_AN, #%hi(start_kernel) 272 lea.4 SRC_AN, %lo(start_kernel)(SRC_AN) 273 ret SRC_AN 274