diff options
Diffstat (limited to 'libgloss/or1k/crt0.S')
-rw-r--r-- | libgloss/or1k/crt0.S | 600 |
1 files changed, 0 insertions, 600 deletions
diff --git a/libgloss/or1k/crt0.S b/libgloss/or1k/crt0.S deleted file mode 100644 index f1753d0d7..000000000 --- a/libgloss/or1k/crt0.S +++ /dev/null @@ -1,600 +0,0 @@ -/* crt0.S -- startup file for OpenRISC 1000. - * - * Copyright (c) 2011, 2014 Authors - * - * Contributor Julius Baxter <juliusbaxter@gmail.com> - * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de> - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. - */ - -/* -------------------------------------------------------------------------- */ -/* Coding convention: - Assembly is hard to read per se, so please follow the following coding - conventions to keep it consistent and ease reading: - * internal jump labels start with L, no identation - * assemble lines have one tab identation - * attributes (.section, .global, ..) are indented with one tab - * code is structured using tabs, i.e., use 'l.sw\t0(r1),r1' with a single - tab. libgloss assumes 8 space tab width, so that might look unstructured - with tab widths below 6. Nevertheless don't use spaces or two tabs. - * no space after comma - * use the defined macros if possible as they reduce errors - * use OR1K_INST with OR1K_DELAYED(_NOP) - * OR1K_DELAYED is multiline for better readability, the inner parts are - indented with another tab. - * COMMENT! Try to accompy every line with a meaningful comment. If possible - use pseudo code to describe the code. Also mention intentions and not only - the obvious things.. */ -/* -------------------------------------------------------------------------- */ - -#include "include/or1k-asm.h" -#include "include/or1k-sprs.h" - -/* -------------------------------------------------------------------------- */ -// Stack definitions -/* -------------------------------------------------------------------------- */ - -// Stacks -// Memory layout: -// +--------------------+ <- board_mem_base+board_mem_size/exception_stack_top -// | exception stack(s) | -// +--------------------+ <- stack_top -// | stack(s) | -// +--------------------+ <- stack_bottom -// | heap | -// +--------------------+ -// | text, data, bss.. | -// +--------------------+ - -// Reserved stack size -#define STACK_SIZE 8192 - -// Reserved stack size for exceptions (can usually be smaller than normal stack) -#define EXCEPTION_STACK_SIZE 8192 - -// Size of redzone + size of space required to store state -// This value must match that in the support library or1k_exception_handler -// function -#define EXCEPTION_STACK_FRAME (128+128) - - .extern _or1k_stack_top /* points to the next address after the stack */ - .extern _or1k_stack_bottom /* points to the last address in the stack */ - .extern _or1k_exception_stack_top - .extern _or1k_exception_stack_bottom - - .section .data - .global _or1k_stack_size /* reserved stack size */ - .global _or1k_exception_stack_size - -_or1k_stack_size: .word STACK_SIZE -_or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE - -#ifdef __OR1K_MULTICORE__ - .extern _or1k_stack_core - .extern _or1k_exception_stack_core -#endif - -#define SHADOW_REG(x) (OR1K_SPR_SYS_GPR_BASE + 32 + x) - -/* -------------------------------------------------------------------------- */ -/*!Macro to handle exceptions. - - Load NPC into r3, EPCR into r4 - */ -/* -------------------------------------------------------------------------- */ - -#define GPR_BUF_OFFSET(x) (x << 2) - -#ifndef __OR1K_MULTICORE__ -#define CALL_EXCEPTION_HANDLER \ - /* store current stack pointer to address 4 */ \ - l.sw 0x4(r0),r1; \ - /* Load top of the exception stack */ \ - l.movhi r1,hi(_or1k_exception_stack_top); \ - l.ori r1,r1,lo(_or1k_exception_stack_top); \ - l.lwz r1,0(r1); \ - /* Reserve red zone and context space */ \ - l.addi r1,r1,-EXCEPTION_STACK_FRAME; \ - /* Store GPR3 in context */ \ - l.sw GPR_BUF_OFFSET(3)(r1),r3; \ - /* Load back software's stack pointer */ \ - l.lwz r3,0x4(r0); \ - /* Store this in the context */ \ - l.sw GPR_BUF_OFFSET(1)(r1),r3; \ - /* Store GPR4 in the context */ \ - l.sw GPR_BUF_OFFSET(4)(r1),r4; \ - /* Copy the current program counter as first */ \ - /* argument for the exception handler. This */ \ - /* is then used to determine the exception. */ \ - l.mfspr r3,r0,OR1K_SPR_SYS_NPC_ADDR; \ - OR1K_DELAYED( \ - /* Copy program counter of exception as */ \ - /* second argument to the exception handler */ \ - OR1K_INST(l.mfspr r4,r0,OR1K_SPR_SYS_EPCR_BASE),\ - /* Jump to exception handler. This will rfe */ \ - OR1K_INST(l.j _or1k_exception_handler) \ - ) -#else -#define CALL_EXCEPTION_HANDLER \ - /* store current stack pointer to shadow reg */ \ - l.mtspr r0,r1,SHADOW_REG(1); \ - /* store current GPR3 as we need it */ \ - l.mtspr r0,r3,SHADOW_REG(2); \ - /* Load pointer to exception stack array */ \ - l.movhi r1,hi(_or1k_exception_stack_core); \ - l.ori r1,r1,lo(_or1k_exception_stack_core); \ - l.lwz r1,0(r1); \ - /* Get core id */ \ - l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR; \ - /* Calculate offset in array */ \ - l.slli r3,r3,2; \ - /* Load value from array to stack pointer */ \ - l.add r1,r1,r3; \ - l.lwz r1,0(r1); \ - /* Reserve red zone and context space */ \ - l.addi r1,r1,-EXCEPTION_STACK_FRAME; \ - /* Load back software's stack pointer */ \ - l.mfspr r3,r0,SHADOW_REG(1); \ - /* Store this in the context */ \ - l.sw GPR_BUF_OFFSET(1)(r1),r3; \ - /* Load back GPR3 */ \ - l.mfspr r3,r0,SHADOW_REG(2); \ - /* Store this in the context */ \ - l.sw GPR_BUF_OFFSET(3)(r1),r3; \ - /* Store GPR4 in the context */ \ - l.sw GPR_BUF_OFFSET(4)(r1),r4; \ - /* Copy the current program counter as first */ \ - /* argument for the exception handler. This */ \ - /* is then used to determine the exception. */ \ - l.mfspr r3,r0,OR1K_SPR_SYS_NPC_ADDR; \ - OR1K_DELAYED( \ - /* Copy program counter of exception as */ \ - /* second argument to the exception handler */ \ - OR1K_INST(l.mfspr r4,r0,OR1K_SPR_SYS_EPCR_BASE),\ - /* Jump to exception handler. This will rfe */ \ - OR1K_INST(l.j _or1k_exception_handler) \ - ) -#endif - -/* -------------------------------------------------------------------------- */ -/*!Exception vectors */ -/* -------------------------------------------------------------------------- */ - .section .vectors,"ax" - - /* 0x100: RESET exception */ - .org 0x100 -_or1k_reset: - l.movhi r0,0 -#ifdef __OR1K_MULTICORE__ - // This is a hack that relies on the fact, that all cores start at the - // same time and they are similarily fast - l.sw 0x4(r0),r0 - // Similarly, we use address 8 to signal how many cores have exit'ed - l.sw 0x8(r0),r0 -#endif - l.movhi r1,0 - l.movhi r2,0 - l.movhi r3,0 - l.movhi r4,0 - l.movhi r5,0 - l.movhi r6,0 - l.movhi r7,0 - l.movhi r8,0 - l.movhi r9,0 - l.movhi r10,0 - l.movhi r11,0 - l.movhi r12,0 - l.movhi r13,0 - l.movhi r14,0 - l.movhi r15,0 - l.movhi r16,0 - l.movhi r17,0 - l.movhi r18,0 - l.movhi r19,0 - l.movhi r20,0 - l.movhi r21,0 - l.movhi r22,0 - l.movhi r23,0 - l.movhi r24,0 - l.movhi r25,0 - l.movhi r26,0 - l.movhi r27,0 - l.movhi r28,0 - l.movhi r29,0 - l.movhi r30,0 - l.movhi r31,0 - - /* Clear status register, set supervisor mode */ - l.ori r1,r0,OR1K_SPR_SYS_SR_SM_MASK - l.mtspr r0,r1,OR1K_SPR_SYS_SR_ADDR - /* Clear timer mode register*/ - l.mtspr r0,r0,OR1K_SPR_TICK_TTMR_ADDR - /* Jump to program initialisation code */ - LOAD_SYMBOL_2_GPR(r4, _or1k_start) - OR1K_DELAYED_NOP(OR1K_INST(l.jr r4)) - - .org 0x200 - CALL_EXCEPTION_HANDLER - - /* 0x300: Data Page Fault exception */ - .org 0x300 - CALL_EXCEPTION_HANDLER - - /* 0x400: Insn Page Fault exception */ - .org 0x400 - CALL_EXCEPTION_HANDLER - - /* 0x500: Timer exception */ - .org 0x500 - CALL_EXCEPTION_HANDLER - - /* 0x600: Aligment exception */ - .org 0x600 - CALL_EXCEPTION_HANDLER - - /* 0x700: Illegal insn exception */ - .org 0x700 - CALL_EXCEPTION_HANDLER - - /* 0x800: External interrupt exception */ - .org 0x800 - CALL_EXCEPTION_HANDLER - - /* 0x900: DTLB miss exception */ - .org 0x900 - CALL_EXCEPTION_HANDLER - - /* 0xa00: ITLB miss exception */ - .org 0xa00 - CALL_EXCEPTION_HANDLER - - /* 0xb00: Range exception */ - .org 0xb00 - CALL_EXCEPTION_HANDLER - - /* 0xc00: Syscall exception */ - .org 0xc00 - CALL_EXCEPTION_HANDLER - - /* 0xd00: Floating point exception */ - .org 0xd00 - CALL_EXCEPTION_HANDLER - - /* 0xe00: Trap exception */ - .org 0xe00 - CALL_EXCEPTION_HANDLER - - /* 0xf00: Reserved exceptions */ - .org 0xf00 - CALL_EXCEPTION_HANDLER - - .org 0x1000 - CALL_EXCEPTION_HANDLER - - .org 0x1100 - CALL_EXCEPTION_HANDLER - - .org 0x1200 - CALL_EXCEPTION_HANDLER - - .org 0x1300 - CALL_EXCEPTION_HANDLER - - .org 0x1400 - CALL_EXCEPTION_HANDLER - - .org 0x1500 - CALL_EXCEPTION_HANDLER - - .org 0x1600 - CALL_EXCEPTION_HANDLER - - .org 0x1700 - CALL_EXCEPTION_HANDLER - - .org 0x1800 - CALL_EXCEPTION_HANDLER - - .org 0x1900 - CALL_EXCEPTION_HANDLER - - .org 0x1a00 - CALL_EXCEPTION_HANDLER - - .org 0x1b00 - CALL_EXCEPTION_HANDLER - - .org 0x1c00 - CALL_EXCEPTION_HANDLER - - .org 0x1d00 - CALL_EXCEPTION_HANDLER - - .org 0x1e00 - CALL_EXCEPTION_HANDLER - - .org 0x1f00 - CALL_EXCEPTION_HANDLER - - /* Pad to the end */ - .org 0x1ffc - l.nop - -/* -------------------------------------------------------------------------- */ -/*!Main entry point - - This is the initialization code of the library. It performs these steps: - - * Call early board initialization: - Before anything happened, the board support may do some very early - initialization. This is at maximum some very basic stuff that would - otherwise prevent the following code from functioning. Other initialization - of peripherals etc. is done later (before calling main). - See the description below and README.board for details. - - * Initialize the stacks: - Two stacks are configured: The system stack is used by the software and - the exception stack is used when an exception occurs. We added this as - this should be flexible with respect to the usage of virtual memory. - - * Activate the caches: - If available the caches are initiliazed and activated. - - * Clear BSS: - The BSS are essentially the uninitialized C variables. They are set to 0 - by default. This is performed by this function. - - * Initialize the impure data structure: - Similarly, we need two library contexts, one for the normal software and - one that is used during exceptions. The impure data structure holds - the context information of the library. The called C function will setup - both data structures. There is furthermore a pointer to the currently - active impure data structure, which is initially set to the normal one. - - * Initialize or1k support library reentrant data structures - - * Initialize constructors: - Call the static and global constructors - - * Set up destructors to call from exit - The library will call the function set via atexit() during exit(). We set - it to call the _fini function which performs destruction. - - * Call board initialization: - The board initialization can perform board specific initializations such as - configuring peripherals etc. - - * Jump to main - Call main with argc = 0 and *argv[] = 0 - - * Call exit after main returns - Now we call exit() - - * Loop forever - We are dead. -*/ - -/* -------------------------------------------------------------------------- */ - .section .text - - /* Following externs from board-specific object passed at link time */ - .extern _or1k_board_mem_base - .extern _or1k_board_mem_size - .extern _or1k_board_uart_base - - /* The early board initialization may for example read the memory size and - set the mem_base and mem_size or do some preliminary board - initialization. As we do not have a stack at this time, the function may - not use the stack (and therefore be a or call a C function. But it can - safely use all registers. - - We define a default implementation, which allows board files in C. As - described above, this can only be used in assembly (board_*.S) as at - the early stage not stack is available. A board that needs early - initialization can overwrite the function with .global _board_init_early. - - Recommendation: Only use when you really need it! */ - .weak _or1k_board_init_early -_or1k_board_init_early: - OR1K_DELAYED_NOP(OR1K_INST(l.jr r9)) - - /* The board initialization is then called after the C library and UART - are initialized. It can then be used to configure UART or other - devices before the actual main function is called. */ - .extern _or1k_board_init - - .global _or1k_start - .type _or1k_start,@function -_or1k_start: - /* It is good to initialize and enable the caches before we do anything, - otherwise the cores will continuously access the bus during the wait - time for the boot barrier (0x4). - Fortunately or1k_cache_init does not need a stack */ - OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_cache_init)) - -#ifdef __OR1K_MULTICORE__ - // All but core 0 have to wait - l.mfspr r1, r0, OR1K_SPR_SYS_COREID_ADDR - l.sfeq r1, r0 - OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lcore0)) -.Lspin: - /* r1 will be used by the other cores to check for the boot variable - Check if r1 is still zero, core 0 will set it to 1 once it booted - As the cache is already turned on, this will not create traffic on - the bus, but the change is snooped by cache coherency then */ - l.lwz r1,0x4(r0) - l.sfeq r1, r0 - OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lspin)) - - /* Initialize core i stack */ - // _or1k_stack_core is the array of stack pointers - LOAD_SYMBOL_2_GPR(r2,_or1k_stack_core) - // Load the base address - l.lwz r2,0(r2) - // Generate offset in array - l.mfspr r1,r0,OR1K_SPR_SYS_COREID_ADDR - l.slli r1,r1,2 - // Add to array base - l.add r2,r2,r1 - // Load pointer to the stack top and set frame pointer - l.lwz r1,0(r2) - l.or r2,r1,r1 - - // The slave cores are done, jump to main part - OR1K_DELAYED_NOP(OR1K_INST(l.j .Linit_done)); - - /* Only core 0 executes the initialization code */ -.Lcore0: -#endif - /* Call early board initialization */ - OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init_early)) - - /* Clear BSS */ -.Lclear_bss: - LOAD_SYMBOL_2_GPR(r3,__bss_start) - LOAD_SYMBOL_2_GPR(r4,end) - -.Lclear_bss_loop: - l.sw (0)(r3),r0 - l.sfltu r3,r4 - OR1K_DELAYED( - OR1K_INST(l.addi r3,r3,4), - OR1K_INST(l.bf .Lclear_bss_loop) - ) - - /* Initialise stack and frame pointer (set to same value) */ - LOAD_SYMBOL_2_GPR(r1,_or1k_board_mem_base) - l.lwz r1,0(r1) - LOAD_SYMBOL_2_GPR(r2,_or1k_board_mem_size) - l.lwz r2,0(r2) - l.add r1,r1,r2 - - /* Store exception stack top address */ - LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_top) - l.sw 0(r3),r1 - - /* Store exception stack bottom address */ - // calculate bottom address - // r3 = *exception stack size - LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_size) - // r3 = exception stack size - l.lwz r3,0(r3) -#ifdef __OR1K_MULTICORE__ - l.mfspr r4,r0,OR1K_SPR_SYS_NUMCORES_ADDR - l.mul r3,r4,r3 -#endif - // r4 = exception stack top - exception stack size = exception stack bottom - l.sub r4,r1,r3 - // r5 = *exception stack bottom - LOAD_SYMBOL_2_GPR(r5,_or1k_exception_stack_bottom) - // store - l.sw 0(r5),r4 - - // Move stack pointer accordingly - l.or r1,r0,r4 - l.or r2,r1,r1 - - /* Store stack top address */ - LOAD_SYMBOL_2_GPR(r3,_or1k_stack_top) - l.sw 0(r3),r1 - - /* Store stack bottom address */ - // calculate bottom address - // r3 = stack size - LOAD_SYMBOL_2_GPR(r3,_or1k_stack_size) - l.lwz r3,0(r3) -#ifdef __OR1K_MULTICORE__ - l.mfspr r4, r0, OR1K_SPR_SYS_NUMCORES_ADDR - l.mul r3, r4, r3 -#endif - // r4 = stack top - stack size = stack bottom - // -> stack bottom - l.sub r4,r1,r3 - // r5 = *exception stack bottom - LOAD_SYMBOL_2_GPR(r5,_or1k_stack_bottom) - // store to variable - l.sw 0(r5),r4 - - /* Reinitialize the or1k support library */ - OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_init)) - - /* Reinitialize the reentrancy structure */ - OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_libc_impure_init)) - - /* Call global and static constructors */ - OR1K_DELAYED_NOP(OR1K_INST(l.jal _init)) - - /* Set up destructors to be called from exit if main ever returns */ - l.movhi r3,hi(_fini) - OR1K_DELAYED( - OR1K_INST(l.ori r3,r3,lo(_fini)), - OR1K_INST(l.jal atexit) - ) - - /* Check if UART is to be initialised */ - LOAD_SYMBOL_2_GPR(r4,_or1k_board_uart_base) - l.lwz r4,0(r4) - /* Is base set? If not, no UART */ - l.sfne r4,r0 - l.bnf .Lskip_uart - l.or r3,r0,r0 - OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_uart_init)) - -.Lskip_uart: - /* Board initialization */ - OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init)) - -#ifdef __OR1K_MULTICORE__ - // Start other cores - l.ori r3, r0, 1 - l.sw 0x4(r0), r3 -#endif - -.Linit_done: - /* Jump to main program entry point (argc = argv = envp = 0) */ - l.or r3,r0,r0 - l.or r4,r0,r0 - OR1K_DELAYED( - OR1K_INST(l.or r5,r0,r0), - OR1K_INST(l.jal main) - ) - -#ifdef __OR1K_MULTICORE__ -.incrementexit: - /* Atomically increment number of finished cores */ - l.lwa r3,0x8(r0) - l.addi r3,r3,1 - l.swa 0x8(r0),r3 - OR1K_DELAYED_NOP(OR1K_INST(l.bnf .incrementexit)); - /* Compare to number of cores in this cluster */ - l.mfspr r4,r0, OR1K_SPR_SYS_NUMCORES_ADDR - /* Compare to number of finished tasks */ - l.sfeq r3,r4 - /* Last core needs to desctruct library etc. */ - OR1K_DELAYED_NOP(OR1K_INST(l.bf .exitcorelast)); - OR1K_DELAYED( - OR1K_INST(l.addi r3,r11,0), - OR1K_INST(l.jal _exit) - ) -.exitcorelast: -#endif - /* If program exits, call exit routine */ - OR1K_DELAYED( - OR1K_INST(l.addi r3,r11,0), - OR1K_INST(l.jal exit) - ) - - /* Loop forever */ -.Lloop_forever: - OR1K_DELAYED_NOP(OR1K_INST(l.j .Lloop_forever)) - - .size _or1k_start,.-_or1k_start |