[arch][or1k] add or1k (OpenRISC 1000) architecture

This add support for the OpenRISC 1000 architecture, and
as the architecture specification defines an on-chip tick-timer
and interrupt controller, drivers for those are included in
this commit.
Support to utilize the MMU is implemented,
and it can be opted in and out with WITH_KERNEL_VM
This commit is contained in:
Stefan Kristiansson
2015-03-06 06:59:57 +02:00
parent 1f91f5fb01
commit c3dc155f16
22 changed files with 4306 additions and 0 deletions

45
arch/or1k/arch.c Normal file
View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2015 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <trace.h>
#include <err.h>
#include <arch/or1k.h>
#include <arch/ops.h>
#include <arch/mmu.h>
void arch_early_init(void)
{
}
void arch_init(void)
{
TRACE;
}
void arch_idle(void)
{
}
void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3)
{
PANIC_UNIMPLEMENTED;
}

58
arch/or1k/asm.S Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <asm.h>
/* void or1k_context_switch(
struct or1k_context_switch_frame *oldcs,
struct or1k_context_switch_frame *newcs); */
FUNCTION(or1k_context_switch)
/* save old context */
l.sw 0(r3), r1
l.sw 4(r3), r2
l.sw 8(r3), r9
l.sw 12(r3), r10
l.sw 16(r3), r14
l.sw 20(r3), r16
l.sw 24(r3), r18
l.sw 28(r3), r20
l.sw 32(r3), r22
l.sw 36(r3), r24
l.sw 40(r3), r26
l.sw 44(r3), r28
l.sw 48(r3), r30
/* restore new context */
l.lwz r30, 48(r4)
l.lwz r28, 44(r4)
l.lwz r26, 40(r4)
l.lwz r24, 36(r4)
l.lwz r22, 32(r4)
l.lwz r20, 28(r4)
l.lwz r18, 24(r4)
l.lwz r16, 20(r4)
l.lwz r14, 16(r4)
l.lwz r10, 12(r4)
l.lwz r9, 8(r4)
l.lwz r2, 4(r4)
l.jr r9
l.lwz r1, 0(r4)

132
arch/or1k/cache-ops.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <arch/ops.h>
#include <arch/or1k.h>
static inline uint32_t dc_block_size(void)
{
uint32_t dccfgr = mfspr(OR1K_SPR_SYS_DCCFGR_ADDR);
return dccfgr & OR1K_SPR_SYS_DCCFGR_CBS_MASK ? 32 : 16;
}
static inline uint32_t dc_sets(void)
{
uint32_t dccfgr = mfspr(OR1K_SPR_SYS_DCCFGR_ADDR);
return 1 << OR1K_SPR_SYS_DCCFGR_NCS_GET(dccfgr);
}
static inline uint32_t ic_block_size(void)
{
uint32_t iccfgr = mfspr(OR1K_SPR_SYS_ICCFGR_ADDR);
return iccfgr & OR1K_SPR_SYS_ICCFGR_CBS_MASK ? 32 : 16;
}
static inline uint32_t ic_sets(void)
{
uint32_t iccfgr = mfspr(OR1K_SPR_SYS_ICCFGR_ADDR);
return 1 << OR1K_SPR_SYS_ICCFGR_NCS_GET(iccfgr);
}
void arch_invalidate_cache_all(void)
{
uint32_t i;
uint32_t cache_size;
uint32_t block_size;
block_size = ic_block_size();
cache_size = block_size * ic_sets();
for (i = 0; i < cache_size; i += block_size)
mtspr(OR1K_SPR_ICACHE_ICBIR_ADDR, i);
block_size = dc_block_size();
cache_size = block_size * dc_sets();
for (i = 0; i < cache_size; i += block_size)
mtspr(OR1K_SPR_DCACHE_DCBIR_ADDR, i);
}
void arch_disable_cache(uint flags)
{
uint32_t sr = mfspr(OR1K_SPR_SYS_SR_ADDR);
if (flags & ICACHE)
sr &= ~OR1K_SPR_SYS_SR_ICE_MASK;
if (flags & DCACHE)
sr &= ~OR1K_SPR_SYS_SR_DCE_MASK;
mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
void arch_enable_cache(uint flags)
{
uint32_t sr = mfspr(OR1K_SPR_SYS_SR_ADDR);
if (flags & ICACHE)
sr |= OR1K_SPR_SYS_SR_ICE_MASK;
if (flags & DCACHE)
sr |= OR1K_SPR_SYS_SR_DCE_MASK;
mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
/* flush dcache */
void arch_clean_cache_range(addr_t start, size_t len)
{
addr_t addr;
uint32_t block_size = dc_block_size();
for (addr = start; addr < start + len; addr += block_size)
mtspr(OR1K_SPR_DCACHE_DCBFR_ADDR, addr);
}
/* invalidate dcache */
void arch_invalidate_cache_range(addr_t start, size_t len)
{
addr_t addr;
uint32_t block_size = dc_block_size();
for (addr = start; addr < start + len; addr += block_size)
mtspr(OR1K_SPR_DCACHE_DCBIR_ADDR, addr);
}
/* flush + invalidate dcache */
void arch_clean_invalidate_cache_range(addr_t start, size_t len)
{
/* invalidate is implied by flush on or1k */
arch_clean_cache_range(start, len);
}
/* flush dcache + invalidate icache */
void arch_sync_cache_range(addr_t start, size_t len)
{
addr_t addr;
uint32_t block_size = ic_block_size();
arch_clean_cache_range(start, len);
for (addr = start; addr < start + len; addr += block_size)
mtspr(OR1K_SPR_ICACHE_ICBIR_ADDR, addr);
}

46
arch/or1k/exceptions.c Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <kernel/thread.h>
enum handler_return platform_irq(void);
enum handler_return platform_tick(void);
void or1k_irq(void)
{
inc_critical_section();
if (platform_irq() == INT_RESCHEDULE)
thread_preempt();
dec_critical_section();
}
void or1k_tick(void)
{
inc_critical_section();
if (platform_tick() == INT_RESCHEDULE)
thread_preempt();
dec_critical_section();
}

105
arch/or1k/faults.c Normal file
View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <arch/or1k.h>
#include <kernel/thread.h>
#include <platform.h>
static void dump_fault_frame(struct or1k_iframe *frame)
{
addr_t stack = (addr_t)((char *)frame + 128 + sizeof(frame));
dprintf(CRITICAL, "r0: 0x%08x r1: 0x%08x: r2: 0x%08x r3: 0x%08x\n",
0, (uint32_t)stack, frame->r2, frame->r3);
dprintf(CRITICAL, "r4: 0x%08x r5: 0x%08x: r6: 0x%08x r7: 0x%08x\n",
frame->r4, frame->r5, frame->r6, frame->r7);
dprintf(CRITICAL, "r8: 0x%08x r9: 0x%08x: r10: 0x%08x r11: 0x%08x\n",
frame->r8, frame->r9, frame->r10, frame->r11);
dprintf(CRITICAL, "r12: 0x%08x r13: 0x%08x: r14: 0x%08x r15: 0x%08x\n",
frame->r12, frame->r13, frame->r14, frame->r15);
dprintf(CRITICAL, "r16: 0x%08x r17: 0x%08x: r18: 0x%08x r19: 0x%08x\n",
frame->r16, frame->r17, frame->r18, frame->r19);
dprintf(CRITICAL, "r20: 0x%08x r21: 0x%08x: r22: 0x%08x r23: 0x%08x\n",
frame->r20, frame->r21, frame->r22, frame->r23);
dprintf(CRITICAL, "r24: 0x%08x r25: 0x%08x: r26: 0x%08x r27: 0x%08x\n",
frame->r24, frame->r25, frame->r26, frame->r27);
dprintf(CRITICAL, "r28: 0x%08x r29: 0x%08x: r30: 0x%08x r31: 0x%08x\n",
frame->r28, frame->r29, frame->r30, frame->r31);
dprintf(CRITICAL, "PC: 0x%08x SR: 0x%08x\n",
frame->pc, frame->sr);
dprintf(CRITICAL, "bottom of stack at 0x%08x:\n", (unsigned int)stack);
hexdump((void *)stack, 128);
}
static void exception_die(struct or1k_iframe *frame, const char *msg)
{
inc_critical_section();
dprintf(CRITICAL, msg);
dump_fault_frame(frame);
platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC);
for (;;);
}
void or1k_busfault_handler(struct or1k_iframe *frame, uint32_t addr)
{
dprintf(CRITICAL, "unhandled busfault (EEAR: 0x%08x)", addr);
exception_die(frame, ", halting\n");
}
void or1k_data_pagefault_handler(struct or1k_iframe *frame, uint32_t addr)
{
dprintf(CRITICAL, "unhandled data pagefault (EEAR: 0x%08x)", addr);
exception_die(frame, ", halting\n");
}
void or1k_instruction_pagefault_handler(struct or1k_iframe *frame, uint32_t addr)
{
dprintf(CRITICAL, "unhandled instruction pagefault (EEAR: 0x%08x)", addr);
exception_die(frame, ", halting\n");
}
void or1k_alignment_handler(struct or1k_iframe *frame, uint32_t addr)
{
dprintf(CRITICAL, "unhandled unaligned access (EEAR: 0x%08x)", addr);
exception_die(frame, ", halting\n");
}
void or1k_illegal_instruction_handler(struct or1k_iframe *frame, uint32_t addr)
{
dprintf(CRITICAL, "unhandled illegal instruction (EEAR: 0x%08x)", addr);
exception_die(frame, ", halting\n");
}
void or1k_syscall_handler(struct or1k_iframe *frame)
{
exception_die(frame, "unhandled syscall, halting\n");
}
void or1k_unhandled_exception(struct or1k_iframe *frame, uint32_t vector)
{
dprintf(CRITICAL, "unhandled exception (vector: 0x%08x)", vector);
exception_die(frame, ", halting\n");
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <compiler.h>
#include <arch/or1k.h>
#ifndef ASSEMBLY
static inline void arch_enable_ints(void)
{
uint32_t sr = mfspr(OR1K_SPR_SYS_SR_ADDR);
sr |= OR1K_SPR_SYS_SR_IEE_MASK | OR1K_SPR_SYS_SR_TEE_MASK;
mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
static inline void arch_disable_ints(void)
{
uint32_t sr = mfspr(OR1K_SPR_SYS_SR_ADDR);
sr &= ~(OR1K_SPR_SYS_SR_IEE_MASK | OR1K_SPR_SYS_SR_TEE_MASK);
mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
static inline int atomic_add(volatile int *ptr, int val)
{
return __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED);
}
static inline int atomic_or(volatile int *ptr, int val)
{
return __atomic_fetch_or(ptr, val, __ATOMIC_RELAXED);
}
static inline int atomic_and(volatile int *ptr, int val)
{
return __atomic_fetch_and(ptr, val, __ATOMIC_RELAXED);
}
static inline int atomic_swap(volatile int *ptr, int val)
{
return __atomic_exchange_n(ptr, val, __ATOMIC_RELAXED);
}
static inline int atomic_cmpxchg(volatile int *ptr, int oldval, int newval)
{
__asm__ __volatile__(
"1: l.lwa %0, 0(%1) \n"
" l.sfeq %0, %2 \n"
" l.bnf 1f \n"
" l.nop \n"
" l.swa 0(%1), %3 \n"
" l.bnf 1b \n"
"1: l.nop \n"
: "=&r"(oldval)
: "r"(ptr), "r"(oldval), "r"(newval)
: "cc", "memory");
return oldval;
}
/* use a global pointer to store the current_thread */
extern struct thread *_current_thread;
static inline struct thread *get_current_thread(void)
{
return _current_thread;
}
static inline void set_current_thread(struct thread *t)
{
_current_thread = t;
}
static inline uint32_t arch_cycle_count(void) { return 0; }
#endif // !ASSEMBLY

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <sys/types.h>
struct or1k_context_switch_frame {
uint32_t r1; // stack pointer
uint32_t r2; // frame pointer
uint32_t r9; // link register
/* callee saved */
uint32_t r10;
uint32_t r14;
uint32_t r16;
uint32_t r18;
uint32_t r20;
uint32_t r22;
uint32_t r24;
uint32_t r26;
uint32_t r28;
uint32_t r30;
};
struct arch_thread {
struct or1k_context_switch_frame cs_frame;
};
void or1k_context_switch(struct or1k_context_switch_frame *oldcs,
struct or1k_context_switch_frame *newcs);

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#define PAGE_SIZE 8192
#define PAGE_SIZE_SHIFT 13
/* Cache line can be configured, but this is max */
#define CACHE_LINE 32
#define ARCH_DEFAULT_STACK_SIZE 8192

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <arch/or1k-sprs.h>
#define mtspr(_spr, _val) \
__asm__ __volatile__( \
"l.mtspr r0, %1, %0" \
: \
: "K" (_spr), "r" (_val) \
)
#define mtspr_off(_spr, _off, _val) \
__asm__ __volatile__ ( \
"l.mtspr %0, %1, %2" \
: \
: "r" (_off), "r" (_val), "K" (_spr) \
)
#define mfspr(_spr) \
({ \
uint32_t _val; \
__asm__ __volatile__( \
"l.mfspr %0, r0, %1" \
: "=r"(_val) \
: "K" (_spr) \
); \
_val; \
})
#define mfspr_off(_spr, _off) \
({ \
uint32_t _val; \
__asm__ __volatile__ ( \
"l.mfspr %0, %1, %2" \
: "=r" (_val) \
: "r" (_off), "K" (_spr) \
); \
_val; \
})
#ifndef ASSEMBLY
struct or1k_iframe {
uint32_t r2;
uint32_t r3;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t r13;
uint32_t r14;
uint32_t r15;
uint32_t r16;
uint32_t r17;
uint32_t r18;
uint32_t r19;
uint32_t r20;
uint32_t r21;
uint32_t r22;
uint32_t r23;
uint32_t r24;
uint32_t r25;
uint32_t r26;
uint32_t r27;
uint32_t r28;
uint32_t r29;
uint32_t r30;
uint32_t r31;
uint32_t pc;
uint32_t sr;
};
#endif // !ASSEMBLY

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#define SECTION_SIZE (16U*1024U*1024U)
#define OR1K_MMU_PG_FLAGS_MASK 0x7ffU
#define OR1K_MMU_PG_PRESENT 0x400
#define OR1K_MMU_PG_L 0x200
#define OR1K_MMU_PG_X 0x100
#define OR1K_MMU_PG_W 0x080
#define OR1K_MMU_PG_U 0x040
#define OR1K_MMU_PG_D 0x020
#define OR1K_MMU_PG_A 0x010
#define OR1K_MMU_PG_WOM 0x008
#define OR1K_MMU_PG_WBC 0x004
#define OR1K_MMU_PG_CI 0x002
#define OR1K_MMU_PG_CC 0x001

98
arch/or1k/linker.ld Normal file
View File

@@ -0,0 +1,98 @@
OUTPUT_FORMAT("elf32-or1k", "elf32-or1k", "elf32-or1k")
OUTPUT_ARCH(or1k)
ENTRY(_start)
SECTIONS
{
. = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%;
_start = .;
/* vector table goes at 0 */
.vectors : AT(0) {
KEEP(*(.vectors))
}
/* text/read-only data */
/* set the load address to physical MEMBASE */
.text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET% + SIZEOF(.vectors)) {
KEEP(*(.text.boot))
*(.text* .gnu.linkonce.t.*)
}
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) }
.plt : { *(.plt) }
.rodata : ALIGN(4) {
__rodata_start = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
INCLUDE "arch/shared_rodata_sections.ld"
. = ALIGN(4);
__rodata_end = .;
}
.data : ALIGN(4) {
/* writable data */
__data_start_rom = .;
/* in one segment binaries, the rom data address is on top of the ram data address */
__data_start = .;
*(.data .data.* .gnu.linkonce.d.*)
INCLUDE "arch/shared_data_sections.ld"
__ctor_list = .;
KEEP(*(.ctors .init_array))
__ctor_end = .;
__dtor_list = .;
KEEP(*(.dtors .fini_array))
__dtor_end = .;
*(.got*)
*(.dynamic)
__data_end = .;
}
/* unintialized data (in same segment as writable data) */
.bss : ALIGN(4) {
KEEP(*(.bss.prebss.*))
. = ALIGN(4);
__bss_start = .;
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end = .;
}
_end = .;
. = %KERNEL_BASE% + %MEMSIZE%;
_end_of_ram = .;
/* Strip unnecessary stuff */
/DISCARD/ : { *(.comment .note .eh_frame) }
}

214
arch/or1k/mmu.c Normal file
View File

@@ -0,0 +1,214 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
* Based on arch/arm/arm/mmu.c
* Copyright (c) 2008-2014 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <trace.h>
#include <err.h>
#include <string.h>
#include <arch/mmu.h>
#include <arch/or1k.h>
#include <arch/or1k/mmu.h>
#include <kernel/vm.h>
#define LOCAL_TRACE 0
#if WITH_KERNEL_VM
uint32_t or1k_kernel_translation_table[256] __ALIGNED(8192) __SECTION(".bss.prebss.translation_table");
/* Pessimistic tlb invalidation, which rather invalidate too much.
* TODO: make it more precise. */
void or1k_invalidate_tlb(vaddr_t vaddr, uint count)
{
uint32_t dmmucfgr = mfspr(OR1K_SPR_SYS_DMMUCFGR_ADDR);
uint32_t immucfgr = mfspr(OR1K_SPR_SYS_IMMUCFGR_ADDR);
uint32_t num_dtlb_ways = OR1K_SPR_SYS_DMMUCFGR_NTW_GET(dmmucfgr) + 1;
uint32_t num_dtlb_sets = 1 << OR1K_SPR_SYS_DMMUCFGR_NTS_GET(dmmucfgr);
uint32_t num_itlb_ways = OR1K_SPR_SYS_IMMUCFGR_NTW_GET(immucfgr) + 1;
uint32_t num_itlb_sets = 1 << OR1K_SPR_SYS_IMMUCFGR_NTS_GET(immucfgr);
uint32_t offs;
for (; count; count--) {
offs = (vaddr >> PAGE_SIZE_SHIFT) & (num_dtlb_sets-1);
switch (num_dtlb_ways) {
case 4:
mtspr_off(0, OR1K_SPR_DMMU_DTLBW_MR_ADDR(3, offs), 0);
case 3:
mtspr_off(0, OR1K_SPR_DMMU_DTLBW_MR_ADDR(2, offs), 0);
case 2:
mtspr_off(0, OR1K_SPR_DMMU_DTLBW_MR_ADDR(1, offs), 0);
case 1:
mtspr_off(0, OR1K_SPR_DMMU_DTLBW_MR_ADDR(0, offs), 0);
}
offs = (vaddr >> PAGE_SIZE_SHIFT) & (num_itlb_sets-1);
switch (num_itlb_ways) {
case 4:
mtspr_off(0, OR1K_SPR_IMMU_ITLBW_MR_ADDR(3, offs), 0);
case 3:
mtspr_off(0, OR1K_SPR_IMMU_ITLBW_MR_ADDR(2, offs), 0);
case 2:
mtspr_off(0, OR1K_SPR_IMMU_ITLBW_MR_ADDR(1, offs), 0);
case 1:
mtspr_off(0, OR1K_SPR_IMMU_ITLBW_MR_ADDR(0, offs), 0);
}
vaddr += PAGE_SIZE;
}
}
status_t arch_mmu_query(vaddr_t vaddr, paddr_t *paddr, uint *flags)
{
uint index = vaddr / SECTION_SIZE;
uint32_t pte = or1k_kernel_translation_table[index];
uint32_t vmask = SECTION_SIZE-1;
if (!(pte & OR1K_MMU_PG_PRESENT))
return ERR_NOT_FOUND;
/* not a l1 entry */
if (!(pte & OR1K_MMU_PG_L)) {
uint32_t *l2_table = paddr_to_kvaddr(pte & ~OR1K_MMU_PG_FLAGS_MASK);
index = (vaddr % SECTION_SIZE) / PAGE_SIZE;
pte = l2_table[index];
vmask = PAGE_SIZE-1;
}
if (paddr)
*paddr = (pte & ~OR1K_MMU_PG_FLAGS_MASK) | (vaddr & vmask);
if (flags) {
*flags = 0;
if (pte & OR1K_MMU_PG_U)
*flags |= ARCH_MMU_FLAG_PERM_USER;
if (!(pte & OR1K_MMU_PG_X))
*flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE;
if (!(pte & OR1K_MMU_PG_W))
*flags |= ARCH_MMU_FLAG_PERM_RO;
if (pte & OR1K_MMU_PG_CI)
*flags |= ARCH_MMU_FLAG_UNCACHED;
}
return NO_ERROR;
}
int arch_mmu_unmap(vaddr_t vaddr, uint count)
{
LTRACEF("vaddr = 0x%x, count = %d\n", vaddr, count);
if (!IS_PAGE_ALIGNED(vaddr))
return ERR_INVALID_ARGS;
uint unmapped = 0;
while (count) {
uint index = vaddr / SECTION_SIZE;
uint32_t pte = or1k_kernel_translation_table[index];
if (!(pte & OR1K_MMU_PG_PRESENT)) {
vaddr += PAGE_SIZE;
count--;
continue;
}
/* Unmapping of l2 tables is not implemented (yet) */
if (!(pte & OR1K_MMU_PG_L) || !IS_ALIGNED(vaddr, SECTION_SIZE) || count < SECTION_SIZE / PAGE_SIZE)
PANIC_UNIMPLEMENTED;
or1k_kernel_translation_table[index] = 0;
or1k_invalidate_tlb(vaddr, SECTION_SIZE / PAGE_SIZE);
vaddr += SECTION_SIZE;
count -= SECTION_SIZE / PAGE_SIZE;
unmapped += SECTION_SIZE / PAGE_SIZE;
}
return unmapped;
}
int arch_mmu_map(vaddr_t vaddr, paddr_t paddr, uint count, uint flags)
{
uint l1_index;
uint32_t pte;
uint32_t arch_flags = 0;
LTRACEF("vaddr = 0x%x, paddr = 0x%x, count = %d, flags = 0x%x\n", vaddr, paddr, count, flags);
if (!IS_PAGE_ALIGNED(vaddr) || !IS_PAGE_ALIGNED(paddr))
return ERR_INVALID_ARGS;
if (flags & ARCH_MMU_FLAG_PERM_USER)
arch_flags |= OR1K_MMU_PG_U;
if (!(flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE))
arch_flags |= OR1K_MMU_PG_X;
if (flags & ARCH_MMU_FLAG_CACHE_MASK)
arch_flags |= OR1K_MMU_PG_CI;
if (!(flags & ARCH_MMU_FLAG_PERM_RO))
arch_flags |= OR1K_MMU_PG_W;
uint mapped = 0;
while (count) {
l1_index = vaddr / SECTION_SIZE;
if (IS_ALIGNED(vaddr, SECTION_SIZE) && IS_ALIGNED(paddr, SECTION_SIZE) && count >= SECTION_SIZE / PAGE_SIZE) {
or1k_kernel_translation_table[l1_index] = (paddr & ~(SECTION_SIZE-1)) | arch_flags | OR1K_MMU_PG_PRESENT | OR1K_MMU_PG_L;
count -= SECTION_SIZE / PAGE_SIZE;
mapped += SECTION_SIZE / PAGE_SIZE;
vaddr += SECTION_SIZE;
paddr += SECTION_SIZE;
continue;
}
uint32_t *l2_table;
pte = or1k_kernel_translation_table[l1_index];
/* FIXME: l1 already mapped as a section */
if (pte & OR1K_MMU_PG_PRESENT && pte & OR1K_MMU_PG_L)
PANIC_UNIMPLEMENTED;
if (pte & OR1K_MMU_PG_PRESENT) {
l2_table = paddr_to_kvaddr(pte & ~OR1K_MMU_PG_FLAGS_MASK);
LTRACEF("l2_table at %p\n", l2_table);
} else {
l2_table = pmm_alloc_kpage();
if (!l2_table) {
TRACEF("failed to allocate pagetable\n");
return mapped;
}
memset(l2_table, 0, PAGE_SIZE);
paddr_t l2_pa = kvaddr_to_paddr(l2_table);
LTRACEF("allocated pagetable at %p, pa 0x%lx\n", l2_table, l2_pa);
or1k_kernel_translation_table[l1_index] = l2_pa | arch_flags | OR1K_MMU_PG_PRESENT;
}
uint l2_index = (vaddr % SECTION_SIZE) / PAGE_SIZE;
LTRACEF("l2_index = 0x%x, vaddr = 0x%x, paddr = 0x%x\n", l2_index, vaddr, paddr);
l2_table[l2_index] = paddr | arch_flags | OR1K_MMU_PG_PRESENT | OR1K_MMU_PG_L;
count--;
mapped++;
vaddr += PAGE_SIZE;
paddr += PAGE_SIZE;
}
return mapped;
}
#endif /* WITH_KERNEL_VM */

52
arch/or1k/rules.mk Normal file
View File

@@ -0,0 +1,52 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
GLOBAL_INCLUDES += \
$(LOCAL_DIR)/include
MODULE_SRCS += \
$(LOCAL_DIR)/start.S \
$(LOCAL_DIR)/arch.c \
$(LOCAL_DIR)/asm.S \
$(LOCAL_DIR)/exceptions.c \
$(LOCAL_DIR)/thread.c \
$(LOCAL_DIR)/cache-ops.c \
$(LOCAL_DIR)/mmu.c \
$(LOCAL_DIR)/faults.c
# set the default toolchain to or1k elf and set a #define
ifndef TOOLCHAIN_PREFIX
TOOLCHAIN_PREFIX := or1k-elf-
endif
LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -print-libgcc-file-name)
$(info LIBGCC = $(LIBGCC))
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`"; \
then echo "$(2)"; else echo "$(3)"; fi ;)
ARCH_OPTFLAGS := -O2
GLOBAL_LDFLAGS += -relax
KERNEL_BASE ?= $(MEMBASE)
KERNEL_LOAD_OFFSET ?= 0
GLOBAL_DEFINES += \
KERNEL_BASE=$(KERNEL_BASE) \
KERNEL_LOAD_OFFSET=$(KERNEL_LOAD_OFFSET)
# potentially generated files that should be cleaned out with clean make rule
GENERATED += \
$(BUILDDIR)/linker.ld
# rules for generating the linker
$(BUILDDIR)/linker.ld: $(LOCAL_DIR)/linker.ld $(wildcard arch/*.ld)
@echo generating $@
@$(MKDIR)
$(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/" < $< > $@
LINKER_SCRIPT += $(BUILDDIR)/linker.ld
include make/module.mk

525
arch/or1k/start.S Normal file
View File

@@ -0,0 +1,525 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <asm.h>
#include <arch/ops.h>
#include <arch/or1k/mmu.h>
#include <kernel/vm.h>
#define RED_ZONE 128
#define EXCEPTION_FRAME (128 + RED_ZONE)
/* clobbers r9 and rd, result will be in rd */
#define get_va_to_pa_offs(rd) \
l.movhi rd, hi(.+12) ;\
l.jal .+8 ;\
l.ori rd, rd, lo(.+4) ;\
l.sub rd, rd, r9
/* clobbers r9 and rd, result will be in rd */
#define to_phys(sym, rd) \
get_va_to_pa_offs(rd) ;\
l.movhi r9, hi(sym) ;\
l.ori r9, r9, lo(sym) ;\
l.sub rd, r9, rd
.macro exception_entry
#if WITH_KERNEL_VM
l.sw 0(r0), r31
l.sw 4(r0), r9
get_va_to_pa_offs(r31)
l.sub r1, r1, r31
l.lwz r9, 4(r0)
#endif
l.addi r1, r1, -EXCEPTION_FRAME
l.sw 0(r1), r2
l.sw 4(r1), r3
l.sw 8(r1), r4
l.sw 12(r1), r5
l.sw 16(r1), r6
l.sw 20(r1), r7
l.sw 24(r1), r8
l.sw 28(r1), r9
l.sw 32(r1), r10
l.sw 36(r1), r11
l.sw 40(r1), r12
l.sw 44(r1), r13
l.sw 48(r1), r14
l.sw 52(r1), r15
l.sw 56(r1), r16
l.sw 60(r1), r17
l.sw 64(r1), r18
l.sw 68(r1), r19
l.sw 72(r1), r20
l.sw 76(r1), r21
l.sw 80(r1), r22
l.sw 84(r1), r23
l.sw 88(r1), r24
l.sw 92(r1), r25
l.sw 96(r1), r26
l.sw 100(r1), r27
l.sw 104(r1), r28
l.sw 108(r1), r29
l.sw 112(r1), r30
l.mfspr r3, r0, OR1K_SPR_SYS_EPCR_ADDR(0)
l.sw 120(r1), r3
l.mfspr r3, r0, OR1K_SPR_SYS_ESR_ADDR(0)
l.sw 124(r1), r3
#if WITH_KERNEL_VM
l.add r1, r1, r31
l.lwz r31, 0(r0)
/* enable dmmu and immu */
l.mfspr r9, r0, OR1K_SPR_SYS_SR_ADDR
l.ori r9, r9, OR1K_SPR_SYS_SR_DME_MASK | OR1K_SPR_SYS_SR_IME_MASK
l.mtspr r0, r9, OR1K_SPR_SYS_ESR_ADDR(0)
l.movhi r9, hi(.+16)
l.ori r9, r9, lo(.+12)
l.mtspr r0, r9, OR1K_SPR_SYS_EPCR_ADDR(0)
l.rfe
#endif
l.sw 116(r1), r31
.endm
.section ".vectors", "ax"
.org 0x100
.global _reset
_reset:
l.jal start
l.nop
.org 0x200
bus_error_exception:
exception_entry
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.jal or1k_busfault_handler
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0x300
data_pagefault_exception:
exception_entry
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.jal or1k_data_pagefault_handler
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0x400
instruction_pagefault_exception:
exception_entry
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.jal or1k_instruction_pagefault_handler
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0x500
tick_timer_exception:
exception_entry
l.jal or1k_tick
l.nop
l.j return_from_exception
l.nop
.org 0x600
alignment_exception:
exception_entry
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.jal or1k_alignment_handler
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0x700
illegal_instruction_exception:
exception_entry
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.jal or1k_illegal_instruction_handler
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0x800
external_interrupt_exception:
exception_entry
l.jal or1k_irq
l.nop
l.j return_from_exception
l.nop
.org 0x900
dtlb_miss_exception:
#if WITH_KERNEL_VM
l.sw 0(r0), r3
l.sw 4(r0), r4
l.sw 8(r0), r9
to_phys(or1k_kernel_translation_table, r3)
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
/* l1 index */
l.srli r9, r4, 24
l.slli r9, r9, 2
l.add r3, r3, r9
l.lwz r3, 0(r3) /* l1 entry */
l.andi r9, r3, OR1K_MMU_PG_PRESENT
l.sfnei r9, OR1K_MMU_PG_PRESENT
l.bf dtlb_miss_fault
l.andi r9, r3, OR1K_MMU_PG_L
l.sfeqi r9, OR1K_MMU_PG_L
/* l2_index */
l.srli r4, r4, 13
l.bf 1f
l.andi r4, r4, 0x7ff
l.slli r4, r4, 2
l.addi r9, r0, 0xffffe000 /* PAGE_SIZE-1 */
l.and r9, r3, r9
l.add r9, r9, r4
l.j 2f
l.lwz r9, 0(r9) /* l2 entry */
/* use bits [23:13] from EEAR */
1: l.slli r4, r4, 13
l.or r9, r3, r4
2: l.ori r3,r0,0xf351 /* sw emulation of dmmupr */
l.srli r4,r9,4 /* get PP Index * 4 */
l.andi r4,r4,0xc /* mask everything but PPI (without X) (& 0b01100)*/
l.srl r3,r3,r4 /* get protection bits from "dmmupr" */
/*
* The protection bits are unconvienently the "wrong" way in DMMUPR
* compared to DTLBR (UWE|URE|SWE|SRE vs SWE|SRE|UWE|URE), so we have
* to swap their places...
*/
l.andi r4,r3,0x3 /* SWE|SRE */
l.slli r4,r4,8 /* 1:0 -> 9:8 */
l.andi r3,r3,0xc /* UWE|URE */
l.slli r3,r3,4 /* 3:2 -> 7:6 */
l.or r3,r3,r4
l.addi r4,r0,0xffffe03f /* protection bit mask */
l.and r4,r9,r4 /* apply the mask */
l.or r9,r4,r3 /* apply protection bits */
l.mfspr r3, r0, OR1K_SPR_SYS_DMMUCFGR_ADDR
l.slli r3, r3, 31-OR1K_SPR_SYS_DMMUCFGR_NTS_MSB
l.srli r3, r3, 31-OR1K_SPR_SYS_DMMUCFGR_NTS_LSB
l.ori r4, r0, 1
l.sll r3, r4, r3
l.addi r3, r3, -1
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.srli r4, r4, 13
l.and r3, r4, r3
l.mtspr r3, r9, OR1K_SPR_DMMU_DTLBW_TR_ADDR(0,0)
l.slli r4, r4, 13
l.ori r4, r4, OR1K_SPR_DMMU_DTLBW_MR_V_MASK
l.mtspr r3, r4, OR1K_SPR_DMMU_DTLBW_MR_ADDR(0,0)
l.lwz r3, 0(r0)
l.lwz r4, 4(r0)
l.lwz r9, 8(r0)
l.rfe
#endif /* WITH_KERNEL_VM */
dtlb_miss_fault:
l.lwz r3, 0(r0)
l.lwz r4, 4(r0)
l.j data_pagefault_exception
l.lwz r9, 8(r0)
.org 0xa00
itlb_miss_exception:
#if WITH_KERNEL_VM
l.sw 0(r0), r3
l.sw 4(r0), r4
l.sw 8(r0), r9
to_phys(or1k_kernel_translation_table, r3)
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
/* l1 index */
l.srli r9, r4, 24
l.slli r9, r9, 2
l.add r3, r3, r9
l.lwz r3, 0(r3) /* l1 entry */
l.andi r9, r3, OR1K_MMU_PG_PRESENT
l.sfnei r9, OR1K_MMU_PG_PRESENT
l.bf itlb_miss_fault
l.andi r9, r3, OR1K_MMU_PG_L
l.sfeqi r9, OR1K_MMU_PG_L
/* l2 index */
l.srli r4, r4, 13
l.bf 1f
l.andi r4, r4, 0x7ff
l.slli r4, r4, 2
l.addi r9, r0, 0xffffe000 /* PAGE_SIZE-1 */
l.and r9, r3, r9
l.add r9, r9, r4
l.j 2f
l.lwz r9, 0(r9) /* l2 entry */
/* use bits [23:13] from EEAR */
1: l.slli r4, r4, 13
l.or r9, r3, r4
2: l.ori r3, r0, 0xd00 /* sw emulation of immupr */
l.srli r4, r9, 5 /* get PP Index * 2 */
l.andi r4, r4, 0xa /* mask everything but PPI (without W) (& 0b1010)*/
l.srl r3, r3, r4 /* get protection bits from "immupr" */
l.andi r3, r3, 0x3 /* mask everything else out */
l.slli r3, r3, 6 /* and put them in their spot */
l.addi r4, r0, 0xffffe03f /* protection bit mask */
l.and r4, r9, r4 /* apply the mask */
l.or r9, r4, r3 /* apply protection bits */
l.mfspr r3, r0, OR1K_SPR_SYS_IMMUCFGR_ADDR
l.slli r3, r3, 31-OR1K_SPR_SYS_IMMUCFGR_NTS_MSB
l.srli r3, r3, 31-OR1K_SPR_SYS_IMMUCFGR_NTS_LSB
l.ori r4, r0, 1
l.sll r3, r4, r3
l.addi r3, r3, -1
l.mfspr r4, r0, OR1K_SPR_SYS_EEAR_ADDR(0)
l.srli r4, r4, 13
l.and r3, r4, r3
l.mtspr r3, r9, OR1K_SPR_IMMU_ITLBW_TR_ADDR(0,0)
l.slli r4, r4, 13
l.ori r4, r4, OR1K_SPR_IMMU_ITLBW_MR_V_MASK
l.mtspr r3, r4, OR1K_SPR_IMMU_ITLBW_MR_ADDR(0,0)
l.lwz r3, 0(r0)
l.lwz r4, 4(r0)
l.lwz r9, 8(r0)
l.rfe
#endif /* WITH_KERNEL_VM */
itlb_miss_fault:
l.lwz r3, 0(r0)
l.lwz r4, 4(r0)
l.j instruction_pagefault_exception
l.lwz r9, 8(r0)
.org 0xb00
range_exception:
exception_entry
l.ori r4, r0, 0xb00
l.jal or1k_unhandled_exception
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0xc00
syscall_exception:
exception_entry
l.jal or1k_syscall_handler
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0xd00
fpu_exception:
exception_entry
l.ori r4, r0, 0xd00
l.jal or1k_unhandled_exception
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.org 0xe00
trap_exception:
exception_entry
l.ori r4, r0, 0xe00
l.jal or1k_unhandled_exception
l.ori r3, r1, 0
l.j return_from_exception
l.nop
.section ".text.boot"
FUNCTION(start)
/* set stack pointer to point at top of default stack */
l.movhi r1, hi(default_stack_top)
l.ori r1, r1, lo(default_stack_top)
#if WITH_KERNEL_VM
/* invalidate tlbs */
l.ori r3, r0, OR1K_SPR_DMMU_DTLBW_MR_ADDR(0, 0)
l.ori r4, r0, OR1K_SPR_IMMU_ITLBW_MR_ADDR(0, 0)
l.addi r6, r0, 3 /* Maximum number of ways - 1 */
1: l.addi r5, r0, 127 /* Maximum number of sets - 1 */
2: l.mtspr r3, r0, 0x0
l.mtspr r4, r0, 0x0
l.addi r3, r3, 1
l.addi r4, r4, 1
l.sfeq r5, r0
l.bnf 2b
l.addi r5, r5, -1
l.addi r3, r3, 128
l.addi r4, r4, 128
l.sfeq r6, r0
l.bnf 1b
l.addi r6, r6, -1
/* setup initial mappings */
get_va_to_pa_offs(r3)
l.movhi r4, hi(or1k_kernel_translation_table)
l.ori r4, r4, lo(or1k_kernel_translation_table)
l.sub r4, r4, r3 /* to phys */
l.movhi r5, hi(mmu_initial_mappings)
l.ori r5, r5, lo(mmu_initial_mappings)
l.sub r5, r5, r3 /* to phys */
/* clear the translation table */
l.addi r3, r4, 255*4
0: l.sw 0(r3), r0
l.sfeq r3, r4
l.bnf 0b
l.addi r3, r3, -4
1: l.lwz r6, 0(r5) /* phys */
l.lwz r7, 4(r5) /* virt */
l.lwz r8, 8(r5) /* size */
l.lwz r9, 12(r5) /* flags */
l.lwz r10, 16(r5) /* name */
l.addi r5, r5, 20
/* divide with 16MB */
l.srli r6, r6, 24
l.srli r7, r7, 24
l.srli r8, r8, 24
l.sfeqi r8, 0
l.bf .Linitial_mapping_done
l.nop
2: l.slli r3, r7, 2
l.add r3, r4, r3
l.slli r10, r6, 24
l.ori r10, r10, OR1K_MMU_PG_PRESENT | OR1K_MMU_PG_X | OR1K_MMU_PG_W | OR1K_MMU_PG_L
l.sfeqi r9, MMU_INITIAL_MAPPING_FLAG_UNCACHED
l.bf 3f
l.sfeqi r9, MMU_INITIAL_MAPPING_FLAG_DEVICE
l.bnf 4f
l.nop
3: l.ori r10, r10, OR1K_MMU_PG_CI
4: l.sw 0(r3), r10
l.addi r6, r6, 1
l.addi r8, r8, -1
l.sfeqi r8, 0
l.bnf 2b
l.addi r7, r7, 1
l.j 1b
l.nop
.Linitial_mapping_done:
/* enable mmu */
l.mfspr r3, r0, OR1K_SPR_SYS_SR_ADDR
l.ori r3, r3, OR1K_SPR_SYS_SR_DME_MASK | OR1K_SPR_SYS_SR_IME_MASK
l.mtspr r0, r3, OR1K_SPR_SYS_ESR_ADDR(0)
/* setup pc to use virtual addresses */
l.movhi r3, hi(.+16)
l.ori r3, r3, lo(.+12)
l.mtspr r0, r3, OR1K_SPR_SYS_EPCR_ADDR(0)
l.rfe
#endif
/* invalidate and enable caches */
l.jal arch_invalidate_cache_all
l.nop
l.jal arch_enable_cache
l.ori r3, r0, UCACHE
/* clear bss */
l.movhi r3, hi(__bss_start)
l.ori r3, r3, lo(__bss_start)
l.movhi r4, hi(__bss_end)
l.ori r4, r4, lo(__bss_end)
1: l.sw 0(r3), r0
l.sfltu r3, r4
l.bf 1b
l.addi r3, r3, 4
/* arguments to main */
l.ori r3, r0, 1
l.ori r4, r0, 2
l.ori r5, r0, 3
l.jal lk_main
l.ori r6, r0, 4
/* shouldn't happen, but loop if it does */
l.j 0
l.nop
FUNCTION(return_from_exception)
l.lwz r3, 120(r1)
l.mtspr r0, r3, OR1K_SPR_SYS_EPCR_BASE
l.lwz r3, 124(r1)
l.mtspr r0, r3, OR1K_SPR_SYS_ESR_BASE
l.lwz r2, 0(r1)
l.lwz r3, 4(r1)
l.lwz r4, 8(r1)
l.lwz r5, 12(r1)
l.lwz r6, 16(r1)
l.lwz r7, 20(r1)
l.lwz r8, 24(r1)
l.lwz r9, 28(r1)
l.lwz r10, 32(r1)
l.lwz r11, 36(r1)
l.lwz r12, 40(r1)
l.lwz r13, 44(r1)
l.lwz r14, 48(r1)
l.lwz r15, 52(r1)
l.lwz r16, 56(r1)
l.lwz r17, 60(r1)
l.lwz r18, 64(r1)
l.lwz r19, 68(r1)
l.lwz r20, 72(r1)
l.lwz r21, 76(r1)
l.lwz r22, 80(r1)
l.lwz r23, 84(r1)
l.lwz r24, 88(r1)
l.lwz r25, 92(r1)
l.lwz r26, 96(r1)
l.lwz r27, 100(r1)
l.lwz r28, 104(r1)
l.lwz r29, 108(r1)
l.lwz r30, 112(r1)
l.lwz r31, 116(r1)
l.addi r1, r1, EXCEPTION_FRAME
l.rfe
.section ".bss"
.align 8
LOCAL_DATA(default_stack)
.skip 8192
LOCAL_DATA(default_stack_top)

76
arch/or1k/thread.c Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
* Based on arch/microblaze/thread.c
* Copyright (c) 2015 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <trace.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <kernel/thread.h>
#define LOCAL_TRACE 0
struct thread *_current_thread;
static void initial_thread_func(void) __NO_RETURN;
static void initial_thread_func(void)
{
thread_t *ct = get_current_thread();
#if LOCAL_TRACE
LTRACEF("thread %p calling %p with arg %p\n", ct, ct->entry, ct->arg);
dump_thread(ct);
#endif
/* exit the implicit critical section we're within */
exit_critical_section();
int ret = ct->entry(ct->arg);
LTRACEF("thread %p exiting with %d\n", ct, ret);
thread_exit(ret);
}
void arch_thread_initialize(thread_t *t)
{
LTRACEF("t %p (%s)\n", t, t->name);
/* some registers we want to clone for the new thread */
register uint32_t r2 asm("r2");
/* zero out the thread context */
memset(&t->arch.cs_frame, 0, sizeof(t->arch.cs_frame));
t->arch.cs_frame.r1 = (vaddr_t)t->stack + t->stack_size;
t->arch.cs_frame.r2 = r2;
t->arch.cs_frame.r9 = (vaddr_t)initial_thread_func;
}
void arch_context_switch(thread_t *oldthread, thread_t *newthread)
{
LTRACEF("old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
or1k_context_switch(&oldthread->arch.cs_frame, &newthread->arch.cs_frame);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <err.h>
#include <debug.h>
#include <kernel/thread.h>
#include <platform/interrupts.h>
#include <platform/pic.h>
#include <arch/or1k.h>
struct int_handler_struct {
int_handler handler;
void *arg;
};
static struct int_handler_struct int_handler_table[MAX_INT];
void register_int_handler(unsigned int vector, int_handler handler, void *arg)
{
if (vector >= MAX_INT)
panic("%s: vector out of range %d\n", __FUNCTION__, vector);
enter_critical_section();
int_handler_table[vector].handler = handler;
int_handler_table[vector].arg = arg;
exit_critical_section();
}
status_t mask_interrupt(unsigned int vector)
{
if (vector >= MAX_INT)
return ERR_INVALID_ARGS;
mtspr(OR1K_SPR_PIC_PICMR_ADDR, mfspr(OR1K_SPR_PIC_PICMR_ADDR) & ~(1 << vector));
return NO_ERROR;
}
status_t unmask_interrupt(unsigned int vector)
{
if (vector >= MAX_INT)
return ERR_INVALID_ARGS;
mtspr(OR1K_SPR_PIC_PICMR_ADDR, mfspr(OR1K_SPR_PIC_PICMR_ADDR) | (1 << vector));
return NO_ERROR;
}
enum handler_return platform_irq(void)
{
enum handler_return ret = INT_NO_RESCHEDULE;
uint irq = __builtin_ffs(mfspr(OR1K_SPR_PIC_PICSR_ADDR)) - 1;
if (irq < MAX_INT && int_handler_table[irq].handler)
ret = int_handler_table[irq].handler(int_handler_table[irq].arg);
return ret;
}

View File

@@ -0,0 +1,11 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
GLOBAL_INCLUDES += \
$(LOCAL_DIR)/include
MODULE_SRCS += \
$(LOCAL_DIR)/or1k_pic.c
include make/module.mk

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <sys/types.h>
void or1k_ticktimer_init(uint32_t freq);

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2015 Stefan Kristiansson
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <trace.h>
#include <err.h>
#include <kernel/thread.h>
#include <platform/timer.h>
#include <platform/debug.h>
#include <sys/types.h>
#include <arch/or1k.h>
#define LOCAL_TRACE 0
static platform_timer_callback timer_cb;
static void *timer_arg;
static uint32_t timer_freq;
static volatile uint64_t ticks = 0;
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval)
{
LTRACEF("cb %p, arg %p, interval %ld\n", callback, arg, interval);
uint32_t ttmr = (uint64_t)timer_freq * interval / 1000;
LTRACEF("count 0x%x\n", ttmr);
timer_cb = callback;
timer_arg = arg;
/* disable timer before doing changes */
mtspr(OR1K_SPR_TICK_TTMR_ADDR, 0);
/* reset timer counter */
mtspr(OR1K_SPR_TICK_TTCR_ADDR, 0);
/* enable timer with given interval in 'restart' mode */
ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr | OR1K_SPR_TICK_TTMR_IE_MASK,
OR1K_SPR_TICK_TTMR_MODE_RESTART);
mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
return NO_ERROR;
}
lk_bigtime_t current_time_hires(void)
{
return (lk_bigtime_t)ticks * 10000;
}
lk_time_t current_time(void)
{
return (lk_time_t)ticks * 10;
}
enum handler_return platform_tick(void)
{
ticks++;
/* clear pending interrupt flag */
mtspr(OR1K_SPR_TICK_TTMR_ADDR,
mfspr(OR1K_SPR_TICK_TTMR_ADDR) & ~(OR1K_SPR_TICK_TTMR_IP_MASK));
return timer_cb(timer_arg, ticks * 10);
}
void or1k_ticktimer_init(uint32_t freq)
{
timer_freq = freq;
/* disable timer */
mtspr(OR1K_SPR_TICK_TTMR_ADDR, 0);
/* reset timer counter */
mtspr(OR1K_SPR_TICK_TTCR_ADDR, 0);
/* clear pending interrupt flag */
mtspr(OR1K_SPR_TICK_TTMR_ADDR,
mfspr(OR1K_SPR_TICK_TTMR_ADDR) & ~(OR1K_SPR_TICK_TTMR_IP_MASK));
}

View File

@@ -0,0 +1,14 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
GLOBAL_INCLUDES += \
$(LOCAL_DIR)/include
#GLOBAL_DEFINES += \
# PLATFORM_HAS_DYNAMIC_TIMER=1
MODULE_SRCS += \
$(LOCAL_DIR)/or1k_ticktimer.c
include make/module.mk

View File