diff options
Diffstat (limited to 'target/linux/ubicom32/files/arch/ubicom32/kernel/head.S')
-rw-r--r-- | target/linux/ubicom32/files/arch/ubicom32/kernel/head.S | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S new file mode 100644 index 000000000..0c60504af --- /dev/null +++ b/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S @@ -0,0 +1,273 @@ +/* + * arch/ubicom32/kernel/head.S + * <TODO: Replace with short file description> + * + * (C) Copyright 2009, Ubicom, Inc. + * + * This file is part of the Ubicom32 Linux Kernel Port. + * + * The Ubicom32 Linux Kernel Port is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * The Ubicom32 Linux Kernel Port is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Ubicom32 Linux Kernel Port. If not, + * see <http://www.gnu.org/licenses/>. + * + * Ubicom32 implementation derived from (with many thanks): + * arch/m68knommu + * arch/blackfin + * arch/parisc + */ +#include <linux/sys.h> +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/page_offset.h> +#define __ASM__ +#include <asm/ip5000.h> + + +#define SRC_AN A3 +#define DST_AN A4 + +#define PARAM_DN D0 +#define TMP_DN D15 +#define TMP2_DN D14 + +/* + * The following code is placed at the start of the Linux section of memory. + * This is the primary entry point for Linux. + * + * However, we also want the syscall entry/exit code to be at a fixed address. + * So we take the primary entry point and reserve 16 bytes. That address is + * where the system_call entry point exists. This 16 bytes basically allows + * us to jump around the system_call entry point code to the actual startup + * code. + * + * Linux Memory Map (see vlinux.lds.S): + * 0x40400000 - Primary Entry Point for Linux (jump around code below). + * 0x40400010 - Old syscall Entry Point. + */ + + .sect .skip_syscall, "ax", @progbits + .global __skip_syscall_section +__skip_syscall_section: + moveai A3, #%hi(_start) + lea.1 A3, %lo(_start)(A3) + ret A3 +/* + * __os_node_offset contains the offset from KERNELBASE to the os_node, it is + * not intended to be used by anything except the boot code. + */ +__os_node_offset: +.long (_os_node - KERNELSTART) + +.text +.global _start + +/* + * start() + * This is the start of the Linux kernel. + */ +_start: + move.4 SCRATCHPAD1, #0 + + +/* + * Setup the range registers... the loader has setup a few, but we will go ahead + * and correct them for our own limits. Note that once set these are never + * changed again. The ranges are as follows + * + * D_RANGE0 - io block (set up by loaded) + * + * I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top + * of ram typically 0x3ffc0000 - 0x440000000 + * I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches) + * typically 0x3FFC0030 - ~0x3FFC0200 + * I_RANGE2 / D_RANGE2 - slab area + * typically 0x40A00000 - ~0x44000000 + * I_RANGE3 + * old system call interface if enabled. + * + * D_RANGE3, D_RANGE4 - unused. + */ + moveai SRC_AN, #%hi(PAGE_OFFSET_RAW) + lea.4 SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN) + move.4 D_RANGE1_LO, SRC_AN + move.4 I_RANGE0_LO, SRC_AN + +; don't try to calculate I_RANGE_HI, see below +; moveai SRC_AN, #%hi(___init_end-4) +; lea.4 SRC_AN, %lo(___init_end-4)(SRC_AN) +; move.4 I_RANGE0_HI, SRC_AN + + moveai SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4) + lea.4 SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN) + move.4 D_RANGE1_HI, SRC_AN + +; for now allow the whole ram to be executable as well so we don't run into problems +; once we load user more code. + move.4 I_RANGE0_HI, SRC_AN + +#ifdef CONFIG_PROTECT_KERNEL +; when kernel protection is enabled, we only open up syscall and non kernel text +; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace. + + ;; syscall range + moveai SRC_AN, #%hi(__syscall_text_run_begin) + lea.4 SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN) + move.4 I_RANGE1_LO, SRC_AN + moveai SRC_AN, #%hi(__syscall_text_run_end) + lea.4 SRC_AN, %lo(__syscall_text_run_end)(SRC_AN) + move.4 I_RANGE1_HI, SRC_AN + + ;; slab instructions + moveai SRC_AN, #%hi(_edata) + lea.4 SRC_AN, %lo(_edata)(SRC_AN) + move.4 I_RANGE2_LO, SRC_AN + ;; End of DDR is already in range0 hi so just copy it. + move.4 I_RANGE2_HI, I_RANGE0_HI + +#ifdef CONFIG_OLD_40400010_SYSTEM_CALL + ;; create a small hole for old syscall location + moveai SRC_AN, #%hi(0x40400000) + lea.4 I_RANGE3_LO, 0x10(SRC_AN) + lea.4 I_RANGE3_HI, 0x14(SRC_AN) +#endif + ;; slab data (same as slab instructions but starting a little earlier). + moveai SRC_AN, #%hi(_data_protection_end) + lea.4 SRC_AN, %lo(_data_protection_end)(SRC_AN) + move.4 D_RANGE2_LO, SRC_AN + move.4 D_RANGE2_HI, I_RANGE0_HI + +;; enable ranges + ;; skip I_RANGE0_EN + move.4 I_RANGE1_EN, #-1 + move.4 I_RANGE2_EN, #-1 +#ifdef CONFIG_OLD_40400010_SYSTEM_CALL + move.4 I_RANGE3_EN, #-1 +#else + move.4 I_RANGE3_EN, #0 +#endif + ;; skip D_RANGE0_EN or D_RANGE1_EN + move.4 D_RANGE2_EN, #-1 + move.4 D_RANGE3_EN, #0 + move.4 D_RANGE4_EN, #0 +#endif + +; +; If __ocm_free_begin is smaller than __ocm_free_end the +; setup OCM text and data ram banks properly +; + moveai DST_AN, #%hi(__ocm_free_begin) + lea.4 TMP_DN, %lo(__ocm_free_begin)(DST_AN) + moveai DST_AN, #%hi(__ocm_free_end) + lea.4 TMP2_DN, %lo(__ocm_free_end)(DST_AN) + sub.4 #0, TMP2_DN, TMP_DN + jmple.f 2f + moveai DST_AN, #%hi(__data_begin) + lea.4 TMP_DN, %lo(__data_begin)(DST_AN) + moveai DST_AN, #%hi(OCMSTART) + lea.4 TMP2_DN, %lo(OCMSTART)(DST_AN) + sub.4 TMP_DN, TMP_DN, TMP2_DN + lsr.4 TMP_DN, TMP_DN, #15 + lsl.4 TMP_DN, #1, TMP_DN + moveai DST_AN, #%hi(OCMC_BASE) + add.4 OCMC_BANK_MASK(DST_AN), #-1, TMP_DN + pipe_flush 0 +2: +; +; Load .ocm_text +; + moveai DST_AN, #%hi(__ocm_text_run_end) + lea.4 TMP_DN, %lo(__ocm_text_run_end)(DST_AN) + moveai DST_AN, #%hi(__ocm_text_run_begin) + lea.4 DST_AN, %lo(__ocm_text_run_begin)(DST_AN) + moveai SRC_AN, #%hi(__ocm_text_load_begin) + lea.4 SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, (SRC_AN)4++ + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b +; +; Load .syscall_text +; + moveai DST_AN, #%hi(__syscall_text_run_end) + lea.4 TMP_DN, %lo(__syscall_text_run_end)(DST_AN) + moveai DST_AN, #%hi(__syscall_text_run_begin) + lea.4 DST_AN, %lo(__syscall_text_run_begin)(DST_AN) + moveai SRC_AN, #%hi(__syscall_text_load_begin) + lea.4 SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, (SRC_AN)4++ + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b + +; +; Load .ocm_data +; + moveai DST_AN, #%hi(__ocm_data_run_end) + lea.4 TMP_DN, %lo(__ocm_data_run_end)(DST_AN) + moveai DST_AN, #%hi(__ocm_data_run_begin) + lea.4 DST_AN, %lo(__ocm_data_run_begin)(DST_AN) + moveai SRC_AN, #%hi(__ocm_data_load_begin) + lea.4 SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, (SRC_AN)4++ + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b + +; Clear .bss +; + moveai SRC_AN, #%hi(_ebss) + lea.4 TMP_DN, %lo(_ebss)(SRC_AN) + moveai DST_AN, #%hi(_sbss) + lea.4 DST_AN, %lo(_sbss)(DST_AN) + jmpt.t 2f + +1: move.4 (DST_AN)4++, #0 + +2: sub.4 #0, DST_AN, TMP_DN + jmpne.t 1b + +; save our parameter to devtree (after clearing .bss) + moveai DST_AN, #%hi(devtree) + lea.4 DST_AN, %lo(devtree)(DST_AN) + move.4 (DST_AN), PARAM_DN + + moveai sp, #%hi(init_thread_union) + lea.4 sp, %lo(init_thread_union)(sp) + movei TMP_DN, #ASM_THREAD_SIZE + add.4 sp, sp, TMP_DN + move.4 -4(sp)++, #0 ; nesting level = 0 + move.4 -4(sp)++, #1 ; KERNEL_THREAD + +;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue +;; or single step commands are issued. scratchpad3 is set to 0 when the +;; debugger detaches from the board. + move.4 TMP_DN, scratchpad3 + lsl.4 TMP_DN, TMP_DN, #0x0 + jmpeq.f _jump_to_start_kernel +_ok_to_set_break_points_in_linux: +;; THREAD_STALL + move.4 mt_dbg_active_clr,#-1 +;; stalling the threads isn't instantaneous.. need to flush the pipe. + pipe_flush 0 + pipe_flush 0 + +_jump_to_start_kernel: + moveai SRC_AN, #%hi(start_kernel) + lea.4 SRC_AN, %lo(start_kernel)(SRC_AN) + ret SRC_AN |