hw: construct kernel irq objects on demand

Ref #1443
This commit is contained in:
Stefan Kalkowski 2015-04-03 17:22:16 +02:00 committed by Christian Helmuth
parent b32af4e0a4
commit 0188b08f6a
10 changed files with 67 additions and 54 deletions

View File

@ -31,10 +31,10 @@ namespace Genode
{
private:
unsigned _irq_number;
Range_allocator * const _irq_alloc;
Irq_session_capability _cap;
Irq_signal _signal;
Genode::uint8_t _kernel_object[sizeof(Kernel::User_irq)];
public:

View File

@ -24,6 +24,7 @@ namespace Kernel
class Signal_receiver;
class Signal_context;
class Vm;
class User_irq;
addr_t mode_transition_base();
size_t mode_transition_size();
@ -54,6 +55,8 @@ namespace Kernel
constexpr Call_arg call_id_pause_vm() { return 29; }
constexpr Call_arg call_id_pause_thread() { return 30; }
constexpr Call_arg call_id_delete_vm() { return 31; }
constexpr Call_arg call_id_new_irq() { return 32; }
constexpr Call_arg call_id_delete_irq() { return 33; }
/**
* Create a domain
@ -346,6 +349,27 @@ namespace Kernel
{
return call(call_id_pause_vm(), (Call_arg) vm);
}
/**
* Create an interrupt object
*
* \param p memory donation for the irq object
* \param irq_nr interrupt number
*/
inline void new_irq(addr_t const p, unsigned irq_nr)
{
call(call_id_new_irq(), (Call_arg) p, irq_nr);
}
/**
* Destruct an interrupt object
*
* \param irq pointer to interrupt kernel object
*/
inline void delete_irq(User_irq * const irq)
{
call(call_id_delete_irq(), (Call_arg) irq);
}
}
#endif /* _KERNEL__CORE_INTERFACE_H_ */

View File

@ -113,16 +113,6 @@ class Kernel::User_irq
*/
static Irq::Pool * _pool();
/**
* Get kernel name of the interrupt-signal receiver
*/
unsigned _receiver_id() const { return Signal_receiver::Object::id(); }
/**
* Get kernel name of the interrupt-signal context
*/
unsigned _context_id() const { return Signal_context::Object::id(); }
/************************
** Signal_ack_handler **
@ -145,6 +135,16 @@ class Kernel::User_irq
Signal_context::ack_handler(this);
}
/**
* Get kernel name of the interrupt-signal receiver
*/
unsigned receiver_id() const { return Signal_receiver::Object::id(); }
/**
* Get kernel name of the interrupt-signal context
*/
unsigned context_id() const { return Signal_context::Object::id(); }
/**
* Handle occurence of the interrupt
*/
@ -154,24 +154,6 @@ class Kernel::User_irq
disable();
}
/**
* Get information that enables a user to handle an interrupt
*
* \param irq_id kernel name of targeted interrupt
*/
static Genode::Irq_signal signal(unsigned const irq_id)
{
typedef Genode::Irq_signal Irq_signal;
static Irq_signal const invalid = { 0, 0 };
User_irq * const irq =
dynamic_cast<User_irq*>(_pool()->object(irq_id));
if (irq) {
Irq_signal s = { irq->_receiver_id(), irq->_context_id() };
return s;
}
return invalid;
}
/**
* Handle occurence of an interrupt
*

View File

@ -237,6 +237,8 @@ class Kernel::Thread
void _call_pause_vm();
void _call_access_thread_regs();
void _call_route_thread_event();
void _call_new_irq();
void _call_delete_irq();
/***************************

View File

@ -42,22 +42,28 @@ Irq_signal Irq_session_component::signal() { return _signal; }
Irq_session_component::~Irq_session_component()
{
using namespace Kernel;
irq_session_ep()->dissolve(this);
_irq_alloc->free((void *)(addr_t)_irq_number);
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_irq_alloc->free((void *)(addr_t)static_cast<Kernel::Irq*>(kirq)->id());
Kernel::delete_irq(kirq);
}
Irq_session_component::Irq_session_component(Cap_session * const cap_session,
Range_allocator * const irq_alloc,
const char * const args)
:
_irq_alloc(irq_alloc)
: _irq_alloc(irq_alloc)
{
using namespace Kernel;
/* check arguments */
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PERR("shared interrupts not supported");
throw Root::Invalid_args();
}
/* allocate interrupt */
long irq_nr = Arg_string::find_arg(args, "irq_number").long_value(-1);
bool error = irq_nr < 0 || !_irq_alloc;
@ -70,8 +76,10 @@ Irq_session_component::Irq_session_component(Cap_session * const cap_session
PERR("unavailable interrupt requested");
throw Root::Invalid_args();
}
/* make interrupt accessible */
_irq_number = (unsigned)plat_irq_nr;
_signal = Kernel::User_irq::signal(plat_irq_nr);
new_irq((addr_t)&_kernel_object, plat_irq_nr);
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_signal = { kirq->receiver_id(), kirq->context_id() };
_cap = Irq_session_capability(irq_session_ep()->manage(this));
}

View File

@ -141,18 +141,6 @@ namespace Kernel
return unmanaged_singleton<Core_pd>(table, slab);
}
/**
* Return wether interrupt 'irq' is private to the kernel
*/
bool private_interrupt(unsigned const irq)
{
for (unsigned i = 0; i < NR_OF_CPUS; i++)
if (irq == Timer::interrupt_id(i)) return true;
if (irq == Pic::IPI) return true;
return false;
}
/**
* Get attributes of the mode transition region in every PD
*/
@ -260,12 +248,6 @@ void init_kernel_mp_primary()
t.init(cpu_pool()->primary_cpu(), core_pd(),
(Native_utcb*)Genode::UTCB_MAIN_THREAD, 1);
/* initialize user interrupt objects */
static Genode::uint8_t _irqs[Kernel::Pic::NR_OF_IRQ * sizeof(User_irq)];
for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++) {
if (private_interrupt(i)) { continue; }
new (&_irqs[i * sizeof(User_irq)]) User_irq(i);
}
/* kernel initialization finished */
Genode::printf("kernel initialized\n");
test();

View File

@ -688,6 +688,14 @@ void Thread::_call_delete_signal_receiver() {
reinterpret_cast<Signal_receiver*>(user_arg_1())->~Signal_receiver(); }
void Thread::_call_new_irq() {
new ((void *)user_arg_1()) User_irq(user_arg_2()); }
void Thread::_call_delete_irq() {
reinterpret_cast<User_irq*>(user_arg_1())->~User_irq(); }
int Thread::_read_reg(addr_t const id, addr_t & value) const
{
addr_t Thread::* const reg = _reg(id);
@ -762,6 +770,8 @@ void Thread::_call()
case call_id_run_vm(): _call_run_vm(); return;
case call_id_pause_vm(): _call_pause_vm(); return;
case call_id_pause_thread(): _call_pause_thread(); return;
case call_id_new_irq(): _call_new_irq(); return;
case call_id_delete_irq(): _call_delete_irq(); return;
default:
PWRN("%s -> %s: unknown kernel call", pd_label(), label());
_stop();

View File

@ -150,9 +150,12 @@ Platform::Platform()
_init_io_port_alloc();
/* make interrupts available to the interrupt allocator */
for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++)
/* make all non-kernel interrupts available to the interrupt allocator */
for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++) {
if (i == Timer::interrupt_id(i) || i == Pic::IPI)
continue;
_irq_alloc.add_range(i, 1);
}
/*
* Use byte granuarity for MMIO regions because on some platforms, devices

View File

@ -25,6 +25,7 @@ void Pic::_init()
for (unsigned i = min_spi; i <= _max_irq; i++) {
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
_distr.write<Distr::Ipriorityr::Priority>(0, i);
_distr.write<Distr::Icenabler::Clear_enable>(1, i);
}
/* enable device */
_distr.write<Distr::Ctlr::Enable>(1);

View File

@ -27,6 +27,7 @@ void Pic::_init()
_distr.write<Distr::Igroupr::Group_status>(1, i);
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
_distr.write<Distr::Ipriorityr::Priority>(0, i);
_distr.write<Distr::Icenabler::Clear_enable>(1, i);
}
/* enable device */
Distr::Ctlr::access_t v = 0;