hw: improve cross-cpu synchronization

This commit addresses several multiprocessing issues in base-hw:

* it reworks cross-cpu maintainance work for TLB invalidation by
  introducing a generic Inter_processor_work and removes the so
  called Cpu_domain_update
* thereby it solves the cross-cpu thread destruction, when the
  corresponding thread is active on another cpu (fix #3043)
* it adds the missing TLB shootdown for x86 (fix #3042)
* on ARM it removes the TLB shootdown via IPIs, because this
  is not needed on the multiprocessing ARM platforms we support
* it enables the per-cpu initialization of the kernel's cpu
  objects, which means those object initialization is executed
  by the proper cpu
* it rollbacks prior decision to make multiprocessing an aspect,
  but puts back certain 'smp' mechanisms (like cross-cpu lock)
  into the generic code base for simplicity reasons
This commit is contained in:
Stefan Kalkowski 2018-11-26 11:18:57 +01:00 committed by Norman Feske
parent 8236a18260
commit 8e13b376b0
51 changed files with 594 additions and 572 deletions

View File

@ -51,16 +51,18 @@ SRC_CC += env.cc
SRC_CC += region_map_support.cc
SRC_CC += pager.cc
SRC_CC += _main.cc
SRC_CC += kernel/cpu.cc
SRC_CC += kernel/cpu_scheduler.cc
SRC_CC += kernel/double_list.cc
SRC_CC += kernel/init.cc
SRC_CC += kernel/thread.cc
SRC_CC += kernel/signal_receiver.cc
SRC_CC += kernel/ipc_node.cc
SRC_CC += kernel/irq.cc
SRC_CC += kernel/cpu.cc
SRC_CC += kernel/timer.cc
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/lock.cc
SRC_CC += kernel/object.cc
SRC_CC += kernel/signal_receiver.cc
SRC_CC += kernel/thread.cc
SRC_CC += kernel/timer.cc
SRC_CC += init_main_thread.cc
SRC_CC += capability.cc
SRC_CC += stack_area_addr.cc

View File

@ -9,6 +9,8 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm
# add C++ sources
SRC_CC += spec/32bit/memory_map.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/pd.cc
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm/kernel/thread.cc
SRC_CC += spec/arm/platform_support.cc

View File

@ -11,10 +11,8 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_v6
# add C++ sources
SRC_CC += spec/arm_v6/cpu.cc
SRC_CC += spec/arm_v6/perf_counter.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/thread_update_pd.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/cpu_up.cc
SRC_S += spec/arm/vfpv2.s

View File

@ -10,10 +10,7 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_gic
# add C++ sources
SRC_CC += spec/cortex_a15/cpu.cc
SRC_CC += spec/cortex_a15/kernel/cpu.cc
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
SRC_CC += spec/arm/smp/kernel/cpu.cc
SRC_CC += kernel/cpu_mp.cc
# include less specific configuration
include $(BASE_DIR)/../base-hw/lib/mk/spec/smp/core-hw.inc
include $(BASE_DIR)/../base-hw/lib/mk/spec/arm_v7/core-hw.inc

View File

@ -9,9 +9,7 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/cortex_a8
# add C++ sources
SRC_CC += spec/cortex_a8/cpu.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/thread_update_pd.cc
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/cpu_up.cc
NR_OF_CPUS = 1

View File

@ -9,14 +9,12 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/cortex_a9
INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_gic
# add C++ sources
SRC_CC += spec/cortex_a9/kernel/cpu.cc
SRC_CC += spec/cortex_a9/board.cc
SRC_CC += spec/cortex_a9/timer.cc
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
SRC_CC += spec/arm/smp/kernel/cpu.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/kernel.cc
# include less specific configuration
include $(BASE_DIR)/../base-hw/lib/mk/spec/smp/core-hw.inc
include $(BASE_DIR)/../base-hw/lib/mk/spec/arm_v7/core-hw.inc

View File

@ -18,23 +18,23 @@ SRC_S += spec/x86_64/crt0.s
SRC_S += spec/x86_64/exception_vector.s
# add C++ sources
SRC_CC += spec/x86_64/muen/kernel/thread_exception.cc
SRC_CC += spec/x86_64/muen/platform_support.cc
SRC_CC += spec/x86_64/muen/kernel/vm.cc
SRC_CC += spec/x86_64/muen/platform_services.cc
SRC_CC += spec/x86_64/muen/sinfo_instance.cc
SRC_CC += spec/x86_64/muen/timer.cc
SRC_CC += kernel/cpu_up.cc
SRC_CC += kernel/vm_thread_on.cc
SRC_CC += kernel/kernel.cc
SRC_CC += spec/x86/io_port_session_component.cc
SRC_CC += spec/x86/io_port_session_support.cc
SRC_CC += spec/x86_64/bios_data_area.cc
SRC_CC += spec/x86_64/cpu.cc
SRC_CC += spec/x86_64/fpu.cc
SRC_CC += spec/x86_64/kernel/cpu.cc
SRC_CC += spec/x86_64/kernel/pd.cc
SRC_CC += spec/x86_64/kernel/thread.cc
SRC_CC += spec/x86_64/kernel/thread.cc
SRC_CC += spec/x86_64/muen/kernel/thread_exception.cc
SRC_CC += spec/x86_64/muen/kernel/vm.cc
SRC_CC += spec/x86_64/muen/platform_services.cc
SRC_CC += spec/x86_64/muen/platform_support.cc
SRC_CC += spec/x86_64/muen/sinfo_instance.cc
SRC_CC += spec/x86_64/muen/timer.cc
SRC_CC += spec/x86_64/platform_support_common.cc
SRC_CC += spec/64bit/memory_map.cc

View File

@ -4,10 +4,12 @@ CC_OPT += -fno-delete-null-pointer-checks
# add C++ sources
SRC_CC += platform_services.cc
SRC_CC += kernel/vm_thread_off.cc kernel/kernel.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += kernel/cpu_up.cc
SRC_CC += spec/riscv/cpu.cc
SRC_CC += spec/riscv/kernel/thread.cc
SRC_CC += spec/riscv/kernel/cpu.cc
SRC_CC += spec/riscv/kernel/pd.cc
SRC_CC += spec/riscv/platform_support.cc
SRC_CC += spec/riscv/timer.cc
SRC_CC += spec/64bit/memory_map.cc

View File

@ -1,12 +0,0 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \date 2016-01-04
#
# add include paths
INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/smp
# add C++ sources
SRC_CC += spec/smp/kernel/kernel.cc
SRC_CC += spec/smp/kernel/cpu.cc

View File

@ -13,6 +13,7 @@ SRC_S += spec/x86_64/crt0.s
SRC_S += spec/x86_64/exception_vector.s
# add C++ sources
SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += spec/x86_64/pic.cc
SRC_CC += spec/x86_64/timer.cc
@ -26,10 +27,10 @@ SRC_CC += spec/x86_64/bios_data_area.cc
SRC_CC += spec/x86_64/cpu.cc
SRC_CC += spec/x86_64/fpu.cc
SRC_CC += spec/x86_64/kernel/cpu.cc
SRC_CC += spec/x86_64/kernel/pd.cc
SRC_CC += spec/x86_64/kernel/thread.cc
SRC_CC += spec/x86_64/kernel/thread.cc
SRC_CC += spec/x86_64/platform_support_common.cc
SRC_CC += spec/x86_64/smp/cpu.cc
SRC_CC += spec/64bit/memory_map.cc
@ -39,4 +40,3 @@ NR_OF_CPUS = 32
# include less specific configuration
include $(BASE_DIR)/../base-hw/lib/mk/core-hw.inc
include $(BASE_DIR)/../base-hw/lib/mk/spec/smp/core-hw.inc

View File

@ -164,5 +164,6 @@ unsigned Bootstrap::Platform::enable_mmu()
/* wait for other cores' coherency activation */
smp_coherency_enabled.wait_for(NR_OF_CPUS);
Cpu::synchronization_barrier();
return Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
}

View File

@ -20,6 +20,7 @@
#include <kernel/pd.h>
#include <pic.h>
#include <hw/assert.h>
#include <hw/boot_info.h>
/* base-internal includes */
#include <base/internal/unmanaged_singleton.h>
@ -194,36 +195,34 @@ addr_t Cpu::stack_start() {
return (addr_t)&kernel_stack + KERNEL_STACK_SIZE * (_id+1); }
Cpu::Cpu(unsigned const id)
Cpu::Cpu(unsigned const id, Pic & pic,
Inter_processor_work_list & global_work_list)
:
_id(id), _timer(_id),
_id(id), _pic(pic), _timer(_id),
_scheduler(&_idle, _quota(), _fill()), _idle(this),
_ipi_irq(*this), _timer_irq(_timer.interrupt_id(), *this)
{ }
_ipi_irq(*this), _timer_irq(_timer.interrupt_id(), *this),
_global_work_list(global_work_list)
{ _arch_init(); }
/**************
** Cpu_pool **
**************/
Cpu * Cpu_pool::cpu(unsigned const id) const
bool Cpu_pool::initialize(Pic & pic)
{
assert(id < NR_OF_CPUS);
char * const p = const_cast<char *>(_cpus[id]);
return reinterpret_cast<Cpu *>(p);
unsigned id = Cpu::executing_id();
_cpus[id].construct(id, pic, _global_work_list);
return --_initialized == 0;
}
Cpu & Cpu_pool::cpu(unsigned const id)
{
assert(id < _count && _cpus[id].constructed());
return *_cpus[id];
}
Cpu_pool::Cpu_pool()
{
for (unsigned id = 0; id < NR_OF_CPUS; id++) {
new (_cpus[id]) Cpu(id); }
}
/***********************
** Cpu_domain_update **
***********************/
Cpu_domain_update::Cpu_domain_update() {
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; } }
: _count(reinterpret_cast<Hw::Boot_info*>(Hw::Mm::boot_info().base)->cpus) { }

View File

@ -15,9 +15,12 @@
#ifndef _CORE__KERNEL__CPU_H_
#define _CORE__KERNEL__CPU_H_
#include <util/reconstructible.h>
/* core includes */
#include <kernel/cpu_context.h>
#include <kernel/irq.h>
#include <kernel/inter_processor_work.h>
#include <kernel/thread.h>
namespace Kernel
@ -67,7 +70,6 @@ namespace Kernel
*/
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
{
private:
@ -79,7 +81,15 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
*/
struct Ipi : Irq
{
bool pending = false;
Cpu & cpu;
bool pending { false };
/**
* Constructor
*
* \param cpu cpu this IPI belongs to
*/
Ipi(Cpu & cpu);
/*********************
@ -87,22 +97,9 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
*********************/
void occurred();
/**
* Constructor
*
* \param p interrupt pool this irq shall reside in
*/
Ipi(Irq::Pool &p);
/**
* Trigger the ipi
*
* \param cpu_id id of the cpu this ipi object is related to
*/
void trigger(unsigned const cpu_id);
};
friend void Ipi::occurred(void);
struct Idle_thread : Kernel::Thread
{
@ -114,12 +111,17 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
unsigned const _id;
Pic &_pic;
Timer _timer;
Cpu_scheduler _scheduler;
Idle_thread _idle;
Ipi _ipi_irq;
Irq _timer_irq; /* timer IRQ implemented as empty event */
Inter_processor_work_list &_global_work_list;
Inter_processor_work_list _local_work_list {};
void _arch_init();
unsigned _quota() const { return _timer.us_to_ticks(cpu_quota_us); }
unsigned _fill() const { return _timer.us_to_ticks(cpu_fill_us); }
@ -130,21 +132,13 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
/**
* Construct object for CPU 'id'
*/
Cpu(unsigned const id);
/**
* Initialize primary cpu object
*
* \param pic interrupt controller object
* \param core_pd core's pd object
* \param board object encapsulating board specifics
*/
void init(Pic &pic/*, Kernel::Pd &core_pd, Genode::Board & board*/);
Cpu(unsigned const id, Pic & pic,
Inter_processor_work_list & global_work_list);
/**
* Raise the IPI of the CPU
*/
void trigger_ip_interrupt() { _ipi_irq.trigger(_id); }
void trigger_ip_interrupt();
/**
* Deliver interrupt to the CPU
@ -188,6 +182,9 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
unsigned timer_interrupt_id() const { return _timer.interrupt_id(); }
Irq::Pool &irq_pool() { return *this; }
Inter_processor_work_list & work_list() {
return _local_work_list; }
};
@ -201,39 +198,40 @@ class Kernel::Cpu_pool
{
private:
/*
* Align to machine word size, otherwise load/stores might fail on some
* platforms.
*/
char _cpus[NR_OF_CPUS][sizeof(Cpu)]
__attribute__((aligned(sizeof(addr_t))));
Inter_processor_work_list _global_work_list {};
unsigned _count;
unsigned _initialized { _count };
Genode::Constructible<Cpu> _cpus[NR_OF_CPUS];
public:
Cpu_pool();
bool initialize(Pic & pic);
/**
* Return object of CPU 'id'
*/
Cpu * cpu(unsigned const id) const;
Cpu & cpu(unsigned const id);
/**
* Return object of primary CPU
*/
Cpu * primary_cpu() const { return cpu(Cpu::primary_id()); }
Cpu & primary_cpu() { return cpu(Cpu::primary_id()); }
/**
* Return object of current CPU
*/
Cpu * executing_cpu() const { return cpu(Cpu::executing_id()); }
Cpu & executing_cpu() { return cpu(Cpu::executing_id()); }
template <typename FUNC>
void for_each_cpu(FUNC const &func) const
void for_each_cpu(FUNC const &func)
{
for (unsigned i = 0; i < sizeof(_cpus)/sizeof(_cpus[i]); i++) {
func(*cpu(i));
}
for (unsigned i = 0; i < _count; i++) func(cpu(i));
}
Inter_processor_work_list & work_list() {
return _global_work_list; }
};
#endif /* _CORE__KERNEL__CPU_H_ */

View File

@ -27,50 +27,8 @@ namespace Kernel
* Context of a job (thread, VM, idle) that shall be executed by a CPU
*/
class Cpu_job;
/**
* Ability to do a domain update on all CPUs
*/
class Cpu_domain_update;
}
class Kernel::Cpu_domain_update : private Double_list_item
{
friend class Cpu_domain_update_list;
friend class Kernel::Double_list_typed<Cpu_domain_update>;
private:
bool _pending[NR_OF_CPUS];
unsigned _domain_id = 0;
/**
* Domain-update back-end
*/
void _domain_update();
/**
* Perform the domain update on the executing CPU
*/
void _do();
protected:
Cpu_domain_update();
virtual ~Cpu_domain_update() { };
/**
* Do an update of domain 'id' on all CPUs and return if this blocks
*/
bool _do_global(unsigned const id);
/**
* Notice that the update isn't pending on any CPU anymore
*/
virtual void _cpu_domain_update_unblocks() = 0;
};
class Kernel::Cpu_job : private Cpu_share
{
private:

View File

@ -0,0 +1,49 @@
/*
* \brief Kernel cpu object implementations for multiprocessor systems
* \author Stefan Kalkowski
* \date 2018-11-18
*/
/*
* Copyright (C) 2018 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>
using namespace Kernel;
void Cpu::Ipi::occurred()
{
/* lambda to iterate over a work-list and execute all work items */
auto iterate = [] (Genode::List<Genode::List_element<Inter_processor_work>> & li) {
Genode::List_element<Inter_processor_work> const *e = li.first();
Genode::List_element<Inter_processor_work> const *next = nullptr;
for ( ; e; e = next) {
next = e->next();
e->object()->execute();
}
};
/* iterate through the local and global work-list */
iterate(cpu._local_work_list);
iterate(cpu._global_work_list);
/* mark the IPI as being received */
pending = false;
}
void Cpu::trigger_ip_interrupt()
{
/* check whether there is still an IPI send */
if (_ipi_irq.pending) return;
pic()->send_ipi(_id);
_ipi_irq.pending = true;
}
Cpu::Ipi::Ipi(Cpu & cpu) : Irq(Pic::IPI, cpu), cpu(cpu) { }

View File

@ -0,0 +1,22 @@
/*
* \brief Kernel cpu object implementations for uniprocessors
* \author Stefan Kalkowski
* \date 2018-11-08
*/
/*
* Copyright (C) 2018 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>
void Kernel::Cpu::Ipi::occurred() { }
void Kernel::Cpu::trigger_ip_interrupt() { }
Kernel::Cpu::Ipi::Ipi(Kernel::Cpu & cpu) : Irq(~0U, cpu), cpu(cpu) { }

View File

@ -16,6 +16,7 @@
#include <kernel/pd.h>
#include <kernel/cpu.h>
#include <kernel/kernel.h>
#include <kernel/lock.h>
#include <platform_pd.h>
#include <pic.h>
#include <board.h>
@ -42,22 +43,32 @@ extern "C" void kernel_init();
*/
extern "C" void kernel_init()
{
static volatile bool initialized = false;
if (Cpu::executing_id()) while (!initialized) ;
else {
static volatile bool pool_ready = false;
static volatile bool kernel_ready = false;
{
Lock::Guard guard(data_lock());
/* initialize current cpu */
pool_ready = cpu_pool()->initialize(*pic());
};
/* wait until all cpus have initialized their corresponding cpu object */
while (!pool_ready) { ; }
/* the boot-cpu initializes the rest of the kernel */
if (Cpu::executing_id() == Cpu::primary_id()) {
Lock::Guard guard(data_lock());
Genode::log("");
Genode::log("kernel initialized");
Core_thread::singleton();
kernel_ready = true;
} else {
/* secondary cpus spin until the kernel is initialized */
while (!kernel_ready) {;}
}
/* initialize cpu pool */
cpu_pool();
/* initialize current cpu */
cpu_pool()->cpu(Cpu::executing_id())->init(*pic());
Core_thread::singleton();
if (!Cpu::executing_id()) initialized = true;
kernel();
}

View File

@ -0,0 +1,42 @@
/*
* \brief Kernel interface for inter-processor communication
* \author Stefan Kalkowski
* \date 2018-11-15
*/
/*
* Copyright (C) 2012-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.
*/
#ifndef _CORE__KERNEL__SMP_H_
#define _CORE__KERNEL__SMP_H_
#include <util/interface.h>
namespace Kernel {
/**
* Work that has to be propagated to a different cpu resp. core
*/
class Inter_processor_work;
using Inter_processor_work_list =
Genode::List<Genode::List_element<Inter_processor_work> >;
}
class Kernel::Inter_processor_work : Genode::Interface
{
public:
virtual void execute() = 0;
protected:
Genode::List_element<Inter_processor_work> _le { this };
};
#endif /* _CORE__KERNEL__SMP_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Kernel entrypoint for non-SMP systems
* \brief Kernel entrypoint
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
@ -14,21 +14,22 @@
/* core includes */
#include <kernel/cpu.h>
#include <kernel/lock.h>
#include <kernel/kernel.h>
extern "C" void kernel()
{
using namespace Kernel;
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->schedule().proceed(*cpu);
Cpu & cpu = cpu_pool()->cpu(Cpu::executing_id());
Cpu_job * new_job;
{
Lock::Guard guard(data_lock());
new_job = &cpu.schedule();
}
new_job->proceed(cpu);
}
void Kernel::Cpu::Ipi::occurred() { }
void Kernel::Cpu::Ipi::trigger(unsigned) { }
Kernel::Cpu::Ipi::Ipi(Kernel::Irq::Pool &p) : Kernel::Irq(Kernel::Pic::IPI, p) { }

View File

@ -0,0 +1,43 @@
/*
* \brief Kernel lock for multi-processor systems
* \author Stefan Kalkowski
* \date 2018-11-20
*/
/*
* 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/lock.h>
#include <kernel/kernel.h>
Kernel::Lock & Kernel::data_lock()
{
static Kernel::Lock lock;
return lock;
}
void Kernel::Lock::lock()
{
/* check for the lock holder being the same cpu */
if (_current_cpu == Cpu::executing_id()) {
/* at least print an error message */
Genode::raw("Cpu ", _current_cpu,
" error: re-entered lock. Kernel exception?!");
for (;;) ;
}
_lock.lock();
_current_cpu = Cpu::executing_id();
}
void Kernel::Lock::unlock()
{
_current_cpu = INVALID;
_lock.unlock();
}

View File

@ -19,9 +19,27 @@
namespace Kernel
{
using Lock = Hw::Spin_lock;
class Lock;
Lock & data_lock();
}
class Kernel::Lock
{
private:
enum { INVALID = ~0U };
Hw::Spin_lock _lock { };
volatile unsigned _current_cpu { INVALID };
public:
void lock();
void unlock();
using Guard = Genode::Lock_guard<Lock>;
};
#endif /* _CORE__SPEC__SMP__KERNEL__LOCK_H_ */

View File

@ -28,6 +28,8 @@ namespace Genode {
namespace Kernel
{
class Cpu;
/**
* Kernel backend of protection domains
*/
@ -81,7 +83,6 @@ class Kernel::Pd : public Kernel::Object
oir->~Object_identity_reference();
}
static capid_t syscall_create(void * const dst,
Hw::Page_table * tt,
Genode::Platform_pd * const pd)
@ -93,6 +94,12 @@ class Kernel::Pd : public Kernel::Object
static void syscall_destroy(Pd * const pd) {
call(call_id_delete_pd(), (Call_arg)pd); }
/**
* Check whether the given 'cpu' needs to do some maintainance
* work, after this pd has had changes in its page-tables
*/
bool update(Cpu & cpu);
/***************
** Accessors **

View File

@ -38,6 +38,30 @@ extern "C" void _core_start(void);
using namespace Kernel;
Thread::Pd_update::Pd_update(Thread & caller, Pd & pd, unsigned cnt)
: caller(caller), pd(pd), cnt(cnt)
{
cpu_pool()->work_list().insert(&_le);
caller._become_inactive(AWAITS_RESTART);
}
Thread::Destroy::Destroy(Thread & caller, Thread & to_delete)
: caller(caller), thread_to_destroy(to_delete)
{
thread_to_destroy._cpu->work_list().insert(&_le);
caller._become_inactive(AWAITS_RESTART);
}
void Thread::Destroy::execute()
{
thread_to_destroy.~Thread();
cpu_pool()->executing_cpu().work_list().remove(&_le);
caller._restart();
}
void Thread_fault::print(Genode::Output &out) const
{
Genode::print(out, "ip=", Genode::Hex(ip));
@ -200,18 +224,13 @@ void Thread::_call_thread_quota()
void Thread::_call_start_thread()
{
/* lookup CPU */
Cpu * const cpu = cpu_pool()->cpu(user_arg_2());
if (!cpu) {
Genode::warning("failed to lookup CPU");
user_arg_0(-2);
return;
}
Cpu & cpu = cpu_pool()->cpu(user_arg_2());
user_arg_0(0);
Thread * const thread = (Thread*) user_arg_1();
assert(thread->_state == AWAITS_START)
assert(thread->_state == AWAITS_START);
thread->affinity(cpu);
thread->affinity(&cpu);
/* join protection domain */
thread->_pd = (Pd *) user_arg_3();
@ -313,6 +332,29 @@ void Thread::_call_yield_thread()
}
void Thread::_call_delete_thread()
{
Thread * to_delete = reinterpret_cast<Thread*>(user_arg_1());
/**
* Delete a thread immediately if it has no cpu assigned yet,
* or it is assigned to this cpu, or the assigned cpu did not scheduled it.
*/
if (!to_delete->_cpu ||
(to_delete->_cpu->id() == Cpu::executing_id() ||
&to_delete->_cpu->scheduled_job() != to_delete)) {
_call_delete<Thread>();
return;
}
/**
* Construct a cross-cpu work item and send an IPI
*/
_destroy.construct(*this, *to_delete);
to_delete->_cpu->trigger_ip_interrupt();
}
void Thread::_call_await_request_msg()
{
if (Ipc_node::await_request(user_arg_1())) {
@ -557,6 +599,20 @@ void Thread::_call_delete_cap()
}
void Kernel::Thread::_call_update_pd()
{
Pd * const pd = (Pd *) user_arg_1();
unsigned cnt = 0;
cpu_pool()->for_each_cpu([&] (Cpu & cpu) {
/* if a cpu needs to update increase the counter */
if (pd->update(cpu)) cnt++; });
/* insert the work item in the list if there are outstanding cpus */
if (cnt) _pd_update.construct(*this, *pd, cnt);
}
void Thread::_call()
{
try {
@ -597,7 +653,7 @@ void Thread::_call()
case call_id_new_thread(): _call_new_thread(); return;
case call_id_new_core_thread(): _call_new_core_thread(); return;
case call_id_thread_quota(): _call_thread_quota(); return;
case call_id_delete_thread(): _call_delete<Thread>(); return;
case call_id_delete_thread(): _call_delete_thread(); return;
case call_id_start_thread(): _call_start_thread(); return;
case call_id_resume_thread(): _call_resume_thread(); return;
case call_id_cancel_thread_blocking(): _call_cancel_thread_blocking(); return;
@ -695,7 +751,7 @@ Core_thread::Core_thread()
regs->sp = (addr_t)&__initial_stack_base[0] + DEFAULT_STACK_SIZE;
regs->ip = (addr_t)&_core_start;
affinity(cpu_pool()->primary_cpu());
affinity(&cpu_pool()->primary_cpu());
_utcb = utcb;
Thread::_pd = core_pd();
_become_active();

View File

@ -14,13 +14,16 @@
#ifndef _CORE__KERNEL__THREAD_H_
#define _CORE__KERNEL__THREAD_H_
#include <base/signal.h>
#include <util/reconstructible.h>
/* core includes */
#include <cpu.h>
#include <kernel/cpu_context.h>
#include <kernel/inter_processor_work.h>
#include <kernel/signal_receiver.h>
#include <kernel/ipc_node.h>
#include <kernel/cpu_context.h>
#include <kernel/object.h>
#include <base/signal.h>
namespace Kernel
{
@ -47,7 +50,7 @@ struct Kernel::Thread_fault
*/
class Kernel::Thread
:
public Kernel::Object, public Cpu_job, public Cpu_domain_update,
public Kernel::Object, public Cpu_job,
public Ipc_node, public Signal_context_killer, public Signal_handler,
private Timeout
{
@ -59,6 +62,47 @@ class Kernel::Thread
Thread(Thread const &);
Thread &operator = (Thread const &);
/**
* An update of page-table entries that requires architecture-wise
* maintainance operations, e.g., a TLB invalidation needs
* cross-cpu synchronization
*/
struct Pd_update : Inter_processor_work
{
Thread & caller; /* the caller gets blocked until all finished */
Pd & pd; /* the corresponding pd */
unsigned cnt; /* count of cpus left */
Pd_update(Thread & caller, Pd & pd, unsigned cnt);
/************************************
** Inter_processor_work interface **
************************************/
void execute();
};
/**
* The destruction of a thread still active on another cpu
* needs cross-cpu synchronization
*/
struct Destroy : Inter_processor_work
{
Thread & caller; /* the caller gets blocked till the end */
Thread & thread_to_destroy; /* thread to be destroyed */
Destroy(Thread & caller, Thread & to_destroy);
/************************************
** Inter_processor_work interface **
************************************/
void execute();
};
friend void Pd_update::execute();
friend void Destroy::execute();
protected:
enum { START_VERBOSE = 0 };
@ -84,6 +128,9 @@ class Kernel::Thread
bool _cancel_next_await_signal = false;
bool const _core = false;
Genode::Constructible<Pd_update> _pd_update {};
Genode::Constructible<Destroy> _destroy {};
/**
* Notice that another thread yielded the CPU to this thread
*/
@ -160,6 +207,7 @@ class Kernel::Thread
void _call_cancel_thread_blocking();
void _call_restart_thread();
void _call_yield_thread();
void _call_delete_thread();
void _call_await_request_msg();
void _call_send_request_msg();
void _call_send_reply_msg();
@ -231,13 +279,6 @@ class Kernel::Thread
void _await_request_succeeded();
void _await_request_failed();
/***********************
** Cpu_domain_update **
***********************/
void _cpu_domain_update_unblocks() { _restart(); }
public:
Genode::Align_at<Genode::Cpu::Context> regs;

View File

@ -132,6 +132,15 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
for (; base < top; base += line_size) { Icimvau::write(base); }
}
/**
* Invalidate TLB regarding the given address space id
*/
static void invalidate_tlb(unsigned asid)
{
if (asid) Tlbiasid::write(asid);
else Tlbiall::write(0);
}
void switch_to(Context&, Mmu_context & o)
{
if (o.cidr == 0) return;

View File

@ -14,25 +14,13 @@
/* core includes */
#include <kernel/cpu.h>
#include <kernel/pd.h>
#include <kernel/perf_counter.h>
#include <pic.h>
void Kernel::Cpu::init(Kernel::Pic &pic)
void Kernel::Cpu::_arch_init()
{
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
pic.unmask(_timer.interrupt_id(), id());
}
void Kernel::Cpu_domain_update::_domain_update()
{
/* flush TLB by ASID */
if (_domain_id)
Cpu::Tlbiasid::write(_domain_id);
else
Cpu::Tlbiall::write(0);
_pic.unmask(_timer.interrupt_id(), id());
}

View File

@ -0,0 +1,29 @@
/*
* \brief Kernel PD object implementations specific to ARM
* \author Stefan Kalkowski
* \date 2018-11-22
*/
/*
* Copyright (C) 2018 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/pd.h>
bool Kernel::Pd::update(Cpu & cpu)
{
/* invalidate the TLB on the local CPU only */
if (cpu.id() == Cpu::executing_id()) {
Cpu::invalidate_tlb(mmu_regs.id());
}
/*
* on all SMP ARM platforms we support the TLB can be maintained
* cross-cpu coherently
*/
return false;
}

View File

@ -54,7 +54,7 @@ void Thread::exception(Cpu & cpu)
void Kernel::Thread::_call_update_data_region()
{
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
Cpu & cpu = cpu_pool()->cpu(Cpu::executing_id());
/*
* FIXME: If the caller is not a core thread, the kernel operates in a
@ -66,19 +66,19 @@ void Kernel::Thread::_call_update_data_region()
* until then we apply operations to caches as a whole instead.
*/
if (!_core) {
cpu->clean_invalidate_data_cache();
cpu.clean_invalidate_data_cache();
return;
}
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
cpu->clean_invalidate_data_cache_by_virt_region(base, size);
cpu->invalidate_instr_cache();
cpu.clean_invalidate_data_cache_by_virt_region(base, size);
cpu.invalidate_instr_cache();
}
void Kernel::Thread::_call_update_instr_region()
{
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
Cpu & cpu = cpu_pool()->cpu(Cpu::executing_id());
/*
* FIXME: If the caller is not a core thread, the kernel operates in a
@ -90,18 +90,25 @@ void Kernel::Thread::_call_update_instr_region()
* until then we apply operations to caches as a whole instead.
*/
if (!_core) {
cpu->clean_invalidate_data_cache();
cpu->invalidate_instr_cache();
cpu.clean_invalidate_data_cache();
cpu.invalidate_instr_cache();
return;
}
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
cpu->clean_invalidate_data_cache_by_virt_region(base, size);
cpu->invalidate_instr_cache_by_virt_region(base, size);
cpu.clean_invalidate_data_cache_by_virt_region(base, size);
cpu.invalidate_instr_cache_by_virt_region(base, size);
}
extern void * kernel_stack;
/**
* 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::Pd_update::execute() { };
void Thread::proceed(Cpu & cpu)
{

View File

@ -1,28 +0,0 @@
/*
* \brief ARM non-SMP specific kernel thread implementations
* \author Stefan Kalkowski
* \date 2015-12-20
*/
/*
* 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.
*/
/* core includes */
#include <kernel/pd.h>
#include <kernel/cpu.h>
#include <kernel/thread.h>
void Kernel::Thread::_call_update_pd()
{
Pd * const pd = (Pd *) user_arg_1();
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->invalidate_instr_cache();
cpu->clean_invalidate_data_cache();
if (pd->mmu_regs.id())
Cpu::Tlbiasid::write(pd->mmu_regs.id()); /* flush TLB by ASID */
else
Cpu::Tlbiall::write(0);
}

View File

@ -1,35 +0,0 @@
/*
* \brief Cpu class implementation specific to ARM SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* 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.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
/* base-internal includes */
#include <base/internal/unmanaged_singleton.h>
/* spin-lock used to synchronize kernel access of different cpus */
Kernel::Lock & Kernel::data_lock() {
return *unmanaged_singleton<Kernel::Lock>(); }
void Kernel::Cpu_domain_update::_domain_update()
{
/* flush TLB by ASID */
if (_domain_id)
Cpu::Tlbiasid::write(_domain_id);
else
Cpu::Tlbiall::write(0);
}

View File

@ -1,23 +0,0 @@
/*
* \brief ARM SMP specific kernel thread implementations
* \author Stefan Kalkowski
* \date 2015-12-20
*/
/*
* 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.
*/
/* core includes */
#include <kernel/pd.h>
#include <kernel/thread.h>
void Kernel::Thread::_call_update_pd()
{
Pd * const pd = (Pd *) user_arg_1();
if (Cpu_domain_update::_do_global(pd->mmu_regs.id())) {
_become_inactive(AWAITS_RESTART); }
}

View File

@ -22,6 +22,15 @@ namespace Genode { struct Arm_v7_cpu; }
struct Genode::Arm_v7_cpu : Arm_cpu
{
/**
* Returns whether this cpu implements the multiprocessor extensions
*/
static bool multi_processor()
{
static bool mp = Mpidr::Me::get(Mpidr::read());
return mp;
}
/**
* Write back dirty lines of inner data cache and invalidate all
*/
@ -31,6 +40,17 @@ struct Genode::Arm_v7_cpu : Arm_cpu
* Invalidate all lines of the inner data cache
*/
static void invalidate_inner_data_cache();
/**
* Invalidate TLB for given address space id
*/
static void invalidate_tlb(unsigned asid)
{
if (multi_processor()) {
if (asid) Tlbiasidis::write(asid);
else Tlbiallis::write(0);
} else Arm_cpu::invalidate_tlb(asid);
}
};
#endif /* _CORE__SPEC__ARM_V7__CPU_SUPPORT_H_ */

View File

@ -25,7 +25,7 @@ Kernel::Vm::Vm(void * const state,
: Cpu_job(Cpu_priority::MIN, 0),
_state((Genode::Vm_state * const)state),
_context(context), _table(0) {
affinity(cpu_pool()->primary_cpu()); }
affinity(&cpu_pool()->primary_cpu()); }
Kernel::Vm::~Vm() {}

View File

@ -58,7 +58,7 @@ struct Kernel::Vm_irq : Kernel::Irq
{
Vm_irq(unsigned const irq)
:
Kernel::Irq(irq, cpu_pool()->executing_cpu()->irq_pool())
Kernel::Irq(irq, cpu_pool()->executing_cpu().irq_pool())
{ }
/**
@ -66,7 +66,7 @@ struct Kernel::Vm_irq : Kernel::Irq
*/
void occurred()
{
Cpu_job & job = cpu_pool()->executing_cpu()->scheduled_job();
Cpu_job & job = cpu_pool()->executing_cpu().scheduled_job();
Vm *vm = dynamic_cast<Vm*>(&job);
if (!vm)
Genode::error("VM timer interrupt while VM is not runnning!");
@ -213,7 +213,7 @@ Kernel::Vm::Vm(void * const state,
_context(context),
_table(table)
{
affinity(cpu_pool()->primary_cpu());
affinity(&cpu_pool()->primary_cpu());
Virtual_pic::pic().irq.enable();
vt_host_context.sp = _cpu->stack_start();

View File

@ -1,33 +0,0 @@
/*
* \brief Cpu class implementation specific to Cortex A15 SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* 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.
*/
/* core includes */
#include <kernel/cpu.h>
#include <kernel/lock.h>
#include <pic.h>
/* base-hw includes */
#include <kernel/perf_counter.h>
using namespace Kernel;
void Kernel::Cpu::init(Kernel::Pic &pic)
{
Lock::Guard guard(data_lock());
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
pic.unmask(_timer.interrupt_id(), id());
}

View File

@ -17,8 +17,8 @@
#include <kernel/cpu.h>
void Genode::Cpu::translation_added(Genode::addr_t const addr,
Genode::size_t const size)
void Genode::Cpu::translation_added(Genode::addr_t const,
Genode::size_t const)
{
using namespace Kernel;
@ -29,9 +29,5 @@ void Genode::Cpu::translation_added(Genode::addr_t const addr,
* page table entry is added. We only do this as core as the kernel
* adds translations solely before MMU and caches are enabled.
*/
if (is_user()) update_data_region(addr, size);
else {
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
cpu->clean_invalidate_data_cache();
}
Cpu::clean_invalidate_data_cache();
}

View File

@ -1,35 +0,0 @@
/*
* \brief Cpu class implementation specific to Cortex A9 SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* 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.
*/
/* core includes */
#include <kernel/perf_counter.h>
#include <kernel/lock.h>
#include <kernel/cpu.h>
#include <kernel/pd.h>
#include <pic.h>
#include <platform_pd.h>
#include <platform.h>
void Kernel::Cpu::init(Kernel::Pic &pic)
{
{
Lock::Guard guard(data_lock());
/* enable performance counter */
perf_counter()->enable();
/* enable timer interrupt */
pic.unmask(_timer.interrupt_id(), id());
}
}

View File

@ -37,8 +37,6 @@ class Genode::Pic : public Hw::Pic
void trigger(unsigned const i) {
write<Swint>(Swint::Intid::bits(i)); }
void trigger_ip_interrupt(unsigned) { }
bool secure(unsigned i) {
return !read<Intsec::Nonsecure>(i); }

View File

@ -15,5 +15,5 @@
#include <kernel/cpu.h>
#include <hw/memory_map.h>
void Kernel::Cpu::init(Kernel::Pic &) {
void Kernel::Cpu::_arch_init() {
Stvec::write(Hw::Mm::supervisor_exception_vector().base); }

View File

@ -0,0 +1,22 @@
/*
* \brief Kernel pd object implementations for RiscV
* \author Stefan Kalkowski
* \date 2018-11-22
*/
/*
* Copyright (C) 2018 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/pd.h>
bool Kernel::Pd::update(Kernel::Cpu&)
{
Genode::Cpu::sfence();
return false;
}

View File

@ -18,6 +18,9 @@
using namespace Kernel;
void Thread::Pd_update::execute() {}
void Thread::exception(Cpu&)
{
using Context = Genode::Cpu::Context;
@ -45,12 +48,6 @@ void Thread::exception(Cpu&)
}
void Thread::_call_update_pd()
{
Genode::Cpu::sfence();
}
void Thread::_call_update_data_region()
{
Genode::Cpu::sfence();

View File

@ -1,108 +0,0 @@
/*
* \brief ARM with SMP support specific aspects of the kernel cpu objects
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2016-01-07
*/
/*
* Copyright (C) 2016-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.
*/
/* core includes */
#include <kernel/cpu.h>
namespace Kernel
{
/**
* Lists all pending domain updates
*/
class Cpu_domain_update_list;
}
class Kernel::Cpu_domain_update_list
: public Double_list_typed<Cpu_domain_update>
{
public:
/**
* Perform all pending domain updates on the executing CPU
*/
void do_each() {
for_each([] (Cpu_domain_update * const u) { u->_do(); }); }
};
using namespace Kernel;
/**
* Return singleton of the CPU domain-udpate list
*/
Cpu_domain_update_list & cpu_domain_update_list() {
return *unmanaged_singleton<Cpu_domain_update_list>(); }
void Cpu::Ipi::occurred()
{
cpu_domain_update_list().do_each();
pending = false;
}
void Cpu::Ipi::trigger(unsigned const cpu_id)
{
if (pending) return;
pic()->send_ipi(cpu_id);
pending = true;
}
Cpu::Ipi::Ipi(Irq::Pool &p) : Irq(Pic::IPI, p) { }
/***********************
** Cpu_domain_update **
***********************/
void Cpu_domain_update::_do()
{
/* perform domain update locally and get pending bit */
unsigned const id = Cpu::executing_id();
if (!_pending[id]) return;
_domain_update();
_pending[id] = false;
/* check wether there are still CPUs pending */
for (unsigned i = 0; i < NR_OF_CPUS; i++)
if (_pending[i]) return;
/* as no CPU is pending anymore, end the domain update */
cpu_domain_update_list().remove(this);
_cpu_domain_update_unblocks();
}
bool Cpu_domain_update::_do_global(unsigned const domain_id)
{
/* perform locally and leave it at that if in uniprocessor mode */
_domain_id = domain_id;
_domain_update();
if (NR_OF_CPUS == 1) return false;
/* inform other CPUs and block until they are done */
cpu_domain_update_list().insert_tail(this);
unsigned const cpu_id = Cpu::executing_id();
for (unsigned i = 0; i < NR_OF_CPUS; i++) {
if (i == cpu_id) continue;
_pending[i] = true;
cpu_pool()->cpu(i)->trigger_ip_interrupt();
}
return true;
}

View File

@ -1,35 +0,0 @@
/*
* \brief Kernel entrypoint for SMP systems
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-20
*/
/*
* Copyright (C) 2011-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.
*/
/* core includes */
#include <kernel/cpu.h>
#include <kernel/lock.h>
extern "C" void kernel()
{
using namespace Kernel;
Cpu_job * new_job;
Cpu * cpu;
{
Lock::Guard guard(data_lock());
cpu = cpu_pool()->cpu(Cpu::executing_id());
new_job = &cpu->schedule();
}
new_job->proceed(*cpu);
}

View File

@ -134,6 +134,12 @@ class Genode::Cpu : public Hw::X86_64_cpu
void switch_to(Context & context, Mmu_context &mmu_context);
static void mmu_fault(Context & regs, Kernel::Thread_fault & fault);
/**
* Invalidate the whole TLB
*/
static void invalidate_tlb() {
Genode::Cpu::Cr3::write(Genode::Cpu::Cr3::read()); }
};
#endif /* _CORE__SPEC__X86_64__CPU_H_ */

View File

@ -15,10 +15,8 @@
/* core includes */
#include <kernel/cpu.h>
#include <kernel/kernel.h>
#include <kernel/pd.h>
void Kernel::Cpu::init(Pic &pic)
void Kernel::Cpu::_arch_init()
{
gdt.init((addr_t)&tss);
Idt::init();
@ -29,10 +27,6 @@ void Kernel::Cpu::init(Pic &pic)
fpu().init();
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic.store_apic_id(cpu);
pic.unmask(_timer.interrupt_id(), cpu);
_pic.store_apic_id(id());
_pic.unmask(_timer.interrupt_id(), id());
}
void Kernel::Cpu_domain_update::_domain_update() { }

View File

@ -0,0 +1,29 @@
/*
* \brief X86-specific implementations for the kernel PD object
* \author Stefan Kalkowski
* \date 2018-11-22
*/
/*
* Copyright (C) 2018 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/pd.h>
bool Kernel::Pd::update(Cpu & cpu)
{
/* on the current CPU invalidate the TLB */
if (cpu.id() == Cpu::executing_id()) {
Cpu::invalidate_tlb();
return false;
}
/* for all other cpus send an IPI */
cpu.trigger_ip_interrupt();
return true;
}

View File

@ -18,6 +18,18 @@
#include <kernel/thread.h>
#include <kernel/pd.h>
void Kernel::Thread::Pd_update::execute()
{
/* invalidate cpu-local TLB */
Cpu::invalidate_tlb();
/* if this is the last cpu, wake up the caller thread */
if (--cnt == 0) {
cpu_pool()->work_list().remove(&_le);
caller._restart();
}
};
void Kernel::Thread::_call_update_data_region() { }
@ -25,11 +37,6 @@ void Kernel::Thread::_call_update_data_region() { }
void Kernel::Thread::_call_update_instr_region() { }
void Kernel::Thread::_call_update_pd() {
Genode::Cpu::Cr3::write(Genode::Cpu::Cr3::read());
}
void Kernel::Thread::proceed(Cpu & cpu)
{
cpu.switch_to(*regs, pd()->mmu_regs);

View File

@ -27,7 +27,7 @@ Kernel::Vm::Vm(void * const state, Kernel::Signal_context * const context,
_context(context),
_table(nullptr)
{
affinity(cpu_pool()->primary_cpu());
affinity(&cpu_pool()->primary_cpu());
}

View File

@ -61,7 +61,6 @@ class Genode::Pic
void unmask(unsigned const, unsigned) { }
void mask(unsigned const) { }
bool is_ip_interrupt(unsigned, unsigned) { return false; }
void trigger_ip_interrupt(unsigned) { }
void store_apic_id(unsigned const) { }
private:

View File

@ -1,25 +0,0 @@
/*
* \brief Cpu class implementation specific to SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* 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.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
/* base-internal includes */
#include <base/internal/unmanaged_singleton.h>
/* spin-lock used to synchronize kernel access of different cpus */
Kernel::Lock & Kernel::data_lock() {
return *unmanaged_singleton<Kernel::Lock>(); }

View File

@ -193,9 +193,15 @@ struct Hw::Arm_cpu
/* Invalidate entire unified TLB */
ARM_CP15_REGISTER_32BIT(Tlbiall, c8, c7, 0, 0);
/* Invalidate entire unified TLB (inner-shareable) */
ARM_CP15_REGISTER_32BIT(Tlbiallis, c8, c3, 0, 0);
/* Invalidate unified TLB by ASID */
ARM_CP15_REGISTER_32BIT(Tlbiasid, c8, c7, 0, 2);
/* Invalidate unified TLB by ASID (inner-shareable) */
ARM_CP15_REGISTER_32BIT(Tlbiasidis, c8, c3, 0, 2);
/* Memory Attribute Indirection Register 0 */
ARM_CP15_REGISTER_32BIT(Mair0, c10, c2, 0, 0,
struct Attr0 : Bitfield<0, 8> { };
@ -256,6 +262,12 @@ struct Hw::Arm_cpu
static void clean_invalidate_data_cache();
static void invalidate_data_cache();
static inline void synchronization_barrier()
{
asm volatile("dsb\n"
"isb\n");
}
};
#endif /* _SRC__LIB__HW__SPEC__ARM__CPU_H_ */