From 90d07741aa3483ef9e6f0e3d878588e33e224bd0 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 21 May 2019 16:27:37 +0200 Subject: [PATCH] hw: support for ARM64 Raspberry Pi 3 Restriction: enables only cpu core 0 and the timer interrupt by now. Fix #3405 --- .../spec/arm_64/kernel/interface_support.h | 27 +++ .../base-hw/lib/mk/spec/arm_64/startup-hw.mk | 3 + .../base-hw/lib/mk/spec/arm_64/syscall-hw.mk | 3 + .../lib/mk/spec/arm_v8/bootstrap-hw-rpi3.mk | 10 + .../lib/mk/spec/arm_v8/core-hw-rpi3.mk | 24 +++ repos/base-hw/lib/mk/spec/arm_v8/ld-hw.mk | 3 + .../base-hw/src/bootstrap/spec/arm_64/crt0.s | 64 +++++++ repos/base-hw/src/bootstrap/spec/rpi3/board.h | 30 +++ .../src/bootstrap/spec/rpi3/platform.cc | 144 ++++++++++++++ repos/base-hw/src/core/spec/arm_v8/cpu.cc | 96 ++++++++++ repos/base-hw/src/core/spec/arm_v8/cpu.h | 93 +++++++++ repos/base-hw/src/core/spec/arm_v8/crt0.s | 56 ++++++ .../src/core/spec/arm_v8/exception_vector.s | 132 +++++++++++++ .../src/core/spec/arm_v8/kernel/cpu.cc | 21 ++ .../src/core/spec/arm_v8/kernel/thread.cc | 141 ++++++++++++++ .../src/core/spec/arm_v8/translation_table.h | 20 ++ repos/base-hw/src/core/spec/rpi3/board.h | 25 +++ repos/base-hw/src/core/spec/rpi3/pic.cc | 58 ++++++ repos/base-hw/src/core/spec/rpi3/pic.h | 69 +++++++ repos/base-hw/src/core/spec/rpi3/timer.cc | 60 ++++++ .../base-hw/src/core/spec/rpi3/timer_driver.h | 34 ++++ .../base-hw/src/include/hw/spec/arm_64/cpu.h | 179 ++++++++++++++++++ .../src/include/hw/spec/arm_64/rpi3_board.h | 41 ++++ .../src/lib/base/arm_64/kernel/interface.cc | 125 ++++++++++++ repos/base/include/drivers/defs/rpi.h | 5 + tool/run/boot_dir/hw | 3 +- 26 files changed, 1465 insertions(+), 1 deletion(-) create mode 100644 repos/base-hw/include/spec/arm_64/kernel/interface_support.h create mode 100644 repos/base-hw/lib/mk/spec/arm_64/startup-hw.mk create mode 100644 repos/base-hw/lib/mk/spec/arm_64/syscall-hw.mk create mode 100644 repos/base-hw/lib/mk/spec/arm_v8/bootstrap-hw-rpi3.mk create mode 100644 repos/base-hw/lib/mk/spec/arm_v8/core-hw-rpi3.mk create mode 100644 repos/base-hw/lib/mk/spec/arm_v8/ld-hw.mk create mode 100644 repos/base-hw/src/bootstrap/spec/arm_64/crt0.s create mode 100644 repos/base-hw/src/bootstrap/spec/rpi3/board.h create mode 100644 repos/base-hw/src/bootstrap/spec/rpi3/platform.cc create mode 100644 repos/base-hw/src/core/spec/arm_v8/cpu.cc create mode 100644 repos/base-hw/src/core/spec/arm_v8/cpu.h create mode 100644 repos/base-hw/src/core/spec/arm_v8/crt0.s create mode 100644 repos/base-hw/src/core/spec/arm_v8/exception_vector.s create mode 100644 repos/base-hw/src/core/spec/arm_v8/kernel/cpu.cc create mode 100644 repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc create mode 100644 repos/base-hw/src/core/spec/arm_v8/translation_table.h create mode 100644 repos/base-hw/src/core/spec/rpi3/board.h create mode 100644 repos/base-hw/src/core/spec/rpi3/pic.cc create mode 100644 repos/base-hw/src/core/spec/rpi3/pic.h create mode 100644 repos/base-hw/src/core/spec/rpi3/timer.cc create mode 100644 repos/base-hw/src/core/spec/rpi3/timer_driver.h create mode 100644 repos/base-hw/src/include/hw/spec/arm_64/cpu.h create mode 100644 repos/base-hw/src/include/hw/spec/arm_64/rpi3_board.h create mode 100644 repos/base-hw/src/lib/base/arm_64/kernel/interface.cc diff --git a/repos/base-hw/include/spec/arm_64/kernel/interface_support.h b/repos/base-hw/include/spec/arm_64/kernel/interface_support.h new file mode 100644 index 000000000..16e4fafee --- /dev/null +++ b/repos/base-hw/include/spec/arm_64/kernel/interface_support.h @@ -0,0 +1,27 @@ +/* + * \brief Interface between kernel and userland + * \author Stefan Kalkowski + * \date 2019-05-09 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__SPEC__ARM_64__KERNEL__INTERFACE_SUPPORT_H_ +#define _INCLUDE__SPEC__ARM_64__KERNEL__INTERFACE_SUPPORT_H_ + +/* Genode includes */ +#include + +namespace Kernel +{ + typedef Genode::uint64_t Call_arg; + typedef Genode::uint64_t Call_ret; + typedef Genode::uint64_t Call_ret_64; +} + +#endif /* _INCLUDE__SPEC__ARM_64__KERNEL__INTERFACE_SUPPORT_H_ */ diff --git a/repos/base-hw/lib/mk/spec/arm_64/startup-hw.mk b/repos/base-hw/lib/mk/spec/arm_64/startup-hw.mk new file mode 100644 index 000000000..613d12074 --- /dev/null +++ b/repos/base-hw/lib/mk/spec/arm_64/startup-hw.mk @@ -0,0 +1,3 @@ +include $(BASE_DIR)/lib/mk/startup.inc + +vpath crt0.s $(BASE_DIR)/src/lib/startup/spec/arm_64 diff --git a/repos/base-hw/lib/mk/spec/arm_64/syscall-hw.mk b/repos/base-hw/lib/mk/spec/arm_64/syscall-hw.mk new file mode 100644 index 000000000..e77c96c1f --- /dev/null +++ b/repos/base-hw/lib/mk/spec/arm_64/syscall-hw.mk @@ -0,0 +1,3 @@ +SRC_CC += kernel/interface.cc + +vpath kernel/interface.cc $(REP_DIR)/src/lib/base/arm_64 diff --git a/repos/base-hw/lib/mk/spec/arm_v8/bootstrap-hw-rpi3.mk b/repos/base-hw/lib/mk/spec/arm_v8/bootstrap-hw-rpi3.mk new file mode 100644 index 000000000..d05f8d1a7 --- /dev/null +++ b/repos/base-hw/lib/mk/spec/arm_v8/bootstrap-hw-rpi3.mk @@ -0,0 +1,10 @@ +INC_DIR += $(BASE_DIR)/../base-hw/src/bootstrap/spec/rpi3 + +SRC_CC += lib/base/arm_64/kernel/interface.cc +SRC_CC += spec/64bit/memory_map.cc +SRC_CC += bootstrap/spec/rpi3/platform.cc +SRC_S += bootstrap/spec/arm_64/crt0.s + +vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw + +include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc diff --git a/repos/base-hw/lib/mk/spec/arm_v8/core-hw-rpi3.mk b/repos/base-hw/lib/mk/spec/arm_v8/core-hw-rpi3.mk new file mode 100644 index 000000000..4c75401c7 --- /dev/null +++ b/repos/base-hw/lib/mk/spec/arm_v8/core-hw-rpi3.mk @@ -0,0 +1,24 @@ +INC_DIR += $(REP_DIR)/src/core/spec/rpi3 +INC_DIR += $(REP_DIR)/src/core/spec/arm_v8 + +# add C++ sources +SRC_CC += platform_services.cc +SRC_CC += kernel/vm_thread_off.cc +SRC_CC += kernel/cpu_up.cc +SRC_CC += kernel/lock.cc +SRC_CC += spec/arm_v8/cpu.cc +SRC_CC += spec/arm_v8/kernel/thread.cc +SRC_CC += spec/arm_v8/kernel/cpu.cc +SRC_CC += spec/arm/platform_support.cc +SRC_CC += spec/rpi3/pic.cc +SRC_CC += spec/rpi3/timer.cc +SRC_CC += spec/64bit/memory_map.cc + +#add assembly sources +SRC_S += spec/arm_v8/exception_vector.s +SRC_S += spec/arm_v8/crt0.s + +vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw + +# include less specific configuration +include $(REP_DIR)/lib/mk/core-hw.inc diff --git a/repos/base-hw/lib/mk/spec/arm_v8/ld-hw.mk b/repos/base-hw/lib/mk/spec/arm_v8/ld-hw.mk new file mode 100644 index 000000000..c79c372e2 --- /dev/null +++ b/repos/base-hw/lib/mk/spec/arm_v8/ld-hw.mk @@ -0,0 +1,3 @@ +BASE_LIBS += base-hw-common base-hw + +include $(BASE_DIR)/lib/mk/spec/arm_64/ld-platform.inc diff --git a/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s b/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s new file mode 100644 index 000000000..98de01e67 --- /dev/null +++ b/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s @@ -0,0 +1,64 @@ +/* + * \brief Startup code for bootstrap + * \author Stefan Kalkowski + * \date 2019-05-11 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +.section ".text.crt0" + + .global _start + _start: + + /*********************** + ** Detect CPU number ** + ***********************/ + + mrs x0, mpidr_el1 + and x0, x0, #0b11111111 + cbz x0, _crt0_fill_bss_zero + wfe + b _start + + + /*************************** + ** Zero-fill BSS segment ** + ***************************/ + + _crt0_fill_bss_zero: + ldr x0, =_bss_start + ldr x1, =_bss_end + 1: + cmp x1, x0 + b.eq _crt0_enable_fpu + str xzr, [x0], #8 + b 1b + + + /**************** + ** Enable FPU ** + ****************/ + + _crt0_enable_fpu: + mov x0, #0b11 + lsl x0, x0, #20 + msr cpacr_el1, x0 + + + /********************** + ** Initialize stack ** + **********************/ + + ldr x0, =_crt0_start_stack + mov sp, x0 + bl init + + .p2align 4 + .space 0x4000 + _crt0_start_stack: diff --git a/repos/base-hw/src/bootstrap/spec/rpi3/board.h b/repos/base-hw/src/bootstrap/spec/rpi3/board.h new file mode 100644 index 000000000..d2a30a65c --- /dev/null +++ b/repos/base-hw/src/bootstrap/spec/rpi3/board.h @@ -0,0 +1,30 @@ +/* + * \brief Board driver for bootstrap + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _BOOTSTRAP__SPEC__RPI3__BOARD_H_ +#define _BOOTSTRAP__SPEC__RPI3__BOARD_H_ + +#include +#include +#include + +namespace Bootstrap { + using Cpu = Hw::Arm_64_cpu; + struct Pic {}; +}; + +namespace Board { + using namespace Hw::Rpi3_board; +}; + +#endif /* _BOOTSTRAP__SPEC__RPI3__BOARD_H_ */ diff --git a/repos/base-hw/src/bootstrap/spec/rpi3/platform.cc b/repos/base-hw/src/bootstrap/spec/rpi3/platform.cc new file mode 100644 index 000000000..a015a355b --- /dev/null +++ b/repos/base-hw/src/bootstrap/spec/rpi3/platform.cc @@ -0,0 +1,144 @@ +/* + * \brief Platform implementations specific for base-hw and Raspberry Pi3 + * \author Stefan Kalkowski + * \date 2019-05-11 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include + +using Bootstrap::Cpu; + + +/** + * Leave out the first page (being 0x0) from bootstraps RAM allocator, + * some code does not feel happy with addresses being zero + */ +Bootstrap::Platform::Board::Board() +: early_ram_regions(Memory_region { ::Board::RAM_BASE + 0x1000, + ::Board::RAM_SIZE - 0x1000 }), + late_ram_regions(Memory_region { ::Board::RAM_BASE, 0x1000 }), + core_mmio(Memory_region { ::Board::UART_BASE, ::Board::UART_SIZE }, + Memory_region { ::Board::LOCAL_IRQ_CONTROLLER_BASE, + ::Board::LOCAL_IRQ_CONTROLLER_SIZE }, + Memory_region { ::Board::IRQ_CONTROLLER_BASE, + ::Board::IRQ_CONTROLLER_SIZE }) {} + + +static inline void prepare_non_secure_world() +{ + bool el2 = Cpu::Id_pfr0::El2::get(Cpu::Id_pfr0::read()); + + Cpu::Scr::access_t scr = Cpu::Scr::read(); + Cpu::Scr::Ns::set(scr, 1); /* set non-secure bit */ + Cpu::Scr::Rw::set(scr, 1); /* exec in aarch64 */ + Cpu::Scr::Smd::set(scr, 1); /* disable smc call */ + Cpu::Scr::write(scr); + + Cpu::Spsr::access_t pstate = 0; + Cpu::Spsr::Sp::set(pstate, 1); /* select non-el0 stack pointer */ + Cpu::Spsr::El::set(pstate, el2 ? Cpu::Current_el::EL2 + : Cpu::Current_el::EL1); + Cpu::Spsr::F::set(pstate, 1); + Cpu::Spsr::I::set(pstate, 1); + Cpu::Spsr::A::set(pstate, 1); + Cpu::Spsr::D::set(pstate, 1); + Cpu::Spsr_el3::write(pstate); + +#ifndef SWITCH_TO_ELX +#define SWITCH_TO_ELX(el) \ + "mov x0, sp \n" \ + "msr sp_" #el ", x0 \n" \ + "adr x0, 1f \n" \ + "msr elr_el3, x0 \n" \ + "eret \n" \ + "1:" + + if (el2) + asm volatile(SWITCH_TO_ELX(el2) ::: "x0"); + else + asm volatile(SWITCH_TO_ELX(el1) ::: "x0"); +#undef SWITCH_TO_ELX +#else +#error "macro SWITCH_TO_ELX already defined" +#endif +} + + +static inline void prepare_hypervisor() +{ + Cpu::Hcr::access_t scr = Cpu::Hcr::read(); + Cpu::Hcr::Rw::set(scr, 1); /* exec in aarch64 */ + Cpu::Hcr::write(scr); + + Cpu::Spsr::access_t pstate = 0; + Cpu::Spsr::Sp::set(pstate, 1); /* select non-el0 stack pointer */ + Cpu::Spsr::El::set(pstate, Cpu::Current_el::EL1); + Cpu::Spsr::F::set(pstate, 1); + Cpu::Spsr::I::set(pstate, 1); + Cpu::Spsr::A::set(pstate, 1); + Cpu::Spsr::D::set(pstate, 1); + Cpu::Spsr_el2::write(pstate); + + asm volatile("mov x0, sp \n" + "msr sp_el1, x0 \n" + "adr x0, 1f \n" + "msr elr_el2, x0 \n" + "eret \n" + "1:"); +} + + +unsigned Bootstrap::Platform::enable_mmu() +{ + while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) { + if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) + prepare_non_secure_world(); + else + prepare_hypervisor(); + } + + Cpu::Vbar_el1::write(Hw::Mm::supervisor_exception_vector().base); + + /* set memory attributes in indirection register */ + Cpu::Mair::access_t mair = 0; + Cpu::Mair::Attr0::set(mair, Cpu::Mair::NORMAL_MEMORY_UNCACHED); + Cpu::Mair::Attr1::set(mair, Cpu::Mair::DEVICE_MEMORY); + Cpu::Mair::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED); + Cpu::Mair::Attr3::set(mair, Cpu::Mair::DEVICE_MEMORY); + Cpu::Mair::write(mair); + + Cpu::Ttbr::access_t ttbr = Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base); + Cpu::Ttbr0_el1::write(ttbr); + Cpu::Ttbr1_el1::write(ttbr); + + Cpu::Tcr_el1::access_t tcr = 0; + Cpu::Tcr_el1::T0sz::set(tcr, 25); + Cpu::Tcr_el1::T1sz::set(tcr, 25); + Cpu::Tcr_el1::Irgn0::set(tcr, 1); + Cpu::Tcr_el1::Irgn1::set(tcr, 1); + Cpu::Tcr_el1::Orgn0::set(tcr, 1); + Cpu::Tcr_el1::Orgn1::set(tcr, 1); + Cpu::Tcr_el1::Sh0::set(tcr, 0b10); + Cpu::Tcr_el1::Sh1::set(tcr, 0b10); + Cpu::Tcr_el1::Ips::set(tcr, 0b10); + Cpu::Tcr_el1::As::set(tcr, 1); + Cpu::Tcr_el1::write(tcr); + + Cpu::Sctlr_el1::access_t sctlr = Cpu::Sctlr_el1::read(); + Cpu::Sctlr_el1::C::set(sctlr, 1); + Cpu::Sctlr_el1::I::set(sctlr, 1); + Cpu::Sctlr_el1::A::set(sctlr, 0); + Cpu::Sctlr_el1::M::set(sctlr, 1); + Cpu::Sctlr_el1::Sa0::set(sctlr, 1); + Cpu::Sctlr_el1::Sa::set(sctlr, 0); + Cpu::Sctlr_el1::write(sctlr); + + return 0; +} diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.cc b/repos/base-hw/src/core/spec/arm_v8/cpu.cc new file mode 100644 index 000000000..57cfbd480 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.cc @@ -0,0 +1,96 @@ +/* + * \brief ARMv8 cpu context initialization + * \author Stefan Kalkowski + * \date 2017-04-12 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include + + +Genode::Cpu::Context::Context(bool privileged) +{ + Spsr::El::set(pstate, privileged ? 1 : 0); +} + + +void Genode::Cpu::switch_to(Context&, Mmu_context & mmu_context) +{ + if (mmu_context.id() == 0) return; + + if (mmu_context.id() != Ttbr::Asid::get(Ttbr0_el1::read())) + Ttbr0_el1::write(mmu_context.ttbr); +} + + +void Genode::Cpu::mmu_fault(Genode::Cpu::Context &, + Kernel::Thread_fault & fault) +{ + Esr::access_t esr = Esr_el1::read(); + + fault.addr = Far_el1::read(); + + switch (Esr::Iss::Abort::Fsc::get(Esr::Iss::get(esr))) { + case Esr::Iss::Abort::Fsc::TRANSLATION: + fault.type = Kernel::Thread_fault::PAGE_MISSING; + return; + case Esr::Iss::Abort::Fsc::PERMISSION: + fault.type = Esr::Iss::Abort::Write::get(Esr::Iss::get(esr)) + ? Kernel::Thread_fault::WRITE : Kernel::Thread_fault::EXEC; + return; + default: + Genode::raw("MMU-fault not handled ESR=", Genode::Hex(esr)); + fault.type = Kernel::Thread_fault::UNKNOWN; + }; +} + + +using Asid_allocator = Genode::Bit_allocator<65536>; + +static Asid_allocator &alloc() { + return *unmanaged_singleton(); } + + +Genode::Cpu::Mmu_context::Mmu_context(addr_t table) +: ttbr(Ttbr::Baddr::masked(table)) +{ + Ttbr::Asid::set(ttbr, (Genode::uint16_t)alloc().alloc()); +} + + +Genode::Cpu::Mmu_context::~Mmu_context() +{ + alloc().free(id()); +} + + +static constexpr Genode::addr_t line_size = 1 << Board::CACHE_LINE_SIZE_LOG2; +static constexpr Genode::addr_t line_align_mask = ~(line_size - 1); + + +void Genode::Cpu::clean_data_cache_by_virt_region(addr_t base, size_t sz) +{ + addr_t const top = base + sz; + base &= line_align_mask; + for (; base < top; base += line_size) { + asm volatile("dc cvau, %0" :: "r" (base)); } +} + + +void Genode::Cpu::invalidate_instr_cache_by_virt_region(addr_t base, + size_t size) +{ + addr_t const top = base + size; + base &= line_align_mask; + for (; base < top; base += line_size) { + asm volatile("ic ivau, %0" :: "r" (base)); } +} diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.h b/repos/base-hw/src/core/spec/arm_v8/cpu.h new file mode 100644 index 000000000..337f332fa --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.h @@ -0,0 +1,93 @@ +/* + * \brief CPU driver for core + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__ARM_V8__CPU_H_ +#define _CORE__SPEC__ARM_V8__CPU_H_ + +/* Genode includes */ +#include +#include +#include +#include + +namespace Kernel { struct Thread_fault; } + +namespace Genode { + struct Cpu; + using sizet_arithm_t = __uint128_t; + using uint128_t = __uint128_t; +} + +struct Genode::Cpu : Hw::Arm_64_cpu +{ + enum Exception_entry { + SYNC_LEVEL_EL1 = 0x000, + IRQ_LEVEL_EL1 = 0x080, + FIQ_LEVEL_EL1 = 0x100, + SERR_LEVEL_EL1 = 0x180, + SYNC_LEVEL_EL1_EXC_MODE = 0x200, + IRQ_LEVEL_EL1_EXC_MODE = 0x280, + FIQ_LEVEL_EL1_EXC_MODE = 0x300, + SERR_LEVEL_EL1_EXC_MODE = 0x380, + SYNC_LEVEL_EL0 = 0x400, + IRQ_LEVEL_EL0 = 0x480, + FIQ_LEVEL_EL0 = 0x500, + SERR_LEVEL_EL0 = 0x580, + AARCH32_SYNC_LEVEL_EL0 = 0x600, + AARCH32_IRQ_LEVEL_EL0 = 0x680, + AARCH32_FIQ_LEVEL_EL0 = 0x700, + AARCH32_SERR_LEVEL_EL0 = 0x780, + RESET = 0x800 + }; + + struct alignas(16) Fpu_state + { + Genode::uint128_t q[32]; + Genode::uint32_t fpsr; + }; + + struct alignas(8) Context : Cpu_state + { + Genode::uint64_t pstate { }; + Genode::uint64_t exception_type { RESET }; + Fpu_state fpu_state { }; + + Context(bool privileged); + }; + + struct Mmu_context + { + Ttbr::access_t ttbr; + + Mmu_context(addr_t page_table_base); + ~Mmu_context(); + + Genode::uint16_t id() { + return Ttbr::Asid::get(ttbr); } + }; + + void switch_to(Context&, Mmu_context &); + + static void mmu_fault(Context &, Kernel::Thread_fault &); + + /** + * Return kernel name of the executing CPU + */ + static unsigned executing_id() { return 0; } + + + static void clean_data_cache_by_virt_region(addr_t, size_t); + static void invalidate_instr_cache_by_virt_region(addr_t, size_t); +}; + +#endif /* _CORE__SPEC__ARM_V8__CPU_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v8/crt0.s b/repos/base-hw/src/core/spec/arm_v8/crt0.s new file mode 100644 index 000000000..9adb479fb --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/crt0.s @@ -0,0 +1,56 @@ +/** + * \brief Startup code for core on ARM + * \author Stefan Kalkowski + * \date 2015-03-06 + */ + +/* + * Copyright (C) 2015-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +.section ".text" + + /*********************** + ** kernel entry code ** + ***********************/ + + .global _start + _start: + + /* switch to cpu-specific kernel stack */ + /*adr r1, _kernel_stack + adr r2, _kernel_stack_size + ldr r1, [r1] + ldr r2, [r2] + ldr r2, [r2] + add r0, #1 + mul r0, r0, r2 + add sp, r1, r0*/ + + /* jump into init C code */ + b kernel_init + + _kernel_stack: .quad kernel_stack + _kernel_stack_size: .quad kernel_stack_size + + + /********************************* + ** core main thread entry code ** + *********************************/ + + .global _core_start + _core_start: + + /* create proper environment for main thread */ + bl init_main_thread + + /* apply environment that was created by init_main_thread */ + ldr x0, =init_main_thread_result + ldr x0, [x0] + mov sp, x0 + + /* jump into init C code instead of calling it as it should never return */ + b _main diff --git a/repos/base-hw/src/core/spec/arm_v8/exception_vector.s b/repos/base-hw/src/core/spec/arm_v8/exception_vector.s new file mode 100644 index 000000000..d96c35e59 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/exception_vector.s @@ -0,0 +1,132 @@ +/* + * \brief Exception vector for ARMv8 + * \author Stefan Kalkowski + * \date 2019-05-11 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +.section .text.crt0 + + .rept 16 + str x0, [sp, #-32] + ldr x0, [sp, #-16] + add x0, x0, #8 + stp x1, x2, [x0], #16 + stp x3, x4, [x0], #16 + stp x5, x6, [x0], #16 + stp x7, x8, [x0], #16 + stp x9, x10, [x0], #16 + stp x11, x12, [x0], #16 + stp x13, x14, [x0], #16 + stp x15, x16, [x0], #16 + stp x17, x18, [x0], #16 + stp x19, x20, [x0], #16 + stp x21, x22, [x0], #16 + stp x23, x24, [x0], #16 + stp x25, x26, [x0], #16 + stp x27, x28, [x0], #16 + stp x29, x30, [x0], #16 + mrs x1, sp_el0 + mrs x2, elr_el1 + mrs x3, spsr_el1 + adr x4, . + and x4, x4, #0xf80 + stp x1, x2, [x0], #16 + stp x3, x4, [x0], #16 + b _kernel_entry + .balign 128 + .endr + +_kernel_entry: + stp q0, q1, [x0], #32 + stp q2, q3, [x0], #32 + stp q4, q5, [x0], #32 + stp q6, q7, [x0], #32 + stp q8, q9, [x0], #32 + stp q10, q11, [x0], #32 + stp q12, q13, [x0], #32 + stp q14, q15, [x0], #32 + stp q16, q17, [x0], #32 + stp q18, q19, [x0], #32 + stp q20, q21, [x0], #32 + stp q22, q23, [x0], #32 + stp q24, q25, [x0], #32 + stp q26, q27, [x0], #32 + stp q28, q29, [x0], #32 + stp q30, q31, [x0], #32 + mrs x2, fpsr + str x2, [x0] + msr fpsr, xzr + ldr x0, [sp, #-16] + ldr x1, [sp, #-32] + str x1, [x0] + bl kernel + + +.section .text + + /******************************* + ** idle loop for idle thread ** + *******************************/ + + .global idle_thread_main + idle_thread_main: + b idle_thread_main + + + /***************************** + ** kernel to userland switch ** + *******************************/ + + .global kernel_to_user_context_switch + kernel_to_user_context_switch: + mov sp, x1 /* reset stack */ + str x0, [sp, #-16] /* store cpu state pointer */ + add x1, x0, #8*31 + ldp x2, x3, [x1], #16 /* load sp, ip */ + ldr x4, [x1], #16 /* load pstate */ + msr sp_el0, x2 + msr elr_el1, x3 + msr spsr_el1, x4 + ldp q0, q1, [x1], #32 + ldp q2, q3, [x1], #32 + ldp q4, q5, [x1], #32 + ldp q6, q7, [x1], #32 + ldp q8, q9, [x1], #32 + ldp q10, q11, [x1], #32 + ldp q12, q13, [x1], #32 + ldp q14, q15, [x1], #32 + ldp q16, q17, [x1], #32 + ldp q18, q19, [x1], #32 + ldp q20, q21, [x1], #32 + ldp q22, q23, [x1], #32 + ldp q24, q25, [x1], #32 + ldp q26, q27, [x1], #32 + ldp q28, q29, [x1], #32 + ldp q30, q31, [x1], #32 + ldr x1, [x1] + msr fpsr, x1 + add x0, x0, #8 + ldp x1, x2, [x0], #16 + ldp x3, x4, [x0], #16 + ldp x5, x6, [x0], #16 + ldp x7, x8, [x0], #16 + ldp x9, x10, [x0], #16 + ldp x11, x12, [x0], #16 + ldp x13, x14, [x0], #16 + ldp x15, x16, [x0], #16 + ldp x17, x18, [x0], #16 + ldp x19, x20, [x0], #16 + ldp x21, x22, [x0], #16 + ldp x23, x24, [x0], #16 + ldp x25, x26, [x0], #16 + ldp x27, x28, [x0], #16 + ldp x29, x30, [x0] + ldr x0, [x0, #-29*8] + eret diff --git a/repos/base-hw/src/core/spec/arm_v8/kernel/cpu.cc b/repos/base-hw/src/core/spec/arm_v8/kernel/cpu.cc new file mode 100644 index 000000000..6954642b0 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/kernel/cpu.cc @@ -0,0 +1,21 @@ +/* + * \brief Kernel cpu driver implementations specific to ARMv8 + * \author Stefan Kalkowski + * \date 2019-05-11 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* core includes */ +#include + +void Kernel::Cpu::_arch_init() +{ + /* enable timer interrupt */ + _pic.unmask(_timer.interrupt_id(), id()); +} diff --git a/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc new file mode 100644 index 000000000..1f021cc3f --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/kernel/thread.cc @@ -0,0 +1,141 @@ +/* + * \brief Kernel backend for execution contexts in userland + * \author Stefan Kalkowski + * \date 2019-05-11 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include + +#include + +extern "C" void kernel_to_user_context_switch(void *, void *); + +using namespace Kernel; + +void Thread::exception(Cpu & cpu) +{ + switch (regs->exception_type) { + case Cpu::RESET: return; + case Cpu::IRQ_LEVEL_EL0: [[fallthrough]] + case Cpu::IRQ_LEVEL_EL1: [[fallthrough]] + case Cpu::FIQ_LEVEL_EL0: [[fallthrough]] + case Cpu::FIQ_LEVEL_EL1: + _interrupt(cpu.id()); + return; + case Cpu::SYNC_LEVEL_EL0: [[fallthrough]] + case Cpu::SYNC_LEVEL_EL1: + { + Cpu::Esr::access_t esr = Cpu::Esr_el1::read(); + switch (Cpu::Esr::Ec::get(esr)) { + case Cpu::Esr::Ec::SVC: + _call(); + return; + case Cpu::Esr::Ec::INST_ABORT_SAME_LEVEL: [[fallthrough]]; + case Cpu::Esr::Ec::DATA_ABORT_SAME_LEVEL: + Genode::raw("Fault in kernel/core ESR=", Genode::Hex(esr)); + [[fallthrough]]; + case Cpu::Esr::Ec::INST_ABORT_LOW_LEVEL: [[fallthrough]]; + case Cpu::Esr::Ec::DATA_ABORT_LOW_LEVEL: + _mmu_exception(); + return; + default: + Genode::raw("Unknown cpu exception EC=", Cpu::Esr::Ec::get(esr), + " ISS=", Cpu::Esr::Iss::get(esr), + " ip=", (void*)regs->ip); + }; + break; + } + default: + Genode::raw("Exception vector: ", (void*)regs->exception_type, + " not implemented!"); + }; + + while (1) { ; } +} + + +/** + * on ARM with multiprocessing extensions, maintainance operations on TLB, + * and caches typically work coherently across CPUs when using the correct + * coprocessor registers (there might be ARM SoCs where this is not valid, + * with several shareability domains, but until now we do not support them) + */ +void Kernel::Thread::Tlb_invalidation::execute() { }; + + +bool Kernel::Pd::invalidate_tlb(Cpu &, addr_t addr, size_t size) +{ + using namespace Genode; + + /** + * The kernel part of the address space is mapped as global + * therefore we have to invalidate it differently + */ + if (addr >= Hw::Mm::supervisor_exception_vector().base) { + for (addr_t end = addr+size; addr < end; addr += get_page_size()) + asm volatile ("tlbi vaae1is, %0" :: "r" (addr >> 12)); + return false; + } + + /** + * Too big mappings will result in long running invalidation loops, + * just invalidate the whole tlb for the ASID then. + */ + if (size > 8 * get_page_size()) { + asm volatile ("tlbi aside1is, %0" + :: "r" ((uint64_t)mmu_regs.id() << 48)); + return false; + } + + for (addr_t end = addr+size; addr < end; addr += get_page_size()) + asm volatile ("tlbi vae1is, %0" + :: "r" (addr >> 12 | (uint64_t)mmu_regs.id() << 48)); + return false; +} + + +void Kernel::Thread::_call_update_data_region() +{ + Genode::raw(__func__, " not implemented yet!"); +} + + +void Kernel::Thread::_call_update_instr_region() +{ + addr_t const base = (addr_t)user_arg_1(); + size_t const size = (size_t)user_arg_2(); + Cpu::clean_data_cache_by_virt_region(base, size); + Cpu::invalidate_instr_cache_by_virt_region(base, size); +} + + +void Thread::proceed(Cpu & cpu) +{ + cpu.switch_to(*regs, pd().mmu_regs); + kernel_to_user_context_switch((static_cast(&*regs)), + (void*)cpu.stack_start()); +} + + +void Thread::user_ret_time(Kernel::time_t const t) { regs->r[0] = t; } +void Thread::user_arg_0(Kernel::Call_arg const arg) { regs->r[0] = arg; } +void Thread::user_arg_1(Kernel::Call_arg const arg) { regs->r[1] = arg; } +void Thread::user_arg_2(Kernel::Call_arg const arg) { regs->r[2] = arg; } +void Thread::user_arg_3(Kernel::Call_arg const arg) { regs->r[3] = arg; } +void Thread::user_arg_4(Kernel::Call_arg const arg) { regs->r[4] = arg; } + +Kernel::Call_arg Thread::user_arg_0() const { return regs->r[0]; } +Kernel::Call_arg Thread::user_arg_1() const { return regs->r[1]; } +Kernel::Call_arg Thread::user_arg_2() const { return regs->r[2]; } +Kernel::Call_arg Thread::user_arg_3() const { return regs->r[3]; } +Kernel::Call_arg Thread::user_arg_4() const { return regs->r[4]; } diff --git a/repos/base-hw/src/core/spec/arm_v8/translation_table.h b/repos/base-hw/src/core/spec/arm_v8/translation_table.h new file mode 100644 index 000000000..56fb10f85 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/translation_table.h @@ -0,0 +1,20 @@ +/* + * \brief Translation table definitions for core + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ +#define _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ + +/* core includes */ +#include + +#endif /* _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ */ diff --git a/repos/base-hw/src/core/spec/rpi3/board.h b/repos/base-hw/src/core/spec/rpi3/board.h new file mode 100644 index 000000000..2b3c0e35c --- /dev/null +++ b/repos/base-hw/src/core/spec/rpi3/board.h @@ -0,0 +1,25 @@ +/* + * \brief Board driver for core + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__RPI3__BOARD_H_ +#define _CORE__SPEC__RPI3__BOARD_H_ + +#include + +namespace Board { + using namespace Hw::Rpi3_board; + + static constexpr bool SMP = true; +}; + +#endif /* _CORE__SPEC__RPI3__BOARD_H_ */ diff --git a/repos/base-hw/src/core/spec/rpi3/pic.cc b/repos/base-hw/src/core/spec/rpi3/pic.cc new file mode 100644 index 000000000..3c464add5 --- /dev/null +++ b/repos/base-hw/src/core/spec/rpi3/pic.cc @@ -0,0 +1,58 @@ +/* + * \brief Pic implementation specific to Rpi3 + * \author Stefan Kalkowski + * \date 2019-05-27 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include + + +Genode::Pic::Pic() +: Mmio(Platform::mmio_to_virt(Board::LOCAL_IRQ_CONTROLLER_BASE)) { } + + +bool Genode::Pic::take_request(unsigned & irq) +{ + Core0_irq_source::access_t src = read(); + if ((1 << TIMER_IRQ) & src) { + irq = TIMER_IRQ; + return true; + } + return false; +} + + +void Genode::Pic::mask() { } + + +void Genode::Pic::unmask(unsigned const i, unsigned cpu) +{ + if (cpu > 0) + Genode::raw("multi-core irq controller not implemented yet"); + + if (i == TIMER_IRQ) { + write(1); + return; + } + + Genode::raw("irq of peripherals != timer not implemented yet!"); +} + + +void Genode::Pic::mask(unsigned const i) +{ + if (i == TIMER_IRQ) { + write(0); + return; + } + + Genode::raw("irq of peripherals != timer not implemented yet!"); +} diff --git a/repos/base-hw/src/core/spec/rpi3/pic.h b/repos/base-hw/src/core/spec/rpi3/pic.h new file mode 100644 index 000000000..b28966311 --- /dev/null +++ b/repos/base-hw/src/core/spec/rpi3/pic.h @@ -0,0 +1,69 @@ +/* + * \brief Programmable interrupt controller for core + * \author Stefan Kalkowski + * \date 2019-05-27 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _CORE__SPEC__RPI3__PIC_H_ +#define _CORE__SPEC__RPI3__PIC_H_ + +#include +#include + +namespace Genode { class Pic; } +namespace Kernel { using Pic = Genode::Pic; } + +class Genode::Pic : Mmio +{ + public: + + enum { + TIMER_IRQ = 1, + NR_OF_IRQ = 64, + + /* + * dummy IPI value on non-SMP platform, + * only used in interrupt reservation within generic code + */ + IPI, + }; + + private: + + + struct Core0_timer_irq_control : Register<0x40, 32> + { + struct Cnt_p_ns_irq : Bitfield<1, 1> {}; + }; + + struct Core1_timer_irq_control : Register<0x44, 32> {}; + struct Core2_timer_irq_control : Register<0x48, 32> {}; + struct Core3_timer_irq_control : Register<0x4c, 32> {}; + + struct Core0_irq_source : Register<0x60, 32> {}; + struct Core1_irq_source : Register<0x64, 32> {}; + struct Core2_irq_source : Register<0x68, 32> {}; + struct Core3_irq_source : Register<0x6c, 32> {}; + + public: + + Pic(); + + void init_cpu_local(); + bool take_request(unsigned &irq); + void finish_request() { } + void mask(); + void unmask(unsigned const i, unsigned); + void mask(unsigned const i); + + static constexpr bool fast_interrupts() { return false; } +}; + +#endif /* _CORE__SPEC__RPI3__PIC_H_ */ diff --git a/repos/base-hw/src/core/spec/rpi3/timer.cc b/repos/base-hw/src/core/spec/rpi3/timer.cc new file mode 100644 index 000000000..0c5b8d32b --- /dev/null +++ b/repos/base-hw/src/core/spec/rpi3/timer.cc @@ -0,0 +1,60 @@ +/* + * \brief Timer driver for core + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include + +using namespace Kernel; + + +unsigned Timer::interrupt_id() const { return Genode::Pic::TIMER_IRQ; } + + +unsigned long Timer_driver::_freq() { return Genode::Cpu::Cntfrq_el0::read(); } + + +Timer_driver::Timer_driver(unsigned) : ticks_per_ms(_freq() / 1000) +{ + Cpu::Cntp_ctl_el0::access_t ctl = 0; + Cpu::Cntp_ctl_el0::Enable::set(ctl, 1); + Cpu::Cntp_ctl_el0::write(ctl); +} + + +void Timer::_start_one_shot(time_t const ticks) +{ + _driver.last_time = Cpu::Cntpct_el0::read(); + Cpu::Cntp_tval_el0::write(ticks); + Cpu::Cntp_ctl_el0::access_t ctl = Cpu::Cntp_ctl_el0::read(); + Cpu::Cntp_ctl_el0::Istatus::set(ctl, 0); + Cpu::Cntp_ctl_el0::write(ctl); +} + + +time_t Timer::_duration() const +{ + return Cpu::Cntpct_el0::read() - _driver.last_time; +} + + +time_t Timer::ticks_to_us(time_t const ticks) const { + return Genode::timer_ticks_to_us(ticks, _driver.ticks_per_ms); } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * _driver.ticks_per_ms; } + + +time_t Timer::_max_value() const { + return _driver.ticks_per_ms * 5000; } diff --git a/repos/base-hw/src/core/spec/rpi3/timer_driver.h b/repos/base-hw/src/core/spec/rpi3/timer_driver.h new file mode 100644 index 000000000..3a72a72c5 --- /dev/null +++ b/repos/base-hw/src/core/spec/rpi3/timer_driver.h @@ -0,0 +1,34 @@ +/* + * \brief Timer driver for core + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Kernel OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* base-hw includes */ +#include + +namespace Kernel { class Timer_driver; } + + +struct Kernel::Timer_driver +{ + unsigned long _freq(); + + unsigned const ticks_per_ms; + + time_t last_time { 0 }; + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_DRIVER_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h new file mode 100644 index 000000000..1b5684ee9 --- /dev/null +++ b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h @@ -0,0 +1,179 @@ +/* + * \brief CPU definitions for ARM 64bit + * \author Stefan Kalkowski + * \date 2019-05-22 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__LIB__HW__SPEC__ARM_64__CPU_H_ +#define _SRC__LIB__HW__SPEC__ARM_64__CPU_H_ + +#define SYSTEM_REGISTER(sz, name, reg, ...) \ + struct name : Genode::Register \ + { \ + static access_t read() \ + { \ + access_t v; \ + asm volatile ("mrs %0, " #reg : "=r" (v)); \ + return v; \ + } \ + \ + static void write(access_t const v) { \ + asm volatile ("msr " #reg ", %0" :: "r" (v)); } \ + \ + __VA_ARGS__; \ + }; + + +namespace Hw { struct Arm_64_cpu; } + +struct Hw::Arm_64_cpu +{ + SYSTEM_REGISTER(64, Id_pfr0, id_aa64pfr0_el1, + struct El2 : Bitfield<8, 4> {}; + struct El3 : Bitfield<8, 4> {}; + ); + + SYSTEM_REGISTER(64, Cntfrq_el0, cntfrq_el0); + + SYSTEM_REGISTER(64, Current_el, currentel, + enum Level { EL0, EL1, EL2, EL3 }; + struct El : Bitfield<2, 2> {}; + ); + + struct Esr : Genode::Register<64> + { + struct Ec : Bitfield<26, 6> + { + enum Exception { + SVC = 0b010101, + INST_ABORT_LOW_LEVEL = 0b100000, + INST_ABORT_SAME_LEVEL = 0b100001, + DATA_ABORT_LOW_LEVEL = 0b100100, + DATA_ABORT_SAME_LEVEL = 0b100101, + }; + }; + + struct Iss : Bitfield<0, 25> + { + struct Abort : Register<32> + { + struct Level : Bitfield<0, 2> {}; + struct Fsc : Bitfield<2, 4> + { + enum Fault { + ADDR_SIZE, + TRANSLATION, + ACCESS_FLAG, + PERMISSION + }; + enum Data_abort_fault { ALIGNMENT = 8 }; + }; + struct Write : Bitfield<6, 1> {}; + }; + }; + }; + + SYSTEM_REGISTER(64, Esr_el1, esr_el1); + SYSTEM_REGISTER(64, Far_el1, far_el1); + + SYSTEM_REGISTER(64, Hcr, hcr_el2, + struct Rw : Bitfield<31, 1> {}; + ); + + SYSTEM_REGISTER(64, Mair, mair_el1, + enum Attributes { + DEVICE_MEMORY = 0x04, + NORMAL_MEMORY_UNCACHED = 0x44, + NORMAL_MEMORY_CACHED = 0xff, + }; + struct Attr0 : Bitfield<0, 8> {}; + struct Attr1 : Bitfield<8, 8> {}; + struct Attr2 : Bitfield<16, 8> {}; + struct Attr3 : Bitfield<24, 8> {}; + ); + + SYSTEM_REGISTER(64, Scr, scr_el3, + struct Ns : Bitfield<0, 1> {}; + struct Smd : Bitfield<7, 1> {}; + struct Rw : Bitfield<10, 1> {}; + ); + + SYSTEM_REGISTER(64, Sctlr_el1, sctlr_el1, + struct M : Bitfield<0, 1> { }; + struct A : Bitfield<1, 1> { }; + struct C : Bitfield<2, 1> { }; + struct Sa : Bitfield<3, 1> { }; + struct Sa0 : Bitfield<4, 1> { }; + struct I : Bitfield<12, 1> { }; + ); + + struct Spsr : Genode::Register<64> + { + struct Sp : Bitfield<0, 1> {}; + struct El : Bitfield<2, 2> {}; + struct F : Bitfield<6, 1> {}; + struct I : Bitfield<7, 1> {}; + struct A : Bitfield<8, 1> {}; + struct D : Bitfield<9, 1> {}; + }; + + SYSTEM_REGISTER(64, Spsr_el2, spsr_el2); + SYSTEM_REGISTER(64, Spsr_el3, spsr_el3); + + SYSTEM_REGISTER(64, Tcr_el1, tcr_el1, + struct T0sz : Bitfield<0, 6> { }; + struct Epd0 : Bitfield<7, 1> { }; + struct Irgn0 : Bitfield<8, 2> { }; + struct Orgn0 : Bitfield<10, 2> { }; + struct Sh0 : Bitfield<12, 2> { }; + struct Tg0 : Bitfield<14, 2> { }; + struct T1sz : Bitfield<16, 6> { }; + struct A1 : Bitfield<22, 1> { }; + struct Epd1 : Bitfield<23, 1> { }; + struct Irgn1 : Bitfield<24, 2> { }; + struct Orgn1 : Bitfield<26, 2> { }; + struct Sh1 : Bitfield<28, 2> { }; + struct Tg1 : Bitfield<30, 2> { }; + struct Ips : Bitfield<32, 3> { }; + struct As : Bitfield<36, 1> { }; + ); + + struct Ttbr : Genode::Register<64> + { + struct Baddr : Bitfield<0, 48> { }; + struct Asid : Bitfield<48, 16> { }; + }; + + SYSTEM_REGISTER(64, Ttbr0_el1, ttbr0_el1); + SYSTEM_REGISTER(64, Ttbr1_el1, ttbr1_el1); + + SYSTEM_REGISTER(64, Vbar_el1, vbar_el1); + + static inline unsigned current_privilege_level() { + return Current_el::El::get(Current_el::read()); } + + + /***************************** + ** Generic timer interface ** + *****************************/ + + SYSTEM_REGISTER(32, Cntp_ctl_el0, cntp_ctl_el0, + struct Enable : Bitfield<0, 1> {}; + struct Istatus : Bitfield<2, 1> {}; + ); + + SYSTEM_REGISTER(64, Cntpct_el0, cntpct_el0); + SYSTEM_REGISTER(32, Cntp_tval_el0, cntp_tval_el0); +}; + + +#undef SYSTEM_REGISTER + +#endif /* _SRC__LIB__HW__SPEC__ARM_64__CPU_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm_64/rpi3_board.h b/repos/base-hw/src/include/hw/spec/arm_64/rpi3_board.h new file mode 100644 index 000000000..9d8d841a8 --- /dev/null +++ b/repos/base-hw/src/include/hw/spec/arm_64/rpi3_board.h @@ -0,0 +1,41 @@ +/* + * \brief Board definitions for Raspberry Pi 3 + * \author Stefan Kalkowski + * \date 2019-05-10 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__INCLUDE__HW__SPEC__ARM__RPI3__BOARD_H_ +#define _SRC__INCLUDE__HW__SPEC__ARM__RPI3__BOARD_H_ + +#include +#include + +namespace Hw::Rpi3_board { + using Serial = Genode::Bcm2835_mini_uart; + + enum { + RAM_BASE = 0, + RAM_SIZE = 0x20000000, + + UART_BASE = 0x3f215000, + UART_SIZE = 0x1000, + UART_CLOCK = 250000000, + + IRQ_CONTROLLER_BASE = 0x3f00b000, + IRQ_CONTROLLER_SIZE = 0x1000, + + LOCAL_IRQ_CONTROLLER_BASE = 0x40000000, + LOCAL_IRQ_CONTROLLER_SIZE = 0x1000, + + CACHE_LINE_SIZE_LOG2 = 6, + }; +}; + +#endif /* _SRC__INCLUDE__HW__SPEC__ARM__RPI3__BOARD_H_ */ diff --git a/repos/base-hw/src/lib/base/arm_64/kernel/interface.cc b/repos/base-hw/src/lib/base/arm_64/kernel/interface.cc new file mode 100644 index 000000000..5a1df3f41 --- /dev/null +++ b/repos/base-hw/src/lib/base/arm_64/kernel/interface.cc @@ -0,0 +1,125 @@ +/* + * \brief Interface between kernel and userland + * \author Stefan Kalkowski + * \date 2019-05-09 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +using namespace Kernel; + + +/************************************ + ** Helper macros for kernel calls ** + ************************************/ + +#define CALL_1_FILL_ARG_REGS \ + register Call_arg arg_0_reg asm("x0") = arg_0; + +#define CALL_2_FILL_ARG_REGS \ + CALL_1_FILL_ARG_REGS \ + register Call_arg arg_1_reg asm("x1") = arg_1; + +#define CALL_3_FILL_ARG_REGS \ + CALL_2_FILL_ARG_REGS \ + register Call_arg arg_2_reg asm("x2") = arg_2; + +#define CALL_4_FILL_ARG_REGS \ + CALL_3_FILL_ARG_REGS \ + register Call_arg arg_3_reg asm("x3") = arg_3; + +#define CALL_5_FILL_ARG_REGS \ + CALL_4_FILL_ARG_REGS \ + register Call_arg arg_4_reg asm("x4") = arg_4; + +#define CALL_6_FILL_ARG_REGS \ + CALL_5_FILL_ARG_REGS \ + register Call_arg arg_5_reg asm("x5") = arg_5; + +#define CALL_1_SWI "svc 0\n" : "+r" (arg_0_reg) +#define CALL_2_SWI CALL_1_SWI: "r" (arg_1_reg) +#define CALL_3_SWI CALL_2_SWI, "r" (arg_2_reg) +#define CALL_4_SWI CALL_3_SWI, "r" (arg_3_reg) +#define CALL_5_SWI CALL_4_SWI, "r" (arg_4_reg) +#define CALL_6_SWI CALL_5_SWI, "r" (arg_5_reg) + + +/****************** + ** Kernel calls ** + ******************/ + +Call_ret_64 Kernel::call64(Call_arg arg_0) +{ + return Kernel::call(arg_0); +} + + +Call_ret Kernel::call(Call_arg arg_0) +{ + CALL_1_FILL_ARG_REGS + asm volatile(CALL_1_SWI); + return arg_0_reg; +} + + +Call_ret Kernel::call(Call_arg arg_0, + Call_arg arg_1) +{ + CALL_2_FILL_ARG_REGS + asm volatile(CALL_2_SWI); + return arg_0_reg; +} + + +Call_ret Kernel::call(Call_arg arg_0, + Call_arg arg_1, + Call_arg arg_2) +{ + CALL_3_FILL_ARG_REGS + asm volatile(CALL_3_SWI); + return arg_0_reg; +} + + +Call_ret Kernel::call(Call_arg arg_0, + Call_arg arg_1, + Call_arg arg_2, + Call_arg arg_3) +{ + CALL_4_FILL_ARG_REGS + asm volatile(CALL_4_SWI); + return arg_0_reg; +} + + +Call_ret Kernel::call(Call_arg arg_0, + Call_arg arg_1, + Call_arg arg_2, + Call_arg arg_3, + Call_arg arg_4) +{ + CALL_5_FILL_ARG_REGS + asm volatile(CALL_5_SWI); + return arg_0_reg; +} + + +Call_ret Kernel::call(Call_arg arg_0, + Call_arg arg_1, + Call_arg arg_2, + Call_arg arg_3, + Call_arg arg_4, + Call_arg arg_5) +{ + CALL_6_FILL_ARG_REGS + asm volatile(CALL_6_SWI); + return arg_0_reg; +} diff --git a/repos/base/include/drivers/defs/rpi.h b/repos/base/include/drivers/defs/rpi.h index ef7594cde..3374a734e 100644 --- a/repos/base/include/drivers/defs/rpi.h +++ b/repos/base/include/drivers/defs/rpi.h @@ -42,6 +42,11 @@ namespace Rpi { PL011_0_MMIO_SIZE = 0x1000, PL011_0_CLOCK = 3000000, + PL011_1_IRQ = 61, + PL011_1_MMIO_BASE = 0x20215000, + PL011_1_MMIO_SIZE = 0x1000, + PL011_1_CLOCK = 3000000, + IRQ_CONTROLLER_BASE = 0x2000b200, IRQ_CONTROLLER_SIZE = 0x100, diff --git a/tool/run/boot_dir/hw b/tool/run/boot_dir/hw index 3fa5aaa2b..f7d6e107a 100644 --- a/tool/run/boot_dir/hw +++ b/tool/run/boot_dir/hw @@ -19,6 +19,7 @@ proc bootstrap_link_address { } { if {[have_spec "zynq"]} { return "0x00100000" } if {[have_spec "riscv"]} { return "0x81000000" } if {[have_spec "rpi"]} { return "0x00800000" } + if {[have_spec "rpi3"]} { return "0x00800000" } if {[have_spec "nit6_solox"]} { return "0x88000000" } puts "unknown platform no linker address known" @@ -154,7 +155,7 @@ proc run_boot_dir {binaries} { run_image [run_dir]/boot/image.elf # set symbolic link to image.elf file in TFTP directory for PXE boot - if {[have_spec arm] && [have_include "load/tftp"]} { + if {[expr [have_spec arm] || [have_spec arm_64]] && [have_include "load/tftp"]} { exec ln -sf [run_dir]/boot/image.elf [load_tftp_base_dir][load_tftp_offset_dir] if {[have_include "image/uboot"]} {