mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-11 13:03:11 +00:00
hw: sanitze cpu context
* Rename Kernel::Cpu_job to Kernel::Cpu_context (alias Kernel::Cpu::Context) * State first Cpu affinity of Cpu::Context at construction time * Move cpu affinity argument from kernel syscall create_thread to start_thread * Ensure that Cpu pointer is always valid Fix genodelabs/genode#5319
This commit is contained in:
parent
e275787119
commit
f97c8cacde
@ -137,10 +137,9 @@ namespace Kernel {
|
|||||||
* \retval 0 suceeded
|
* \retval 0 suceeded
|
||||||
* \retval !=0 failed
|
* \retval !=0 failed
|
||||||
*/
|
*/
|
||||||
inline int start_thread(Thread & thread, unsigned const cpu_id,
|
inline int start_thread(Thread & thread, Pd & pd, Native_utcb & utcb)
|
||||||
Pd & pd, Native_utcb & utcb)
|
|
||||||
{
|
{
|
||||||
return (int)call(call_id_start_thread(), (Call_arg)&thread, cpu_id,
|
return (int)call(call_id_start_thread(), (Call_arg)&thread,
|
||||||
(Call_arg)&pd, (Call_arg)&utcb);
|
(Call_arg)&pd, (Call_arg)&utcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,35 +27,35 @@
|
|||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
/*************
|
/*****************
|
||||||
** Cpu_job **
|
** Cpu_context **
|
||||||
*************/
|
*****************/
|
||||||
|
|
||||||
void Cpu_job::_activate() { _cpu->schedule(this); }
|
void Cpu_context::_activate() { _cpu().schedule(*this); }
|
||||||
|
|
||||||
|
|
||||||
void Cpu_job::_deactivate()
|
void Cpu_context::_deactivate()
|
||||||
{
|
{
|
||||||
assert(_cpu->id() == Cpu::executing_id());
|
assert(_cpu().id() == Cpu::executing_id());
|
||||||
_cpu->scheduler().unready(*this);
|
_cpu().scheduler().unready(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_job::_yield()
|
void Cpu_context::_yield()
|
||||||
{
|
{
|
||||||
assert(_cpu->id() == Cpu::executing_id());
|
assert(_cpu().id() == Cpu::executing_id());
|
||||||
_cpu->scheduler().yield();
|
_cpu().scheduler().yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_job::_interrupt(Irq::Pool &user_irq_pool, unsigned const /* cpu_id */)
|
void Cpu_context::_interrupt(Irq::Pool &user_irq_pool)
|
||||||
{
|
{
|
||||||
/* let the IRQ controller take a pending IRQ for handling, if any */
|
/* let the IRQ controller take a pending IRQ for handling, if any */
|
||||||
unsigned irq_id;
|
unsigned irq_id;
|
||||||
if (_cpu->pic().take_request(irq_id))
|
if (_cpu().pic().take_request(irq_id))
|
||||||
|
|
||||||
/* let the CPU of this job handle the IRQ if it is a CPU-local one */
|
/* let the CPU of this context handle the IRQ if it is a CPU-local one */
|
||||||
if (!_cpu->handle_if_cpu_local_interrupt(irq_id)) {
|
if (!_cpu().handle_if_cpu_local_interrupt(irq_id)) {
|
||||||
|
|
||||||
/* it isn't a CPU-local IRQ, so, it must be a user IRQ */
|
/* it isn't a CPU-local IRQ, so, it must be a user IRQ */
|
||||||
User_irq * irq = User_irq::object(user_irq_pool, irq_id);
|
User_irq * irq = User_irq::object(user_irq_pool, irq_id);
|
||||||
@ -64,38 +64,37 @@ void Cpu_job::_interrupt(Irq::Pool &user_irq_pool, unsigned const /* cpu_id */)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* let the IRQ controller finish the currently taken IRQ */
|
/* let the IRQ controller finish the currently taken IRQ */
|
||||||
_cpu->pic().finish_request();
|
_cpu().pic().finish_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_job::affinity(Cpu &cpu)
|
void Cpu_context::affinity(Cpu &cpu)
|
||||||
{
|
{
|
||||||
_cpu = &cpu;
|
_cpu().scheduler().remove(*this);
|
||||||
_cpu->scheduler().insert(*this);
|
_cpu_ptr = &cpu;
|
||||||
|
_cpu().scheduler().insert(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_job::quota(unsigned const q)
|
void Cpu_context::quota(unsigned const q)
|
||||||
{
|
{
|
||||||
if (_cpu)
|
_cpu().scheduler().quota(*this, q);
|
||||||
_cpu->scheduler().quota(*this, q);
|
|
||||||
else
|
|
||||||
Context::quota(q);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cpu_job::Cpu_job(Priority const p, unsigned const q)
|
Cpu_context::Cpu_context(Cpu &cpu,
|
||||||
|
Priority const priority,
|
||||||
|
unsigned const quota)
|
||||||
:
|
:
|
||||||
Context(p, q), _cpu(0)
|
Context(priority, quota), _cpu_ptr(&cpu)
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
Cpu_job::~Cpu_job()
|
|
||||||
{
|
{
|
||||||
if (!_cpu)
|
_cpu().scheduler().insert(*this);
|
||||||
return;
|
}
|
||||||
|
|
||||||
_cpu->scheduler().remove(*this);
|
|
||||||
|
Cpu_context::~Cpu_context()
|
||||||
|
{
|
||||||
|
_cpu().scheduler().remove(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -112,19 +111,17 @@ Cpu::Idle_thread::Idle_thread(Board::Address_space_id_allocator &addr_space_id_a
|
|||||||
Cpu &cpu,
|
Cpu &cpu,
|
||||||
Pd &core_pd)
|
Pd &core_pd)
|
||||||
:
|
:
|
||||||
Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
Thread { addr_space_id_alloc, user_irq_pool, cpu_pool, cpu,
|
||||||
Priority::min(), 0, "idle", Thread::IDLE }
|
core_pd, Priority::min(), 0, "idle", Thread::IDLE }
|
||||||
{
|
{
|
||||||
regs->ip = (addr_t)&idle_thread_main;
|
regs->ip = (addr_t)&idle_thread_main;
|
||||||
|
|
||||||
affinity(cpu);
|
|
||||||
Thread::_pd = &core_pd;
|
Thread::_pd = &core_pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu::schedule(Job * const job)
|
void Cpu::schedule(Context &context)
|
||||||
{
|
{
|
||||||
_scheduler.ready(*static_cast<Scheduler::Context*>(job));
|
_scheduler.ready(static_cast<Scheduler::Context&>(context));
|
||||||
if (_id != executing_id() && _scheduler.need_to_schedule())
|
if (_id != executing_id() && _scheduler.need_to_schedule())
|
||||||
trigger_ip_interrupt();
|
trigger_ip_interrupt();
|
||||||
}
|
}
|
||||||
@ -142,26 +139,26 @@ bool Cpu::handle_if_cpu_local_interrupt(unsigned const irq_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cpu_job & Cpu::schedule()
|
Cpu::Context & Cpu::handle_exception_and_schedule()
|
||||||
{
|
{
|
||||||
/* update scheduler */
|
Context &context = current_context();
|
||||||
Job & old_job = scheduled_job();
|
context.exception();
|
||||||
old_job.exception(*this);
|
|
||||||
|
|
||||||
if (_state == SUSPEND || _state == HALT)
|
if (_state == SUSPEND || _state == HALT)
|
||||||
return _halt_job;
|
return _halt_job;
|
||||||
|
|
||||||
|
/* update schedule if necessary */
|
||||||
if (_scheduler.need_to_schedule()) {
|
if (_scheduler.need_to_schedule()) {
|
||||||
_timer.process_timeouts();
|
_timer.process_timeouts();
|
||||||
_scheduler.update(_timer.time());
|
_scheduler.update(_timer.time());
|
||||||
time_t t = _scheduler.current_time_left();
|
time_t t = _scheduler.current_time_left();
|
||||||
_timer.set_timeout(&_timeout, t);
|
_timer.set_timeout(&_timeout, t);
|
||||||
time_t duration = _timer.schedule_timeout();
|
time_t duration = _timer.schedule_timeout();
|
||||||
old_job.update_execution_time(duration);
|
context.update_execution_time(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return new job */
|
/* return current context */
|
||||||
return scheduled_job();
|
return current_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,9 +39,11 @@ namespace Kernel {
|
|||||||
class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
||||||
public Genode::List<Cpu>::Element
|
public Genode::List<Cpu>::Element
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
|
|
||||||
using Job = Cpu_job;
|
using Context = Cpu_context;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inter-processor-interrupt object of the cpu
|
* Inter-processor-interrupt object of the cpu
|
||||||
@ -83,13 +85,14 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
|||||||
Pd &core_pd);
|
Pd &core_pd);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Halt_job : Job
|
struct Halt_job : Cpu_context
|
||||||
{
|
{
|
||||||
Halt_job() : Job (0, 0) { }
|
Halt_job(Cpu &cpu)
|
||||||
|
: Cpu_context(cpu, 0, 0) { }
|
||||||
|
|
||||||
void exception(Kernel::Cpu &) override { }
|
void exception() override { }
|
||||||
void proceed(Kernel::Cpu &) override;
|
void proceed() override;
|
||||||
} _halt_job { };
|
} _halt_job { *this };
|
||||||
|
|
||||||
enum State { RUN, HALT, SUSPEND };
|
enum State { RUN, HALT, SUSPEND };
|
||||||
|
|
||||||
@ -140,14 +143,14 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
|||||||
bool handle_if_cpu_local_interrupt(unsigned const irq_id);
|
bool handle_if_cpu_local_interrupt(unsigned const irq_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule 'job' at this CPU
|
* Schedule 'context' at this CPU
|
||||||
*/
|
*/
|
||||||
void schedule(Job * const job);
|
void schedule(Context& context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the job that should be executed at next
|
* Return the context that should be executed next
|
||||||
*/
|
*/
|
||||||
Cpu_job& schedule();
|
Context& handle_exception_and_schedule();
|
||||||
|
|
||||||
Board::Pic & pic() { return _pic; }
|
Board::Pic & pic() { return _pic; }
|
||||||
Timer & timer() { return _timer; }
|
Timer & timer() { return _timer; }
|
||||||
@ -155,10 +158,10 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
|||||||
addr_t stack_start();
|
addr_t stack_start();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the currently active job
|
* Returns the currently scheduled context
|
||||||
*/
|
*/
|
||||||
Job & scheduled_job() {
|
Context & current_context() {
|
||||||
return static_cast<Job&>(_scheduler.current().helping_destination()); }
|
return static_cast<Context&>(_scheduler.current().helping_destination()); }
|
||||||
|
|
||||||
unsigned id() const { return _id; }
|
unsigned id() const { return _id; }
|
||||||
Scheduler &scheduler() { return _scheduler; }
|
Scheduler &scheduler() { return _scheduler; }
|
||||||
|
@ -22,45 +22,38 @@
|
|||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class Cpu;
|
class Cpu;
|
||||||
|
class Cpu_context;
|
||||||
/**
|
|
||||||
* Context of a job (thread, VM, idle) that shall be executed by a CPU
|
|
||||||
*/
|
|
||||||
class Cpu_job;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Kernel::Cpu_job : private Scheduler::Context
|
/**
|
||||||
|
* Context (thread, vcpu) that shall be executed by a CPU
|
||||||
|
*/
|
||||||
|
class Kernel::Cpu_context : private Scheduler::Context
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class Cpu; /* static_cast from 'Scheduler::Context' to 'Cpu_job' */
|
friend class Cpu;
|
||||||
|
|
||||||
time_t _execution_time { 0 };
|
time_t _execution_time { 0 };
|
||||||
|
Cpu *_cpu_ptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Noncopyable
|
* Noncopyable
|
||||||
*/
|
*/
|
||||||
Cpu_job(Cpu_job const &);
|
Cpu_context(Cpu_context const &);
|
||||||
Cpu_job &operator = (Cpu_job const &);
|
Cpu_context &operator = (Cpu_context const &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Cpu * _cpu;
|
Cpu &_cpu() const { return *_cpu_ptr; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle interrupt exception that occured during execution on CPU 'id'
|
* Handle interrupt exception
|
||||||
*/
|
*/
|
||||||
void _interrupt(Irq::Pool &user_irq_pool, unsigned const id);
|
void _interrupt(Irq::Pool &user_irq_pool);
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate our own CPU-share
|
|
||||||
*/
|
|
||||||
void _activate();
|
void _activate();
|
||||||
|
|
||||||
/**
|
|
||||||
* Deactivate our own CPU-share
|
|
||||||
*/
|
|
||||||
void _deactivate();
|
void _deactivate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,47 +62,34 @@ class Kernel::Cpu_job : private Scheduler::Context
|
|||||||
void _yield();
|
void _yield();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return wether we are allowed to help job 'j' with our CPU-share
|
* Return possibility to help context 'j' scheduling-wise
|
||||||
*/
|
*/
|
||||||
bool _helping_possible(Cpu_job const &j) const { return j._cpu == _cpu; }
|
bool _helping_possible(Cpu_context const &j) const {
|
||||||
|
return j._cpu_ptr == _cpu_ptr; }
|
||||||
|
|
||||||
|
void _help(Cpu_context &context) { Context::help(context); }
|
||||||
|
|
||||||
using Context::ready;
|
using Context::ready;
|
||||||
using Context::helping_finished;
|
using Context::helping_finished;
|
||||||
|
|
||||||
void help(Cpu_job &job) { Context::help(job); }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using Context = Scheduler::Context;
|
using Context = Scheduler::Context;
|
||||||
using Priority = Scheduler::Priority;
|
using Priority = Scheduler::Priority;
|
||||||
|
|
||||||
/**
|
Cpu_context(Cpu &cpu,
|
||||||
* Handle exception that occured during execution on CPU 'id'
|
Priority const priority,
|
||||||
*/
|
unsigned const quota);
|
||||||
virtual void exception(Cpu & cpu) = 0;
|
|
||||||
|
virtual ~Cpu_context();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue execution on CPU 'id'
|
* Link context to CPU 'cpu'
|
||||||
*/
|
|
||||||
virtual void proceed(Cpu & cpu) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a job with scheduling priority 'p' and time quota 'q'
|
|
||||||
*/
|
|
||||||
Cpu_job(Priority const p, unsigned const q);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
virtual ~Cpu_job();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link job to CPU 'cpu'
|
|
||||||
*/
|
*/
|
||||||
void affinity(Cpu &cpu);
|
void affinity(Cpu &cpu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set CPU quota of the job to 'q'
|
* Set CPU quota of the context to 'q'
|
||||||
*/
|
*/
|
||||||
void quota(unsigned const q);
|
void quota(unsigned const q);
|
||||||
|
|
||||||
@ -123,12 +103,15 @@ class Kernel::Cpu_job : private Scheduler::Context
|
|||||||
*/
|
*/
|
||||||
time_t execution_time() const { return _execution_time; }
|
time_t execution_time() const { return _execution_time; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle exception that occured during execution of this context
|
||||||
|
*/
|
||||||
|
virtual void exception() = 0;
|
||||||
|
|
||||||
/***************
|
/**
|
||||||
** Accessors **
|
* Continue execution of this context
|
||||||
***************/
|
*/
|
||||||
|
virtual void proceed() = 0;
|
||||||
void cpu(Cpu &cpu) { _cpu = &cpu; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__CPU_CONTEXT_H_ */
|
#endif /* _CORE__KERNEL__CPU_CONTEXT_H_ */
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CORE__KERNEL__SMP_H_
|
#ifndef _CORE__KERNEL__INTER_PROCESSOR_WORK_H_
|
||||||
#define _CORE__KERNEL__SMP_H_
|
#define _CORE__KERNEL__INTER_PROCESSOR_WORK_H_
|
||||||
|
|
||||||
#include <util/interface.h>
|
#include <util/interface.h>
|
||||||
|
|
||||||
@ -32,11 +32,11 @@ class Kernel::Inter_processor_work : Genode::Interface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute(Cpu &) = 0;
|
virtual void execute(Cpu & cpu) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Genode::List_element<Inter_processor_work> _le { this };
|
Genode::List_element<Inter_processor_work> _le { this };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__SMP_H_ */
|
#endif /* _CORE__KERNEL__INTER_PROCESSOR_WORK_H_ */
|
||||||
|
@ -63,16 +63,16 @@ Kernel::Main *Kernel::Main::_instance;
|
|||||||
|
|
||||||
void Kernel::Main::_handle_kernel_entry()
|
void Kernel::Main::_handle_kernel_entry()
|
||||||
{
|
{
|
||||||
Cpu &cpu = _cpu_pool.cpu(Cpu::executing_id());
|
Cpu::Context * context;
|
||||||
Cpu_job * new_job;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Lock::Guard guard(_data_lock);
|
Lock::Guard guard(_data_lock);
|
||||||
|
|
||||||
new_job = &cpu.schedule();
|
context =
|
||||||
|
&_cpu_pool.cpu(Cpu::executing_id()).handle_exception_and_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
new_job->proceed(cpu);
|
context->proceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ Thread::Destroy::Destroy(Thread & caller, Core::Kernel_object<Thread> & to_delet
|
|||||||
:
|
:
|
||||||
caller(caller), thread_to_destroy(to_delete)
|
caller(caller), thread_to_destroy(to_delete)
|
||||||
{
|
{
|
||||||
thread_to_destroy->_cpu->work_list().insert(&_le);
|
thread_to_destroy->_cpu().work_list().insert(&_le);
|
||||||
caller._become_inactive(AWAITS_RESTART);
|
caller._become_inactive(AWAITS_RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ Thread::Destroy::Destroy(Thread & caller, Core::Kernel_object<Thread> & to_delet
|
|||||||
void
|
void
|
||||||
Thread::Destroy::execute(Cpu &)
|
Thread::Destroy::execute(Cpu &)
|
||||||
{
|
{
|
||||||
thread_to_destroy->_cpu->work_list().remove(&_le);
|
thread_to_destroy->_cpu().work_list().remove(&_le);
|
||||||
thread_to_destroy.destruct();
|
thread_to_destroy.destruct();
|
||||||
caller._restart();
|
caller._restart();
|
||||||
}
|
}
|
||||||
@ -272,14 +272,14 @@ void Thread::ipc_await_request_failed()
|
|||||||
|
|
||||||
void Thread::_become_active()
|
void Thread::_become_active()
|
||||||
{
|
{
|
||||||
if (_state != ACTIVE && !_paused) Cpu_job::_activate();
|
if (_state != ACTIVE && !_paused) Cpu_context::_activate();
|
||||||
_state = ACTIVE;
|
_state = ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_become_inactive(State const s)
|
void Thread::_become_inactive(State const s)
|
||||||
{
|
{
|
||||||
if (_state == ACTIVE && !_paused) Cpu_job::_deactivate();
|
if (_state == ACTIVE && !_paused) Cpu_context::_deactivate();
|
||||||
_state = s;
|
_state = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
|||||||
|
|
||||||
/* we assert at timer construction that cpu_quota_us in ticks fits size_t */
|
/* we assert at timer construction that cpu_quota_us in ticks fits size_t */
|
||||||
size_t const ticks = (size_t)
|
size_t const ticks = (size_t)
|
||||||
_cpu->timer().us_to_ticks(Kernel::cpu_quota_us);
|
_cpu().timer().us_to_ticks(Kernel::cpu_quota_us);
|
||||||
return Cpu_session::quota_lim_downscale(quota, ticks);
|
return Cpu_session::quota_lim_downscale(quota, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,24 +301,20 @@ size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
|||||||
void Thread::_call_thread_quota()
|
void Thread::_call_thread_quota()
|
||||||
{
|
{
|
||||||
Thread * const thread = (Thread *)user_arg_1();
|
Thread * const thread = (Thread *)user_arg_1();
|
||||||
thread->Cpu_job::quota((unsigned)(_core_to_kernel_quota(user_arg_2())));
|
thread->Cpu_context::quota((unsigned)(_core_to_kernel_quota(user_arg_2())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_start_thread()
|
void Thread::_call_start_thread()
|
||||||
{
|
{
|
||||||
/* lookup CPU */
|
|
||||||
Cpu & cpu = _cpu_pool.cpu((unsigned)user_arg_2());
|
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
Thread &thread = *(Thread*)user_arg_1();
|
Thread &thread = *(Thread*)user_arg_1();
|
||||||
|
|
||||||
assert(thread._state == AWAITS_START);
|
assert(thread._state == AWAITS_START);
|
||||||
|
|
||||||
thread.affinity(cpu);
|
|
||||||
|
|
||||||
/* join protection domain */
|
/* join protection domain */
|
||||||
thread._pd = (Pd *) user_arg_3();
|
thread._pd = (Pd *) user_arg_2();
|
||||||
switch (thread._ipc_init(*(Native_utcb *)user_arg_4(), *this)) {
|
switch (thread._ipc_init(*(Native_utcb *)user_arg_3(), *this)) {
|
||||||
case Ipc_alloc_result::OK:
|
case Ipc_alloc_result::OK:
|
||||||
break;
|
break;
|
||||||
case Ipc_alloc_result::EXHAUSTED:
|
case Ipc_alloc_result::EXHAUSTED:
|
||||||
@ -338,7 +334,8 @@ void Thread::_call_start_thread()
|
|||||||
* semantic changes, and additional core threads are started
|
* semantic changes, and additional core threads are started
|
||||||
* across cpu cores.
|
* across cpu cores.
|
||||||
*/
|
*/
|
||||||
if (thread._pd == &_core_pd && cpu.id() != _cpu_pool.primary_cpu().id())
|
if (thread._pd == &_core_pd &&
|
||||||
|
thread._cpu().id() != _cpu_pool.primary_cpu().id())
|
||||||
Genode::raw("Error: do not start core threads"
|
Genode::raw("Error: do not start core threads"
|
||||||
" on CPU cores different than boot cpu");
|
" on CPU cores different than boot cpu");
|
||||||
|
|
||||||
@ -433,7 +430,7 @@ void Thread::_cancel_blocking()
|
|||||||
|
|
||||||
void Thread::_call_yield_thread()
|
void Thread::_call_yield_thread()
|
||||||
{
|
{
|
||||||
Cpu_job::_yield();
|
Cpu_context::_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -443,12 +440,11 @@ void Thread::_call_delete_thread()
|
|||||||
*(Core::Kernel_object<Thread>*)user_arg_1();
|
*(Core::Kernel_object<Thread>*)user_arg_1();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a thread immediately if it has no cpu assigned yet,
|
* Delete a thread immediately if it is assigned to this cpu,
|
||||||
* or it is assigned to this cpu, or the assigned cpu did not scheduled it.
|
* or the assigned cpu did not scheduled it.
|
||||||
*/
|
*/
|
||||||
if (!to_delete->_cpu ||
|
if (to_delete->_cpu().id() == Cpu::executing_id() ||
|
||||||
(to_delete->_cpu->id() == Cpu::executing_id() ||
|
&to_delete->_cpu().current_context() != &*to_delete) {
|
||||||
&to_delete->_cpu->scheduled_job() != &*to_delete)) {
|
|
||||||
_call_delete<Thread>();
|
_call_delete<Thread>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -457,7 +453,7 @@ void Thread::_call_delete_thread()
|
|||||||
* Construct a cross-cpu work item and send an IPI
|
* Construct a cross-cpu work item and send an IPI
|
||||||
*/
|
*/
|
||||||
_destroy.construct(*this, to_delete);
|
_destroy.construct(*this, to_delete);
|
||||||
to_delete->_cpu->trigger_ip_interrupt();
|
to_delete->_cpu().trigger_ip_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -466,8 +462,8 @@ void Thread::_call_delete_pd()
|
|||||||
Core::Kernel_object<Pd> & pd =
|
Core::Kernel_object<Pd> & pd =
|
||||||
*(Core::Kernel_object<Pd>*)user_arg_1();
|
*(Core::Kernel_object<Pd>*)user_arg_1();
|
||||||
|
|
||||||
if (_cpu->active(pd->mmu_regs))
|
if (_cpu().active(pd->mmu_regs))
|
||||||
_cpu->switch_to(_core_pd.mmu_regs);
|
_cpu().switch_to(_core_pd.mmu_regs);
|
||||||
|
|
||||||
_call_delete<Pd>();
|
_call_delete<Pd>();
|
||||||
}
|
}
|
||||||
@ -499,7 +495,7 @@ void Thread::_call_await_request_msg()
|
|||||||
|
|
||||||
void Thread::_call_timeout()
|
void Thread::_call_timeout()
|
||||||
{
|
{
|
||||||
Timer & t = _cpu->timer();
|
Timer & t = _cpu().timer();
|
||||||
_timeout_sigid = (Kernel::capid_t)user_arg_2();
|
_timeout_sigid = (Kernel::capid_t)user_arg_2();
|
||||||
t.set_timeout(this, t.us_to_ticks(user_arg_1()));
|
t.set_timeout(this, t.us_to_ticks(user_arg_1()));
|
||||||
}
|
}
|
||||||
@ -507,13 +503,13 @@ void Thread::_call_timeout()
|
|||||||
|
|
||||||
void Thread::_call_timeout_max_us()
|
void Thread::_call_timeout_max_us()
|
||||||
{
|
{
|
||||||
user_ret_time(_cpu->timer().timeout_max_us());
|
user_ret_time(_cpu().timer().timeout_max_us());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_time()
|
void Thread::_call_time()
|
||||||
{
|
{
|
||||||
Timer & t = _cpu->timer();
|
Timer & t = _cpu().timer();
|
||||||
user_ret_time(t.ticks_to_us(t.time()));
|
user_ret_time(t.ticks_to_us(t.time()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +536,7 @@ void Thread::_call_send_request_msg()
|
|||||||
_become_inactive(DEAD);
|
_become_inactive(DEAD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool const help = Cpu_job::_helping_possible(*dst);
|
bool const help = Cpu_context::_helping_possible(*dst);
|
||||||
oir = oir->find(dst->pd());
|
oir = oir->find(dst->pd());
|
||||||
|
|
||||||
if (!_ipc_node.ready_to_send()) {
|
if (!_ipc_node.ready_to_send()) {
|
||||||
@ -558,7 +554,7 @@ void Thread::_call_send_request_msg()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_state = AWAITS_IPC;
|
_state = AWAITS_IPC;
|
||||||
if (help) Cpu_job::help(*dst);
|
if (help) Cpu_context::_help(*dst);
|
||||||
if (!help || !dst->ready()) _deactivate();
|
if (!help || !dst->ready()) _deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +723,7 @@ void Thread::_call_new_irq()
|
|||||||
(Genode::Irq_session::Polarity) (user_arg_3() & 0b11);
|
(Genode::Irq_session::Polarity) (user_arg_3() & 0b11);
|
||||||
|
|
||||||
_call_new<User_irq>((unsigned)user_arg_2(), trigger, polarity, *c,
|
_call_new<User_irq>((unsigned)user_arg_2(), trigger, polarity, *c,
|
||||||
_cpu->pic(), _user_irq_pool);
|
_cpu().pic(), _user_irq_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -869,13 +865,15 @@ void Thread::_call()
|
|||||||
switch (call_id) {
|
switch (call_id) {
|
||||||
case call_id_new_thread():
|
case call_id_new_thread():
|
||||||
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
||||||
_core_pd, (unsigned) user_arg_2(),
|
_cpu_pool.cpu((unsigned)user_arg_2()),
|
||||||
(unsigned) _core_to_kernel_quota(user_arg_3()),
|
_core_pd, (unsigned) user_arg_3(),
|
||||||
(char const *) user_arg_4(), USER);
|
(unsigned) _core_to_kernel_quota(user_arg_4()),
|
||||||
|
(char const *) user_arg_5(), USER);
|
||||||
return;
|
return;
|
||||||
case call_id_new_core_thread():
|
case call_id_new_core_thread():
|
||||||
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
_call_new<Thread>(_addr_space_id_alloc, _user_irq_pool, _cpu_pool,
|
||||||
_core_pd, (char const *) user_arg_2());
|
_cpu_pool.cpu((unsigned)user_arg_2()),
|
||||||
|
_core_pd, (char const *) user_arg_3());
|
||||||
return;
|
return;
|
||||||
case call_id_thread_quota(): _call_thread_quota(); 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;
|
||||||
@ -972,6 +970,7 @@ void Thread::_exception()
|
|||||||
Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
||||||
Irq::Pool &user_irq_pool,
|
Irq::Pool &user_irq_pool,
|
||||||
Cpu_pool &cpu_pool,
|
Cpu_pool &cpu_pool,
|
||||||
|
Cpu &cpu,
|
||||||
Pd &core_pd,
|
Pd &core_pd,
|
||||||
unsigned const priority,
|
unsigned const priority,
|
||||||
unsigned const quota,
|
unsigned const quota,
|
||||||
@ -979,7 +978,7 @@ Thread::Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
|||||||
Type type)
|
Type type)
|
||||||
:
|
:
|
||||||
Kernel::Object { *this },
|
Kernel::Object { *this },
|
||||||
Cpu_job { priority, quota },
|
Cpu_context { cpu, priority, quota },
|
||||||
_addr_space_id_alloc { addr_space_id_alloc },
|
_addr_space_id_alloc { addr_space_id_alloc },
|
||||||
_user_irq_pool { user_irq_pool },
|
_user_irq_pool { user_irq_pool },
|
||||||
_cpu_pool { cpu_pool },
|
_cpu_pool { cpu_pool },
|
||||||
@ -1016,8 +1015,8 @@ Core_main_thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
|||||||
Cpu_pool &cpu_pool,
|
Cpu_pool &cpu_pool,
|
||||||
Pd &core_pd)
|
Pd &core_pd)
|
||||||
:
|
:
|
||||||
Core_object<Thread>(
|
Core_object<Thread>(core_pd, addr_space_id_alloc, user_irq_pool, cpu_pool,
|
||||||
core_pd, addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd, "core")
|
cpu_pool.primary_cpu(), core_pd, "core")
|
||||||
{
|
{
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
|
|
||||||
@ -1033,7 +1032,6 @@ Core_main_thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
|||||||
regs->sp = (addr_t)&__initial_stack_base[0] + DEFAULT_STACK_SIZE;
|
regs->sp = (addr_t)&__initial_stack_base[0] + DEFAULT_STACK_SIZE;
|
||||||
regs->ip = (addr_t)&_core_start;
|
regs->ip = (addr_t)&_core_start;
|
||||||
|
|
||||||
affinity(_cpu_pool.primary_cpu());
|
|
||||||
_utcb = &_utcb_instance;
|
_utcb = &_utcb_instance;
|
||||||
Thread::_pd = &core_pd;
|
Thread::_pd = &core_pd;
|
||||||
_become_active();
|
_become_active();
|
||||||
|
@ -53,7 +53,7 @@ struct Kernel::Thread_fault
|
|||||||
/**
|
/**
|
||||||
* Kernel back-end for userland execution-contexts
|
* Kernel back-end for userland execution-contexts
|
||||||
*/
|
*/
|
||||||
class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
class Kernel::Thread : private Kernel::Object, public Cpu_context, private Timeout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -335,6 +335,7 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
||||||
Irq::Pool &user_irq_pool,
|
Irq::Pool &user_irq_pool,
|
||||||
Cpu_pool &cpu_pool,
|
Cpu_pool &cpu_pool,
|
||||||
|
Cpu &cpu,
|
||||||
Pd &core_pd,
|
Pd &core_pd,
|
||||||
unsigned const priority,
|
unsigned const priority,
|
||||||
unsigned const quota,
|
unsigned const quota,
|
||||||
@ -349,11 +350,12 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
Thread(Board::Address_space_id_allocator &addr_space_id_alloc,
|
||||||
Irq::Pool &user_irq_pool,
|
Irq::Pool &user_irq_pool,
|
||||||
Cpu_pool &cpu_pool,
|
Cpu_pool &cpu_pool,
|
||||||
|
Cpu &cpu,
|
||||||
Pd &core_pd,
|
Pd &core_pd,
|
||||||
char const *const label)
|
char const *const label)
|
||||||
:
|
:
|
||||||
Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, core_pd,
|
Thread(addr_space_id_alloc, user_irq_pool, cpu_pool, cpu,
|
||||||
Scheduler::Priority::min(), 0, label, CORE)
|
core_pd, Scheduler::Priority::min(), 0, label, CORE)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~Thread();
|
~Thread();
|
||||||
@ -390,13 +392,14 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
* \retval capability id of the new kernel object
|
* \retval capability id of the new kernel object
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(Core::Kernel_object<Thread> &t,
|
static capid_t syscall_create(Core::Kernel_object<Thread> &t,
|
||||||
|
unsigned const cpu_id,
|
||||||
unsigned const priority,
|
unsigned const priority,
|
||||||
size_t const quota,
|
size_t const quota,
|
||||||
char const * const label)
|
char const * const label)
|
||||||
{
|
{
|
||||||
return (capid_t)call(call_id_new_thread(), (Call_arg)&t,
|
return (capid_t)call(call_id_new_thread(), (Call_arg)&t,
|
||||||
(Call_arg)priority, (Call_arg)quota,
|
(Call_arg)cpu_id, (Call_arg)priority,
|
||||||
(Call_arg)label);
|
(Call_arg)quota, (Call_arg)label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -408,10 +411,11 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
* \retval capability id of the new kernel object
|
* \retval capability id of the new kernel object
|
||||||
*/
|
*/
|
||||||
static capid_t syscall_create(Core::Kernel_object<Thread> &t,
|
static capid_t syscall_create(Core::Kernel_object<Thread> &t,
|
||||||
|
unsigned const cpu_id,
|
||||||
char const * const label)
|
char const * const label)
|
||||||
{
|
{
|
||||||
return (capid_t)call(call_id_new_core_thread(), (Call_arg)&t,
|
return (capid_t)call(call_id_new_core_thread(), (Call_arg)&t,
|
||||||
(Call_arg)label);
|
(Call_arg)cpu_id, (Call_arg)label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -448,12 +452,12 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
|||||||
void signal_receive_signal(void * const base, size_t const size);
|
void signal_receive_signal(void * const base, size_t const size);
|
||||||
|
|
||||||
|
|
||||||
/*************
|
/*****************
|
||||||
** Cpu_job **
|
** Cpu_context **
|
||||||
*************/
|
*****************/
|
||||||
|
|
||||||
void exception(Cpu & cpu) override;
|
void exception() override;
|
||||||
void proceed(Cpu & cpu) override;
|
void proceed() override;
|
||||||
|
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
|
@ -31,7 +31,7 @@ namespace Kernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Kernel::Vm : private Kernel::Object, public Cpu_job
|
class Kernel::Vm : private Kernel::Object, public Cpu_context
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
|||||||
void _pause_vcpu()
|
void _pause_vcpu()
|
||||||
{
|
{
|
||||||
if (_scheduled != INACTIVE)
|
if (_scheduled != INACTIVE)
|
||||||
Cpu_job::_deactivate();
|
Cpu_context::_deactivate();
|
||||||
|
|
||||||
_scheduled = INACTIVE;
|
_scheduled = INACTIVE;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
|||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
_sync_from_vmm();
|
_sync_from_vmm();
|
||||||
if (_scheduled != ACTIVE) Cpu_job::_activate();
|
if (_scheduled != ACTIVE) Cpu_context::_activate();
|
||||||
_scheduled = ACTIVE;
|
_scheduled = ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,12 +146,12 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************
|
/*****************
|
||||||
** Cpu_job **
|
** Cpu_context **
|
||||||
*************/
|
*****************/
|
||||||
|
|
||||||
void exception(Cpu & cpu) override;
|
void exception() override;
|
||||||
void proceed(Cpu & cpu) override;
|
void proceed() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__VM_H_ */
|
#endif /* _CORE__KERNEL__VM_H_ */
|
||||||
|
@ -93,7 +93,7 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb)
|
|||||||
_utcb((addr_t)&utcb),
|
_utcb((addr_t)&utcb),
|
||||||
_main_thread(false),
|
_main_thread(false),
|
||||||
_location(Affinity::Location()),
|
_location(Affinity::Location()),
|
||||||
_kobj(_kobj.CALLED_FROM_CORE, _label.string())
|
_kobj(_kobj.CALLED_FROM_CORE, _location.xpos(), _label.string())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
@ -115,7 +115,8 @@ Platform_thread::Platform_thread(Platform_pd &pd,
|
|||||||
_quota((unsigned)quota),
|
_quota((unsigned)quota),
|
||||||
_main_thread(!pd.has_any_thread),
|
_main_thread(!pd.has_any_thread),
|
||||||
_location(location),
|
_location(location),
|
||||||
_kobj(_kobj.CALLED_FROM_CORE, _priority, _quota, _label.string())
|
_kobj(_kobj.CALLED_FROM_CORE, _location.xpos(),
|
||||||
|
_priority, _quota, _label.string())
|
||||||
{
|
{
|
||||||
_address_space = pd.weak_ptr();
|
_address_space = pd.weak_ptr();
|
||||||
pd.has_any_thread = true;
|
pd.has_any_thread = true;
|
||||||
@ -171,9 +172,6 @@ void Platform_thread::start(void * const ip, void * const sp)
|
|||||||
_kobj->regs->ip = reinterpret_cast<addr_t>(ip);
|
_kobj->regs->ip = reinterpret_cast<addr_t>(ip);
|
||||||
_kobj->regs->sp = reinterpret_cast<addr_t>(sp);
|
_kobj->regs->sp = reinterpret_cast<addr_t>(sp);
|
||||||
|
|
||||||
/* start executing new thread */
|
|
||||||
unsigned const cpu = _location.xpos();
|
|
||||||
|
|
||||||
Native_utcb &utcb = *Thread::myself()->utcb();
|
Native_utcb &utcb = *Thread::myself()->utcb();
|
||||||
|
|
||||||
/* reset capability counter */
|
/* reset capability counter */
|
||||||
@ -183,7 +181,9 @@ void Platform_thread::start(void * const ip, void * const sp)
|
|||||||
utcb.cap_add(Capability_space::capid(_pd.parent()));
|
utcb.cap_add(Capability_space::capid(_pd.parent()));
|
||||||
utcb.cap_add(Capability_space::capid(_utcb._ds));
|
utcb.cap_add(Capability_space::capid(_utcb._ds));
|
||||||
}
|
}
|
||||||
Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *(Native_utcb*)_utcb.core_addr);
|
|
||||||
|
Kernel::start_thread(*_kobj, _pd.kernel_pd(),
|
||||||
|
*(Native_utcb*)_utcb.core_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,32 +23,35 @@
|
|||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
extern "C" void kernel_to_user_context_switch(Cpu::Context*, Cpu::Fpu_context*);
|
extern "C" void kernel_to_user_context_switch(Core::Cpu::Context*,
|
||||||
|
Core::Cpu::Fpu_context*);
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_suspend() { }
|
void Thread::_call_suspend() { }
|
||||||
|
|
||||||
|
|
||||||
void Thread::exception(Cpu & cpu)
|
void Thread::exception()
|
||||||
{
|
{
|
||||||
|
using Ctx = Core::Cpu::Context;
|
||||||
|
|
||||||
switch (regs->cpu_exception) {
|
switch (regs->cpu_exception) {
|
||||||
case Cpu::Context::SUPERVISOR_CALL:
|
case Ctx::SUPERVISOR_CALL:
|
||||||
_call();
|
_call();
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::PREFETCH_ABORT:
|
case Ctx::PREFETCH_ABORT:
|
||||||
case Cpu::Context::DATA_ABORT:
|
case Ctx::DATA_ABORT:
|
||||||
_mmu_exception();
|
_mmu_exception();
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::INTERRUPT_REQUEST:
|
case Ctx::INTERRUPT_REQUEST:
|
||||||
case Cpu::Context::FAST_INTERRUPT_REQUEST:
|
case Ctx::FAST_INTERRUPT_REQUEST:
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::UNDEFINED_INSTRUCTION:
|
case Ctx::UNDEFINED_INSTRUCTION:
|
||||||
Genode::raw(*this, ": undefined instruction at ip=",
|
Genode::raw(*this, ": undefined instruction at ip=",
|
||||||
Genode::Hex(regs->ip));
|
Genode::Hex(regs->ip));
|
||||||
_die();
|
_die();
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::RESET:
|
case Ctx::RESET:
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
Genode::raw(*this, ": triggered an unknown exception ",
|
Genode::raw(*this, ": triggered an unknown exception ",
|
||||||
@ -71,17 +74,17 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { }
|
|||||||
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
|
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
|
||||||
|
|
||||||
|
|
||||||
void Cpu::Halt_job::proceed(Kernel::Cpu &) { }
|
void Cpu::Halt_job::proceed() { }
|
||||||
|
|
||||||
|
|
||||||
void Thread::proceed(Cpu & cpu)
|
void Thread::proceed()
|
||||||
{
|
{
|
||||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
if (!_cpu().active(pd().mmu_regs) && type() != CORE)
|
||||||
cpu.switch_to(pd().mmu_regs);
|
_cpu().switch_to(pd().mmu_regs);
|
||||||
|
|
||||||
regs->cpu_exception = cpu.stack_start();
|
regs->cpu_exception = _cpu().stack_start();
|
||||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
kernel_to_user_context_switch((static_cast<Core::Cpu::Context*>(&*regs)),
|
||||||
(static_cast<Cpu::Fpu_context*>(&*regs)));
|
(static_cast<Core::Cpu::Fpu_context*>(&*regs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,14 +28,13 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
Identity & id)
|
Identity & id)
|
||||||
:
|
:
|
||||||
Kernel::Object { *this },
|
Kernel::Object { *this },
|
||||||
Cpu_job(Scheduler::Priority::min(), 0),
|
Cpu_context(cpu, Scheduler::Priority::min(), 0),
|
||||||
_user_irq_pool(user_irq_pool),
|
_user_irq_pool(user_irq_pool),
|
||||||
_state(data),
|
_state(data),
|
||||||
_context(context),
|
_context(context),
|
||||||
_id(id),
|
_id(id),
|
||||||
_vcpu_context(cpu)
|
_vcpu_context(cpu)
|
||||||
{
|
{
|
||||||
affinity(cpu);
|
|
||||||
/* once constructed, exit with a startup exception */
|
/* once constructed, exit with a startup exception */
|
||||||
pause();
|
pause();
|
||||||
_state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP;
|
_state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP;
|
||||||
@ -46,12 +45,12 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
Vm::~Vm() {}
|
Vm::~Vm() {}
|
||||||
|
|
||||||
|
|
||||||
void Vm::exception(Cpu & cpu)
|
void Vm::exception()
|
||||||
{
|
{
|
||||||
switch(_state.cpu_exception) {
|
switch(_state.cpu_exception) {
|
||||||
case Genode::Cpu_state::INTERRUPT_REQUEST: [[fallthrough]];
|
case Genode::Cpu_state::INTERRUPT_REQUEST: [[fallthrough]];
|
||||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
return;
|
return;
|
||||||
case Genode::Cpu_state::DATA_ABORT:
|
case Genode::Cpu_state::DATA_ABORT:
|
||||||
_state.dfar = Cpu::Dfar::read();
|
_state.dfar = Cpu::Dfar::read();
|
||||||
@ -69,19 +68,19 @@ bool secure_irq(unsigned const i);
|
|||||||
extern "C" void monitor_mode_enter_normal_world(Genode::Vcpu_state&, void*);
|
extern "C" void monitor_mode_enter_normal_world(Genode::Vcpu_state&, void*);
|
||||||
|
|
||||||
|
|
||||||
void Vm::proceed(Cpu & cpu)
|
void Vm::proceed()
|
||||||
{
|
{
|
||||||
unsigned const irq = _state.irq_injection;
|
unsigned const irq = _state.irq_injection;
|
||||||
if (irq) {
|
if (irq) {
|
||||||
if (cpu.pic().secure(irq)) {
|
if (_cpu().pic().secure(irq)) {
|
||||||
Genode::raw("Refuse to inject secure IRQ into VM");
|
Genode::raw("Refuse to inject secure IRQ into VM");
|
||||||
} else {
|
} else {
|
||||||
cpu.pic().trigger(irq);
|
_cpu().pic().trigger(irq);
|
||||||
_state.irq_injection = 0;
|
_state.irq_injection = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_mode_enter_normal_world(_state, (void*) cpu.stack_start());
|
monitor_mode_enter_normal_world(_state, (void*) _cpu().stack_start());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ void Board::Vcpu_context::Vm_irq::handle(Vm & vm, unsigned irq) {
|
|||||||
|
|
||||||
void Board::Vcpu_context::Vm_irq::occurred()
|
void Board::Vcpu_context::Vm_irq::occurred()
|
||||||
{
|
{
|
||||||
Vm *vm = dynamic_cast<Vm*>(&_cpu.scheduled_job());
|
Vm *vm = dynamic_cast<Vm*>(&_cpu.current_context());
|
||||||
if (!vm) Genode::raw("VM interrupt while VM is not runnning!");
|
if (!vm) Genode::raw("VM interrupt while VM is not runnning!");
|
||||||
else handle(*vm, _irq_nr);
|
else handle(*vm, _irq_nr);
|
||||||
}
|
}
|
||||||
@ -140,14 +140,13 @@ Kernel::Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
Identity & id)
|
Identity & id)
|
||||||
:
|
:
|
||||||
Kernel::Object { *this },
|
Kernel::Object { *this },
|
||||||
Cpu_job(Scheduler::Priority::min(), 0),
|
Cpu_context(cpu, Scheduler::Priority::min(), 0),
|
||||||
_user_irq_pool(user_irq_pool),
|
_user_irq_pool(user_irq_pool),
|
||||||
_state(data),
|
_state(data),
|
||||||
_context(context),
|
_context(context),
|
||||||
_id(id),
|
_id(id),
|
||||||
_vcpu_context(cpu)
|
_vcpu_context(cpu)
|
||||||
{
|
{
|
||||||
affinity(cpu);
|
|
||||||
/* once constructed, exit with a startup exception */
|
/* once constructed, exit with a startup exception */
|
||||||
pause();
|
pause();
|
||||||
_state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP;
|
_state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP;
|
||||||
@ -164,29 +163,29 @@ Kernel::Vm::~Vm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Vm::exception(Cpu & cpu)
|
void Kernel::Vm::exception()
|
||||||
{
|
{
|
||||||
switch(_state.cpu_exception) {
|
switch(_state.cpu_exception) {
|
||||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pause();
|
pause();
|
||||||
_context.submit(1);
|
_context.submit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu.pic().ack_virtual_irq(_vcpu_context.pic))
|
if (_cpu().pic().ack_virtual_irq(_vcpu_context.pic))
|
||||||
inject_irq(Board::VT_MAINTAINANCE_IRQ);
|
inject_irq(Board::VT_MAINTAINANCE_IRQ);
|
||||||
_vcpu_context.vtimer_irq.disable();
|
_vcpu_context.vtimer_irq.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Vm::proceed(Cpu & cpu)
|
void Kernel::Vm::proceed()
|
||||||
{
|
{
|
||||||
if (_state.timer.irq) _vcpu_context.vtimer_irq.enable();
|
if (_state.timer.irq) _vcpu_context.vtimer_irq.enable();
|
||||||
|
|
||||||
cpu.pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq);
|
_cpu().pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the following values have to be enforced by the hypervisor
|
* the following values have to be enforced by the hypervisor
|
||||||
@ -202,7 +201,7 @@ void Kernel::Vm::proceed(Cpu & cpu)
|
|||||||
_state.esr_el2 = Cpu::Hstr::init();
|
_state.esr_el2 = Cpu::Hstr::init();
|
||||||
_state.hpfar_el2 = Cpu::Hcr::init();
|
_state.hpfar_el2 = Cpu::Hcr::init();
|
||||||
|
|
||||||
Hypervisor::switch_world(_state, host_context(cpu));
|
Hypervisor::switch_world(_state, host_context(_cpu()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ using namespace Kernel;
|
|||||||
void Thread::_call_suspend() { }
|
void Thread::_call_suspend() { }
|
||||||
|
|
||||||
|
|
||||||
void Thread::exception(Cpu & cpu)
|
void Thread::exception()
|
||||||
{
|
{
|
||||||
switch (regs->exception_type) {
|
switch (regs->exception_type) {
|
||||||
case Cpu::RESET: return;
|
case Cpu::RESET: return;
|
||||||
@ -35,7 +35,7 @@ void Thread::exception(Cpu & cpu)
|
|||||||
case Cpu::IRQ_LEVEL_EL1: [[fallthrough]];
|
case Cpu::IRQ_LEVEL_EL1: [[fallthrough]];
|
||||||
case Cpu::FIQ_LEVEL_EL0: [[fallthrough]];
|
case Cpu::FIQ_LEVEL_EL0: [[fallthrough]];
|
||||||
case Cpu::FIQ_LEVEL_EL1:
|
case Cpu::FIQ_LEVEL_EL1:
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
return;
|
return;
|
||||||
case Cpu::SYNC_LEVEL_EL0: [[fallthrough]];
|
case Cpu::SYNC_LEVEL_EL0: [[fallthrough]];
|
||||||
case Cpu::SYNC_LEVEL_EL1:
|
case Cpu::SYNC_LEVEL_EL1:
|
||||||
@ -94,51 +94,51 @@ void Kernel::Thread::Tlb_invalidation::execute(Cpu &) { }
|
|||||||
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
|
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
|
||||||
|
|
||||||
|
|
||||||
void Cpu::Halt_job::proceed(Kernel::Cpu &) { }
|
void Cpu::Halt_job::proceed() { }
|
||||||
|
|
||||||
|
|
||||||
bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size)
|
bool Kernel::Pd::invalidate_tlb(Cpu & cpu, addr_t addr, size_t size)
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
/* only apply to the active cpu */
|
/* only apply to the active cpu */
|
||||||
if (cpu.id() != Cpu::executing_id())
|
if (cpu.id() != Cpu::executing_id())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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())
|
for (addr_t end = addr+size; addr < end; addr += get_page_size())
|
||||||
asm volatile ("tlbi vaae1is, %0" :: "r" (addr >> 12));
|
asm volatile ("tlbi vae1is, %0"
|
||||||
|
:: "r" (addr >> 12 | (uint64_t)mmu_regs.id() << 48));
|
||||||
return false;
|
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())
|
void Thread::proceed()
|
||||||
asm volatile ("tlbi vae1is, %0"
|
{
|
||||||
:: "r" (addr >> 12 | (uint64_t)mmu_regs.id() << 48));
|
if (!_cpu().active(pd().mmu_regs) && type() != CORE)
|
||||||
return false;
|
_cpu().switch_to(pd().mmu_regs);
|
||||||
}
|
|
||||||
|
|
||||||
|
kernel_to_user_context_switch((static_cast<Core::Cpu::Context*>(&*regs)),
|
||||||
void Thread::proceed(Cpu & cpu)
|
(void*)_cpu().stack_start());
|
||||||
{
|
|
||||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
|
||||||
cpu.switch_to(pd().mmu_regs);
|
|
||||||
|
|
||||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
|
||||||
(void*)cpu.stack_start());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ void Board::Vcpu_context::Vm_irq::handle(Vm & vm, unsigned irq) {
|
|||||||
|
|
||||||
void Board::Vcpu_context::Vm_irq::occurred()
|
void Board::Vcpu_context::Vm_irq::occurred()
|
||||||
{
|
{
|
||||||
Vm *vm = dynamic_cast<Vm*>(&_cpu.scheduled_job());
|
Vm *vm = dynamic_cast<Vm*>(&_cpu.current_context());
|
||||||
if (!vm) Genode::raw("VM interrupt while VM is not runnning!");
|
if (!vm) Genode::raw("VM interrupt while VM is not runnning!");
|
||||||
else handle(*vm, _irq_nr);
|
else handle(*vm, _irq_nr);
|
||||||
}
|
}
|
||||||
@ -115,15 +115,13 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
Identity & id)
|
Identity & id)
|
||||||
:
|
:
|
||||||
Kernel::Object { *this },
|
Kernel::Object { *this },
|
||||||
Cpu_job(Scheduler::Priority::min(), 0),
|
Cpu_context(cpu, Scheduler::Priority::min(), 0),
|
||||||
_user_irq_pool(user_irq_pool),
|
_user_irq_pool(user_irq_pool),
|
||||||
_state(data),
|
_state(data),
|
||||||
_context(context),
|
_context(context),
|
||||||
_id(id),
|
_id(id),
|
||||||
_vcpu_context(cpu)
|
_vcpu_context(cpu)
|
||||||
{
|
{
|
||||||
affinity(cpu);
|
|
||||||
|
|
||||||
_state.id_aa64isar0_el1 = Cpu::Id_aa64isar0_el1::read();
|
_state.id_aa64isar0_el1 = Cpu::Id_aa64isar0_el1::read();
|
||||||
_state.id_aa64isar1_el1 = Cpu::Id_aa64isar1_el1::read();
|
_state.id_aa64isar1_el1 = Cpu::Id_aa64isar1_el1::read();
|
||||||
_state.id_aa64mmfr0_el1 = Cpu::Id_aa64mmfr0_el1::read();
|
_state.id_aa64mmfr0_el1 = Cpu::Id_aa64mmfr0_el1::read();
|
||||||
@ -167,14 +165,14 @@ Vm::~Vm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Vm::exception(Cpu & cpu)
|
void Vm::exception()
|
||||||
{
|
{
|
||||||
switch (_state.exception_type) {
|
switch (_state.exception_type) {
|
||||||
case Cpu::IRQ_LEVEL_EL0: [[fallthrough]];
|
case Cpu::IRQ_LEVEL_EL0: [[fallthrough]];
|
||||||
case Cpu::IRQ_LEVEL_EL1: [[fallthrough]];
|
case Cpu::IRQ_LEVEL_EL1: [[fallthrough]];
|
||||||
case Cpu::FIQ_LEVEL_EL0: [[fallthrough]];
|
case Cpu::FIQ_LEVEL_EL0: [[fallthrough]];
|
||||||
case Cpu::FIQ_LEVEL_EL1:
|
case Cpu::FIQ_LEVEL_EL1:
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
break;
|
break;
|
||||||
case Cpu::SYNC_LEVEL_EL0: [[fallthrough]];
|
case Cpu::SYNC_LEVEL_EL0: [[fallthrough]];
|
||||||
case Cpu::SYNC_LEVEL_EL1: [[fallthrough]];
|
case Cpu::SYNC_LEVEL_EL1: [[fallthrough]];
|
||||||
@ -188,17 +186,17 @@ void Vm::exception(Cpu & cpu)
|
|||||||
" not implemented!");
|
" not implemented!");
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cpu.pic().ack_virtual_irq(_vcpu_context.pic))
|
if (_cpu().pic().ack_virtual_irq(_vcpu_context.pic))
|
||||||
inject_irq(Board::VT_MAINTAINANCE_IRQ);
|
inject_irq(Board::VT_MAINTAINANCE_IRQ);
|
||||||
_vcpu_context.vtimer_irq.disable();
|
_vcpu_context.vtimer_irq.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Vm::proceed(Cpu & cpu)
|
void Vm::proceed()
|
||||||
{
|
{
|
||||||
if (_state.timer.irq) _vcpu_context.vtimer_irq.enable();
|
if (_state.timer.irq) _vcpu_context.vtimer_irq.enable();
|
||||||
|
|
||||||
cpu.pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq);
|
_cpu().pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the following values have to be enforced by the hypervisor
|
* the following values have to be enforced by the hypervisor
|
||||||
@ -208,7 +206,7 @@ void Vm::proceed(Cpu & cpu)
|
|||||||
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id.id);
|
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id.id);
|
||||||
addr_t guest = Hw::Mm::el2_addr(&_state);
|
addr_t guest = Hw::Mm::el2_addr(&_state);
|
||||||
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
||||||
addr_t host = Hw::Mm::el2_addr(&host_context(cpu));
|
addr_t host = Hw::Mm::el2_addr(&host_context(_cpu()));
|
||||||
|
|
||||||
Hypervisor::switch_world(guest, host, pic, vttbr_el2);
|
Hypervisor::switch_world(guest, host, pic, vttbr_el2);
|
||||||
}
|
}
|
||||||
|
@ -25,21 +25,21 @@ void Thread::Tlb_invalidation::execute(Cpu &) { }
|
|||||||
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
|
void Thread::Flush_and_stop_cpu::execute(Cpu &) { }
|
||||||
|
|
||||||
|
|
||||||
void Cpu::Halt_job::proceed(Kernel::Cpu &) { }
|
void Cpu::Halt_job::proceed() { }
|
||||||
|
|
||||||
|
|
||||||
void Thread::exception(Cpu & cpu)
|
void Thread::exception()
|
||||||
{
|
{
|
||||||
using Context = Core::Cpu::Context;
|
using Context = Core::Cpu::Context;
|
||||||
using Stval = Core::Cpu::Stval;
|
using Stval = Core::Cpu::Stval;
|
||||||
|
|
||||||
if (regs->is_irq()) {
|
if (regs->is_irq()) {
|
||||||
/* cpu-local timer interrupt */
|
/* cpu-local timer interrupt */
|
||||||
if (regs->irq() == cpu.timer().interrupt_id()) {
|
if (regs->irq() == _cpu().timer().interrupt_id()) {
|
||||||
cpu.handle_if_cpu_local_interrupt(cpu.timer().interrupt_id());
|
_cpu().handle_if_cpu_local_interrupt(_cpu().timer().interrupt_id());
|
||||||
} else {
|
} else {
|
||||||
/* interrupt controller */
|
/* interrupt controller */
|
||||||
_interrupt(_user_irq_pool, 0);
|
_interrupt(_user_irq_pool);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ void Kernel::Thread::_call_cache_line_size()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::proceed(Cpu & cpu)
|
void Kernel::Thread::proceed()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The sstatus register defines to which privilege level
|
* The sstatus register defines to which privilege level
|
||||||
@ -123,8 +123,8 @@ void Kernel::Thread::proceed(Cpu & cpu)
|
|||||||
Cpu::Sstatus::Spp::set(v, (type() == USER) ? 0 : 1);
|
Cpu::Sstatus::Spp::set(v, (type() == USER) ? 0 : 1);
|
||||||
Cpu::Sstatus::write(v);
|
Cpu::Sstatus::write(v);
|
||||||
|
|
||||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
if (!_cpu().active(pd().mmu_regs) && type() != CORE)
|
||||||
cpu.switch_to(_pd->mmu_regs);
|
_cpu().switch_to(_pd->mmu_regs);
|
||||||
|
|
||||||
asm volatile("csrw sscratch, %1 \n"
|
asm volatile("csrw sscratch, %1 \n"
|
||||||
"mv x31, %0 \n"
|
"mv x31, %0 \n"
|
||||||
|
@ -55,9 +55,9 @@ void Kernel::Thread::Flush_and_stop_cpu::execute(Cpu &cpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Cpu::Halt_job::Halt_job::proceed(Kernel::Cpu &cpu)
|
void Kernel::Cpu::Halt_job::Halt_job::proceed()
|
||||||
{
|
{
|
||||||
switch (cpu.state()) {
|
switch (_cpu().state()) {
|
||||||
case HALT:
|
case HALT:
|
||||||
while (true) {
|
while (true) {
|
||||||
asm volatile ("hlt"); }
|
asm volatile ("hlt"); }
|
||||||
@ -83,7 +83,7 @@ void Kernel::Cpu::Halt_job::Halt_job::proceed(Kernel::Cpu &cpu)
|
|||||||
/* adhere to ACPI specification */
|
/* adhere to ACPI specification */
|
||||||
asm volatile ("wbinvd" : : : "memory");
|
asm volatile ("wbinvd" : : : "memory");
|
||||||
|
|
||||||
fadt.suspend(cpu.suspend.typ_a, cpu.suspend.typ_b);
|
fadt.suspend(_cpu().suspend.typ_a, _cpu().suspend.typ_b);
|
||||||
|
|
||||||
Genode::raw("kernel: unexpected resume");
|
Genode::raw("kernel: unexpected resume");
|
||||||
});
|
});
|
||||||
@ -143,7 +143,7 @@ void Kernel::Thread::_call_suspend()
|
|||||||
/* single core CPU case */
|
/* single core CPU case */
|
||||||
if (cpu_count == 1) {
|
if (cpu_count == 1) {
|
||||||
/* current CPU triggers final ACPI suspend outside kernel lock */
|
/* current CPU triggers final ACPI suspend outside kernel lock */
|
||||||
_cpu->next_state_suspend();
|
_cpu().next_state_suspend();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +176,12 @@ void Kernel::Thread::_call_cache_line_size()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::proceed(Cpu & cpu)
|
void Kernel::Thread::proceed()
|
||||||
{
|
{
|
||||||
if (!cpu.active(pd().mmu_regs) && type() != CORE)
|
if (!_cpu().active(pd().mmu_regs) && type() != CORE)
|
||||||
cpu.switch_to(pd().mmu_regs);
|
_cpu().switch_to(pd().mmu_regs);
|
||||||
|
|
||||||
cpu.switch_to(*regs);
|
_cpu().switch_to(*regs);
|
||||||
|
|
||||||
asm volatile("fxrstor (%1) \n"
|
asm volatile("fxrstor (%1) \n"
|
||||||
"mov %0, %%rsp \n"
|
"mov %0, %%rsp \n"
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
void Thread::exception(Cpu & cpu)
|
void Thread::exception()
|
||||||
{
|
{
|
||||||
using Genode::Cpu_state;
|
using Genode::Cpu_state;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ void Thread::exception(Cpu & cpu)
|
|||||||
|
|
||||||
if (regs->trapno >= Cpu_state::INTERRUPTS_START &&
|
if (regs->trapno >= Cpu_state::INTERRUPTS_START &&
|
||||||
regs->trapno <= Cpu_state::INTERRUPTS_END) {
|
regs->trapno <= Cpu_state::INTERRUPTS_END) {
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,15 +41,12 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
|||||||
Identity & id)
|
Identity & id)
|
||||||
:
|
:
|
||||||
Kernel::Object { *this },
|
Kernel::Object { *this },
|
||||||
Cpu_job(Scheduler::Priority::min(), 0),
|
Cpu_context(cpu, Scheduler::Priority::min(), 0),
|
||||||
_user_irq_pool(user_irq_pool),
|
_user_irq_pool(user_irq_pool),
|
||||||
_state(*data.vcpu_state),
|
_state(*data.vcpu_state),
|
||||||
_context(context),
|
_context(context),
|
||||||
_id(id),
|
_id(id),
|
||||||
_vcpu_context(id.id, data)
|
_vcpu_context(id.id, data) { }
|
||||||
{
|
|
||||||
affinity(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Vm::~Vm()
|
Vm::~Vm()
|
||||||
@ -57,10 +54,10 @@ Vm::~Vm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Vm::proceed(Cpu & cpu)
|
void Vm::proceed()
|
||||||
{
|
{
|
||||||
using namespace Board;
|
using namespace Board;
|
||||||
cpu.switch_to(*_vcpu_context.regs);
|
_cpu().switch_to(*_vcpu_context.regs);
|
||||||
|
|
||||||
if (_vcpu_context.exit_reason == EXIT_INIT) {
|
if (_vcpu_context.exit_reason == EXIT_INIT) {
|
||||||
_vcpu_context.regs->trapno = TRAP_VMSKIP;
|
_vcpu_context.regs->trapno = TRAP_VMSKIP;
|
||||||
@ -83,7 +80,7 @@ void Vm::proceed(Cpu & cpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Vm::exception(Cpu & cpu)
|
void Vm::exception()
|
||||||
{
|
{
|
||||||
using namespace Board;
|
using namespace Board;
|
||||||
|
|
||||||
@ -121,18 +118,18 @@ void Vm::exception(Cpu & cpu)
|
|||||||
* it needs to handle an exit.
|
* it needs to handle an exit.
|
||||||
*/
|
*/
|
||||||
if (_vcpu_context.exit_reason == EXIT_PAUSED)
|
if (_vcpu_context.exit_reason == EXIT_PAUSED)
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
else
|
else
|
||||||
pause = true;
|
pause = true;
|
||||||
break;
|
break;
|
||||||
case Cpu_state::INTERRUPTS_START ... Cpu_state::INTERRUPTS_END:
|
case Cpu_state::INTERRUPTS_START ... Cpu_state::INTERRUPTS_END:
|
||||||
_interrupt(_user_irq_pool, cpu.id());
|
_interrupt(_user_irq_pool);
|
||||||
break;
|
break;
|
||||||
case TRAP_VMSKIP:
|
case TRAP_VMSKIP:
|
||||||
/* vCPU is running for the first time */
|
/* vCPU is running for the first time */
|
||||||
_vcpu_context.initialize(cpu,
|
_vcpu_context.initialize(_cpu(),
|
||||||
reinterpret_cast<addr_t>(_id.table));
|
reinterpret_cast<addr_t>(_id.table));
|
||||||
_vcpu_context.tsc_aux_host = cpu.id();
|
_vcpu_context.tsc_aux_host = _cpu().id();
|
||||||
/*
|
/*
|
||||||
* We set the artificial startup exit code, stop the
|
* We set the artificial startup exit code, stop the
|
||||||
* vCPU thread and ask the VMM to handle it.
|
* vCPU thread and ask the VMM to handle it.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user