[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/arch/mips/arch.c b/src/bsp/lk/arch/mips/arch.c
new file mode 100644
index 0000000..e12982f
--- /dev/null
+++ b/src/bsp/lk/arch/mips/arch.c
@@ -0,0 +1,143 @@
+/*
+ * 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 <debug.h>
+#include <stdint.h>
+#include <bits.h>
+#include <arch/mips.h>
+#include <platform.h>
+
+#define LOCAL_TRACE 0
+
+void arch_early_init(void)
+{
+ LTRACE;
+
+ /* configure the vector table */
+ uint32_t temp = mips_read_c0_status();
+ temp &= ~(1<<22); /* unset BEV, which moves vectors to 0x80000000 */
+ temp &= ~(1<<2); /* clear ERL */
+
+ /* mask all of the irq handlers */
+ temp &= ~(1<<8); // IM0
+ temp &= ~(1<<9); // IM1
+ temp &= ~(1<<10); // IM2
+ temp &= ~(1<<11); // IM3
+ temp &= ~(1<<12); // IM4
+ temp &= ~(1<<13); // IM5
+ temp &= ~(1<<14); // IM6
+ temp &= ~(1<<15); // IM7
+ temp &= ~(1<<16); // IM8
+ temp &= ~(1<<18); // IM9 (note the bit gap)
+
+ mips_write_c0_status(temp);
+
+ /* set ebase */
+ mips_write_c0_ebase(MEMBASE);
+
+ /* make sure we take exceptions in 32bit mips mode */
+ mips_write_c0_config3(mips_read_c0_config3() & ~(1<<16));
+
+ /* set vectored mode */
+ temp = mips_read_c0_intctl();
+ temp &= ~(0b1111 << 5);
+ temp |= 1 << 5; /* 32 byte spacing */
+ STATIC_ASSERT(VECTORED_OFFSET_SHIFT == 32);
+
+ mips_write_c0_intctl(temp);
+
+ temp = mips_read_c0_cause();
+ temp |= (1<<23); /* IV vectored mode */
+ mips_write_c0_cause(temp);
+}
+
+void arch_init(void)
+{
+ LTRACE;
+
+ printf("MIPS registers:\n");
+ printf("\tPRId 0x%x\n", mips_read_c0_prid());
+ printf("\tconfig 0x%x\n", mips_read_c0_config());
+ printf("\tconfig1 0x%x\n", mips_read_c0_config1());
+ printf("\tconfig2 0x%x\n", mips_read_c0_config2());
+ printf("\tconfig3 0x%x\n", mips_read_c0_config3());
+ printf("\tconfig4 0x%x\n", mips_read_c0_config4());
+ printf("\tconfig5 0x%x\n", mips_read_c0_config5());
+ printf("\tconfig6 0x%x\n", mips_read_c0_config6());
+ printf("\tconfig7 0x%x\n", mips_read_c0_config7());
+ printf("\tstatus 0x%x\n", mips_read_c0_status());
+ uint32_t intctl = mips_read_c0_intctl();
+ printf("\tintctl 0x%x\n", intctl);
+ printf("\t\tIPTI 0x%lx\n", BITS_SHIFT(intctl, 31, 29));
+ printf("\t\tIPPCI 0x%lx\n", BITS_SHIFT(intctl, 28, 26));
+ printf("\t\tIPFDC 0x%lx\n", BITS_SHIFT(intctl, 25, 23));
+ printf("\tsrsctl 0x%x\n", mips_read_c0_srsctl());
+ printf("\tebase 0x%x\n", mips_read_c0_ebase());
+ printf("\tcount 0x%x\n", mips_read_c0_count());
+ printf("\tcompare 0x%x\n", mips_read_c0_compare());
+
+ __asm__ volatile("syscall");
+
+ LTRACE_EXIT;
+}
+
+void arch_idle(void)
+{
+ asm volatile("wait");
+}
+
+void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3)
+{
+ PANIC_UNIMPLEMENTED;
+}
+
+void mips_enable_irq(uint num)
+{
+ uint32_t temp = mips_read_c0_status();
+ if (num < 9) {
+ temp |= (1 << (num + 8));
+ } else if (num == 9) {
+ temp |= (1 << 18);
+ }
+ mips_write_c0_status(temp);
+}
+
+void mips_disable_irq(uint num)
+{
+ uint32_t temp = mips_read_c0_status();
+ if (num < 9) {
+ temp &= ~(1 << (num + 8));
+ } else if (num == 9) {
+ temp &= ~(1 << 18);
+ }
+ mips_write_c0_status(temp);
+}
+
+/* unimplemented cache operations */
+void arch_disable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
+void arch_enable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
+
+void arch_clean_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
+void arch_clean_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
+void arch_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
+void arch_sync_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
diff --git a/src/bsp/lk/arch/mips/asm.S b/src/bsp/lk/arch/mips/asm.S
new file mode 100644
index 0000000..7700039
--- /dev/null
+++ b/src/bsp/lk/arch/mips/asm.S
@@ -0,0 +1,60 @@
+/*
+ * 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 <asm.h>
+
+/* void mips_context_switch(
+ struct mips_context_switch_frame *oldcs,
+ struct mips_context_switch_frame *newcs); */
+FUNCTION(mips_context_switch)
+ # a0 = oldcs
+ # a1 = newcs
+
+ # save old state
+ sw $s0, 0($a0)
+ sw $s1, 4($a0)
+ sw $s2, 8($a0)
+ sw $s3, 12($a0)
+ sw $s4, 16($a0)
+ sw $s5, 20($a0)
+ sw $s6, 24($a0)
+ sw $s7, 28($a0)
+ sw $s8, 32($a0)
+ sw $ra, 36($a0)
+ sw $sp, 40($a0)
+
+ # load new state
+ lw $s0, 0($a1)
+ lw $s1, 4($a1)
+ lw $s2, 8($a1)
+ lw $s3, 12($a1)
+ lw $s4, 16($a1)
+ lw $s5, 20($a1)
+ lw $s6, 24($a1)
+ lw $s7, 28($a1)
+ lw $s8, 32($a1)
+ lw $ra, 36($a1)
+ lw $sp, 40($a1)
+
+ jr $ra
+ nop
+
diff --git a/src/bsp/lk/arch/mips/exceptions.c b/src/bsp/lk/arch/mips/exceptions.c
new file mode 100644
index 0000000..f2b1035
--- /dev/null
+++ b/src/bsp/lk/arch/mips/exceptions.c
@@ -0,0 +1,82 @@
+/*
+ * 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 <debug.h>
+#include <assert.h>
+#include <stdint.h>
+#include <bits.h>
+#include <kernel/thread.h>
+#include <kernel/debug.h>
+#include <arch/mips.h>
+
+#define LOCAL_TRACE 0
+
+extern enum handler_return platform_irq(struct mips_iframe *iframe, uint num);
+
+void mips_gen_exception(struct mips_iframe *iframe)
+{
+ uint32_t excode = BITS_SHIFT(iframe->cause, 6, 2);
+ if (excode == 0x8) {
+ LTRACEF("SYSCALL, EPC 0x%x\n", iframe->epc);
+ iframe->epc += 4;
+ } else {
+ LTRACEF("status 0x%x\n", iframe->status);
+ LTRACEF("cause 0x%x\n", iframe->cause);
+ LTRACEF("\texcode 0x%x\n", excode);
+ LTRACEF("epc 0x%x\n", iframe->epc);
+ for (;;);
+ }
+}
+
+void mips_irq(struct mips_iframe *iframe, uint num)
+{
+ // unset IE and clear EXL
+ mips_write_c0_status(mips_read_c0_status() & ~(3<<0));
+
+ THREAD_STATS_INC(interrupts);
+ KEVLOG_IRQ_ENTER(num);
+
+ LTRACEF("IRQ %u, EPC 0x%x, old status 0x%x, status 0x%x\n",
+ num, iframe->epc, iframe->status, mips_read_c0_status());
+
+ enum handler_return ret = INT_NO_RESCHEDULE;
+
+ // figure out which interrupt the timer is set to
+ uint32_t ipti = BITS_SHIFT(mips_read_c0_intctl(), 31, 29);
+ if (ipti >= 2 && ipti == num) {
+ // builtin timer
+ ret = mips_timer_irq();
+#if PLATFORM_QEMU_MIPS
+ } else if (num == 2) {
+ ret = platform_irq(iframe, num);
+#endif
+ } else {
+ panic("mips: unhandled irq\n");
+ }
+
+ KEVLOG_IRQ_EXIT(num);
+
+ if (ret != INT_NO_RESCHEDULE)
+ thread_preempt();
+}
+
diff --git a/src/bsp/lk/arch/mips/include/arch/arch_ops.h b/src/bsp/lk/arch/mips/include/arch/arch_ops.h
new file mode 100644
index 0000000..42a178b
--- /dev/null
+++ b/src/bsp/lk/arch/mips/include/arch/arch_ops.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <compiler.h>
+#include <arch/mips.h>
+
+static inline void arch_enable_ints(void)
+{
+ CF;
+#if 0
+ uint32_t status = mips_read_c0_status();
+ status |= 0x1;
+ mips_write_c0_status(status);
+#else
+ __asm__ volatile("ei");
+#endif
+}
+
+static inline void arch_disable_ints(void)
+{
+#if 0
+ uint32_t status = mips_read_c0_status();
+ status &= ~0x1;
+ mips_write_c0_status(status);
+#else
+ __asm__ volatile("di");
+#endif
+ CF;
+}
+
+static inline bool arch_ints_disabled(void)
+{
+ uint32_t state;
+
+ state = mips_read_c0_status();
+
+ return (state & (1<<1)) || !(state & (1<<0)); // check if EXL or IE is set
+}
+
+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);
+}
+
+/* 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; }
+
+static inline uint arch_curr_cpu_num(void)
+{
+ return 0;
+}
+
diff --git a/src/bsp/lk/arch/mips/include/arch/arch_thread.h b/src/bsp/lk/arch/mips/include/arch/arch_thread.h
new file mode 100644
index 0000000..9dd8480
--- /dev/null
+++ b/src/bsp/lk/arch/mips/include/arch/arch_thread.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+struct mips_context_switch_frame {
+ /* callee saved */
+ uint32_t s0;
+ uint32_t s1;
+ uint32_t s2;
+ uint32_t s3;
+ uint32_t s4;
+ uint32_t s5;
+ uint32_t s6;
+ uint32_t s7;
+ uint32_t s8;
+ uint32_t ra;
+ uint32_t sp;
+};
+
+struct arch_thread {
+ struct mips_context_switch_frame cs_frame;
+};
+
+void mips_context_switch(struct mips_context_switch_frame *oldcs, struct mips_context_switch_frame *newcs);
+
diff --git a/src/bsp/lk/arch/mips/include/arch/defines.h b/src/bsp/lk/arch/mips/include/arch/defines.h
new file mode 100644
index 0000000..2d3d8e7
--- /dev/null
+++ b/src/bsp/lk/arch/mips/include/arch/defines.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#define PAGE_SIZE 4096
+#define PAGE_SIZE_SHIFT 12
+
+// XXX is this right?
+#define CACHE_LINE 32
+
+#define ARCH_DEFAULT_STACK_SIZE 4096
diff --git a/src/bsp/lk/arch/mips/include/arch/mips.h b/src/bsp/lk/arch/mips/include/arch/mips.h
new file mode 100644
index 0000000..a73eb66
--- /dev/null
+++ b/src/bsp/lk/arch/mips/include/arch/mips.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#ifndef ASSEMBLY
+#include <compiler.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#define GEN_CP_REG_FUNCS(regname, regnum, sel) \
+static inline __ALWAYS_INLINE uint32_t mips_read_##regname(void) { \
+ uint32_t val; \
+ __asm__ volatile("mfc0 %0, $" #regnum ", " #sel : "=r" (val)); \
+ return val; \
+} \
+\
+static inline __ALWAYS_INLINE uint32_t mips_read_##regname##_relaxed(void) { \
+ uint32_t val; \
+ __asm__("mfc0 %0, $" #regnum ", " #sel : "=r" (val)); \
+ return val; \
+} \
+\
+static inline __ALWAYS_INLINE void mips_write_##regname(uint32_t val) { \
+ __asm__ volatile("mtc0 %0, $" #regnum ", " #sel :: "r" (val)); \
+} \
+\
+static inline __ALWAYS_INLINE void mips_write_##regname##_relaxed(uint32_t val) { \
+ __asm__ volatile("mtc0 %0, $" #regnum ", " #sel :: "r" (val)); \
+}
+
+GEN_CP_REG_FUNCS(c0_count, 9, 0)
+GEN_CP_REG_FUNCS(c0_compare, 11, 0)
+GEN_CP_REG_FUNCS(c0_status, 12, 0)
+GEN_CP_REG_FUNCS(c0_intctl, 12, 1)
+GEN_CP_REG_FUNCS(c0_srsctl, 12, 2)
+GEN_CP_REG_FUNCS(c0_srsmap1, 12, 3)
+GEN_CP_REG_FUNCS(c0_view_ipl, 12, 4)
+GEN_CP_REG_FUNCS(c0_srsmap2, 12, 5)
+GEN_CP_REG_FUNCS(c0_cause, 13, 0)
+GEN_CP_REG_FUNCS(c0_epc, 14, 0)
+GEN_CP_REG_FUNCS(c0_prid, 15, 0)
+GEN_CP_REG_FUNCS(c0_ebase, 15, 1)
+GEN_CP_REG_FUNCS(c0_cdmmbase, 15, 2)
+GEN_CP_REG_FUNCS(c0_config, 16, 0)
+GEN_CP_REG_FUNCS(c0_config1, 16, 1)
+GEN_CP_REG_FUNCS(c0_config2, 16, 2)
+GEN_CP_REG_FUNCS(c0_config3, 16, 3)
+GEN_CP_REG_FUNCS(c0_config4, 16, 4)
+GEN_CP_REG_FUNCS(c0_config5, 16, 5)
+GEN_CP_REG_FUNCS(c0_config6, 16, 6)
+GEN_CP_REG_FUNCS(c0_config7, 16, 7)
+GEN_CP_REG_FUNCS(c0_config8, 16, 8)
+
+struct mips_iframe {
+ uint32_t at;
+ uint32_t v0;
+ uint32_t v1;
+ uint32_t a0;
+ uint32_t a1;
+ uint32_t a2;
+ uint32_t a3;
+ uint32_t t0;
+ uint32_t t1;
+ uint32_t t2;
+ uint32_t t3;
+ uint32_t t4;
+ uint32_t t5;
+ uint32_t t6;
+ uint32_t t7;
+ uint32_t t8;
+ uint32_t t9;
+ uint32_t gp;
+ uint32_t ra;
+ uint32_t status;
+ uint32_t cause;
+ uint32_t epc;
+};
+STATIC_ASSERT(sizeof(struct mips_iframe) == 88);
+
+void mips_init_timer(uint32_t freq);
+enum handler_return mips_timer_irq(void);
+
+void mips_enable_irq(uint num);
+void mips_disable_irq(uint num);
+
+#endif // !ASSEMBLY
+
+#define VECTORED_OFFSET_SHIFT 32
+
diff --git a/src/bsp/lk/arch/mips/include/arch/spinlock.h b/src/bsp/lk/arch/mips/include/arch/spinlock.h
new file mode 100644
index 0000000..5c50c5b
--- /dev/null
+++ b/src/bsp/lk/arch/mips/include/arch/spinlock.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <arch/ops.h>
+#include <stdbool.h>
+
+#if WITH_SMP
+#error microblaze does not support SMP
+#endif
+
+#define SPIN_LOCK_INITIAL_VALUE (0)
+
+typedef unsigned int spin_lock_t;
+
+typedef unsigned int spin_lock_saved_state_t;
+typedef unsigned int spin_lock_save_flags_t;
+
+static inline void arch_spin_lock(spin_lock_t *lock)
+{
+ *lock = 1;
+}
+
+static inline int arch_spin_trylock(spin_lock_t *lock)
+{
+ return 0;
+}
+
+static inline void arch_spin_unlock(spin_lock_t *lock)
+{
+ *lock = 0;
+}
+
+static inline void arch_spin_lock_init(spin_lock_t *lock)
+{
+ *lock = SPIN_LOCK_INITIAL_VALUE;
+}
+
+static inline bool arch_spin_lock_held(spin_lock_t *lock)
+{
+ return *lock != 0;
+}
+
+ /* default arm flag is to just disable plain irqs */
+#define ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS 0
+
+enum {
+ /* private */
+ SPIN_LOCK_STATE_RESTORE_IRQ = 1,
+};
+
+static inline void
+arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags)
+{
+ spin_lock_saved_state_t state = 0;
+ if (!arch_ints_disabled()) {
+ state |= SPIN_LOCK_STATE_RESTORE_IRQ;
+ arch_disable_ints();
+ }
+ *statep = state;
+}
+
+static inline void
+arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags)
+{
+ if (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)
+ arch_enable_ints();
+}
+
+
+
+
diff --git a/src/bsp/lk/arch/mips/linker.ld b/src/bsp/lk/arch/mips/linker.ld
new file mode 100644
index 0000000..c237648
--- /dev/null
+++ b/src/bsp/lk/arch/mips/linker.ld
@@ -0,0 +1,135 @@
+OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-littlemips")
+OUTPUT_ARCH(mips)
+
+ENTRY(_start)
+SECTIONS
+{
+ . = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%;
+
+ /* text/read-only data */
+ .text : {
+ KEEP(*(.text.vectab))
+ 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.*)
+ }
+
+ .sdata2 : ALIGN(4) {
+ _SDATA2_START__ = .;
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ _SDATA2_END__ = .;
+ }
+
+ .sbss2 : ALIGN(4) {
+ /* read only small variables without initial value */
+ _SBSS2_START__ = .;
+ *(.sbss2*)
+ _SBSS2_END__ = .;
+ }
+
+ /*
+ * extra linker scripts tend to insert sections just after .rodata,
+ * so we want to make sure this symbol comes after anything inserted above,
+ * but not aligned to the next section necessarily.
+ */
+ .dummy_post_rodata : {
+ __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.*)
+ __ctor_list = .;
+ KEEP(*(.ctors .init_array))
+ __ctor_end = .;
+ __dtor_list = .;
+ KEEP(*(.dtors .fini_array))
+ __dtor_end = .;
+ *(.got*)
+ *(.dynamic)
+
+ }
+
+ .sdata : {
+ /* read-write small data with initial value */
+ _SDATA_START__ = .;
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ _SDATA_END__ = .;
+ }
+
+ /*
+ * extra linker scripts tend to insert sections just after .data,
+ * so we want to make sure this symbol comes after anything inserted above,
+ * but not aligned to the next section necessarily.
+ */
+ .dummy_post_data : {
+ __data_end = .;
+ }
+
+ . = ALIGN(4);
+ __bss_start = .;
+
+ .sbss : {
+ /* read-write small variables without initial value */
+ _sbss_start__ = .;
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ _sbss_end__ = .;
+ }
+
+ /* unintialized data (in same segment as writable data) */
+ .bss : {
+ /* regular bss */
+ *(.dynbss)
+ *(.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) }
+}
+
diff --git a/src/bsp/lk/arch/mips/mips.ld b/src/bsp/lk/arch/mips/mips.ld
new file mode 100644
index 0000000..9963f06
--- /dev/null
+++ b/src/bsp/lk/arch/mips/mips.ld
@@ -0,0 +1,227 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-littlemips")
+OUTPUT_ARCH(mips)
+ENTRY(__start)
+SECTIONS
+{
+
+ . = 0;
+
+ /* Read-only sections, merged into text segment: */
+ .interp : { *(.interp) }
+ .reginfo : { *(.reginfo) }
+ .dynamic : { *(.dynamic) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+ .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+ .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+ .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+ .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+ .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+ .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+ .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+ .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+ .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+ .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+ .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x47ff041f
+ .plt : { *(.plt) }
+ .text :
+ {
+ _ftext = . ;
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.mips16.fn.*) *(.mips16.call.*)
+ } =0x47ff041f
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x47ff041f
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 :
+ {
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .ctors :
+ {
+ __ctor_list = .;
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin*.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctor_end = .;
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin*.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ . = DATA_SEGMENT_RELRO_END (0, .);
+ .data :
+ {
+ _fdata = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ . = .;
+ _gp = ALIGN(16) + 0x7ff0;
+ .got : { *(.got.plt) *(.got) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ _edata = .; PROVIDE (edata = .);
+ __bss_start = .;
+ _fbss = .;
+ .sbss :
+ {
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ _end = .; PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/src/bsp/lk/arch/mips/rules.mk b/src/bsp/lk/arch/mips/rules.mk
new file mode 100644
index 0000000..715818e
--- /dev/null
+++ b/src/bsp/lk/arch/mips/rules.mk
@@ -0,0 +1,79 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/arch.c \
+ $(LOCAL_DIR)/asm.S \
+ $(LOCAL_DIR)/exceptions.c \
+ $(LOCAL_DIR)/start.S \
+ $(LOCAL_DIR)/thread.c \
+ $(LOCAL_DIR)/timer.c \
+ $(LOCAL_DIR)/vectors.S \
+
+# $(LOCAL_DIR)/cache.c \
+ $(LOCAL_DIR)/cache-ops.S \
+ $(LOCAL_DIR)/ops.S \
+ $(LOCAL_DIR)/mmu.c \
+ $(LOCAL_DIR)/faults.c \
+ $(LOCAL_DIR)/descriptor.c
+
+GLOBAL_DEFINES += \
+ SMP_MAX_CPUS=1
+
+# set the default toolchain to microblaze elf and set a #define
+ifndef TOOLCHAIN_PREFIX
+TOOLCHAIN_PREFIX := mips-elf-
+endif
+
+WITH_LINKER_GC ?= 0
+LITTLE_ENDIAN ?= 0
+
+ifneq ($(LITTLE_ENDIAN),0)
+GLOBAL_COMPILEFLAGS += -EL
+GLOBAL_ASFLAGS += -EL
+GLOBAL_LDFLAGS += -EL
+GLOBAL_MODULE_LDFLAGS += -EL
+endif
+
+ARCH_COMPILEFLAGS := -mno-gpopt
+ARCH_OPTFLAGS := -O2
+
+ifeq ($(MIPS_CPU),m14k)
+ARCH_COMPILEFLAGS += -march=m14k
+endif
+ifeq ($(MIPS_CPU),microaptiv-uc)
+ARCH_COMPILEFLAGS += -march=m14k
+endif
+
+
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`"; \
+ then echo "$(2)"; else echo "$(3)"; fi ;)
+
+KERNEL_BASE ?= $(MEMBASE)
+KERNEL_LOAD_OFFSET ?= 0
+VECTOR_BASE_PHYS ?= 0
+
+GLOBAL_DEFINES += \
+ MEMBASE=$(MEMBASE) \
+ MEMSIZE=$(MEMSIZE) \
+ 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) linkerscript.phony
+ @echo generating $@
+ @$(MKDIR)
+ $(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/;s/%VECTOR_BASE_PHYS%/$(VECTOR_BASE_PHYS)/" < $< > $@.tmp
+ @$(call TESTANDREPLACEFILE,$@.tmp,$@)
+
+linkerscript.phony:
+.PHONY: linkerscript.phony
+
+LINKER_SCRIPT += $(BUILDDIR)/linker.ld
+
+include make/module.mk
diff --git a/src/bsp/lk/arch/mips/start.S b/src/bsp/lk/arch/mips/start.S
new file mode 100644
index 0000000..4097648
--- /dev/null
+++ b/src/bsp/lk/arch/mips/start.S
@@ -0,0 +1,53 @@
+/*
+ * 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 <asm.h>
+
+.section ".text.boot"
+FUNCTION(_start)
+ # set the default stack
+ la $sp, default_stack_top
+
+ # zero out the bss section
+ la $t0, __bss_start
+ la $t1, __bss_end
+0:
+ sw $zero, ($t0)
+ addi $t0, 4
+ bne $t0, $t1, 0b
+
+ # args to main and call it
+ li $a0, 1
+ li $a1, 2
+ li $a2, 3
+ li $a3, 4
+ jal lk_main
+
+ # should never return here
+ b .
+
+.bss
+.align 3
+LOCAL_DATA(default_stack)
+ .skip 4096
+LOCAL_DATA(default_stack_top)
+
diff --git a/src/bsp/lk/arch/mips/thread.c b/src/bsp/lk/arch/mips/thread.c
new file mode 100644
index 0000000..eaef3d9
--- /dev/null
+++ b/src/bsp/lk/arch/mips/thread.c
@@ -0,0 +1,81 @@
+/*
+ * 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>
+#include <arch/mips.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
+
+ /* release the thread lock that was implicitly held across the reschedule */
+ spin_unlock(&thread_lock);
+ arch_enable_ints();
+
+ 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);
+
+ /* zero out the thread context */
+ memset(&t->arch.cs_frame, 0, sizeof(t->arch.cs_frame));
+
+ t->arch.cs_frame.ra = (vaddr_t)&initial_thread_func;
+ t->arch.cs_frame.sp = (vaddr_t)t->stack + t->stack_size;
+}
+
+void arch_context_switch(thread_t *oldthread, thread_t *newthread)
+{
+ LTRACEF("old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
+
+ mips_context_switch(&oldthread->arch.cs_frame, &newthread->arch.cs_frame);
+}
+
+void arch_dump_thread(thread_t *t)
+{
+ if (t->state != THREAD_RUNNING) {
+ dprintf(INFO, "\tarch: ");
+ dprintf(INFO, "sp 0x%x\n", t->arch.cs_frame.sp);
+ }
+}
+
diff --git a/src/bsp/lk/arch/mips/timer.c b/src/bsp/lk/arch/mips/timer.c
new file mode 100644
index 0000000..2b665cd
--- /dev/null
+++ b/src/bsp/lk/arch/mips/timer.c
@@ -0,0 +1,155 @@
+/*
+ * 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 <arch/mips.h>
+#include <err.h>
+#include <trace.h>
+#include <debug.h>
+#include <assert.h>
+#include <stdint.h>
+#include <bits.h>
+#include <arch/ops.h>
+#include <platform.h>
+#include <platform/timer.h>
+
+#define LOCAL_TRACE 0
+
+static volatile uint64_t ticks;
+static volatile uint32_t last_compare_set;
+
+static uint32_t tick_rate;
+static uint32_t tick_rate_mhz;
+
+static lk_time_t tick_interval_ms;
+static lk_bigtime_t tick_interval_us;
+static uint32_t tick_interval;
+
+static platform_timer_callback cb;
+static void *cb_args;
+
+enum handler_return mips_timer_irq(void)
+{
+ LTRACEF("count 0x%x\n", mips_read_c0_count());
+ LTRACEF("compare 0x%x\n", mips_read_c0_compare());
+
+ /* reset it for the next interval */
+retry:
+ ticks++;
+ last_compare_set += tick_interval;
+ uint32_t count = mips_read_c0_count();
+ if (unlikely(TIME_GT(count, last_compare_set))) {
+ /* if it took us too long to get to this irq, make sure it fires immediately */
+ //printf("took too long to service timer irq! %u %u\n", count, last_compare_set);
+ goto retry;
+ //mips_write_c0_compare(mips_read_c0_count() + tick_rate_mhz);
+ } else {
+ mips_write_c0_compare(last_compare_set);
+ }
+
+ enum handler_return ret = INT_NO_RESCHEDULE;
+ if (cb) {
+ lk_time_t now = current_time();
+ ret = cb(cb_args, now);
+ }
+
+ return ret;
+}
+
+status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval)
+{
+ TRACEF("callback %p, arg %p, interval %u\n", callback, arg, interval);
+
+ DEBUG_ASSERT(interval > 0);
+ DEBUG_ASSERT(tick_rate != 0 && tick_rate_mhz != 0);
+
+ cb = callback;
+ cb_args = arg;
+
+ tick_interval_ms = interval;
+ tick_interval_us = interval * 1000;
+ tick_interval = interval * (tick_rate / 1000);
+
+ uint32_t now = mips_read_c0_count();
+ last_compare_set = now + tick_interval;
+ mips_write_c0_compare(last_compare_set);
+
+ // enable the counter
+ mips_write_c0_cause(mips_read_c0_cause() & ~(1<<27));
+
+ return NO_ERROR;
+}
+
+lk_time_t current_time(void)
+{
+ uint64_t t;
+ uint32_t last_compare;
+ uint32_t delta;
+
+ /* sample the tick counter, the last compare register set, and the current count atomically */
+ do {
+ t = ticks;
+ last_compare = last_compare_set;
+ delta = mips_read_c0_count();
+ } while (ticks != t || last_compare_set != last_compare);
+
+ /* convert ticks to msec */
+ delta = (delta - last_compare - tick_interval) / (tick_rate_mhz * 1000);
+ lk_time_t res = (t * tick_interval_ms) + delta;
+
+ return res;
+}
+
+lk_bigtime_t current_time_hires(void)
+{
+ uint64_t t;
+ uint32_t last_compare;
+ uint32_t delta;
+
+ /* sample the tick counter, the last compare register set, and the current count atomically */
+ do {
+ t = ticks;
+ last_compare = last_compare_set;
+ delta = mips_read_c0_count();
+ } while (ticks != t);
+
+ /* convert ticks to usec */
+ delta = (delta - last_compare - tick_interval) / tick_rate_mhz;
+ lk_bigtime_t res = (t * tick_interval_us) + delta;
+
+ return res;
+}
+
+void mips_init_timer(uint32_t freq)
+{
+ tick_rate = freq;
+ tick_rate_mhz = freq / 1000000;
+
+ // disable the counter
+ mips_write_c0_cause(mips_read_c0_cause() | (1<<27));
+
+ // figure out which interrupt the timer is set to
+ uint32_t ipti = BITS_SHIFT(mips_read_c0_intctl(), 31, 29);
+ if (ipti >= 2) {
+ mips_enable_irq(ipti);
+ }
+}
+
diff --git a/src/bsp/lk/arch/mips/vectors.S b/src/bsp/lk/arch/mips/vectors.S
new file mode 100644
index 0000000..aacfde4
--- /dev/null
+++ b/src/bsp/lk/arch/mips/vectors.S
@@ -0,0 +1,145 @@
+/*
+ * 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 <asm.h>
+#include <arch/mips.h>
+
+.section ".text.vectab"
+FUNCTION(vectab)
+.org 0
+_tlb_refill:
+ b .
+
+.macro iframe_save
+ .set push
+ .set noat
+ addiu $sp, -88
+
+ /* save all the non temporary registers */
+ sw $at, 0($sp)
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $t8, 60($sp)
+ sw $t9, 64($sp)
+ sw $gp, 68($sp)
+ sw $ra, 72($sp)
+
+ /* save the control registers */
+ mfc0 $at, $12 /* status */
+ sw $at, 76($sp)
+ mfc0 $at, $13 /* cause */
+ sw $at, 80($sp)
+ mfc0 $at, $14 /* epc */
+ sw $at, 84($sp)
+
+ .set pop
+.endm
+
+.macro iframe_restore
+ .set push
+ .set noat
+
+ /* restore the temporary registers */
+ lw $at, 0($sp)
+ lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $t8, 60($sp)
+ lw $t9, 64($sp)
+ lw $gp, 68($sp)
+ lw $ra, 72($sp)
+
+ /* restore the control registers */
+ lw $k0, 76($sp)
+ mtc0 $k0, $12 /* status */
+ lw $k0, 80($sp)
+ mtc0 $k0, $13 /* cause */
+ lw $k0, 84($sp)
+ mtc0 $k0, $14 /* epc */
+
+ addiu $sp, 88
+ .set pop
+.endm
+
+/* compatibility mode irq/syscall/general exception */
+.org 0x180
+_irq:
+ la $k0, mips_gen_exception
+ li $k1, 0
+ b shared_irq_save_return
+
+/* vectored base */
+.macro vectored_irq, num
+.org 0x200 + VECTORED_OFFSET_SHIFT * \num
+_vectored_irq\num:
+ la $k0, mips_irq
+ li $k1, \num
+ b shared_irq_save_return
+ b .
+.endm
+
+vectored_irq 0
+vectored_irq 1
+vectored_irq 2
+vectored_irq 3
+vectored_irq 4
+vectored_irq 5
+vectored_irq 6
+vectored_irq 7
+vectored_irq 8
+vectored_irq 9
+
+/* branched to from above, k0 holds address to call, k1 holds arg to function */
+shared_irq_save_return:
+ iframe_save
+
+ move $a0, $sp
+ move $a1, $k1
+ jal $k0
+
+ iframe_restore
+
+ eret
+