From 8f363e5d7123feec49f7a8bad98fdf99b9e3bc0e Mon Sep 17 00:00:00 2001
From: Claudio Fontana <claudio.fontana@huawei.com>
Date: Thu, 20 Mar 2014 17:06:50 +0100
Subject: [PATCH] arch/aarch64: first implementation

Signed-off-by: Claudio Fontana <claudio.fontana@huawei.com>
---
 arch/aarch64/arch-cpu.cc          |  18 ++++
 arch/aarch64/arch-cpu.hh          |  50 +++++++++++
 arch/aarch64/arch-setup.cc        |  47 +++++++++++
 arch/aarch64/arch-setup.hh        |  20 +++++
 arch/aarch64/arch-switch.hh       |  74 +++++++++++++++++
 arch/aarch64/arch-thread-state.hh |  17 ++++
 arch/aarch64/arch.hh              | 104 +++++++++++++++++++++++
 arch/aarch64/arm-clock.cc         |  45 ++++++++++
 arch/aarch64/arm-clock.hh         |  15 ++++
 arch/aarch64/backtrace.cc         |  33 ++++++++
 arch/aarch64/bitops.h             |  31 +++++++
 arch/aarch64/boot.S               |  75 +++++++++++++++++
 arch/aarch64/elf-dl.S             |  32 +++++++
 arch/aarch64/entry.S              |  69 ++++++++++++++++
 arch/aarch64/exceptions.hh        |  60 ++++++++++++++
 arch/aarch64/loader.ld            | 133 ++++++++++++++++++++++++++++++
 arch/aarch64/macros.S             |  14 ++++
 arch/aarch64/math.cc              |  16 ++++
 arch/aarch64/preboot.S            |  19 +++++
 arch/aarch64/preboot.ld           |   4 +
 arch/aarch64/processor.hh         | 117 ++++++++++++++++++++++++++
 arch/aarch64/safe-ptr.hh          |  31 +++++++
 arch/aarch64/signal.cc            |  54 ++++++++++++
 arch/aarch64/smp.cc               |  29 +++++++
 arch/aarch64/smp.hh               |  15 ++++
 arch/aarch64/string.cc            |  35 ++++++++
 26 files changed, 1157 insertions(+)
 create mode 100644 arch/aarch64/arch-cpu.cc
 create mode 100644 arch/aarch64/arch-cpu.hh
 create mode 100644 arch/aarch64/arch-setup.cc
 create mode 100644 arch/aarch64/arch-setup.hh
 create mode 100644 arch/aarch64/arch-switch.hh
 create mode 100644 arch/aarch64/arch-thread-state.hh
 create mode 100644 arch/aarch64/arch.hh
 create mode 100644 arch/aarch64/arm-clock.cc
 create mode 100644 arch/aarch64/arm-clock.hh
 create mode 100644 arch/aarch64/backtrace.cc
 create mode 100644 arch/aarch64/bitops.h
 create mode 100644 arch/aarch64/boot.S
 create mode 100644 arch/aarch64/elf-dl.S
 create mode 100644 arch/aarch64/entry.S
 create mode 100644 arch/aarch64/exceptions.hh
 create mode 100644 arch/aarch64/loader.ld
 create mode 100644 arch/aarch64/macros.S
 create mode 100644 arch/aarch64/math.cc
 create mode 100644 arch/aarch64/preboot.S
 create mode 100644 arch/aarch64/preboot.ld
 create mode 100644 arch/aarch64/processor.hh
 create mode 100644 arch/aarch64/safe-ptr.hh
 create mode 100644 arch/aarch64/signal.cc
 create mode 100644 arch/aarch64/smp.cc
 create mode 100644 arch/aarch64/smp.hh
 create mode 100644 arch/aarch64/string.cc

diff --git a/arch/aarch64/arch-cpu.cc b/arch/aarch64/arch-cpu.cc
new file mode 100644
index 000000000..e76eea954
--- /dev/null
+++ b/arch/aarch64/arch-cpu.cc
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include "arch-cpu.hh"
+#include <osv/sched.hh>
+#include <osv/debug.hh>
+
+namespace sched {
+
+__thread unsigned exception_depth = 0;
+
+}
diff --git a/arch/aarch64/arch-cpu.hh b/arch/aarch64/arch-cpu.hh
new file mode 100644
index 000000000..7b631e06b
--- /dev/null
+++ b/arch/aarch64/arch-cpu.hh
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_CPU_HH
+#define ARCH_CPU_HH
+
+#include "processor.hh"
+#include "osv/pagealloc.hh"
+#include <osv/debug.h>
+
+namespace sched {
+
+struct arch_cpu;
+struct arch_thread;
+
+struct arch_cpu {
+    arch_cpu();
+
+    unsigned int gic_id;
+
+    void init_on_cpu();
+};
+
+struct arch_thread {
+};
+
+struct arch_fpu {
+    struct processor::fpu_state s;
+    void save() { processor::fpu_state_save(&s); }
+    void restore() { processor::fpu_state_load(&s); }
+};
+
+inline arch_cpu::arch_cpu()
+{
+}
+
+inline void arch_cpu::init_on_cpu()
+{
+    processor::halt_no_interrupts();
+}
+
+}
+
+#endif /* ARCH_CPU_HH */
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
new file mode 100644
index 000000000..d72d42187
--- /dev/null
+++ b/arch/aarch64/arch-setup.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include "arch.hh"
+#include "arch-setup.hh"
+#include <osv/sched.hh>
+#include <osv/mempool.hh>
+#include <osv/elf.hh>
+#include <osv/types.h>
+#include <string.h>
+#include <osv/boot.hh>
+#include <osv/debug.hh>
+
+extern elf::Elf64_Ehdr* elf_header;
+extern size_t elf_size;
+extern void* elf_start;
+extern boot_time_chart boot_time;
+
+void arch_setup_free_memory()
+{
+    register u64 edata;
+    asm ("adrp %0, .edata" : "=r"(edata));
+
+    elf_start = reinterpret_cast<void*>(elf_header);
+    elf_size = (u64)edata - (u64)elf_start;
+
+    /* just a test for now, we hardcode 512MB of memory */
+    u64 addr = (u64)elf_start + elf_size + 0x10000;
+    addr = addr & ~0xffffull;
+
+    memory::free_initial_memory_range((void*)addr, 0x20000000);
+}
+
+void arch_setup_tls(thread_control_block *tcb)
+{
+    asm volatile ("msr tpidr_el0, %0; isb; " :: "r"(tcb));
+}
+
+void arch_init_premain()
+{
+}
diff --git a/arch/aarch64/arch-setup.hh b/arch/aarch64/arch-setup.hh
new file mode 100644
index 000000000..9aa3d06f8
--- /dev/null
+++ b/arch/aarch64/arch-setup.hh
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_SETUP_HH_
+#define ARCH_SETUP_HH_
+
+#include <osv/tls.hh>
+
+void arch_init_premain();
+void arch_setup_tls(thread_control_block *tcb);
+
+void arch_setup_free_memory();
+
+#endif /* ARCH_SETUP_HH_ */
diff --git a/arch/aarch64/arch-switch.hh b/arch/aarch64/arch-switch.hh
new file mode 100644
index 000000000..763534f83
--- /dev/null
+++ b/arch/aarch64/arch-switch.hh
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_SWITCH_HH_
+#define ARCH_SWITCH_HH_
+
+#include <osv/barrier.hh>
+#include <string.h>
+
+extern "C" {
+void thread_main(void);
+void thread_main_c(sched::thread* t);
+void stack_trampoline(sched::thread* t, void (*func)(sched::thread*),
+                      void** stacktop);
+}
+
+namespace sched {
+
+void thread::switch_to()
+{
+    abort();
+}
+
+void thread::switch_to_first()
+{
+    abort();
+}
+
+void thread::init_stack()
+{
+    auto& stack = _attr._stack;
+    if (!stack.size) {
+        stack.size = 65536;
+    }
+    if (!stack.begin) {
+        stack.begin = malloc(stack.size);
+        stack.deleter = stack.default_deleter;
+    }
+    void** stacktop = reinterpret_cast<void**>(stack.begin + stack.size);
+    _state.fp = this;
+    _state.pc = reinterpret_cast<void*>(thread_main);
+    _state.sp = stacktop;
+}
+
+void thread::setup_tcb()
+{
+    assert(tls.size);
+
+    void* p = malloc(sched::tls.size + sizeof(*_tcb));
+    memcpy(p, sched::tls.start, sched::tls.size);
+    _tcb = static_cast<thread_control_block*>(p + tls.size);
+    _tcb->self = _tcb;
+    _tcb->tls_base = p;
+}
+
+void thread::free_tcb()
+{
+    free(_tcb->tls_base);
+}
+
+void thread_main_c(thread* t)
+{
+    abort();
+}
+
+}
+
+#endif /* ARCH_SWITCH_HH_ */
diff --git a/arch/aarch64/arch-thread-state.hh b/arch/aarch64/arch-thread-state.hh
new file mode 100644
index 000000000..bc592b6fb
--- /dev/null
+++ b/arch/aarch64/arch-thread-state.hh
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_THREAD_STATE_HH_
+#define ARCH_THREAD_STATE_HH_
+
+struct thread_state {
+    void* sp;
+    void* fp;
+    void* pc;
+};
+
+#endif /* ARCH_THREAD_STATE_HH_ */
diff --git a/arch/aarch64/arch.hh b/arch/aarch64/arch.hh
new file mode 100644
index 000000000..6f64c9ed9
--- /dev/null
+++ b/arch/aarch64/arch.hh
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_HH_
+#define ARCH_HH_
+
+#include "processor.hh"
+
+// architecture independent interface for architecture dependent operations
+
+namespace arch {
+
+#define CACHELINE_ALIGNED __attribute__((aligned(64)))
+
+inline void irq_disable()
+{
+    processor::irq_disable();
+}
+
+__attribute__((no_instrument_function))
+inline void irq_disable_notrace();
+
+inline void irq_disable_notrace()
+{
+    processor::irq_disable_notrace();
+}
+
+inline void irq_enable()
+{
+    processor::irq_enable();
+}
+
+inline void wait_for_interrupt()
+{
+    processor::wait_for_interrupt();
+}
+
+inline void halt_no_interrupts()
+{
+    processor::halt_no_interrupts();
+}
+
+class irq_flag {
+public:
+    void save() {
+        asm volatile("mrs %0, daif;" : "=r"(daif) :: "memory");
+    }
+
+    void restore() {
+        asm volatile("msr daif, %0" :: "r"(daif) : "memory");
+    }
+    bool enabled() const {
+        return !(daif & processor::daif_i);
+    }
+
+private:
+    unsigned long daif;
+};
+
+class irq_flag_notrace {
+public:
+    __attribute__((no_instrument_function)) void save();
+    __attribute__((no_instrument_function)) void restore();
+    __attribute__((no_instrument_function)) bool enabled() const;
+private:
+    unsigned long daif;
+};
+
+inline void irq_flag_notrace::save() {
+    asm volatile("mrs %0, daif;" : "=r"(daif) :: "memory");
+}
+
+inline void irq_flag_notrace::restore() {
+    asm volatile("msr daif, x0" :: "r"(daif) : "memory");
+}
+
+inline bool irq_flag_notrace::enabled() const {
+    return !(daif & processor::daif_i);
+}
+
+inline bool irq_enabled()
+{
+    irq_flag f;
+    f.save();
+    return f.enabled();
+}
+
+extern bool tls_available() __attribute__((no_instrument_function));
+
+inline bool tls_available()
+{
+    /* XXX */
+    return false;
+}
+
+} // namespace arch
+
+#endif /* ARCH_HH_ */
diff --git a/arch/aarch64/arm-clock.cc b/arch/aarch64/arm-clock.cc
new file mode 100644
index 000000000..f0ac5fe92
--- /dev/null
+++ b/arch/aarch64/arm-clock.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include "drivers/clockevent.hh"
+#include "drivers/clock.hh"
+#include "arm-clock.hh"
+
+using namespace processor;
+
+class arm_clock_events : public clock_event_driver {
+public:
+    explicit arm_clock_events();
+    ~arm_clock_events();
+    virtual void setup_on_cpu();
+    virtual void set(std::chrono::nanoseconds nanos);
+private:
+    unsigned _vector;
+};
+
+
+arm_clock_events::arm_clock_events()
+{
+}
+
+arm_clock_events::~arm_clock_events()
+{
+}
+
+void arm_clock_events::setup_on_cpu()
+{
+}
+
+void arm_clock_events::set(std::chrono::nanoseconds nanos)
+{
+}
+
+void __attribute__((constructor)) init_arm_clock()
+{
+    debug_early_entry("init_arm_clock()");
+    clock_event = new arm_clock_events;
+}
diff --git a/arch/aarch64/arm-clock.hh b/arch/aarch64/arm-clock.hh
new file mode 100644
index 000000000..60cc5d0a0
--- /dev/null
+++ b/arch/aarch64/arm-clock.hh
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_ARM_CLOCK_HH
+#define ARCH_ARM_CLOCK_HH
+
+namespace processor {
+}
+
+
+#endif /* ARCH_ARM_CLOCK_HH */
diff --git a/arch/aarch64/backtrace.cc b/arch/aarch64/backtrace.cc
new file mode 100644
index 000000000..4f369db06
--- /dev/null
+++ b/arch/aarch64/backtrace.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include "safe-ptr.hh"
+#include <osv/debug.h>
+
+struct frame {
+    frame* next;
+    void* pc;
+};
+
+int backtrace_safe(void** pc, int nr)
+{
+    register frame* fp;
+    frame* next;
+
+    asm("mov %0, x29" : "=r"(fp));
+
+    int i = 0;
+    while (i < nr
+           && safe_load(&fp->next, next)
+           && safe_load(&fp->pc, pc[i])
+           && pc[i]) {
+        fp = next;
+        ++i;
+    }
+
+    return i;
+}
diff --git a/arch/aarch64/bitops.h b/arch/aarch64/bitops.h
new file mode 100644
index 000000000..0e041971b
--- /dev/null
+++ b/arch/aarch64/bitops.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_BITOPS_H_
+#define ARCH_BITOPS_H_
+static inline unsigned int
+bsrl(unsigned int mask)
+{
+    unsigned int result;
+    asm volatile("clz %1,%0" : "=r" (result) : "r" (mask));
+    return result;
+}
+
+static inline unsigned long
+bsrq(unsigned long mask)
+{
+    unsigned long result;
+    asm volatile("clz %1,%0" : "=r" (result) : "r" (mask));
+    return result;
+}
+
+static inline int
+fls(int mask)
+{
+    return (mask == 0 ? mask : (int)bsrl((unsigned int)mask) + 1);
+}
+#endif /* ARCH_BITOPS_H */
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
new file mode 100644
index 000000000..e46518d83
--- /dev/null
+++ b/arch/aarch64/boot.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+.text
+.align 16
+.globl start_elf
+start_elf:
+        /* elf program start address */
+        /* input: x0 = elf header address */
+        mov     x2, x0      // elf_header ptr => x2
+        bl      validate_el // check that we are at EL1 or die
+
+        bl      init_stack
+        bl      zero_bss    // initialize bss contents to 0
+        bl      init_boot_cpu
+
+        adrp    x1, elf_header // requires page alignment */
+        str     x2, [x1]    // store elf header address
+
+        mov     x29, xzr
+        mov     x30, xzr
+        bl      premain
+        /*
+        adrp    x2, __argc
+        ldr     x0, [x2]
+        adrp    x2, __argv
+        ldr     x1, [x2]
+        b       main
+        */
+
+init_stack:
+        adrp    x0, init_stack_top
+        mov     sp, x0
+        ret
+
+validate_el:
+	mrs     x0, currentel
+        ubfm    x0, x0, #2, #3 // current EL[3:2] -> X0
+        cmp     x0, #1
+        b.ne    halt
+        ret
+
+halt:   wfi
+        b       halt
+
+zero_bss:
+        adrp    x0, .bss
+        adrp    x1, .edata
+zero_bss_loop:
+        stp     xzr, xzr, [x0], #16
+        cmp     x0, x1
+        b.lo    zero_bss_loop
+        ret
+init_boot_cpu:
+        mov x0, #3 << 20
+        msr cpacr_el1, x0  // no trapping on FP/SIMD instructions
+        msr mdscr_el1, xzr // monitor debug: all disabled
+        isb
+        ret
+
+.bss
+.align 16
+init_stack_bottom = .
+. = . + 4096*4
+init_stack_top = .
+
+/* hmm should we provide an interrupt stack?
+. = . + 4096*10
+.global interrupt_stack_top
+interrupt_stack_top = .
+*/
diff --git a/arch/aarch64/elf-dl.S b/arch/aarch64/elf-dl.S
new file mode 100644
index 000000000..ab38c624c
--- /dev/null
+++ b/arch/aarch64/elf-dl.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include "macros.S"
+
+/* XXX this will halt, because it is not reached/tested.
+   When we reach this, test, verify, develop against the ELF AArch64 ABI */
+.text
+
+.global __elf_resolve_pltgot
+
+// calling convention:
+// sp + 8: index
+// sp + 0: object
+__elf_resolve_pltgot:
+        .type __elf_resolve_pltgot, @function
+
+1:      wfi
+        b 1b
+        sub sp, sp, #16            // make room for resolved address
+
+        /* XXX
+         * push caller-saved gp/fp-regs,
+         * elf_resolve_pltgot passing x0 and x1 with the args,
+         * restore caller-saved gp/fp-regs. */
+
+        add sp, sp, #16
+        ret
diff --git a/arch/aarch64/entry.S b/arch/aarch64/entry.S
new file mode 100644
index 000000000..20a312490
--- /dev/null
+++ b/arch/aarch64/entry.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+/* XXX TODO nothing to see here, move along XXX */
+
+#include "macros.S"
+        /*
+        .macro	exception_entry name, handler, has_error_code
+	push_pair x28, x29
+	push_pair x26, x27
+	push_pair x24, x25
+	push_pair x22, x23
+	push_pair x20, x21
+
+	push_pair x18, x19
+	push_pair x16, x17
+	push_pair x14, x15
+	push_pair x12, x13
+	push_pair x10, x11
+
+	push_pair x8, x9
+	push_pair x6, x7
+	push_pair x4, x5
+	push_pair x2, x3
+	push_pair x0, x1
+
+	push_pair x29, x30
+        ...
+        .endm
+
+.macro exception_error_entry name, handler
+	exception_entry \name, \handler, 1
+.endm
+
+.macro exception_noerror_entry name, handler
+	exception_entry \name, \handler, 0
+.endm
+
+.cfi_sections .eh_frame,  .debug_frame
+
+.text
+
+*/
+
+.global thread_main
+thread_main:
+        .type thread_main, @function
+	mov x0, x29
+	bl thread_main_c
+
+.global call_signal_handler_thunk
+call_signal_handler_thunk:
+        .type call_signal_handler_thunk, @function
+        # stack contains a signal_frame
+        /*
+        .cfi_offset reg, offset
+        ...
+        mov x0, sp
+        call call_signal_handler
+        # FIXME: fpu
+
+        pop_pair...
+        add sp, sp, 16 # error_code
+        */
+        ret
diff --git a/arch/aarch64/exceptions.hh b/arch/aarch64/exceptions.hh
new file mode 100644
index 000000000..25f45bb1c
--- /dev/null
+++ b/arch/aarch64/exceptions.hh
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef EXCEPTIONS_HH
+#define EXCEPTIONS_HH
+
+#include <stdint.h>
+#include <functional>
+#include <osv/types.h>
+#include <osv/rcu.hh>
+#include <osv/mutex.h>
+#include <vector>
+
+struct exception_frame {
+    u64 regs[31];
+    u64 sp;
+    u64 pc;
+    u64 pstate;
+    u64 error_code;
+    u64 reserved; /* align to 16 */
+};
+
+extern __thread exception_frame* current_interrupt_frame;
+
+struct shared_vector {
+    unsigned vector;
+    unsigned id;
+    shared_vector(unsigned v, unsigned i)
+        : vector(v), id(i)
+    {};
+};
+
+class interrupt_table {
+public:
+    interrupt_table();
+    void load_on_cpu();
+    unsigned register_handler(std::function<void ()> handler);
+    // The pre_eoi should 'true' when the interrupt is for the device, 'false' otherwise.
+    shared_vector register_level_triggered_handler(unsigned gsi, std::function<bool ()> pre_eoi, std::function<void ()> handler);
+    void unregister_level_triggered_handler(shared_vector v);
+    unsigned register_interrupt_handler(std::function<bool ()> pre_eoi, std::function<void ()> eoi, std::function<void ()> handler);
+    void unregister_handler(unsigned vector);
+    void invoke_interrupt(unsigned vector);
+};
+
+extern interrupt_table interrupt_table;
+
+extern "C" {
+    void page_fault(exception_frame* ef);
+}
+
+bool fixup_fault(exception_frame*);
+
+#endif /* EXCEPTIONS_HH */
diff --git a/arch/aarch64/loader.ld b/arch/aarch64/loader.ld
new file mode 100644
index 000000000..a027cbcdb
--- /dev/null
+++ b/arch/aarch64/loader.ld
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+SECTIONS
+{
+	/* Set the initial program counter to one page beyond the minimal
+	 * aligned segment size.  This allows the ELF header to reside with
+	 * the text segment, which is useful since we need the ELF header
+	 * to link against libraries later on.
+	 *
+	 * We can't export the ELF header base as a symbol, because ld
+	 * insists on moving stuff around if we do.
+	 */
+    . = 0x40091000;
+
+    .dynamic : ALIGN(16) { *(.dynamic) } : dynamic : text
+
+    .rela.dyn : ALIGN(4096) {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+      *(.rela.ifunc)
+     } : dynamic : text
+
+     .rela.plt : ALIGN(4096) {
+      *(.rela.plt)
+      __rela_iplt_start = .;
+      *(.rela.iplt)
+      __rela_iplt_end = .;
+     } : dynamic : text
+
+    .plt : ALIGN (4096) { *(.plt) *(.iplt) } : dynamic : text
+    .got : ALIGN (4096) { *(.got) *(.igot) } : dynamic : text
+    .got.plt : ALIGN (4096) { *(.got.plt) *(.igot.plt) } : dynamic : text
+
+    .text : ALIGN (16) {
+        text_start = .;
+        *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+        *(.text.exit .text.exit.*)
+        *(.text.startup .text.startup.*)
+        *(.text.hot .text.hot.*)
+        *(.text .stub .text.* .gnu.linkonce.t.*)
+        text_end = .;
+    } : text
+
+    .eh_frame : { *(.eh_frame) } : text
+    .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame
+    .rodata : { *(.rodata*) } :text
+    .note : { *(.note*) } :text :note
+
+    .gcc_except_table : { *(.gcc_except_table) *(.gcc_except_table.*) } : text
+
+    .tracepoint_patch_sites : ALIGN(8) {
+        __tracepoint_patch_sites_start = .;
+        *(.tracepoint_patch_sites)
+        __tracepoint_patch_sites_end = .;
+    } : text
+
+    .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } : text
+
+    .data : { *(.data .data.*) } : text
+
+    _init_array_start = .;
+    .init_array : ALIGN(16) {
+        *(SORT_BY_NAME(.preinit_array.*) .preinit_array)
+        *(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))
+        *(.init_array .ctors)
+    } : text
+    _init_array_end = .;
+
+    .percpu : ALIGN (4096) {
+        _percpu_start = .;
+        *(.percpu)
+        . = ALIGN(4096);
+        _percpu_end = .;
+    }
+    .percpu_workers : ALIGN (4096) {
+        _percpu_workers_start = .;
+        *(.percpu_workers)
+        _percpu_workers_end = .;
+    }
+
+    .tdata : ALIGN(64) { *(.tdata .tdata.* .gnu.linkonce.td.*) } : tls : text
+    .tbss : ALIGN(64) { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } : tls : text
+    .tls_template_size = SIZEOF(.tdata) + SIZEOF(.tbss);
+    .bss : { *(.dynbss .bss .bss.* .gnu.linkonce.b.*) } : text
+
+    . = ALIGN(64);
+    tcb0 = .;
+    . = . + .tls_template_size + 256;
+    . = ALIGN(4096);
+    .edata = .;
+
+    .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+    .debug_srcinfo 0 : { *(.debug_srcinfo) }
+    .debug_sfnames 0 : { *(.debug_sfnames) }
+    .debug_pubnames 0 : { *(.debug_pubnames) }
+    .debug_frame 0 : { *(.debug_frame) }
+    .debug_abbrev 0 : { *(.debug_abbrev) }
+    .debug_aranges 0 : { *(.debug_aranges) }
+    .debug_ranges 0 : { *(.debug_ranges) }
+    .debug_line 0 : { *(.debug_line) }
+    .debug_loc 0 : { *(.debug_loc) }
+    .debug_str 0 : { *(.debug_str) }
+    .debug_macinfo 0 : { *(.debug_macinfo) }
+    .debug_typenames 0 : { *(.debug_typenames) }
+    .debug_varnames 0 : { *(.debug_varnames) }
+    .debug_weaknames 0 : { *(.debug_weaknames) }
+    .gdb_index 0 : { *(.gdb_index) }
+    .comment : { *(.comment) }
+}
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS;
+	tls PT_TLS;
+	dynamic PT_DYNAMIC;
+	eh_frame PT_GNU_EH_FRAME;
+	note PT_NOTE;
+}
+ENTRY(start_elf);
diff --git a/arch/aarch64/macros.S b/arch/aarch64/macros.S
new file mode 100644
index 000000000..8c790ca27
--- /dev/null
+++ b/arch/aarch64/macros.S
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+.macro push_pair reg1, reg2
+        stp \reg1, \reg2, [sp, #-16]!
+.endm
+
+.macro pop_pair reg1, reg2
+        ldp \reg1, \reg2, [sp], #16
+.endm
diff --git a/arch/aarch64/math.cc b/arch/aarch64/math.cc
new file mode 100644
index 000000000..908da3492
--- /dev/null
+++ b/arch/aarch64/math.cc
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+/* XXX todo XXX */
+#include <math.h>
+#include <osv/types.h>
+
+extern "C"
+int __isnan(double v)
+{
+    return false; /* XXX */
+}
diff --git a/arch/aarch64/preboot.S b/arch/aarch64/preboot.S
new file mode 100644
index 000000000..036b1fca6
--- /dev/null
+++ b/arch/aarch64/preboot.S
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+target = . + 0x10000
+elf_entry = 24 + target
+
+.text
+.align 16
+
+.globl prestart
+prestart: // x4 = 0x40080000 set by qemu bootloader
+    adr x0, target /* elf header start */
+    adr x1, elf_entry
+    ldr x2, [x1] // load entry point from ELF header
+    br  x2
diff --git a/arch/aarch64/preboot.ld b/arch/aarch64/preboot.ld
new file mode 100644
index 000000000..4ddca8ef1
--- /dev/null
+++ b/arch/aarch64/preboot.ld
@@ -0,0 +1,4 @@
+SECTIONS
+{
+        .text : { *(.text) }
+}
diff --git a/arch/aarch64/processor.hh b/arch/aarch64/processor.hh
new file mode 100644
index 000000000..2646adb68
--- /dev/null
+++ b/arch/aarch64/processor.hh
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef AARCH64_PROCESSOR_HH
+#define AARCH64_PROCESSOR_HH
+
+#include <osv/types.h>
+#include <osv/debug.h>
+
+namespace processor {
+
+constexpr unsigned daif_i = 1 << 7;
+
+inline void wfi()
+{
+    asm volatile ("wfi" ::: "memory");
+}
+
+inline void irq_enable()
+{
+    asm volatile ("msr daifclr, #2; isb; " ::: "memory");
+}
+
+inline void irq_disable()
+{
+    asm volatile ("msr daifset, #2; isb; " ::: "memory");
+}
+
+__attribute__((no_instrument_function))
+inline void irq_disable_notrace();
+
+inline void irq_disable_notrace()
+{
+    asm volatile ("msr daifset, #2; isb; " ::: "memory");
+}
+
+inline void wait_for_interrupt() {
+    irq_enable();
+    wfi();
+}
+
+inline void halt_no_interrupts() {
+    irq_disable();
+    while (1) {
+        wfi();
+    }
+}
+
+inline u64 ticks()
+{
+    static u64 i;
+    return ++i;
+}
+
+struct fpu_state {
+    __uint128_t vregs[32];
+    unsigned long fpsr;
+    unsigned long fpcr;
+};
+
+inline void fpu_state_save(fpu_state *s)
+{
+    debug_early_entry("fpu_state_save(s)");
+
+    asm volatile("stp q0, q1, %0" : "=Ump"(s->vregs[0]) :: "memory");
+    asm volatile("stp q2, q3, %0" : "=Ump"(s->vregs[2]) :: "memory");
+    asm volatile("stp q4, q5, %0" : "=Ump"(s->vregs[4]) :: "memory");
+    asm volatile("stp q6, q7, %0" : "=Ump"(s->vregs[6]) :: "memory");
+    asm volatile("stp q8, q9, %0" : "=Ump"(s->vregs[8]) :: "memory");
+    asm volatile("stp q10, q11, %0" : "=Ump"(s->vregs[10]) :: "memory");
+    asm volatile("stp q12, q13, %0" : "=Ump"(s->vregs[12]) :: "memory");
+    asm volatile("stp q14, q15, %0" : "=Ump"(s->vregs[14]) :: "memory");
+    asm volatile("stp q16, q17, %0" : "=Ump"(s->vregs[16]) :: "memory");
+    asm volatile("stp q18, q19, %0" : "=Ump"(s->vregs[18]) :: "memory");
+    asm volatile("stp q20, q21, %0" : "=Ump"(s->vregs[20]) :: "memory");
+    asm volatile("stp q22, q23, %0" : "=Ump"(s->vregs[22]) :: "memory");
+    asm volatile("stp q24, q25, %0" : "=Ump"(s->vregs[24]) :: "memory");
+    asm volatile("stp q26, q27, %0" : "=Ump"(s->vregs[26]) :: "memory");
+    asm volatile("stp q28, q29, %0" : "=Ump"(s->vregs[28]) :: "memory");
+    asm volatile("stp q30, q31, %0" : "=Ump"(s->vregs[30]) :: "memory");
+
+    asm volatile("mrs %0, fpsr" : "=r"(s->fpsr) :: "memory");
+    asm volatile("mrs %0, fpcr" : "=r"(s->fpcr) :: "memory");
+}
+
+inline void fpu_state_load(fpu_state *s)
+{
+    debug_early_entry("fpu_state_load(s)");
+
+    asm volatile("ldp q0, q1, %0" :: "Ump"(s->vregs[0]) : "q0", "q1");
+    asm volatile("ldp q2, q3, %0" :: "Ump"(s->vregs[2]) : "q2", "q3");
+    asm volatile("ldp q4, q5, %0" :: "Ump"(s->vregs[4]) : "q4", "q5");
+    asm volatile("ldp q6, q7, %0" :: "Ump"(s->vregs[6]) : "q6", "q7");
+    asm volatile("ldp q8, q9, %0" :: "Ump"(s->vregs[8]) : "q8", "q9");
+    asm volatile("ldp q10, q11, %0" :: "Ump"(s->vregs[10]) : "q10", "q11");
+    asm volatile("ldp q12, q13, %0" :: "Ump"(s->vregs[12]) : "q12", "q13");
+    asm volatile("ldp q14, q15, %0" :: "Ump"(s->vregs[14]) : "q14", "q15");
+    asm volatile("ldp q16, q17, %0" :: "Ump"(s->vregs[16]) : "q16", "q17");
+    asm volatile("ldp q18, q19, %0" :: "Ump"(s->vregs[18]) : "q18", "q19");
+    asm volatile("ldp q20, q21, %0" :: "Ump"(s->vregs[20]) : "q20", "q21");
+    asm volatile("ldp q22, q23, %0" :: "Ump"(s->vregs[22]) : "q22", "q23");
+    asm volatile("ldp q24, q25, %0" :: "Ump"(s->vregs[24]) : "q24", "q25");
+    asm volatile("ldp q26, q27, %0" :: "Ump"(s->vregs[26]) : "q26", "q27");
+    asm volatile("ldp q28, q29, %0" :: "Ump"(s->vregs[28]) : "q28", "q29");
+    asm volatile("ldp q30, q31, %0" :: "Ump"(s->vregs[30]) : "q30", "q31");
+
+    asm volatile("msr fpsr, %0" :: "r"(s->fpsr) : "memory");
+    asm volatile("msr fpcr, %0" :: "r"(s->fpcr) : "memory");
+}
+
+}
+
+#endif /* AARCH64_PROCESSOR_HH */
diff --git a/arch/aarch64/safe-ptr.hh b/arch/aarch64/safe-ptr.hh
new file mode 100644
index 000000000..f6026e2e8
--- /dev/null
+++ b/arch/aarch64/safe-ptr.hh
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef SAFE_PTR_HH_
+#define SAFE_PTR_HH_
+
+#include <osv/compiler.h>
+
+/* warning: not "safe" at all for now. */
+
+template <typename T>
+static inline bool
+safe_load(const T* potentially_bad_pointer, T& data)
+{
+    data = *potentially_bad_pointer;
+    return true;
+}
+
+template <typename T>
+static inline bool
+safe_store(const T* potentially_bad_pointer, const T& data)
+{
+    *potentially_bad_pointer = data;
+    return true;
+}
+
+#endif /* SAFE_PTR_HH_ */
diff --git a/arch/aarch64/signal.cc b/arch/aarch64/signal.cc
new file mode 100644
index 000000000..b9d0de30c
--- /dev/null
+++ b/arch/aarch64/signal.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/align.hh>
+#include "exceptions.hh"
+#include <signal.h>
+#include <stdlib.h>
+#include <arch-cpu.hh>
+#include <osv/debug.hh>
+
+namespace arch {
+
+struct signal_frame {
+    exception_frame state;
+    siginfo_t si;
+    struct sigaction sa;
+};
+
+}
+
+extern "C" {
+    void call_signal_handler(arch::signal_frame* frame);
+    void call_signal_handler_thunk(void);
+}
+
+namespace arch {
+
+void build_signal_frame(exception_frame* ef,
+                        const siginfo_t& si,
+                        const struct sigaction& sa)
+{
+    void* sp = reinterpret_cast<void*>(ef->sp);
+    sp -= sizeof(signal_frame);
+    sp = align_down(sp, 16);
+    signal_frame* frame = static_cast<signal_frame*>(sp);
+    frame->state = *ef;
+    frame->si = si;
+    frame->sa = sa;
+    ef->pc = reinterpret_cast<ulong>(call_signal_handler_thunk);
+    ef->sp = reinterpret_cast<ulong>(sp);
+}
+
+}
+
+void call_signal_handler(arch::signal_frame* frame)
+{
+    processor::halt_no_interrupts();
+}
diff --git a/arch/aarch64/smp.cc b/arch/aarch64/smp.cc
new file mode 100644
index 000000000..3236ca027
--- /dev/null
+++ b/arch/aarch64/smp.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/debug.h>
+#include <osv/sched.hh>
+#include <osv/prio.hh>
+
+volatile unsigned smp_processors = 1;
+
+sched::cpu* smp_initial_find_current_cpu()
+{
+    for (auto c : sched::cpus) {
+        /* just return the single cpu we have for now */
+        return c;
+    }
+    abort();
+}
+
+void __attribute__((constructor(init_prio::sched))) smp_init()
+{
+    auto c = new sched::cpu(0);
+    c->arch.gic_id = 0;
+    sched::cpus.push_back(c);
+    sched::current_cpu = sched::cpus[0];
+}
diff --git a/arch/aarch64/smp.hh b/arch/aarch64/smp.hh
new file mode 100644
index 000000000..8b00230a7
--- /dev/null
+++ b/arch/aarch64/smp.hh
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef ARCH_SMP_HH
+#define ARCH_SMP_HH
+
+#include <osv/sched.hh>
+
+sched::cpu* smp_initial_find_current_cpu();
+
+#endif /* ARCH_SMP_HH_ */
diff --git a/arch/aarch64/string.cc b/arch/aarch64/string.cc
new file mode 100644
index 000000000..cd842d87f
--- /dev/null
+++ b/arch/aarch64/string.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Huawei Technologies Duesseldorf GmbH
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <bits/alltypes.h>
+#include <osv/string.h>
+
+extern "C"
+void *memcpy_base(void *__restrict dest, const void *__restrict src, size_t n);
+extern "C"
+void *memset_base(void *__restrict dest, int c, size_t n);
+extern "C"
+void *memcpy_base_backwards(void *__restrict dest, const void *__restrict src, size_t n);
+
+
+extern "C"
+void *memcpy(void *__restrict dest, const void *__restrict src, size_t n)
+{
+    return memcpy_base(dest, src, n);
+}
+
+extern "C"
+void *memcpy_backwards(void *__restrict dest, const void *__restrict src, size_t n)
+{
+    return memcpy_base_backwards(dest, src, n);
+}
+
+extern "C"
+void *memset(void *__restrict dest, int c, size_t n)
+{
+    return memset_base(dest, c, n);
+}
-- 
GitLab