This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, OR1K] libor1k


Hi again,

This patch is the libgloss' libor1k itself.

Bye,
Stefan
commit b7f3a25194d9384ee80d756b0a0abe903741e5f5
Author: Stefan Wallentowitz <stefan.wallentowitz@tum.de>
Date:   Thu Dec 11 16:48:03 2014 +0100

    OR1K: libgloss implementation
    
    This is the libgloss implementation for or1k/or1knd. It contains:
    
     * All necessary initialization functions as called from crt0
    
     * The generic exception and interrupt handler implementations
    
     * The syscalls required by newlib (i.e., write)
    
     * The or1k-support functions as described in the header. Those are
       low level functions to access the CPU state and to register
       exception/interrupt handler hooks
    
    libgloss/Changelog:
    	* or1k/Makefile.in: Add libor1k
    	* or1k/README: New file
    	* or1k/caches-asm.S: New file
    	* or1k/exceptions-asm.S: New file
    	* or1k/exceptions.c: New file
    	* or1k/impure.c: New file
    	* or1k/include/or1k-nop.h: New file
    	* or1k/include/or1k-support.h: New file
    	* or1k/interrupts-asm.S: New file
    	* or1k/interrupts.c: New file
    	* or1k/mmu-asm.S: New file
    	* or1k/or1k-internals.h: New file
    	* or1k/or1k_uart.c: New file
    	* or1k/or1k_uart.h: New file
    	* or1k/outbyte.S: New file
    	* or1k/sbrk.c: New file
    	* or1k/sync-asm.S: New file
    	* or1k/syscalls.c: New file
    	* or1k/timer.c: New file
    	* or1k/util.c: New file

diff --git a/libgloss/or1k/Makefile.in b/libgloss/or1k/Makefile.in
index cf6197a..59d385c 100644
--- a/libgloss/or1k/Makefile.in
+++ b/libgloss/or1k/Makefile.in
@@ -55,10 +55,29 @@ OBJCOPY = `if [ -f ${objroot}/../binutils/objcopy ] ; \
 	then echo ${objroot}/../binutils/objcopy ; \
 	else t='$(program_transform_name)'; echo objcopy | sed -e $$t ; fi`
 
+# object files needed
+COMMON_FILES = syscalls \
+	or1k_uart \
+	outbyte \
+	caches-asm \
+	exceptions \
+	exceptions-asm \
+	interrupts \
+	interrupts-asm \
+	mmu-asm \
+	timer \
+	sbrk \
+	impure \
+	util \
+	sync-asm
+
+LIBOR1K_FILES = $(COMMON_FILES)
+LIBOR1K_OBJS = $(addsuffix .o,$(LIBOR1K_FILES))
+
 GCC_LDFLAGS = `if [ -d ${objroot}/../gcc ] ; \
 	then echo -L${objroot}/../gcc ; fi`
 
-OUTPUTS = crt0.o
+OUTPUTS = libor1k.a crt0.o
 
 # Host specific makefile fragment comes in here.
 @host_makefile_frag@
@@ -70,6 +89,10 @@ all: ${OUTPUTS}
 # here's where we build the library for each target
 #
 
+libor1k.a: $(LIBOR1K_OBJS)
+	${AR} ${ARFLAGS} $@ $(LIBOR1K_OBJS)
+	${RANLIB} $@
+
 doc:
 
 clean mostlyclean:
diff --git a/libgloss/or1k/README b/libgloss/or1k/README
new file mode 100644
index 0000000..e9b0a20
--- /dev/null
+++ b/libgloss/or1k/README
@@ -0,0 +1,77 @@
+This document describes the internals of the port for OpenRISC
+1000. The API is documented in or1k-support.h as Doxygen comments.
+
+# Data Structures
+
++----------------+ 0x0
+|    vectors     |
++----------------+
+|  text,data,..  |
++----------------+
+|      bss       |
++----------------+
+|      heap      |
+|       vv       |
+|                |
+|       ^^       |
+|    stack(s)    |
++----------------+ _or1k_board_mem_base +
+		   _or1k_board_mem_size
+
+## Stack and Heap
+
+The stack is allocated at the end of available physical memory which
+is defined by each board as _or1k_board_mem_base and
+_or1k_board_mem_size. The _or1k_stack_top and _or1k_stack_bottom are
+determined by those variables and _or1k_stack_size (which may be
+overwritten in _or1k_board_init_early).
+
+A second stack for exceptions is allocated as we allow exceptions to
+be arbitrary complex and call C functions etc. It is not an option to
+re-use the current software stack as we want to be so generic, that
+this can also be a virtual memory stack at moment of exception. The
+exception starts below the normal software stack and is
+_or1k_exception_stack_size large.
+
+Multicore: For each core a stack and exception stack is allocated and
+the stack pointer set at boot. That is: sp(core0) = _or1k_stack_top,
+sp(core1) = _or1k_stack_top - _or1k_stack_size, etc.
+
+## _or1k_stack_core (multicore only)
+
+An array of pointers to the software stacks (size:
+4*or1k_numcores()). It is dynamically allocated from heap in or1k_init
+by calling sbrk(). The pointers contain the values for stack top
+pointers as described above. This variable is essentially used on boot
+of the slave cores to configure the stack register.
+
+## _or1k_exception_stack_core (multicore only)
+
+An array of pointers to the exception stacks (size:
+4*or1k_numcores()). It is allocated identical as the stack_core
+array. It is loaded whenever an exception occurs to start with a clean
+stack in the exception.
+
+## _or1k_exception_handler_table
+
+A table of function pointers to the handlers of the exceptions. The
+generic exception handler checks if an exception handler is registered
+and calls it. There are 30 exceptions defined (0x0 is not an exception
+vector and 0x100 is reset which is static). This array resides in BSS
+and is therefore initialized as 0 (no handler registered) after start.
+
+Multicore: As the number of course is not known at compile time, the
+variable is a pointer to and array of arrays (cores x 30) which is
+allocated in or1k_init() on heap (using sbrk).
+
+## _or1k_interrupt_handler_table and _or1k_interrupt_handler_table_data_ptr 
+
+The interrupt handlers are stored identical to to the exception handler table.
+
+## _or1k_reent
+
+The struct _or1k_reent contains formerly global data and allows for
+reentrancy. In the single core case, this is an allocated object,
+while it is a pointer to an array of structs in the multicore library.
+It is allocated in _or1k_reent_init() on the heap.
+
diff --git a/libgloss/or1k/caches-asm.S b/libgloss/or1k/caches-asm.S
new file mode 100644
index 0000000..f2ac096
--- /dev/null
+++ b/libgloss/or1k/caches-asm.S
@@ -0,0 +1,233 @@
+/* caches-asm.S -- cache manipulation 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.
+ */
+
+#include "include/or1k-asm.h"
+#include "include/or1k-sprs.h"
+
+/* -------------------------------------------------------------------------- */
+/*!Function used at reset to clear and enable all caches
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	_or1k_cache_init
+	.type	_or1k_cache_init,@function
+
+_or1k_cache_init:
+	/* Instruction cache enable */
+	/* Check if IC present and skip enabling otherwise */
+	l.mfspr	r3,r0,OR1K_SPR_SYS_UPR_ADDR
+	l.andi	r4,r3,OR1K_SPR_SYS_UPR_ICP_MASK
+	l.sfeq	r4,r0
+	OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lnoic))
+
+	/* Disable IC */
+	l.mfspr	r6,r0,OR1K_SPR_SYS_SR_ADDR
+	l.addi	r5,r0,-1
+	l.xori	r5,r5,OR1K_SPR_SYS_SR_ICE_MASK
+	l.and	r5,r6,r5
+	l.mtspr	r0,r5,OR1K_SPR_SYS_SR_ADDR
+
+	/* Establish cache block size
+	If BS=0, 16;
+	If BS=1, 32;
+	r14 contain block size
+	*/
+	l.mfspr	r3,r0,OR1K_SPR_SYS_ICCFGR_ADDR
+	l.andi	r4,r3,OR1K_SPR_SYS_ICCFGR_CBS_MASK
+	l.srli	r7,r4,7
+	l.ori	r8,r0,16
+	l.sll	r14,r8,r7
+
+	/* Establish number of cache sets
+	r13 contains number of cache sets
+	r7 contains log(# of cache sets)
+	*/
+	l.andi	r4,r3,OR1K_SPR_SYS_ICCFGR_NCS_MASK
+	l.srli	r7,r4,3
+	l.ori	r8,r0,1
+	l.sll	r13,r8,r7
+
+	/* Invalidate IC */
+	l.addi	r6,r0,0
+	l.sll	r5,r14,r7
+
+.Linvi:	l.mtspr	r0,r6,OR1K_SPR_ICACHE_ICBIR_ADDR
+	l.sfne	r6,r5
+	OR1K_DELAYED(
+		OR1K_INST(l.add r6,r6,r14),
+		OR1K_INST(l.bf  .Linvi)
+	)
+
+	/* Enable IC */
+	l.mfspr	r6,r0,OR1K_SPR_SYS_SR_ADDR
+	l.ori	r6,r6,OR1K_SPR_SYS_SR_ICE_MASK
+	l.mtspr	r0,r6,OR1K_SPR_SYS_SR_ADDR
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+
+	/* Data cache enable */
+	/* Check if DC present and skip enabling otherwise */
+.Lnoic:	l.mfspr	r3,r0,OR1K_SPR_SYS_UPR_ADDR
+	l.andi	r4,r3,OR1K_SPR_SYS_UPR_DCP_MASK
+	l.sfeq	r4,r0
+	OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lnodc))
+	/* Disable DC */
+	l.mfspr	r6,r0,OR1K_SPR_SYS_SR_ADDR
+	l.addi	r5,r0,-1
+	l.xori	r5,r5,OR1K_SPR_SYS_SR_DCE_MASK
+	l.and	r5,r6,r5
+	l.mtspr	r0,r5,OR1K_SPR_SYS_SR_ADDR
+	/* Establish cache block size
+	   If BS=0, 16;
+	   If BS=1, 32;
+	   r14 contain block size */
+	l.mfspr	r3,r0,OR1K_SPR_SYS_DCCFGR_ADDR
+	l.andi	r4,r3,OR1K_SPR_SYS_DCCFGR_CBS_MASK
+	l.srli	r7,r4,7
+	l.ori	r8,r0,16
+	l.sll	r14,r8,r7
+	/* Establish number of cache sets
+	   r13 contains number of cache sets
+	   r7 contains log(# of cache sets) */
+	l.andi	r4,r3,OR1K_SPR_SYS_ICCFGR_NCS_MASK
+	l.srli	r7,r4,3
+	l.ori	r8,r0,1
+	l.sll	r13,r8,r7
+	/* Invalidate DC */
+	l.addi	r6,r0,0
+	l.sll	r5,r14,r7
+
+.Linvd:	l.mtspr	r0,r6,OR1K_SPR_DCACHE_DCBIR_ADDR
+	l.sfne	r6,r5
+	OR1K_DELAYED(
+		OR1K_INST(l.add r6,r6,r14),
+		OR1K_INST(l.bf  .Linvd)
+	)
+	/* Enable DC */
+	l.mfspr	r6,r0,OR1K_SPR_SYS_SR_ADDR
+	l.ori	r6,r6,OR1K_SPR_SYS_SR_DCE_MASK
+	l.mtspr	r0,r6,OR1K_SPR_SYS_SR_ADDR
+
+.Lnodc:
+	/* Return */
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+
+/* -------------------------------------------------------------------------- */
+/*!Function to enable instruction cache
+                                                                              */
+/* -------------------------------------------------------------------------- */
+
+	.global	or1k_icache_enable
+	.type	or1k_icache_enable,@function
+
+or1k_icache_enable:
+	/* Enable IC */
+	l.mfspr	r13,r0,OR1K_SPR_SYS_SR_ADDR
+	l.ori	r13,r13,OR1K_SPR_SYS_SR_ICE_MASK
+	l.mtspr	r0,r13,OR1K_SPR_SYS_SR_ADDR
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+
+/* -------------------------------------------------------------------------- */
+/*!Function to disable instruction cache
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_icache_disable
+	.type	or1k_icache_disable,@function
+
+or1k_icache_disable:
+	/* Disable IC */
+	l.mfspr	r13,r0,OR1K_SPR_SYS_SR_ADDR
+	l.addi	r12,r0,-1
+	l.xori	r12,r12,OR1K_SPR_SYS_SR_ICE_MASK
+	l.and	r12,r13,r12
+	l.mtspr	r0,r12,OR1K_SPR_SYS_SR_ADDR
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+
+/* -------------------------------------------------------------------------- */
+/*!Function to flush address of instruction cache
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_icache_flush
+	.type	or1k_icache_flush,@function
+
+or1k_icache_flush:
+	OR1K_DELAYED(
+		OR1K_INST(l.mtspr r0,r3,OR1K_SPR_ICACHE_ICBIR_ADDR),
+		/* Push r3 into IC invalidate reg */
+		OR1K_INST(l.jr    r9)
+	)
+
+
+/* -------------------------------------------------------------------------- */
+/*!Function to enable data cache
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_dcache_enable
+	.type	or1k_dcache_enable,@function
+
+or1k_dcache_enable:
+	/* Enable DC */
+	l.mfspr	r13,r0,OR1K_SPR_SYS_SR_ADDR
+	l.ori	r13,r13,OR1K_SPR_SYS_SR_DCE_MASK
+	l.mtspr	r0,r13,OR1K_SPR_SYS_SR_ADDR
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	l.nop
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+
+/* -------------------------------------------------------------------------- */
+/*!Function to disable data cache
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_dcache_disable
+	.type	or1k_dcache_disable,@function
+
+or1k_dcache_disable:
+	/* Disable DC */
+	l.mfspr	r13,r0,OR1K_SPR_SYS_SR_ADDR
+	l.addi	r12,r0,-1
+	l.xori	r12,r12,OR1K_SPR_SYS_SR_DCE_MASK
+	l.and	r12,r13,r12
+	l.mtspr	r0,r12,OR1K_SPR_SYS_SR_ADDR
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+
+/* -------------------------------------------------------------------------- */
+/*!Function to flush address of data cache
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_dcache_flush
+	.type	or1k_dcache_flush,@function
+
+or1k_dcache_flush:
+	OR1K_DELAYED(
+		OR1K_INST(l.mtspr r0,r3,OR1K_SPR_DCACHE_DCBIR_ADDR),
+		/* Push r3 into DC invalidate reg */
+		OR1K_INST(l.jr    r9)
+	)
diff --git a/libgloss/or1k/exceptions-asm.S b/libgloss/or1k/exceptions-asm.S
new file mode 100644
index 0000000..7248683
--- /dev/null
+++ b/libgloss/or1k/exceptions-asm.S
@@ -0,0 +1,201 @@
+/* exceptions-asm.S -- exception handling 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.
+ */
+
+#include "include/or1k-asm.h"
+#include "include/or1k-sprs.h"
+
+/* -------------------------------------------------------------------------- */
+/*!Generic exception handler function
+                                                                              */
+/* -------------------------------------------------------------------------- */
+// Warning - this must be the same as specified in crt0.S
+#define EXCEPTION_STACK_SIZE 128+128
+
+	.extern _or1k_exception_handler_table
+
+/* -------------------------------------------------------------------------- */
+/*!Function to call appropriate exception handler
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.section .text
+	.global	_or1k_exception_handler
+	.type	_or1k_exception_handler,@function
+
+	/*
+	r3 = address of exception vector
+	r4 = address where exception occurred
+	*/
+
+#define GPR_BUF_OFFSET(x) (x << 2)
+
+_or1k_exception_handler:
+	/* Store remainder of state (r3,r4 stored in vector entry)*/
+	l.sw	GPR_BUF_OFFSET(2)(r1),r2
+	l.sw	GPR_BUF_OFFSET(5)(r1),r5
+	l.sw	GPR_BUF_OFFSET(6)(r1),r6
+	l.sw	GPR_BUF_OFFSET(7)(r1),r7
+	l.sw	GPR_BUF_OFFSET(8)(r1),r8
+	l.sw	GPR_BUF_OFFSET(9)(r1),r9
+	l.sw	GPR_BUF_OFFSET(10)(r1),r10
+	l.sw	GPR_BUF_OFFSET(11)(r1),r11
+	l.sw	GPR_BUF_OFFSET(12)(r1),r12
+	l.sw	GPR_BUF_OFFSET(13)(r1),r13
+	l.sw	GPR_BUF_OFFSET(14)(r1),r14
+	l.sw	GPR_BUF_OFFSET(15)(r1),r15
+	l.sw	GPR_BUF_OFFSET(16)(r1),r16
+	l.sw	GPR_BUF_OFFSET(17)(r1),r17
+	l.sw	GPR_BUF_OFFSET(18)(r1),r18
+	l.sw	GPR_BUF_OFFSET(19)(r1),r19
+	l.sw	GPR_BUF_OFFSET(20)(r1),r20
+	l.sw	GPR_BUF_OFFSET(21)(r1),r21
+	l.sw	GPR_BUF_OFFSET(22)(r1),r22
+	l.sw	GPR_BUF_OFFSET(23)(r1),r23
+	l.sw	GPR_BUF_OFFSET(24)(r1),r24
+	l.sw	GPR_BUF_OFFSET(25)(r1),r25
+	l.sw	GPR_BUF_OFFSET(26)(r1),r26
+	l.sw	GPR_BUF_OFFSET(27)(r1),r27
+	l.sw	GPR_BUF_OFFSET(28)(r1),r28
+	l.sw	GPR_BUF_OFFSET(29)(r1),r29
+	l.sw	GPR_BUF_OFFSET(30)(r1),r30
+	l.sw	GPR_BUF_OFFSET(31)(r1),r31
+
+	/* Replace impure pointer for exception */
+	l.movhi	r20,hi(_or1k_exception_impure_ptr)
+	l.ori	r20,r20,lo(_or1k_exception_impure_ptr)
+#ifdef __OR1K_MULTICORE__
+	l.lwz	r20,0(r20)
+	l.mfspr	r22,r0,OR1K_SPR_SYS_COREID_ADDR
+	l.slli	r22,r22,2
+	l.add	r20,r20,r22
+#endif
+	l.lwz	r20,0(r20)
+
+	l.movhi	r21,hi(_or1k_current_impure_ptr)
+	l.ori	r21,r21,lo(_or1k_current_impure_ptr)
+#ifdef __OR1K_MULTICORE__
+	l.lwz	r21,0(r21)
+	l.add	r21,r21,r22
+#endif
+	l.sw	0(r21),r20
+
+	/* Determine offset in table of exception handler using r3*/
+	l.andi	r13,r3,0xff00
+	l.srli	r13,r13,6
+	/* Substract 2 words, as we have no vector at 0 and no reset handler */
+	l.addi	r13,r13,-8
+	/* r13 now contains offset in or1k_exception_handler_table for
+	   function
+	*/
+	/* Get or1k_exception_handler_table address */
+	l.movhi	r14,hi(_or1k_exception_handler_table)
+	l.ori	r14,r14,lo(_or1k_exception_handler_table)
+#ifdef __OR1K_MULTICORE__
+	/* Read the address of the array of cores */
+	/* r14 = (*or1k_exception_handler_table)  */
+	l.lwz	r14,0(r14)
+	/* Generate core offset in array (off = coreid*30*4 = coreid*120) */
+	/* r15 = coreid */
+	l.mfspr	r15,r0,OR1K_SPR_SYS_COREID_ADDR
+	/* r16 = coreid * 128 */
+	l.slli	r16,r15,7
+	/* r15 = coreid * 8 */
+	l.slli	r15,r15,3
+	/* r15 = coreid*128 - coreid*8 = coreid*120 = off */
+	l.sub	r15,r16,r15
+	/* r14 = (*or1k_exception_handler_table)[coreid] =  r14 + off */
+	l.add	r14,r14,r15
+#endif
+	/* r14 now contains base of exception handler table */
+	/* add offset of exception vector */
+	l.add	r14,r14,r13
+	/* load handler address from table */
+	l.lwz	r13, 0(r14)
+
+	/* Check to see if this handler has been set yet */
+	l.sfne	r13,r0
+	OR1K_DELAYED_NOP(OR1K_INST(l.bnf exception_exit))
+
+	/* Call exception handler, copy EPCR to r3 */
+	OR1K_DELAYED(
+		OR1K_INST(l.or   r3,r4,r4),
+		OR1K_INST(l.jalr r13)
+	)
+
+	/* Restore impure pointer */
+	l.movhi	r20,hi(_or1k_impure_ptr)
+	l.ori	r20,r20,lo(_or1k_impure_ptr)
+#ifdef __OR1K_MULTICORE__
+	l.lwz	r20,0(r20)
+	l.mfspr	r22,r0,OR1K_SPR_SYS_COREID_ADDR
+	l.slli	r22,r22,2
+	l.add	r20,r20,r22
+#endif
+	l.lwz	r20,0(r20)
+
+	l.movhi	r21,hi(_or1k_current_impure_ptr)
+	l.ori	r21,r21,lo(_or1k_current_impure_ptr)
+#ifdef __OR1K_MULTICORE__
+	l.lwz	r21,0(r21)
+	l.add	r21,r21,r22
+#endif
+	l.sw	0(r21),r20
+
+	/* Restore state */
+	l.lwz	r2,GPR_BUF_OFFSET(2)(r1)
+	l.lwz	r3,GPR_BUF_OFFSET(3)(r1)
+	l.lwz	r4,GPR_BUF_OFFSET(4)(r1)
+	l.lwz	r5,GPR_BUF_OFFSET(5)(r1)
+	l.lwz	r6,GPR_BUF_OFFSET(6)(r1)
+	l.lwz	r7,GPR_BUF_OFFSET(7)(r1)
+	l.lwz	r8,GPR_BUF_OFFSET(8)(r1)
+	l.lwz	r9,GPR_BUF_OFFSET(9)(r1)
+	l.lwz	r10,GPR_BUF_OFFSET(10)(r1)
+	l.lwz	r11,GPR_BUF_OFFSET(11)(r1)
+	l.lwz	r12,GPR_BUF_OFFSET(12)(r1)
+	l.lwz	r13,GPR_BUF_OFFSET(13)(r1)
+	l.lwz	r14,GPR_BUF_OFFSET(14)(r1)
+	l.lwz	r15,GPR_BUF_OFFSET(15)(r1)
+	l.lwz	r16,GPR_BUF_OFFSET(16)(r1)
+	l.lwz	r17,GPR_BUF_OFFSET(17)(r1)
+	l.lwz	r18,GPR_BUF_OFFSET(18)(r1)
+	l.lwz	r19,GPR_BUF_OFFSET(19)(r1)
+	l.lwz	r20,GPR_BUF_OFFSET(20)(r1)
+	l.lwz	r21,GPR_BUF_OFFSET(21)(r1)
+	l.lwz	r22,GPR_BUF_OFFSET(22)(r1)
+	l.lwz	r23,GPR_BUF_OFFSET(23)(r1)
+	l.lwz	r24,GPR_BUF_OFFSET(24)(r1)
+	l.lwz	r25,GPR_BUF_OFFSET(25)(r1)
+	l.lwz	r26,GPR_BUF_OFFSET(26)(r1)
+	l.lwz	r27,GPR_BUF_OFFSET(27)(r1)
+	l.lwz	r28,GPR_BUF_OFFSET(28)(r1)
+	l.lwz	r29,GPR_BUF_OFFSET(29)(r1)
+	l.lwz	r30,GPR_BUF_OFFSET(30)(r1)
+	l.lwz	r31,GPR_BUF_OFFSET(31)(r1)
+
+	// Restore original stack
+	l.lwz	r1,GPR_BUF_OFFSET(1)(r1)
+
+	l.rfe
+	l.nop
+
+exception_exit:
+	/* Exception handler not set, exit */
+	OR1K_DELAYED(
+		OR1K_INST(l.or  r3,r4,r4),
+		OR1K_INST(l.jal exit)
+	)
diff --git a/libgloss/or1k/exceptions.c b/libgloss/or1k/exceptions.c
new file mode 100644
index 0000000..8240d09
--- /dev/null
+++ b/libgloss/or1k/exceptions.c
@@ -0,0 +1,21 @@
+#include "include/or1k-support.h"
+
+#include "or1k-internals.h"
+
+#ifdef __OR1K_MULTICORE__
+or1k_exception_handler_table_t *_or1k_exception_handler_table;
+#else
+or1k_exception_handler_table_t _or1k_exception_handler_table;
+#endif
+
+void or1k_exception_handler_add(int id, or1k_exception_handler_fptr handler)
+{
+	// Subtract 2 as we do not have a vector at 0 and reset is static
+	id = id - 2;
+#ifdef __OR1K_MULTICORE__
+	_or1k_exception_handler_table[or1k_coreid()][id] = handler;
+
+#else
+	_or1k_exception_handler_table[id] = handler;
+#endif
+}
diff --git a/libgloss/or1k/impure.c b/libgloss/or1k/impure.c
new file mode 100644
index 0000000..f4eb4ad
--- /dev/null
+++ b/libgloss/or1k/impure.c
@@ -0,0 +1,120 @@
+/* impure.c. Handling of re-entrancy data structure for OpenRISC 1000.
+
+   Copyright (C) 2014, Authors
+ 
+   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.
+ */
+
+#include <reent.h>
+#include "or1k-internals.h"
+
+#include <string.h>
+
+/* As an exception handler may also use the library, it is better to use
+ * a different re-entrancy data structure for the exceptions.
+ * This data structure is configured here and as part of the exception
+ * handler (or1k_exception_handler) temporarily replaces the software's
+ * impure data pointer.
+ *
+ * During initialization, the libraries standard _impure_data and the exception
+ * impure data (_exception_impure_data) are initialized. Afterwards,
+ * the current value _current_impure_ptr is set to _impure_ptr.
+ *
+ * At runtime __getreent is called to return the current reentrancy pointer,
+ * which is stored in _current_impure_ptr.
+ *
+ * In the or1k_exception_handler the _current_impure_ptr is set to point to
+ * _exception_impure_ptr. After the exception handler returned, it is set back
+ * to _impure_ptr.
+ */
+
+/* Link in the external impure_data structure */
+extern struct _reent *__ATTRIBUTE_IMPURE_PTR__ _impure_ptr;
+
+#ifdef __OR1K_MULTICORE__
+struct _reent **_or1k_impure_ptr;
+struct _reent **_or1k_exception_impure_ptr;
+struct _reent **_or1k_current_impure_ptr;
+#else
+struct _reent *__ATTRIBUTE_IMPURE_PTR__ _or1k_impure_ptr;
+
+/* Create exception impure data structure */
+static struct _reent _or1k_exception_impure_data = _REENT_INIT (_or1k_exception_impure_data);
+
+/* Link to the exception impure data structure */
+struct _reent *__ATTRIBUTE_IMPURE_PTR__ _or1k_exception_impure_ptr = &_or1k_exception_impure_data;
+
+/* Link to the currently used data structure. */
+struct _reent *__ATTRIBUTE_IMPURE_PTR__ _or1k_current_impure_ptr;
+#endif
+
+#ifdef __OR1K_MULTICORE__
+#define OR1K_LIBC_GETREENT _or1k_current_impure_ptr[or1k_coreid()]
+#else
+#define OR1K_LIBC_GETREENT _or1k_current_impure_ptr
+#endif
+
+void
+_or1k_libc_impure_init (void)
+{
+#ifdef __OR1K_MULTICORE__
+	uint32_t c;
+
+	_or1k_impure_ptr = _sbrk_r(0, sizeof(struct _reent*) * or1k_numcores());
+	_or1k_exception_impure_ptr = _sbrk_r(0, sizeof(struct _reent*) * or1k_numcores());
+	_or1k_current_impure_ptr = _sbrk_r(0, sizeof(struct _reent*) * or1k_numcores());
+
+	_or1k_impure_ptr[0] = _impure_ptr;
+	_REENT_INIT_PTR(_impure_ptr);
+	for (c = 1; c < or1k_numcores(); c++) {
+		_or1k_impure_ptr[c] = _sbrk_r(0, sizeof(struct _reent));
+		_REENT_INIT_PTR(_or1k_impure_ptr[c]);
+	}
+
+	for (c = 0; c < or1k_numcores(); c++) {
+		_or1k_exception_impure_ptr[c] = _sbrk_r(0, sizeof(struct _reent));
+		_REENT_INIT_PTR(_or1k_exception_impure_ptr[c]);
+	}
+
+	for (c = 0; c < or1k_numcores(); c++) {
+		_or1k_current_impure_ptr[c] = _or1k_impure_ptr[c];
+	}
+#else
+	// Initialize both impure data structures
+	_REENT_INIT_PTR (_impure_ptr);
+	_REENT_INIT_PTR (_or1k_exception_impure_ptr);
+
+	// Set current to standard impure pointer
+	_or1k_current_impure_ptr = _impure_ptr;
+#endif
+}
+
+struct _reent*
+_or1k_libc_getreent(void) {
+	return OR1K_LIBC_GETREENT;
+}
+
+#ifdef __OR1K_MULTICORE__
+struct _or1k_reent (*_or1k_reent)[];
+#else
+struct _or1k_reent _or1k_reent;
+#endif
+
+void
+_or1k_reent_init(void)
+{
+#ifdef __OR1K_MULTICORE__
+	size_t memsize = sizeof(struct _or1k_reent) * or1k_numcores();
+	_or1k_reent = (struct _or1k_reent*) _sbrk_r(0, memsize);
+#endif
+}
diff --git a/libgloss/or1k/include/or1k-nop.h b/libgloss/or1k/include/or1k-nop.h
new file mode 100644
index 0000000..d50a6f3
--- /dev/null
+++ b/libgloss/or1k/include/or1k-nop.h
@@ -0,0 +1,41 @@
+/* or1k-nop.h -- Defines codes OR1K simulator NOP Hack 
+
+   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
+   Copyright (C) 2008 Embecosm Limited
+  
+   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
+   Contributor Peter Gavin <pgavin@gmail.com>
+  
+   This program 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 3 of the License, or (at your option)
+   any later version.
+  
+   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OR1K_NOP__H
+#define OR1K_NOP__H
+
+/*
+ * l.nop constants used only in simulations
+ */
+#define OR1K_NOP_NOP         0x0000  /* Normal nop instruction */
+#define OR1K_NOP_EXIT        0x0001  /* End of simulation */
+#define OR1K_NOP_REPORT      0x0002  /* Simple report */
+#define OR1K_NOP_PUTC        0x0004  /* putc instruction */
+#define OR1K_NOP_CNT_RESET   0x0005  /* Reset statistics counters */
+#define OR1K_NOP_GET_TICKS   0x0006  /* Get # ticks running */
+#define OR1K_NOP_GET_PS      0x0007  /* Get picosecs/cycle */
+#define OR1K_NOP_TRACE_ON    0x0008  /* Turn on tracing */
+#define OR1K_NOP_TRACE_OFF   0x0009  /* Turn off tracing */
+#define OR1K_NOP_RANDOM      0x000a  /* Return 4 random bytes */
+#define OR1K_NOP_OR1KSIM     0x000b  /* Return non-zero if this is Or1ksim */
+#define OR1K_NOP_EXIT_SILENT 0x000c  /* End of simulation, quiet version */
+
+#endif  /* OR1K_NOP__H */
diff --git a/libgloss/or1k/include/or1k-support.h b/libgloss/or1k/include/or1k-support.h
new file mode 100644
index 0000000..c29b064
--- /dev/null
+++ b/libgloss/or1k/include/or1k-support.h
@@ -0,0 +1,665 @@
+/* Copyright (c) 2014 Authors
+ *
+ * Contributor Julius Baxter <julius.baxter@orsoc.se>
+ * 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.
+ */
+
+/* -------------------------------------------------------------------------- */
+/* This program is commented throughout in a fashion suitable for processing
+with Doxygen. */
+/* -------------------------------------------------------------------------- */
+
+#include <stdint.h>
+
+#ifndef __OR1K_SUPPORT_H__
+#define __OR1K_SUPPORT_H__
+
+/*!
+* \defgroup or1k_macros OR1K macros
+* @{
+*/
+
+/*!
+* Access byte-sized memory mapped register
+*
+* Used to access a byte-sized memory mapped register. It avoids usage errors
+* when not defining register addresses volatile and handles casting correctly.
+*
+* Example for both read and write:
+*
+* \code
+* uint8_t status = REG8(IPBLOCK_STATUS_REG_ADDR);
+* REG8(IPBLOCK_ENABLE) = 1;
+* \endcode
+*
+* \param add Register address
+*/
+#define REG8(add) *((volatile unsigned char *) (add))
+
+/*!
+* Access halfword-sized memory mapped register
+*
+* Used to access a 16 byte-sized memory mapped register. It avoids usage errors
+* when not defining register addresses volatile and handles casting correctly.
+*
+* See REG8() for an example.
+*
+* \param add Register address
+*/
+#define REG16(add) *((volatile unsigned short *) (add))
+
+/*!
+* Access word-sized memory mapped register
+*
+* Used to access a word-sized memory mapped register. It avoids usage errors
+* when not defining register addresses volatile and handles casting correctly.
+*
+* See REG8() for an example.
+*
+* \param add Register address
+*/
+#define REG32(add) *((volatile unsigned long *) (add))
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_interrupts OR1K interrupt control
+*
+* Interrupt control function prototypes
+*
+* @{
+*/
+
+/*! Function pointer to interrupt handler functions */
+typedef void (*or1k_interrupt_handler_fptr)(void* data);
+
+/*!
+* Add interrupt handler for interrupt line
+*
+* Registers a callback function for a certain interrupt line.
+*
+* \param line Interrupt line/id to register a handler for
+* \param handler Handler to register
+* \param data Data value passed to the handler
+*/
+void or1k_interrupt_handler_add(uint32_t line,
+		or1k_interrupt_handler_fptr handler,
+		void* data);
+
+/*!
+* Enable interrupts from a given line
+*
+* Unmask the given interrupt line. It is also important to enable interrupts
+* in general, e.g., using or1k_interrupts_enable().
+*
+* \param line Interrupt line to enable
+*/
+void or1k_interrupt_enable(int line);
+
+/*!
+* Disable interrupts from a given line
+*
+* Mask given interrupt line. It can be unmasked using or1k_interrupt_enable().
+*
+* \param line Interrupt line to disable
+*/
+void or1k_interrupt_disable(int line);
+
+/*!
+* Disable interrupts
+*
+* This disables the interrupt exception. This is sufficient to disable all
+* interrupts. It does not change the mask register (which is modified using
+* or1k_interrupt_enable() and or1k_interrupt_disable()).
+*
+* The interrupt exception can be enabled using or1k_interrupts_enable().
+*
+* Finally, the status of the interrupt exception enable flag is returned by
+* this function. That allows to call this function even if interrupts are
+* already disabled. To restore the value of the interrupt exception enable
+* flag, use the or1k_interrupts_restore() function. That way you avoid to
+* accidentally enable interrupts. Example:
+*
+* \code
+* void f() {
+*   uint32_t interrupt_status = or1k_interrupts_disable();
+*   // do something
+*   or1k_interrupts_restore(status);
+* }
+* \endcode
+*
+* This code will preserve the original status of the interrupt enable flag.
+*
+* \return Interrupt exception enable flag before call
+*/
+uint32_t or1k_interrupts_disable(void);
+
+/*!
+* Enable interrupt exception
+*
+* Enable the interrupt exception. Beside the interrupt exception, it is also
+* necessary to enable the individual interrupt lines using
+* or1k_interrupt_enable().
+*
+* You should avoid using this function together with or1k_interrupts_disable()
+* to guard atomic blocks as it unconditionally enables the interrupt
+* exception (see documentation of or1k_interrupts_disable()).
+*/
+void or1k_interrupts_enable(void);
+
+/*!
+* Restore interrupt exception enable flag
+*
+* This function restores the given status to the processor.
+* or1k_interrupts_restore(0) is identical to or1k_interrupts_disable() and
+* or1k_interrupts_restore(SPR_SR_IEE) is identical to or1k_interrupts_enable().
+*
+* It is for example used to guard an atomic block and restore the original
+* status of the interrupt exception enable flag as returned by
+* or1k_interrupts_disable(). See the documentation of or1k_interrupts_disable()
+* for a usage example.
+*
+* \param status Status of the flag to restore
+*/
+void or1k_interrupts_restore(uint32_t status);
+
+/*!
+ * Disable timer and interrupt exception
+ *
+ * This function disables the timer and interrupt exception to guard critical
+ * sections. It returns the status of the enable bits before the critical
+ * section, that is restored with or1k_critical_end().
+ *
+ * Example:
+ * \code
+ * ...
+ * uint32_t status = or1k_critical_start();
+ * // critical part
+ * or1k_critical_end(status);
+ * ...
+ * \endcode
+ *
+ * \return Status of timer and interrupt exception at time of call
+ */
+uint32_t or1k_critical_begin();
+
+/*!
+ * Enable timer and interrupt exception
+ *
+ * Restore the timer and interrupt exception enable. The restore value is the
+ * return value from or1k_critical_start().
+ *
+ * \param restore Interrupt and timer exception enable restore value
+ */
+void or1k_critical_end(uint32_t restore);
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_exception Exception handling
+* @{
+*/
+/*! Function pointer to an exception handler function */
+typedef void (*or1k_exception_handler_fptr)(void);
+
+/*!
+* Register exception handler
+*
+* Register an exception handler for the given exception id. This handler is
+* in the following then called when the exception occurs. You can thereby
+* individually handle those exceptions.
+*
+* \param id Exception id
+* \param handler Handler callback
+*/
+void or1k_exception_handler_add(int id, or1k_exception_handler_fptr handler);
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_spr SPR access
+* @{
+*/
+
+/*!
+* Move value to special purpose register
+*
+* Move data value to a special purpose register
+*
+* \param spr SPR identifier, see spr-defs.h for macros
+* \param value value to move to SPR
+*/
+static inline void or1k_mtspr (uint32_t spr, uint32_t value)
+{
+	__asm__ __volatile__ ("l.mtspr\t\t%0,%1,0": : "r" (spr), "r" (value));
+}
+
+/*!
+* Copy value from special purpose register
+*
+* Copy a data value from the given special purpose register.
+*
+* \param spr SPR identifier, see spr-defs.h for macros
+* \return SPR data value
+*/
+static inline uint32_t or1k_mfspr (uint32_t spr) {
+	uint32_t value;
+	__asm__ __volatile__ ("l.mfspr\t\t%0,%1,0" : "=r" (value) : "r" (spr));
+	return value;
+}
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_util Miscellaneous utility functions
+*
+* @{
+*/
+
+/*!
+* Report value to simulator
+*
+* Uses the built-in simulator functionality.
+*
+* \param value Value to report
+*/
+void or1k_report (unsigned long int value);
+
+/*!
+* Get (pseudo) random number
+*
+* This should return pseudo-random numbers, based on a Galois LFSR.
+*
+* \return (Pseudo) Random number
+*/
+unsigned long int or1k_rand(void);
+
+/*!
+ * Register UART callback
+ *
+ * This function sets a callback function that is called when a character is
+ * received via UART. The callback function has no return and a gets the
+ * character as parameter. When a character is received, the function is called.
+ *
+ * Example (UART echo):
+ * \code
+ * void uart_in(char c) {
+ *   printf("%c", c); // Echo
+ * }
+ *
+ * int main() {
+ *   or1k_uart_set_read_cb(&uart_in);
+ *   or1k_interrupts_enable();
+ *
+ *   while (1) {}
+ * }
+ * \endcode
+ */
+void or1k_uart_set_read_cb(void (*cb)(char c));
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_cache Cache control
+*
+* @{
+*/
+
+/*!
+* Enable instruction cache
+*/
+void or1k_icache_enable(void);
+
+/*!
+* Disable instruction cache
+*/
+void or1k_icache_disable(void);
+
+/*!
+* Flush instruction cache
+*
+* Invalidate instruction cache entry
+*
+* \param entry Entry to invalidate
+*/
+void or1k_icache_flush(uint32_t entry);
+
+/*!
+* Enable data cache
+*/
+void or1k_dcache_enable(void);
+
+/*!
+* Disable data cache
+*/
+void or1k_dcache_disable(void);
+
+/*!
+* Flush data cache
+*
+* Invalidate data cache entry
+*
+* \param entry Entry to invalidate
+*/
+void or1k_dcache_flush(unsigned long entry);
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_mmu MMU control
+* @{
+*/
+
+/*!
+* Enable instruction MMU
+*/
+void or1k_immu_enable(void);
+
+/*!
+* Disable instruction MMU
+*/
+void or1k_immu_disable(void);
+
+/*!
+* Enable data MMU
+*/
+void or1k_dmmu_enable(void);
+
+/*!
+* Disable data MMU
+*/
+void or1k_dmmu_disable(void);
+/*!
+* @}
+*/
+
+/*!
+* \defgroup or1k_timer Timer control
+*
+* The tick timer can be used for time measurement, operating system scheduling
+* etc. By default it is initialized to continuously count the ticks of a
+* certain period after calling or1k_timer_init(). The period can later be
+* changed using or1k_timer_set_period().
+*
+* The timer is controlled using or1k_timer_enable(), or1k_timer_disable(),
+* or1k_timer_restore(), or1k_timer_pause(). After initialization it is required
+* to enable the timer the first time using or1k_timer_enable().
+* or1k_timer_disable() only disables the tick timer interrupts, it does not
+* disable the timer counting. If you plan to use a pair of or1k_timer_disable()
+* and or1k_timer_enable() to protect sections of your code against interrupts
+* you should use or1k_timer_disable() and or1k_timer_restore(), as it may be
+* possible that the timer interrupt was not enabled before disabling it,
+* enable would then start it unconditionally. or1k_timer_pause() pauses the
+* counting.
+*
+* In the default mode you can get the tick value using or1k_timer_get_ticks()
+* and reset this value using or1k_timer_reset_ticks().
+*
+* Example for using the default mode:
+*
+* \code
+* int main() {
+*   uint32_t ticks = 0;
+*   uint32_t timerstate;
+*   or1k_timer_init(100);
+*   or1k_timer_enable();
+*   while (1) {
+*     while (ticks == or1k_timer_get_ticks()) { }
+*     timerstate = or1k_timer_disable();
+*     // do something atomar
+*     or1k_timer_restore(timerstate);
+*     if (ticks == 100) {
+*       printf("A second elapsed\n");
+*       or1k_timer_reset_ticks();
+*       ticks = 0;
+*     }
+*   }
+* }
+* \endcode
+*
+* It is possible to change the mode of the tick timer using
+* or1k_timer_set_mode(). Allowed values are the correct bit pattern (including
+* the bit positions) for the TTMR register, it is recommended to use the macros
+* defined in spr-defs.h. For example, implementing an operating system with
+* scheduling decisions of varying duration favors the implementation of single
+* run tick timer. Here, each quantum is started before leaving the operating
+* system kernel. The counter can be restarted with or1k_timer_reset().
+* Example:
+*
+* \code
+* void tick_handler(void) {
+*   // Make schedule decision
+*   // and set new thread
+*   or1k_timer_reset();
+*   // End of exception, new thread will run
+* }
+*
+* int main() {
+*   // Configure operating system and start threads..
+*
+*   // Configure timer
+*   or1k_timer_init(50);
+*   or1k_timer_set_handler(&tick_handler);
+*   or1k_timer_set_mode(SPR_TTMR_SR);
+*   or1k_timer_enable();
+*
+*   // Schedule first thread and die..
+* }
+* \endcode
+*
+* @{
+*/
+
+/*!
+* Initialize tick timer
+*
+* This initializes the tick timer in default mode (see \ref or1k_timer for
+* details).
+*
+* \param hz Initial period of the tick timer
+* \return 0 if successful, -1 if timer not present
+*/
+int or1k_timer_init(unsigned int hz);
+
+/*!
+* Set period of timer
+*
+* Set the period of the timer to a value in Hz. The frequency from the board
+* support package is used to determine the match value.
+*/
+void or1k_timer_set_period(uint32_t hz);
+
+/*!
+* Replace the timer interrupt handler
+*
+* By default the tick timer is used to handle timer ticks. The user can replace
+* this with an own handler for example when implementing an operating system.
+*
+* \param handler The callback function pointer to the handler
+*/
+void or1k_timer_set_handler(void (*handler)(void));
+
+/*!
+* Set timer mode
+*
+* The timer has different modes (see architecture manual). The default is to
+* automatically restart counting (SPR_TTMR_RT), others are single run
+* (SPR_TTMR_SR) and continuous run (SPR_TTMR_CR).
+*
+* \param mode a valid mode (use definitions from spr-defs.h as it is important
+* that those are also at the correct position in the bit field!)
+*/
+void or1k_timer_set_mode(uint32_t mode);
+
+/*!
+* Enable timer interrupt
+*
+* Enable the timer interrupt exception, independent of the status before.
+* If you want to enable the timer conditionally, for example to implement a
+* non-interruptible sequence of code, you should use or1k_timer_restore(). See
+* the description of or1k_timer_disable() for more details.
+*
+* The enable will also restore the mode if the timer was paused previously.
+*/
+void or1k_timer_enable(void);
+
+/*!
+* Disable timer interrupt
+*
+* This disables the timer interrupt exception and returns the state of the
+* interrupt exception enable flag before the call. This can be used with
+* or1k_timer_restore() to implement sequences of code that are not allowed to
+* be interrupted. Using or1k_timer_enable() will unconditionally enable the
+* interrupt independent of the state before calling or1k_timer_disable().
+* For an example see \ref or1k_timer.
+*
+* \return Status of timer interrupt before call
+*/
+uint32_t or1k_timer_disable(void);
+
+/*!
+* Restore timer interrupt exception flag
+*
+* Restores the timer interrupt exception flag as returned by
+* or1k_timer_disable(). See the description of or1k_timer_disable() and \ref
+* or1k_timer for details and an example.
+*
+* \param sr_tee Status of timer interrupt
+*/
+void or1k_timer_restore(uint32_t sr_tee);
+
+/*!
+* Pause timer counter
+*
+* Pauses the counter of the tick timer. The counter will hold its current value
+* and it can be started again with or1k_timer_enable() which will restore the
+* configured mode.
+*/
+void or1k_timer_pause(void);
+
+/*!
+* Reset timer counter
+*/
+void or1k_timer_reset(void);
+
+/*!
+* Get timer ticks
+*
+* Get the global ticks of the default configuration. This will increment the
+* tick counter according to the preconfigured period.
+*
+* \return Current value of ticks
+*/
+unsigned long or1k_timer_get_ticks(void);
+
+/*!
+* Reset timer ticks
+*
+* Resets the timer ticks in default configuration to 0.
+*/
+void or1k_timer_reset_ticks(void);
+/*!
+* @}
+*/
+
+/*!
+ * \defgroup or1k_multicore Multicore and Synchronization Support
+ *
+ * @{
+ */
+
+/*!
+ * Compiled with multicore support
+ *
+ * \return 1 if compiled with multicore support, 0 otherwise
+ */
+uint32_t or1k_has_multicore_support(void);
+
+/*!
+ * Read core identifier
+ *
+ * \return Core identifier
+ */
+uint32_t or1k_coreid(void);
+
+/*!
+ * Read number of cores
+ *
+ * \return Total number of cores
+ */
+uint32_t or1k_numcores(void);
+
+/*!
+ * Load linked
+ *
+ * Load a value from the given address and link it. If the following
+ * or1k_sync_sc() goes to the same address and there was no conflicting access
+ * between loading and storing, the value is written back, else the write fails.
+ *
+ * \param address Address to load value from
+ * \return Value read from the address
+ */
+uint32_t or1k_sync_ll(void *address);
+
+/**
+ * Store conditional
+ *
+ * Conditionally store a value to the address. The address must have been read
+ * before using or1k_sync_ll() and there must be no other load link after that,
+ * otherwise this will always fail. In case there was no other write to the same
+ * address in between the load link and the store conditional, the store is
+ * successful, otherwise it will also fail.
+ *
+ * \param address Address to conditionally store to
+ * \param value Value to write to address
+ * \return 1 if success, 0 if fail
+ */
+int or1k_sync_sc(void *address, uint32_t value);
+
+/*!
+ * Compare and Swap
+ *
+ * Loads a data item from the memory and compares a given value to it. If the
+ * values match, a new value is written to the memory, if they mismatch, the
+ * operation is aborted. The whole operation is atomic, i.e., it is guaranteed
+ * that no other core changes the value between the read and the write.
+ *
+ * \param address Address to operate on
+ * \param compare Compare value
+ * \param swap New value to write
+ * \return The value read from memory (can be used to check for success)
+ */
+uint32_t or1k_sync_cas(void *address, uint32_t compare, uint32_t swap);
+
+/*!
+ * Test and Set Lock
+ *
+ * Check for a lock on an address. This means, if there is 0 at an address it
+ * will overwrite it with 1 and return 0. If the lock was already set (value
+ * 1 read from address), the function returns 1. The operation is atomic.
+ *
+ * \param address Address of the lock
+ * \return 0 if success, 1 if failed
+ */
+int or1k_sync_tsl(void *address);
+/*!
+ * @}
+ */
+
+#endif /* __NEWLIB_OR1K_SUPPORT_H__ */
diff --git a/libgloss/or1k/interrupts-asm.S b/libgloss/or1k/interrupts-asm.S
new file mode 100644
index 0000000..5600352
--- /dev/null
+++ b/libgloss/or1k/interrupts-asm.S
@@ -0,0 +1,166 @@
+/* interrupts-asm.S -- interrupt handling for OpenRISC 1000.
+ *
+ * Copyright (c) 2011, 2012, 2014 Authors
+ *
+ * Contributor Julius Baxter <juliusbaxter@gmail.com>
+ * Contributor Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * 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.
+ */
+
+/* -------------------------------------------------------------------------- */
+/*!Generic interrupt handler function for or1k
+                                                                              */
+/* -------------------------------------------------------------------------- */
+
+#include "include/or1k-asm.h"
+#include "include/or1k-sprs.h"
+
+	.extern _or1k_interrupt_handler_table
+	.extern _or1k_interrupt_handler_data_ptr_table
+
+/* -------------------------------------------------------------------------- */
+/*!Function to call appropriate interrupt handler
+                                                                              */
+/* -------------------------------------------------------------------------- */
+
+	.section .text
+	.global	_or1k_interrupt_handler
+	.type	_or1k_interrupt_handler,@function
+
+_or1k_interrupt_handler:
+	/* Make room on stack, save link register */
+	l.addi	r1,r1,-12
+	l.sw	0(r1),r9
+
+	/* Read PICSR */
+	l.mfspr	r3,r0,OR1K_SPR_PIC_PICSR_ADDR
+
+	/* Load handler table base address */
+	l.movhi r7,hi(_or1k_interrupt_handler_table)
+	l.ori	r7,r7,lo(_or1k_interrupt_handler_table)
+	/* Load data pointer table base address */
+	l.movhi r12,hi(_or1k_interrupt_handler_data_ptr_table)
+	l.ori	r12,r12,lo(_or1k_interrupt_handler_data_ptr_table)
+#ifdef __OR1K_MULTICORE__
+	/* Read the addresses of the arrays of cores */
+	/* r7 = (*or1k_interrupt_handler_table)  */
+	l.lwz	r7,0(r7)
+	/* r12 = (*or1k_interrupt_handler_data_ptr_table)  */
+	l.lwz	r12,0(r12)
+	/* Generate offset in arrays */
+	/* r14 = coreid */
+	l.mfspr	r14,r0,OR1K_SPR_SYS_COREID_ADDR
+	/* r14 = coreid*32*4 = off */
+	l.slli	r14,r14,7
+	/* r7 = (*or1k_exception_handler_table)[coreid] */
+	l.add	r7,r7,r14
+	/* r12 = (*or1k_exception_handler_table)[coreid] */
+	l.add	r12,r12,r14
+#endif
+
+.L0:
+	/* Find first set bit in PICSR */
+	l.ff1	r4,r3
+	/* Any bits set? */
+	l.sfne	r4,r0
+	/* If none, finish */
+	OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L2))
+	/* What is IRQ function table offset? */
+	l.addi	r5,r4,-1
+	l.slli	r6,r5,2
+	/* Add this to table bases */
+	l.add	r14,r6,r7
+	l.add	r13,r6,r12
+
+	/* Fetch handler function address */
+	l.lwz	r14,0(r14)
+
+	/* Double check it's valid, compare against INTERRUPT_HANDLER_NOT_SET */
+	l.sfne	r14,r0
+	/* Skip if no handler: TODO: Indicate interrupt fired but no handler*/
+	OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L1))
+
+	/* Pull out data pointer from table, save r3, we'll write over it */
+	l.sw	4(r1),r3
+	l.lwz	r3,0(r13)
+	/* Call handler, save r5 in delay slot */
+	OR1K_DELAYED(
+		OR1K_INST(l.sw   8(r1),r5),
+		OR1K_INST(l.jalr r14)
+	)
+
+	/* Reload r3,r5 */
+	l.lwz	r3,4(r1)
+	l.lwz	r5,8(r1)
+.L1:
+	/* Clear bit from PICSR, return to start of checking loop */
+	l.ori	r6,r0,1
+	l.sll	r6,r6,r5
+	OR1K_DELAYED(
+		OR1K_INST(l.xor r3,r3,r6),
+		OR1K_INST(l.j   .L0)
+	)
+
+.L2:
+	/* Finish up - write PICSR back, restore r9*/
+	l.lwz	r9,0(r1)
+	l.mtspr	r0,r3,OR1K_SPR_PIC_PICSR_ADDR
+	OR1K_DELAYED(
+		OR1K_INST(l.addi r1,r1,12),
+		OR1K_INST(l.jr   r9)
+	)
+
+/* -------------------------------------------------------------------------- */
+/*!Function to enable an interrupt handler in the PICMR
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_interrupt_enable
+	.type	or1k_interrupt_enable,@function
+
+	/* r3 should have IRQ line for peripheral */
+or1k_interrupt_enable:
+	l.addi 	r1,r1,-4
+	l.sw	0(r1),r4
+	l.ori	r4,r0,0x1
+	l.sll	r4,r4,r3
+	l.mfspr	r3,r0,OR1K_SPR_PIC_PICMR_ADDR
+	l.or	r3,r3,r4
+	l.mtspr	r0,r3,OR1K_SPR_PIC_PICMR_ADDR
+	l.lwz	r4,0(r1)
+	OR1K_DELAYED(
+		OR1K_INST(l.addi	r1,r1,4),
+		OR1K_INST(l.jr	r9)
+	)
+
+/* -------------------------------------------------------------------------- */
+/*!Function to disable an interrupt handler in the PICMR
+                                                                              */
+/* -------------------------------------------------------------------------- */
+	.global	or1k_interrupt_disable
+	.type	or1k_interrupt_disable,@function
+
+	/* r3 should have IRQ line for peripheral */
+or1k_interrupt_disable:
+	l.addi 	r1,r1,-4
+	l.sw	0(r1),r4
+	l.ori	r4,r0,0x1
+	l.sll	r4,r4,r3
+	l.xori	r4,r4,0xffff
+	l.mfspr	r3,r0,OR1K_SPR_PIC_PICMR_ADDR
+	l.and	r3,r3,r4
+	l.mtspr	r0,r3,OR1K_SPR_PIC_PICMR_ADDR
+	l.lwz	r4,0(r1)
+	OR1K_DELAYED(
+		OR1K_INST(l.addi r1,r1,4),
+		OR1K_INST(l.jr   r9)
+	)
diff --git a/libgloss/or1k/interrupts.c b/libgloss/or1k/interrupts.c
new file mode 100644
index 0000000..6badc49
--- /dev/null
+++ b/libgloss/or1k/interrupts.c
@@ -0,0 +1,69 @@
+/* interrupts.c -- interrupt handling for OpenRISC 1000.
+ *
+ * Copyright (c) 2014 Authors
+ *
+ * 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.
+ */
+
+#include "include/or1k-support.h"
+#include "include/or1k-sprs.h"
+#include <stdint.h>
+
+#include "or1k-internals.h"
+
+#ifdef __OR1K_MULTICORE__
+or1k_interrupt_handler_table_t *_or1k_interrupt_handler_table;
+or1k_interrupt_handler_data_ptr_table_t *_or1k_interrupt_handler_data_ptr_table;
+#else
+or1k_interrupt_handler_table_t _or1k_interrupt_handler_table;
+or1k_interrupt_handler_data_ptr_table_t _or1k_interrupt_handler_data_ptr_table;
+#endif
+
+void or1k_interrupt_handler_add(uint32_t id,
+		or1k_interrupt_handler_fptr handler,
+		void *data_ptr)
+{
+#ifdef __OR1K_MULTICORE__
+	_or1k_interrupt_handler_table[or1k_coreid()][id] = handler;
+	_or1k_interrupt_handler_data_ptr_table[or1k_coreid()][id] = (uint32_t) data_ptr;
+#else
+	_or1k_interrupt_handler_table[id] = handler;
+	_or1k_interrupt_handler_data_ptr_table[id] = (uint32_t) data_ptr;
+#endif
+}
+
+void
+or1k_interrupts_enable(void)
+{
+	uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
+	sr = OR1K_SPR_SYS_SR_IEE_SET(sr, 1);
+	or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
+}
+
+uint32_t
+or1k_interrupts_disable(void)
+{
+	uint32_t oldsr, newsr;
+	oldsr= or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
+	newsr = OR1K_SPR_SYS_SR_IEE_SET(oldsr, 0);
+	or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, newsr);
+	return OR1K_SPR_SYS_SR_IEE_GET(oldsr);
+}
+
+void
+or1k_interrupts_restore(uint32_t sr_iee)
+{
+	uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
+	sr = OR1K_SPR_SYS_SR_IEE_SET(sr, sr_iee);
+	or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
+}
diff --git a/libgloss/or1k/mmu-asm.S b/libgloss/or1k/mmu-asm.S
new file mode 100644
index 0000000..535824c
--- /dev/null
+++ b/libgloss/or1k/mmu-asm.S
@@ -0,0 +1,67 @@
+/* mmu-asm.S -- MMU handling 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.
+ */
+
+/* -------------------------------------------------------------------------- */
+/*!Function to control MMU
+                                                                              */
+/* -------------------------------------------------------------------------- */
+
+#include "include/or1k-asm.h"
+#include "include/or1k-sprs.h"
+
+/* MMU control functions always switch MMU control with a l.rfe to return
+   from function */
+	.section .text
+
+	.global or1k_dmmu_enable
+or1k_dmmu_enable:
+	l.mfspr	r3,r0,OR1K_SPR_SYS_SR_ADDR
+	l.ori	r3,r3,OR1K_SPR_SYS_SR_DME_MASK
+	l.mtspr	r0,r3,OR1K_SPR_SYS_ESR_BASE
+	l.mtspr	r0,r9,OR1K_SPR_SYS_EPCR_BASE
+	OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
+
+
+	.global or1k_dmmu_disable
+or1k_dmmu_disable:
+	l.ori	r3,r0,OR1K_SPR_SYS_SR_DME_MASK
+	l.xori	r4,r3,0xffff
+	l.mfspr	r3,r0,OR1K_SPR_SYS_SR_ADDR
+	l.and	r3,r4,r3
+	l.mtspr	r0,r3,OR1K_SPR_SYS_ESR_BASE
+	l.mtspr	r0,r9,OR1K_SPR_SYS_EPCR_BASE
+	OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
+
+
+	.global or1k_immu_enable
+or1k_immu_enable:
+	l.mfspr	r3,r0,OR1K_SPR_SYS_SR_ADDR
+	l.ori	r3,r3,OR1K_SPR_SYS_SR_IME_MASK
+	l.mtspr	r0,r3,OR1K_SPR_SYS_ESR_BASE
+	l.mtspr	r0,r9,OR1K_SPR_SYS_EPCR_BASE
+	OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
+
+	.global or1k_immu_disable
+or1k_immu_disable:
+	l.ori	r3,r0,OR1K_SPR_SYS_SR_IME_MASK
+	l.xori	r4,r3,0xffff
+	l.mfspr	r3,r0,OR1K_SPR_SYS_SR_ADDR
+	l.and	r3,r4,r3
+	l.mtspr	r0,r3,OR1K_SPR_SYS_ESR_BASE
+	l.mtspr	r0,r9,OR1K_SPR_SYS_EPCR_BASE
+	OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
diff --git a/libgloss/or1k/or1k-internals.h b/libgloss/or1k/or1k-internals.h
new file mode 100644
index 0000000..b24ad13
--- /dev/null
+++ b/libgloss/or1k/or1k-internals.h
@@ -0,0 +1,67 @@
+#ifndef __OR1K_INTERNAL_H__
+#define __OR1K_INTERNAL_H__
+
+#include <stdint.h>
+#include <string.h>
+
+#include "include/or1k-support.h"
+
+extern uint32_t* _or1k_stack_top;
+extern size_t _or1k_stack_size;
+extern uint32_t* _or1k_stack_bottom;
+
+extern uint32_t* _or1k_exception_stack_top;
+extern size_t _or1k_exception_stack_size;
+extern uint32_t* _or1k_exception_stack_bottom;
+
+#ifdef __OR1K_MULTICORE__
+extern uint32_t* *_or1k_stack_core;
+extern uint32_t* *_or1k_exception_stack_core;
+#endif
+
+
+// The first two vectors are not used (address 0 and reset)
+#define OR1K_NUM_EXCEPTIONS 30
+
+typedef or1k_exception_handler_fptr or1k_exception_handler_table_t[OR1K_NUM_EXCEPTIONS];
+
+#ifdef __OR1K_MULTICORE__
+extern or1k_exception_handler_table_t *_or1k_exception_handler_table;
+#else
+extern or1k_exception_handler_table_t _or1k_exception_handler_table;
+#endif
+
+typedef or1k_interrupt_handler_fptr or1k_interrupt_handler_table_t[32];
+typedef void* or1k_interrupt_handler_data_ptr_table_t[32];
+
+#ifdef __OR1K_MULTICORE__
+extern or1k_interrupt_handler_table_t *_or1k_interrupt_handler_table;
+extern or1k_interrupt_handler_data_ptr_table_t *_or1k_interrupt_handler_data_ptr_table;
+#else
+extern or1k_interrupt_handler_table_t _or1k_interrupt_handler_table;
+extern or1k_interrupt_handler_data_ptr_table_t _or1k_interrupt_handler_data_ptr_table;
+#endif
+
+extern void _or1k_interrupt_handler(void);
+
+struct _or1k_reent {
+	/* Tick timer variable */
+	volatile uint32_t or1k_timer_ticks;
+
+	/* Tick rate storage */
+	uint32_t or1k_timer_period;
+	uint32_t or1k_timer_mode;
+};
+
+
+#ifdef __OR1K_MULTICORE__
+extern struct _or1k_reent (*_or1k_reent)[];
+#define OR1K_REENT (*_or1k_reent)[or1k_coreid()]
+#else
+extern struct _or1k_reent _or1k_reent;
+#define OR1K_REENT _or1k_reent
+#endif
+
+extern void _or1k_reent_init();
+
+#endif
diff --git a/libgloss/or1k/or1k_uart.c b/libgloss/or1k/or1k_uart.c
new file mode 100644
index 0000000..3d79f45
--- /dev/null
+++ b/libgloss/or1k/or1k_uart.c
@@ -0,0 +1,82 @@
+/* or1k_uart.c -- UART implementation for OpenRISC 1000.
+ *
+ *Copyright (c) 2014 Authors
+ *
+ * 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.
+ */
+
+#include "include/or1k-support.h"
+#include "or1k_uart.h"
+
+#include <stdint.h>
+
+void (*_or1k_uart_read_cb)(char c);
+
+void _or1k_uart_interrupt_handler(uint32_t data)
+{
+	_or1k_uart_read_cb(REG8(RB));
+}
+
+int _or1k_uart_init(void)
+{
+	uint16_t divisor;
+
+	// Is uart present?
+	if (!_or1k_board_uart_base) {
+			return -1;
+	}
+
+	// Reset the callback function
+	_or1k_uart_read_cb = 0;
+
+	// Calculate and set divisor
+	divisor = _or1k_board_clk_freq / (_or1k_board_uart_baud * 16);
+	REG8(LCR) = LCR_DLA;
+	REG8(DLB1) = divisor & 0xff;
+	REG8(DLB2) = divisor >> 8;
+
+	// Set line control register:
+	//  - 8 bits per character
+	//  - 1 stop bit
+	//  - No parity
+	//  - Break disabled
+	//  - Disallow access to divisor latch
+	REG8(LCR) = LCR_BPC_8;
+
+	// Reset FIFOs and set trigger level to 14 bytes
+	REG8(FCR) = FCR_CLRRECV | FCR_CLRTMIT | FCR_TRIG_14;
+
+	// Disable all interrupts
+	REG8(IER) = 0;
+
+	return 0;
+}
+
+void _or1k_uart_write(char c)
+{
+	while (!REG8(LSR) & LSR_TFE) {}
+
+	REG8(THR) = c;
+}
+
+void or1k_uart_set_read_cb(void (*cb)(char c))
+{
+	_or1k_uart_read_cb = cb;
+
+	// Enable interrupt
+	REG8(IER) = 1 << IER_RDAI;
+
+	or1k_interrupt_handler_add(_or1k_board_uart_IRQ,
+			_or1k_uart_interrupt_handler, 0);
+	or1k_interrupt_enable(_or1k_board_uart_IRQ);
+}
diff --git a/libgloss/or1k/or1k_uart.h b/libgloss/or1k/or1k_uart.h
new file mode 100644
index 0000000..dc8a3db
--- /dev/null
+++ b/libgloss/or1k/or1k_uart.h
@@ -0,0 +1,83 @@
+/* or1k_uart.h -- UART definitions for OpenRISC 1000.
+ *
+ * Copyright (c) 2014 Authors
+ *
+ * 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.
+ */
+
+/* This is the generic board support for the OpenCores UART device */
+
+#include <stdint.h>
+
+#include "board.h"
+
+extern void (*_or1k_uart_read_cb)(char c);
+
+void _or1k_uart_interrupt_handler(uint32_t data);
+
+int _or1k_uart_init(void);
+void _or1k_uart_write(char c);
+
+#define RB  _or1k_board_uart_base + 0
+#define THR _or1k_board_uart_base + 0
+#define IER _or1k_board_uart_base + 1
+#define IIR _or1k_board_uart_base + 2
+#define FCR _or1k_board_uart_base + 2
+#define LCR _or1k_board_uart_base + 3
+#define MCR _or1k_board_uart_base + 4
+#define LSR _or1k_board_uart_base + 5
+#define MSR _or1k_board_uart_base + 6
+
+#define DLB1 _or1k_board_uart_base + 0
+#define DLB2 _or1k_board_uart_base + 1
+
+#define IER_RDAI 0
+#define IER_TEI  1
+#define IER_RLSI 2
+#define IER_MSI  3
+
+#define IIR_RLS  0xC3
+#define IIR_RDA  0xC2
+#define IIR_TO   0xC6
+#define IIR_THRE 0xC1
+#define IIT_MS   0xC0
+
+#define FCR_CLRRECV 0x1
+#define FCR_CLRTMIT 0x2
+#define FCR_TRIG_1  0x0
+#define FCR_TRIG_4  0x40
+#define FCR_TRIG_8  0x80
+#define FCR_TRIG_14 0xC0
+
+#define LCR_BPC_MASK 0x3
+#define LCR_SB_MASK  0x4
+
+#define LCR_BPC_5 0x0
+#define LCR_BPC_6 0x1
+#define LCR_BPC_7 0x2
+#define LCR_BPC_8 0x3
+#define LCR_SB_1  0x0
+#define LCR_SB_2  0x4
+#define LCR_PE    0x8
+#define LCR_EPS   0x10
+#define LCR_SP    0x20
+#define LCR_BC    0x40
+#define LCR_DLA   0x80
+
+#define LSR_DR  0x0
+#define LSR_OE  0x2
+#define LSR_PE  0x4
+#define LSR_FE  0x8
+#define LSR_BI  0x10
+#define LSR_TFE 0x20
+#define LSR_TEI 0x40
diff --git a/libgloss/or1k/outbyte.S b/libgloss/or1k/outbyte.S
new file mode 100644
index 0000000..2cd5148
--- /dev/null
+++ b/libgloss/or1k/outbyte.S
@@ -0,0 +1,34 @@
+/* outbyte.S -- Write one byte for OpenRISC 1000.
+ *
+ * Copyright (c) 2014 Authors
+ *
+ * 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.
+ */
+
+#include "include/or1k-asm.h"
+
+.global _or1k_outbyte
+
+.text
+_or1k_outbyte:
+	LOAD_SYMBOL_2_GPR(r4,_or1k_board_uart_base)
+	l.lwz	r4, 0(r4)
+	l.sfeq	r4, r0
+	OR1K_DELAYED_NOP(l.bf .Lnouart)
+.Luart:
+	OR1K_DELAYED_NOP(l.j _or1k_uart_write)
+.Lnouart:
+	OR1K_DELAYED(
+		OR1K_INST(l.nop 0x4),
+		OR1K_INST(l.jr r9)
+	)
diff --git a/libgloss/or1k/sbrk.c b/libgloss/or1k/sbrk.c
new file mode 100644
index 0000000..de80663
--- /dev/null
+++ b/libgloss/or1k/sbrk.c
@@ -0,0 +1,52 @@
+/* sbrk.c -- allocate space on heap on OpenRISC 1000.
+ *
+ * Copyright (c) 2014 Authors
+ *
+ * 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.
+ */
+
+#include <reent.h>
+
+#include "include/or1k-support.h"
+
+static uint32_t _or1k_heap_end;
+
+void *
+_sbrk_r (struct _reent * reent, ptrdiff_t incr)
+{
+	extern uint32_t	end; /* Set by linker.  */
+	uint32_t	prev_heap_end;
+
+	// This needs to be atomic
+
+	// Disable interrupts on this core
+	uint32_t sr_iee = or1k_interrupts_disable();
+	uint32_t sr_tee = or1k_timer_disable();
+
+	// Initialize heap end to end if not initialized before
+	or1k_sync_cas((void*) &_or1k_heap_end, 0, (uint32_t) &end);
+
+	do {
+		// Read previous heap end
+		prev_heap_end = _or1k_heap_end;
+		// and try to set it to the new value as long as it has changed
+	} while (or1k_sync_cas((void*) &_or1k_heap_end,
+			(uint32_t) prev_heap_end,
+			(uint32_t) (prev_heap_end + incr)) != (uint32_t) prev_heap_end);
+
+	// Restore interrupts on this core
+	or1k_timer_restore(sr_tee);
+	or1k_interrupts_restore(sr_iee);
+
+	return (void*) prev_heap_end;
+}
diff --git a/libgloss/or1k/sync-asm.S b/libgloss/or1k/sync-asm.S
new file mode 100644
index 0000000..911e255
--- /dev/null
+++ b/libgloss/or1k/sync-asm.S
@@ -0,0 +1,135 @@
+#include "include/or1k-asm.h"
+#include "include/or1k-sprs.h"
+
+	.section .text
+
+
+	.global	or1k_has_multicore_support
+	.type	or1k_has_multicore_support,@function
+or1k_has_multicore_support:
+#ifdef __OR1K_MULTICORE__
+	// Return 1
+	OR1K_DELAYED(
+		OR1K_INST(l.ori r11,r0,1),
+		OR1K_INST(l.jr  r9)
+	)
+#else
+	// Return 0
+	OR1K_DELAYED(
+		OR1K_INST(l.or r11,r0,r0),
+		OR1K_INST(l.jr r9)
+	)
+#endif
+
+	.global	or1k_coreid
+	.type	or1k_coreid,@function
+or1k_coreid:
+#ifdef __OR1K_MULTICORE__
+	// Return SPR with core identifier
+	OR1K_DELAYED(
+		OR1K_INST(l.mfspr r11,r0,OR1K_SPR_SYS_COREID_ADDR),
+		OR1K_INST(l.jr    r9)
+	)
+#else
+	// Return 0
+	OR1K_DELAYED(
+		OR1K_INST(l.or r11,r0,r0),
+		OR1K_INST(l.jr r9)
+	)
+#endif
+
+	.global	or1k_numcores
+	.type	or1k_numcores,@function
+or1k_numcores:
+#ifdef __OR1K_MULTICORE__
+	// Return SPR with number of cores
+	OR1K_DELAYED(
+		OR1K_INST(l.mfspr r11,r0,OR1K_SPR_SYS_NUMCORES_ADDR),
+		OR1K_INST(l.jr    r9)
+	)
+#else
+	// Return 1
+	OR1K_DELAYED(
+		OR1K_INST(l.ori r11,r0,1),
+		OR1K_INST(l.jr r9)
+	)
+#endif
+
+	.global	or1k_sync_ll
+	.type	or1k_sync_ll,@function
+or1k_sync_ll:
+#ifdef __OR1K_MULTICORE__
+	// Load word atomic
+	OR1K_DELAYED(
+		OR1K_INST(l.lwa r11, 0(r3)),
+		OR1K_INST(l.jr  r9)
+	)
+#else
+	// Simply load word, TODO: throw exception? which?
+	OR1K_DELAYED(
+		OR1K_INST(l.lwz r11, 0(r3)),
+		OR1K_INST(l.jr  r9)
+	)
+#endif
+
+	.global	or1k_sync_sc
+	.type	or1k_sync_sc,@function
+or1k_sync_sc:
+#ifdef __OR1K_MULTICORE__
+	// swa sets the flag if it was succesfull
+	// Store the value to address and set flag
+	l.swa 0(r3),r4
+	OR1K_DELAYED(
+		// Set return to success speculatively (may go to delay slot)
+		OR1K_INST(l.ori r11,r0,1),
+		// If the swa was successfull, jump to end
+		OR1K_INST(l.bf  .or1k_sync_sc_done)
+	)
+	// If the swa was not successfull, set
+	l.or r11,r0,r0
+.or1k_sync_sc_done:
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+#else
+	// Simply store word, TODO: throw exception? which?
+	OR1K_DELAYED(
+		OR1K_INST(l.sw 0(r3),r4),
+		OR1K_INST(l.jr r9)
+	)
+#endif
+
+
+	.global or1k_sync_cas
+	.type	or1k_sync_sc,@function
+or1k_sync_cas:
+#ifdef __OR1K_MULTICORE__
+	/* Load linked address value to return register */
+	l.lwa	r11,0(r3)
+	/* Compare value to parameter */
+	l.sfeq	r11,r4
+	/* If not equal: abort and return the read value */
+	OR1K_DELAYED_NOP(OR1K_INST(l.bnf .or1k_sync_cas_done))
+	/* If compare was successfull: try writing */
+	l.swa	0(r3),r5
+	/* If writing was not successful: restart */
+	OR1K_DELAYED_NOP(OR1K_INST(l.bnf or1k_sync_cas))
+.or1k_sync_cas_done:
+	/* Return value is the original read value */
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+#else
+	// Non-atomic CAS, TODO: throw exception? which?
+	l.lwz	r11,0(r3)
+	l.sfeq	r11,r4
+	OR1K_DELAYED_NOP(OR1K_INST(l.bnf .or1k_sync_cas_done))
+	l.sw	0(r3),r5
+.or1k_sync_cas_done:
+	OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
+#endif
+
+	.global or1k_sync_tsl
+	.type	or1k_sync_tsl,@function
+or1k_sync_tsl:
+	l.or	r4,r0,r0
+	OR1K_DELAYED(
+		OR1K_INST(l.addi r5,r0,1),
+		OR1K_INST(l.j    or1k_sync_cas)
+	)
diff --git a/libgloss/or1k/syscalls.c b/libgloss/or1k/syscalls.c
new file mode 100644
index 0000000..690d21a
--- /dev/null
+++ b/libgloss/or1k/syscalls.c
@@ -0,0 +1,160 @@
+/* syscalls.c -- reentrant syscalls 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.
+ */
+
+#include <errno.h>
+#include <reent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "board.h"
+
+/* Write is actually the only thing we provide. All other are stubs.. */
+
+extern void _or1k_outbyte(char c);
+
+_ssize_t
+_write_r(struct _reent * reent, int fd, const void *buf, size_t nbytes)
+{
+	int i;
+	char* b = (char*) buf;
+
+	for (i = 0; i < nbytes; i++) {
+		if (*(b + i) == '\n') {
+			_or1k_outbyte ('\r');
+		}
+		_or1k_outbyte (*(b + i));
+	}
+	return (nbytes);
+}
+
+void
+_exit(int rc)
+{
+	_or1k_board_exit();
+	while (1) {}
+}
+
+int
+_close_r(struct _reent *reent, int fildes)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+char *__env[1] = { 0 };
+char **environ = __env;
+
+int
+_execve_r(struct _reent *reent, const char *name, char * const *argv,
+		char * const *env)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_fork_r(struct _reent *reent)
+{
+	errno = ENOSYS;
+	return -1;
+}
+
+int
+_fstat_r(struct _reent *reent, int fildes, struct stat *st)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_getpid_r(struct _reent *reent)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_gettimeofday(struct _reent *reent, struct timeval  *ptimeval, void *ptimezone)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_isatty_r(struct _reent *reent, int file)
+{
+	reent->_errno = ENOSYS;
+	return 0;
+}
+
+int
+_kill_r(struct _reent *reent, int pid, int sig)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_link_r(struct _reent *reent, const char *existing, const char *new)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+_off_t
+_lseek_r(struct _reent *reent, int file, _off_t ptr, int dir)
+{
+	errno = ENOSYS;
+	return -1;
+}
+
+int
+_open(struct _reent *reent, char *file, int flags, int mode)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+_ssize_t
+_read_r(struct _reent *reent, int file, void *ptr, size_t len)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_readlink_r(struct _reent *reent, const char *path, char *buf, size_t bufsize)
+{
+	reent->_errno = ENOSYS;
+	return -1;
+}
+
+int
+_stat_r(struct _reent *reent, const char *path, struct stat *buf)
+{
+	reent->_errno = EIO;
+	return -1;
+}
+
+int
+_unlink_r(struct _reent *reent, const char * path)
+{
+	reent->_errno = EIO;
+	return (-1);
+}
+
diff --git a/libgloss/or1k/timer.c b/libgloss/or1k/timer.c
new file mode 100644
index 0000000..27a24a1
--- /dev/null
+++ b/libgloss/or1k/timer.c
@@ -0,0 +1,186 @@
+/* timer.c -- tick timer functions 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.
+ */
+
+#include "include/or1k-support.h"
+#include "include/or1k-sprs.h"
+
+#include "or1k-internals.h"
+#include "board.h"
+
+/* --------------------------------------------------------------------------*/
+/*!Tick timer interrupt handler
+
+   Increment timer ticks counter, reload TTMR
+                                                                             */
+/* --------------------------------------------------------------------------*/
+void
+_or1k_timer_interrupt_handler(void)
+{
+	OR1K_REENT.or1k_timer_ticks++;
+	uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
+	ttmr = OR1K_SPR_TICK_TTMR_IE_SET(ttmr, 1);
+	ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, OR1K_SPR_TICK_TTMR_MODE_RESTART);
+	ttmr = OR1K_SPR_TICK_TTMR_IE_SET(ttmr, 1);
+	or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
+}
+
+/* --------------------------------------------------------------------------*/
+/*!Enable tick timer
+
+   Install handler, calculate TTMR period, reset tick counter
+
+   @param[in] hz     Rate at which to trigger timer ticks                    */
+/* --------------------------------------------------------------------------*/
+int
+or1k_timer_init(unsigned int hz)
+{
+	uint32_t upr = or1k_mfspr(OR1K_SPR_SYS_UPR_ADDR);
+	if (OR1K_SPR_SYS_UPR_TTP_GET(upr) == 0) {
+		return -1;
+	}
+
+	/* Set this, for easy access when reloading */
+	uint32_t period = (_or1k_board_clk_freq/hz) & OR1K_SPR_TICK_TTMR_TP_MASK;
+	OR1K_REENT.or1k_timer_period = period;
+	or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, period);
+
+	/* Reset timer tick counter */
+	OR1K_REENT.or1k_timer_ticks = 0;
+
+	/* Install handler */
+	or1k_exception_handler_add(0x5, _or1k_timer_interrupt_handler);
+	OR1K_REENT.or1k_timer_mode = OR1K_SPR_TICK_TTMR_MODE_RESTART;
+
+	/* Reset counter register */
+	or1k_mtspr(OR1K_SPR_TICK_TTCR_ADDR, 0);
+
+	return 0;
+}
+
+void
+or1k_timer_set_period(uint32_t hz)
+{
+	uint32_t period = (_or1k_board_clk_freq/hz) & OR1K_SPR_TICK_TTMR_TP_MASK;
+	uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
+	ttmr = OR1K_SPR_TICK_TTMR_TP_SET(ttmr, period);
+	or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
+	OR1K_REENT.or1k_timer_period = period;
+}
+
+void
+or1k_timer_set_handler(void (*handler)(void))
+{
+	or1k_exception_handler_add(0x5, handler);
+}
+
+void
+or1k_timer_set_mode(uint32_t mode)
+{
+	// Store mode in variable
+	OR1K_REENT.or1k_timer_mode = mode;
+
+	uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
+	// If the timer is currently running, we also change the mode
+	if (OR1K_SPR_TICK_TTMR_MODE_GET(ttmr) != 0) {
+		ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, mode);
+		or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
+	}
+}
+
+/* --------------------------------------------------------------------------*/
+/*!Enable tick timer
+
+   Enable timer interrupt, install handler, load TTMR
+                                                                             */
+/* --------------------------------------------------------------------------*/
+void
+or1k_timer_enable(void)
+{
+	uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
+	ttmr = OR1K_SPR_TICK_TTMR_IE_SET(ttmr, 1);
+	ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, OR1K_REENT.or1k_timer_mode);
+	or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
+
+	uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
+	sr = OR1K_SPR_SYS_SR_TEE_SET(sr, 1);
+	or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
+}
+
+/* --------------------------------------------------------------------------*/
+/*!Disable tick timer
+
+   Disable timer interrupt in SR
+                                                                             */
+/* --------------------------------------------------------------------------*/
+uint32_t
+or1k_timer_disable(void)
+{
+	uint32_t oldsr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
+	uint32_t sr = OR1K_SPR_SYS_SR_TEE_SET(oldsr, 0);
+	or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
+	return OR1K_SPR_SYS_SR_TEE_GET(oldsr);
+}
+
+void
+or1k_timer_restore(uint32_t sr_tee)
+{
+	uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
+	sr = OR1K_SPR_SYS_SR_TEE_SET(sr, 1);
+	or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
+}
+
+void
+or1k_timer_pause(void)
+{
+	uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
+	ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, OR1K_SPR_TICK_TTMR_MODE_DISABLE);
+	or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
+}
+
+void
+or1k_timer_reset(void)
+{
+	uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
+	ttmr = OR1K_SPR_TICK_TTMR_IP_SET(ttmr, 0);
+	or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
+	or1k_mtspr(OR1K_SPR_TICK_TTCR_ADDR, 0);
+}
+
+/* --------------------------------------------------------------------------*/
+/*!Get tick timer
+
+   Return value of tick timer
+                                                                             */
+/* --------------------------------------------------------------------------*/
+unsigned long
+or1k_timer_get_ticks(void)
+{
+	return OR1K_REENT.or1k_timer_ticks;
+}
+
+/* --------------------------------------------------------------------------*/
+/*!Reset tick timer
+
+   Clear value of tick timer
+                                                                             */
+/* --------------------------------------------------------------------------*/
+void
+or1k_timer_reset_ticks(void)
+{
+	OR1K_REENT.or1k_timer_ticks = 0;
+}
diff --git a/libgloss/or1k/util.c b/libgloss/or1k/util.c
new file mode 100644
index 0000000..7407171
--- /dev/null
+++ b/libgloss/or1k/util.c
@@ -0,0 +1,83 @@
+/* util.c -- Utility functions for OpenRISC 1000.
+ *
+ * Copyright (c) 2014 Authors
+ *
+ * Contributor Julius Baxter <julius.baxter@orsoc.se>
+ * 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.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <reent.h>
+
+#include "or1k-internals.h"
+
+#ifdef __OR1K_MULTICORE__
+uint32_t* *_or1k_stack_core;
+uint32_t* *_or1k_exception_stack_core;
+#endif
+
+uint32_t* _or1k_stack_top;
+uint32_t* _or1k_stack_bottom;
+
+uint32_t* _or1k_exception_stack_top;
+uint32_t* _or1k_exception_stack_bottom;
+
+void _or1k_init() {
+#ifdef __OR1K_MULTICORE__
+	uint32_t c;
+
+	// Initialize stacks
+	_or1k_stack_core = _sbrk_r(0, sizeof(uint32_t*) * or1k_numcores());
+	_or1k_exception_stack_core = _sbrk_r(0, sizeof(uint32_t*) * or1k_numcores());
+
+	_or1k_stack_core[0] = _or1k_stack_top;
+	_or1k_exception_stack_core[0] = _or1k_exception_stack_top;
+
+	for (c = 1; c < or1k_numcores(); c++) {
+		_or1k_stack_core[c] = _or1k_stack_core[c-1] - _or1k_stack_size;
+		_or1k_exception_stack_core[c] = _or1k_exception_stack_core[c-1] -
+				_or1k_exception_stack_size;
+	}
+
+	size_t exc_size = sizeof(void*) * or1k_numcores() * OR1K_NUM_EXCEPTIONS;
+	_or1k_exception_handler_table = _sbrk_r(0, exc_size);
+
+	size_t int_size = sizeof(void*) * or1k_numcores() * 32;
+	size_t intdata_size = sizeof(void*) * or1k_numcores() * 32;
+	_or1k_interrupt_handler_table = _sbrk_r(0, int_size);
+	_or1k_interrupt_handler_data_ptr_table = _sbrk_r(0, intdata_size);
+#endif
+
+	_or1k_reent_init();
+
+#ifdef __OR1K_MULTICORE__
+	for (c = 0; c < or1k_numcores(); c++) {
+		_or1k_exception_handler_table[c][6] = _or1k_interrupt_handler;
+	}
+#else
+	_or1k_exception_handler_table[6] = _or1k_interrupt_handler;
+#endif
+}
+
+uint32_t or1k_critical_begin() {
+	uint32_t iee = or1k_interrupts_disable();
+	uint32_t tee = or1k_timer_disable();
+	return (iee << 1) | tee;
+}
+
+void or1k_critical_end(uint32_t restore) {
+	or1k_timer_restore(restore & 0x1);
+	or1k_interrupts_restore((restore >> 1) & 0x1);
+}
+

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]