hw: support for ARM64 Raspberry Pi 3

Restriction: enables only cpu core 0 and the timer interrupt by now.

Fix #3405
This commit is contained in:
Stefan Kalkowski 2019-05-21 16:27:37 +02:00 committed by Christian Helmuth
parent 87015df66c
commit 90d07741aa
26 changed files with 1465 additions and 1 deletions

View File

@ -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 <base/stdint.h>
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_ */

View File

@ -0,0 +1,3 @@
include $(BASE_DIR)/lib/mk/startup.inc
vpath crt0.s $(BASE_DIR)/src/lib/startup/spec/arm_64

View File

@ -0,0 +1,3 @@
SRC_CC += kernel/interface.cc
vpath kernel/interface.cc $(REP_DIR)/src/lib/base/arm_64

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
BASE_LIBS += base-hw-common base-hw
include $(BASE_DIR)/lib/mk/spec/arm_64/ld-platform.inc

View File

@ -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:

View File

@ -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 <hw/spec/arm_64/rpi3_board.h>
#include <hw/spec/arm_64/cpu.h>
#include <hw/spec/arm/lpae.h>
namespace Bootstrap {
using Cpu = Hw::Arm_64_cpu;
struct Pic {};
};
namespace Board {
using namespace Hw::Rpi3_board;
};
#endif /* _BOOTSTRAP__SPEC__RPI3__BOARD_H_ */

View File

@ -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 <platform.h>
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;
}

View File

@ -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 <board.h>
#include <cpu.h>
#include <kernel/thread.h>
#include <util/bit_allocator.h>
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<Asid_allocator>(); }
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)); }
}

View File

@ -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 <util/register.h>
#include <cpu/cpu_state.h>
#include <base/internal/align_at.h>
#include <hw/spec/arm_64/cpu.h>
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_ */

View File

@ -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

View File

@ -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

View File

@ -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 <kernel/cpu.h>
void Kernel::Cpu::_arch_init()
{
/* enable timer interrupt */
_pic.unmask(_timer.interrupt_id(), id());
}

View File

@ -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 <kernel/cpu.h>
#include <kernel/kernel.h>
#include <kernel/pd.h>
#include <kernel/thread.h>
#include <hw/memory_map.h>
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<Cpu::Context*>(&*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]; }

View File

@ -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 <hw/spec/arm/lpae.h>
#endif /* _CORE__SPEC__ARM_V8__TRANSLATION_TABLE_H_ */

View File

@ -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 <hw/spec/arm_64/rpi3_board.h>
namespace Board {
using namespace Hw::Rpi3_board;
static constexpr bool SMP = true;
};
#endif /* _CORE__SPEC__RPI3__BOARD_H_ */

View File

@ -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 <pic.h>
#include <platform.h>
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<Core0_irq_source>();
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<Core0_timer_irq_control::Cnt_p_ns_irq>(1);
return;
}
Genode::raw("irq of peripherals != timer not implemented yet!");
}
void Genode::Pic::mask(unsigned const i)
{
if (i == TIMER_IRQ) {
write<Core0_timer_irq_control::Cnt_p_ns_irq>(0);
return;
}
Genode::raw("irq of peripherals != timer not implemented yet!");
}

View File

@ -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 <util/mmio.h>
#include <board.h>
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_ */

View File

@ -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 <drivers/timer/util.h>
#include <kernel/timer.h>
#include <kernel/cpu.h>
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; }

View File

@ -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 <kernel/types.h>
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_ */

View File

@ -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<sz> \
{ \
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_ */

View File

@ -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 <drivers/uart/bcm2835_mini.h>
#include <hw/spec/arm/boot_info.h>
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_ */

View File

@ -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 <kernel/interface.h>
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;
}

View File

@ -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,

View File

@ -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"]} {