[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
+