hw: make 'smp' property an aspect (Ref #1312)

This commit separates certain SMP aspects into 'spec/smp' subdirectories.
Thereby it simplifies non-SMP implementations again, where no locking
and several platform specific maintainance operations are not needed.
Moreover, it moves several platform specifics to appropriated places,
removes dead code from x86, and starts to turn global static pointers
into references that are handed over.
This commit is contained in:
Stefan Kalkowski 2015-12-09 12:02:00 +01:00 committed by Christian Helmuth
parent 8899d9cb6d
commit e05d26567d
36 changed files with 436 additions and 420 deletions

View File

@ -47,7 +47,7 @@ SRC_CC += pager.cc
SRC_CC += _main.cc
SRC_CC += kernel/cpu_scheduler.cc
SRC_CC += kernel/double_list.cc
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/init.cc
SRC_CC += kernel/thread.cc
SRC_CC += kernel/signal_receiver.cc
SRC_CC += kernel/ipc_node.cc

View File

@ -9,7 +9,7 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/arm
# add C++ sources
SRC_CC += spec/arm/kernel/thread.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/cpu_idle.cc
SRC_CC += spec/arm/kernel/pd.cc
SRC_CC += spec/arm/platform_support.cc

View File

@ -12,6 +12,8 @@ SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/arm_v6/cpu.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += kernel/kernel.cc
# add assembly sources
SRC_S += spec/arm_v6/mode_transition.s

View File

@ -7,9 +7,15 @@
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a15
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_gic
INC_DIR += $(REP_DIR)/src/core/include/spec/smp
# add C++ sources
SRC_CC += spec/cortex_a15/cpu.cc
SRC_CC += spec/arm_v7/smp/kernel/cpu.cc
SRC_CC += spec/smp/kernel/kernel.cc
# add assembler sources
SRC_S += spec/arm/smp/kernel/crt0.s
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/arm_v7/core.inc

View File

@ -10,6 +10,8 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += kernel/kernel.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/arm_v7/core.inc

View File

@ -13,6 +13,8 @@ SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += kernel/kernel.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/spec/arm_v7/core.inc

View File

@ -9,11 +9,12 @@
INC_DIR += $(REP_DIR)/src/core/include/spec/x86
# add C++ sources
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/x86/platform_support.cc
SRC_CC += spec/x86/kernel/pd.cc
SRC_CC += spec/x86/cpu.cc
SRC_CC += spec/x86/bios_data_area.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/x86/io_port_session_component.cc
SRC_CC += spec/x86/platform_services.cc

View File

@ -269,7 +269,7 @@ class Kernel::Cpu : public Genode::Cpu,
Cpu_idle _idle;
Timer * const _timer;
Cpu_scheduler _scheduler;
Ipi _ipi_irq;
Ipi _ipi_irq;
Irq _timer_irq; /* timer irq implemented as empty event */
unsigned _quota() const { return _timer->ms_to_tics(cpu_quota_ms); }
@ -282,6 +282,14 @@ class Kernel::Cpu : public Genode::Cpu,
*/
Cpu(unsigned const id, Timer * const timer);
/**
* Initialize primary cpu object
*
* \param pic interrupt controller object
* \param core_pd core's pd object
*/
void init(Pic &pic, Kernel::Pd &core_pd);
/**
* Raise the IPI of the CPU
*/
@ -301,9 +309,9 @@ class Kernel::Cpu : public Genode::Cpu,
void schedule(Job * const job);
/**
* Handle recent exception of the CPU and proceed its user execution
* Return the job that should be executed at next
*/
void exception();
Cpu_job& schedule();
/***************
@ -313,8 +321,8 @@ class Kernel::Cpu : public Genode::Cpu,
/**
* Returns the currently active job
*/
Job * scheduled_job() const {
return static_cast<Job *>(_scheduler.head())->helping_sink(); }
Job & scheduled_job() const {
return *static_cast<Job *>(_scheduler.head())->helping_sink(); }
unsigned id() const { return _id; }
Cpu_scheduler * scheduler() { return &_scheduler; }

View File

@ -11,6 +11,20 @@
* under the terms of the GNU General Public License version 2.
*/
/**
* Get base of the first kernel-stack and the common kernel-stack size
*
* \param base_dst_reg register that shall receive the stack-area base
* \param size_dst_reg register that shall receive the size of a kernel stack
*/
.macro _get_constraints_of_kernel_stacks base_dst_reg, size_dst_reg
ldr \base_dst_reg, =kernel_stack
ldr \size_dst_reg, =kernel_stack_size
ldr \size_dst_reg, [\size_dst_reg]
.endm
/**
* Calculate and apply kernel SP for a given kernel-stacks area
*

View File

@ -125,15 +125,13 @@ class Genode::Cpu : public Arm
*
* \param pd kernel's pd object
*/
static void init_virt_kernel(Kernel::Pd* pd);
static void init_virt_kernel(Kernel::Pd& pd);
/**
* Ensure that TLB insertions get applied
*/
static void tlb_insertions() { flush_tlb(); }
static void start_secondary_cpus(void *) { assert(!Board::is_smp()); }
/**
* Return wether to retry an undefined user instruction after this call
*/

View File

@ -155,7 +155,7 @@ class Genode::Arm_v7 : public Arm
*
* \param pd kernel's pd object
*/
static void init_virt_kernel(Kernel::Pd* pd);
static void init_virt_kernel(Kernel::Pd& pd);
inline static void finish_init_phys_kernel();
@ -176,17 +176,6 @@ class Genode::Arm_v7 : public Arm
*/
static void data_synchronization_barrier() { asm volatile ("dsb"); }
/**
* Enable secondary CPUs with instr. pointer 'ip'
*/
static void start_secondary_cpus(void * const ip)
{
if (!(NR_OF_CPUS > 1)) { return; }
Board::secondary_cpus_ip(ip);
data_synchronization_barrier();
asm volatile ("sev\n");
}
/**
* Wait for the next interrupt as cheap as possible
*/

View File

@ -427,7 +427,7 @@ class Genode::Cpu : public Arm_v7
*
* \param pd kernel pd object pointer
*/
static void init_virt_kernel(Kernel::Pd * pd);
static void init_virt_kernel(Kernel::Pd & pd);
/*************

View File

@ -144,7 +144,7 @@ class Genode::Cpu
{
friend class Cpu_lazy_state;
private:
protected:
Idt *_idt;
Tss *_tss;
@ -311,96 +311,6 @@ class Genode::Cpu
Kernel::Call_arg user_arg_7() const { return r11; }
};
/**
* Returns true if current execution context is running in user mode
*/
static bool is_user()
{
PDBG("not implemented");
return false;
}
/**
* Invalidate all entries of all instruction caches
*/
__attribute__((always_inline)) static void invalidate_instr_caches() { }
/**
* Flush all entries of all data caches
*/
inline static void flush_data_caches() { }
/**
* Invalidate all entries of all data caches
*/
inline static void invalidate_data_caches() { }
/**
* Flush all caches
*/
static void flush_caches()
{
flush_data_caches();
invalidate_instr_caches();
}
/**
* Invalidate all TLB entries of the address space named 'pid'
*/
static void flush_tlb_by_pid(unsigned const pid)
{
flush_caches();
}
/**
* Invalidate all TLB entries
*/
static void flush_tlb()
{
flush_caches();
}
/**
* Flush data-cache entries for virtual region ['base', 'base + size')
*/
static void
flush_data_caches_by_virt_region(addr_t base, size_t const size) { }
/**
* Bin instr.-cache entries for virtual region ['base', 'base + size')
*/
static void
invalidate_instr_caches_by_virt_region(addr_t base, size_t const size)
{ }
static void inval_branch_predicts() { };
/**
* Switch to the virtual mode in kernel
*
* \param pd kernel's pd object
*/
static void init_virt_kernel(Kernel::Pd * pd);
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
Timer::disable_pit();
_init_fpu();
};
/**
* Finish all previous data transfers
*/
static void data_synchronization_barrier() { }
/**
* Enable secondary CPUs with instr. pointer 'ip'
*/
static void start_secondary_cpus(void * const ip) { }
/**
* Wait for the next interrupt as cheap as possible
*/
@ -455,12 +365,22 @@ class Genode::Cpu
_disable_fpu();
}
/*************
** Dummies **
*************/
static void tlb_insertions() { inval_branch_predicts(); }
/*********************************************
** Dummy implementations not needed on x86 **
*********************************************/
static void tlb_insertions() { }
static void translation_added(addr_t, size_t) { }
static void flush_data_caches() { }
static void flush_caches() { }
static void flush_tlb_by_pid(unsigned const pid) { }
static void flush_data_caches_by_virt_region(addr_t base,
size_t const size) { }
static void invalidate_instr_caches() { }
static void invalidate_data_caches() { }
static void invalidate_instr_caches_by_virt_region(addr_t base,
size_t const size) {}
};
struct Genode::Cpu::Cr0 : Register<64>

View File

@ -1,25 +0,0 @@
/*
* \brief CPU context of a virtual machine
* \author Martin Stein
* \date 2013-10-30
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _KERNEL__VM_STATE_H_
#define _KERNEL__VM_STATE_H_
namespace Kernel
{
/**
* Dummy
*/
struct Vm_state { };
}
#endif /* _KERNEL__VM_STATE_H_ */

View File

@ -274,7 +274,6 @@ class Genode::Pic : public Mmio
*/
void mask() { }
void init_cpu_local() { }
bool is_ip_interrupt(unsigned, unsigned) { return false; }
void trigger_ip_interrupt(unsigned) { }
};

View File

@ -18,7 +18,7 @@
#include <pic.h>
namespace Kernel {
void init_trustzone(Pic * pic);
void init_trustzone(Pic & pic);
}
#endif /* _CORE__INCLUDE__TRUSTZONE_H_ */

View File

@ -177,12 +177,10 @@ bool Cpu::interrupt(unsigned const irq_id)
}
void Cpu::exception()
Cpu_job & Cpu::schedule()
{
/* update old job */
Job * const old_job = scheduled_job();
old_job->exception(_id);
/* get new job */
Job & old_job = scheduled_job();
/* update scheduler */
unsigned const old_time = _scheduler.head_quota();
@ -191,18 +189,18 @@ void Cpu::exception()
_scheduler.update(quota);
/* get new job */
Job * const new_job = scheduled_job();
Job & new_job = scheduled_job();
quota = _scheduler.head_quota();
assert(quota);
_timer->start_one_shot(quota, _id);
/* switch between lazy state of old and new job */
Cpu_lazy_state * const old_state = old_job->lazy_state();
Cpu_lazy_state * const new_state = new_job->lazy_state();
Cpu_lazy_state * const old_state = old_job.lazy_state();
Cpu_lazy_state * const new_state = new_job.lazy_state();
prepare_proceeding(old_state, new_state);
/* resume new job */
new_job->proceed(_id);
/* return new job */
return new_job;
}

View File

@ -0,0 +1,69 @@
/*
* \brief Common kernel initialization
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
*/
/*
* Copyright (C) 2011-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/pd.h>
#include <kernel/kernel.h>
#include <kernel/test.h>
#include <platform_pd.h>
#include <pic.h>
#include <platform_thread.h>
/* base includes */
#include <unmanaged_singleton.h>
#include <base/native_types.h>
using namespace Kernel;
static_assert(sizeof(Genode::sizet_arithm_t) >= 2 * sizeof(size_t),
"Bad result type for size_t arithmetics.");
Pd * Kernel::core_pd() {
return unmanaged_singleton<Genode::Core_platform_pd>()->kernel_pd(); }
Pic * Kernel::pic() { return unmanaged_singleton<Pic>(); }
/**
* Setup kernel environment
*/
extern "C" void init_kernel()
{
/*
* As atomic operations are broken in physical mode on some platforms
* we must avoid the use of 'cmpxchg' by now (includes not using any
* local static objects.
*/
/* calculate in advance as needed later when data writes aren't allowed */
core_pd();
/* initialize cpu pool */
cpu_pool();
/* initialize PIC */
pic();
/* initialize current cpu */
cpu_pool()->cpu(Cpu::executing_id())->init(*pic(), *core_pd());
Core_thread::singleton();
Genode::printf("kernel initialized\n");
test();
kernel();
}

View File

@ -1,19 +1,8 @@
/*
* \brief Singlethreaded minimalistic kernel
* \brief Kernel entrypoint
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
*
* This kernel is the only code except the mode transition PIC, that runs in
* privileged CPU mode. It has two tasks. First it initializes the process
* 'core', enriches it with the whole identically mapped address range,
* joins and applies it, assigns one thread to it with a userdefined
* entrypoint (the core main thread) and starts this thread in userland.
* Afterwards it is called each time an exception occurs in userland to do
* a minimum of appropriate exception handling. Thus it holds a CPU context
* for itself as for any other thread. But due to the fact that it never
* relies on prior kernel runs this context only holds some constant pointers
* such as SP and IP.
*/
/*
@ -24,137 +13,14 @@
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/pd.h>
#include <kernel/kernel.h>
#include <kernel/test.h>
#include <platform_pd.h>
#include <trustzone.h>
#include <timer.h>
#include <pic.h>
#include <platform_thread.h>
/* base includes */
#include <unmanaged_singleton.h>
#include <base/native_types.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
using namespace Kernel;
extern void * _start_secondary_cpus;
static_assert(sizeof(Genode::sizet_arithm_t) >= 2 * sizeof(size_t),
"Bad result type for size_t arithmetics.");
Lock & Kernel::data_lock() { return *unmanaged_singleton<Kernel::Lock>(); }
Pd * Kernel::core_pd() {
return unmanaged_singleton<Genode::Core_platform_pd>()->kernel_pd(); }
Pic * Kernel::pic() { return unmanaged_singleton<Pic>(); }
/**
* Setup kernel environment before activating secondary CPUs
*/
extern "C" void init_kernel_up()
{
/*
* As atomic operations are broken in physical mode on some platforms
* we must avoid the use of 'cmpxchg' by now (includes not using any
* local static objects.
*/
/* calculate in advance as needed later when data writes aren't allowed */
core_pd();
/* initialize all CPU objects */
cpu_pool();
/* initialize PIC */
pic();
/* go multiprocessor mode */
Cpu::start_secondary_cpus(&_start_secondary_cpus);
}
/**
* Setup kernel enviroment after activating secondary CPUs as primary CPU
*/
void init_kernel_mp_primary()
{
Core_thread::singleton();
Genode::printf("kernel initialized\n");
test();
}
/**
* Setup kernel enviroment after activating secondary CPUs
*/
extern "C" void init_kernel_mp()
{
/*
* As updates on a cached kernel lock might not be visible to CPUs that
* have not enabled caches, we can't synchronize the activation of MMU and
* caches. Hence we must avoid write access to kernel data by now.
*/
/* synchronize data view of all CPUs */
Cpu::invalidate_data_caches();
Cpu::invalidate_instr_caches();
Cpu::data_synchronization_barrier();
/* locally initialize interrupt controller */
pic()->init_cpu_local();
/* initialize CPU in physical mode */
Cpu::init_phys_kernel();
/* switch to core address space */
Cpu::init_virt_kernel(core_pd());
/*
* Now it's safe to use 'cmpxchg'
*/
Lock::Guard guard(data_lock());
/*
* Now it's save to write to kernel data
*/
/*
* TrustZone initialization code
*
* FIXME This is a plattform specific feature
*/
init_trustzone(pic());
/*
* Enable performance counter
*
* FIXME This is an optional CPU specific feature
*/
perf_counter()->enable();
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic()->unmask(Timer::interrupt_id(cpu), cpu);
/* do further initialization only as primary CPU */
if (Cpu::primary_id() != cpu) { return; }
init_kernel_mp_primary();
}
#include <kernel/cpu.h>
extern "C" void kernel()
{
data_lock().lock();
cpu_pool()->cpu(Cpu::executing_id())->exception();
using namespace Kernel;
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->scheduled_job().exception(cpu->id());
cpu->schedule().proceed(cpu->id());
}

View File

@ -13,7 +13,6 @@
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/pd.h>
/* Genode includes */
@ -69,9 +68,6 @@ void Mode_transition_control::switch_to(Cpu::Context * const context,
addr_t const entry_raw,
addr_t const context_ptr_base)
{
/* unlock kernel data */
data_lock().unlock();
/* override client-context pointer of the executing CPU */
size_t const context_ptr_offset = cpu * sizeof(context);
addr_t const context_ptr = context_ptr_base + context_ptr_offset;

View File

@ -34,7 +34,7 @@ using namespace Genode;
extern int _prog_img_beg;
extern int _prog_img_end;
void __attribute__((weak)) Kernel::init_trustzone(Pic * pic) { }
void __attribute__((weak)) Kernel::init_trustzone(Pic & pic) { }
/**
* Format of a boot-module header

View File

@ -13,29 +13,39 @@
*/
/* core includes */
#include <assert.h>
#include <kernel/cpu.h>
#include <kernel/kernel.h>
#include <kernel/pd.h>
#include <kernel/perf_counter.h>
#include <pic.h>
#include <trustzone.h>
using namespace Kernel;
Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::MIN, 0)
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd)
{
Cpu_job::cpu(cpu);
cpu_exception = RESET;
ip = (addr_t)&_main;
sp = (addr_t)&_stack[stack_size];
init_thread((addr_t)core_pd()->translation_table(), core_pd()->asid);
/* locally initialize interrupt controller */
pic.init_cpu_local();
/* initialize CPU in physical mode */
Cpu::init_phys_kernel();
/* switch to core address space */
Cpu::init_virt_kernel(core_pd);
/*
* TrustZone initialization code
*
* FIXME This is a plattform specific feature
*/
init_trustzone(pic);
/*
* Enable performance counter
*
* FIXME This is an optional CPU specific feature
*/
perf_counter()->enable();
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic.unmask(Timer::interrupt_id(cpu), cpu);
}
void Cpu_idle::exception(unsigned const cpu)
{
switch (cpu_exception) {
case INTERRUPT_REQUEST: _interrupt(cpu); return;
case FAST_INTERRUPT_REQUEST: _interrupt(cpu); return;
case RESET: return;
default: assert(0); }
}

View File

@ -0,0 +1,41 @@
/*
* \brief Class for kernel data that is needed to manage a specific CPU
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2014-01-14
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <assert.h>
#include <kernel/cpu.h>
#include <kernel/kernel.h>
#include <kernel/pd.h>
using namespace Kernel;
Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::MIN, 0)
{
Cpu_job::cpu(cpu);
cpu_exception = RESET;
ip = (addr_t)&_main;
sp = (addr_t)&_stack[stack_size];
init_thread((addr_t)core_pd()->translation_table(), core_pd()->asid);
}
void Cpu_idle::exception(unsigned const cpu)
{
switch (cpu_exception) {
case INTERRUPT_REQUEST: _interrupt(cpu); return;
case FAST_INTERRUPT_REQUEST: _interrupt(cpu); return;
case RESET: return;
default: assert(0); }
}

View File

@ -20,20 +20,6 @@
.include "macros.s"
/**
* Get base of the first kernel-stack and the common kernel-stack size
*
* \param base_dst_reg register that shall receive the stack-area base
* \param size_dst_reg register that shall receive the size of a kernel stack
*/
.macro _get_constraints_of_kernel_stacks base_dst_reg, size_dst_reg
ldr \base_dst_reg, =kernel_stack
ldr \size_dst_reg, =kernel_stack_size
ldr \size_dst_reg, [\size_dst_reg]
.endm
.section ".text.crt0"
/**********************************
@ -65,29 +51,12 @@
b 1b
2:
/* setup temporary stack pointer for uniprocessor mode */
/* setup temporary stack pointer */
_get_constraints_of_kernel_stacks r0, r1
add sp, r0, r1
/* uniprocessor kernel-initialization which activates multiprocessor */
bl init_kernel_up
/* kernel-initialization */
bl init_kernel
/*********************************************
** Startup code that is common to all CPUs **
*********************************************/
.global _start_secondary_cpus
_start_secondary_cpus:
/* setup multiprocessor-aware kernel stack-pointer */
_get_constraints_of_kernel_stacks r0, r1
_init_kernel_sp r0, r1
/* do multiprocessor kernel-initialization */
bl init_kernel_mp
/* call the kernel main-routine */
bl kernel
/* catch erroneous return of the kernel main-routine */
/* catch erroneous return of the kernel initialization routine */
1: b 1b

View File

@ -0,0 +1,42 @@
/*
* \brief Startup code for SMP kernel
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2015-12-08
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/************
** Macros **
************/
/* core includes */
.include "macros.s"
.section ".text.crt0"
/*********************************************
** Startup code that is common to all CPUs **
*********************************************/
.global _start_secondary_cpus
_start_secondary_cpus:
/* setup multiprocessor-aware kernel stack-pointer */
_get_constraints_of_kernel_stacks r0, r1
_init_kernel_sp r0, r1
/* do multiprocessor kernel-initialization */
bl init_kernel_mp
/* call the kernel main-routine */
bl kernel
/* catch erroneous return of the kernel main-routine */
1: b 1b

View File

@ -23,11 +23,11 @@ void Genode::Arm::invalidate_data_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c6, 0" :: [rd]"r"(0) : ); }
void Genode::Cpu::init_virt_kernel(Kernel::Pd* pd)
void Genode::Cpu::init_virt_kernel(Kernel::Pd& pd)
{
Cidr::write(pd->asid);
Cidr::write(pd.asid);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd->translation_table()));
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table()));
Ttbcr::write(0);
Sctlr::write(Sctlr::init_virt_kernel());
}

View File

@ -159,11 +159,11 @@ Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
}
void Genode::Arm_v7::init_virt_kernel(Kernel::Pd * pd)
void Genode::Arm_v7::init_virt_kernel(Kernel::Pd & pd)
{
Cidr::write(pd->asid);
Cidr::write(pd.asid);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd->translation_table()));
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table()));
Ttbcr::write(0);
Sctlr::write(Sctlr::init_virt_kernel());
inval_branch_predicts();

View File

@ -0,0 +1,99 @@
/*
* \brief Cpu class implementation specific to Armv7 SMP
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/pd.h>
#include <kernel/kernel.h>
#include <kernel/test.h>
#include <platform_pd.h>
#include <trustzone.h>
#include <timer.h>
#include <pic.h>
#include <board.h>
#include <platform_thread.h>
/* base includes */
#include <unmanaged_singleton.h>
#include <base/native_types.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
using namespace Kernel;
extern "C" void * _start_secondary_cpus;
Lock & Kernel::data_lock() { return *unmanaged_singleton<Kernel::Lock>(); }
/**
* Setup kernel enviroment after activating secondary CPUs
*/
extern "C" void init_kernel_mp()
{
/*
* As updates on a cached kernel lock might not be visible to CPUs that
* have not enabled caches, we can't synchronize the activation of MMU and
* caches. Hence we must avoid write access to kernel data by now.
*/
/* synchronize data view of all CPUs */
Cpu::invalidate_data_caches();
Cpu::invalidate_instr_caches();
Cpu::data_synchronization_barrier();
/* locally initialize interrupt controller */
pic()->init_cpu_local();
/* initialize CPU in physical mode */
Cpu::init_phys_kernel();
/* switch to core address space */
Cpu::init_virt_kernel(*core_pd());
/*
* Now it's safe to use 'cmpxchg'
*/
{
Lock::Guard guard(data_lock());
/*
* Now it's save to write to kernel data
*/
/* TrustZone initialization code */
init_trustzone(*pic());
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic()->unmask(Timer::interrupt_id(cpu), cpu);
PINF("ok CPU awake");
}
}
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd)
{
if (NR_OF_CPUS > 1) {
Genode::Board::secondary_cpus_ip(&_start_secondary_cpus);
data_synchronization_barrier();
asm volatile ("sev\n");
}
init_kernel_mp();
}

View File

@ -56,8 +56,8 @@ struct Kernel::Vm_irq : Kernel::Irq
*/
void occurred()
{
Cpu_job * job = cpu_pool()->executing_cpu()->scheduled_job();
Vm *vm = dynamic_cast<Vm*>(job);
Cpu_job & job = cpu_pool()->executing_cpu()->scheduled_job();
Vm *vm = dynamic_cast<Vm*>(&job);
if (!vm)
PERR("VM timer interrupt while VM is not runnning!");
else

View File

@ -15,12 +15,12 @@
#include <kernel/pd.h>
#include <cpu.h>
void Genode::Cpu::init_virt_kernel(Kernel::Pd * pd)
void Genode::Cpu::init_virt_kernel(Kernel::Pd & pd)
{
Mair0::write(Mair0::init_virt_kernel());
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd->translation_table(),
pd->asid));
Ttbr0::write(Ttbr0::init((Genode::addr_t)pd.translation_table(),
pd.asid));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
inval_branch_predicts();

View File

@ -0,0 +1,37 @@
/*
* \brief Kernel entrypoint
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
*/
/*
* Copyright (C) 2011-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/cpu.h>
#include <kernel/lock.h>
extern "C" void kernel()
{
using namespace Kernel;
Cpu_job * new_job;
unsigned cpu_id;
{
Lock::Guard guard(data_lock());
cpu_id = Cpu::executing_id();
Cpu * const cpu = cpu_pool()->cpu(cpu_id);
cpu->scheduled_job().exception(cpu_id);
new_job = &cpu->schedule();
}
new_job->proceed(cpu_id);
}

View File

@ -15,20 +15,6 @@
#include <cpu.h>
#include <kernel/pd.h>
void Genode::Cpu::init_virt_kernel(Kernel::Pd * pd)
{
/*
* Please do not remove the PINF(), because the serial constructor requires
* access to the Bios Data Area, which is available in the initial
* translation table set, but not in the final tables used after
* Cr3::write().
*/
PINF("Switch to core's final translation table");
Cr3::write(Cr3::init((addr_t)pd->translation_table()));
}
void Genode::Cpu::_init_fpu()
{
Cr0::access_t cr0_value = Cr0::read();

View File

@ -40,3 +40,25 @@ void Cpu_idle::exception(unsigned const cpu)
errcode, (void *)ip);
assert(0);
}
void Kernel::Cpu::init(Pic &pic, Kernel::Pd &core_pd)
{
Timer::disable_pit();
_init_fpu();
/*
* Please do not remove the PINF(), because the serial constructor requires
* access to the Bios Data Area, which is available in the initial
* translation table set, but not in the final tables used after
* Cr3::write().
*/
PINF("Switch to core's final translation table");
Cr3::write(Cr3::init((addr_t)core_pd.translation_table()));
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic.unmask(Timer::interrupt_id(cpu), cpu);
}

View File

@ -1,22 +0,0 @@
/*
* \brief Kernel backend for virtual machines
* \author Martin Stein
* \date 2013-10-30
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/vm.h>
using namespace Kernel;
void Vm::exception(unsigned const cpu) {
PDBG("not implemented"); }

View File

@ -94,23 +94,10 @@
movq __initial_bx@GOTPCREL(%rip),%rax
movq %rbx, (%rax)
/* uniprocessor kernel-initialization which activates multiprocessor */
call init_kernel_up
/* kernel-initialization */
call init_kernel
/*********************************************
** Startup code that is common to all CPUs **
*********************************************/
.global _start_secondary_cpus
_start_secondary_cpus:
/* do multiprocessor kernel-initialization */
call init_kernel_mp
/* call the kernel main-routine */
call kernel
/* catch erroneous return of the kernel main-routine */
/* catch erroneous return of the kernel initialization */
1: jmp 1b