sel4: add MSI support for x86

Fixes #5423
This commit is contained in:
Alexander Boettcher 2025-01-16 09:41:48 +01:00 committed by Christian Helmuth
parent ea3ed25431
commit 2ad1c450ee
6 changed files with 53 additions and 27 deletions

View File

@ -23,6 +23,7 @@
/* core includes */
#include <types.h>
#include <irq_args.h>
namespace Core { class Irq_object; }
@ -41,11 +42,12 @@ class Core::Irq_object : public Thread {
void entry() override;
long _associate(Irq_session::Trigger const &irq_trigger,
Irq_session::Polarity const &irq_polarity);
long _associate(Irq_args const &);
public:
enum { MSI_OFFSET = 64 };
Irq_object(unsigned irq);
void sigh(Signal_context_capability cap) { _sig_cap = cap; }
@ -53,7 +55,9 @@ class Core::Irq_object : public Thread {
void ack_irq();
Start_result start() override;
bool associate(Irq_session::Trigger const, Irq_session::Polarity const);
bool associate(Irq_args const &);
bool msi() const { return _irq >= MSI_OFFSET; }
};
#endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */

View File

@ -22,12 +22,11 @@
using namespace Core;
bool Irq_object::associate(Irq_session::Trigger const irq_trigger,
Irq_session::Polarity const irq_polarity)
bool Irq_object::associate(Irq_args const &args)
{
/* allocate notification object within core's CNode */
Platform &platform = platform_specific();
Range_allocator &phys_alloc = platform.ram_alloc();
auto &platform = platform_specific();
auto &phys_alloc = platform.ram_alloc();
{
addr_t const phys_addr = Untyped_memory::alloc_page(phys_alloc);
@ -38,7 +37,7 @@ bool Irq_object::associate(Irq_session::Trigger const irq_trigger,
}
/* setup IRQ platform specific */
long res = _associate(irq_trigger, irq_polarity);
long res = _associate(args);
if (res != seL4_NoError)
return false;
@ -100,22 +99,20 @@ Irq_object::Irq_object(unsigned irq)
Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
const char *args)
:
_irq_number((unsigned)Arg_string::find_arg(args, "irq_number").long_value(-1)),
_irq_number(unsigned(Irq_args(args).type() == TYPE_LEGACY ?
Irq_args(args).irq_number() :
Irq_args(args).irq_number() + Irq_object::MSI_OFFSET)),
_irq_alloc(irq_alloc),
_irq_object(_irq_number)
{
Irq_args const irq_args(args);
bool msi { irq_args.type() != Irq_session::TYPE_LEGACY };
if (msi)
throw Service_denied();
if (irq_alloc.alloc_addr(1, _irq_number).failed()) {
error("unavailable IRQ ", _irq_number, " requested");
throw Service_denied();
}
if (!_irq_object.associate(irq_args.trigger(), irq_args.polarity())) {
if (!_irq_object.associate(irq_args)) {
error("could not associate with IRQ ", irq_args.irq_number());
throw Service_denied();
}
@ -144,6 +141,13 @@ void Irq_session_component::sigh(Signal_context_capability cap)
Irq_session::Info Irq_session_component::info()
{
/* no MSI support */
return { .type = Info::Type::INVALID, .address = 0, .value = 0 };
if (!_irq_object.msi())
return { .type = Info::Type::INVALID, .address = 0, .value = 0 };
// see include/plat/pc99/plat/machine.h
enum { PIC_IRQ_LINES = 16, IRQ_INT_OFFSET = 0x20 };
return { .type = Info::Type::MSI,
.address = 0xfee00000ul,
.value = IRQ_INT_OFFSET + PIC_IRQ_LINES + _irq_number };
}

View File

@ -380,6 +380,7 @@ void Core::Platform::_init_rom_modules()
xml.node("kernel", [&] {
xml.attribute("name", "sel4");
xml.attribute("acpi", true);
xml.attribute("msi" , true);
});
xml.node("hardware", [&] {
xml.node("features", [&] {

View File

@ -11,8 +11,7 @@
using namespace Core;
long Irq_object::_associate(Irq_session::Trigger const &,
Irq_session::Polarity const &)
long Irq_object::_associate(Irq_args const &)
{
seL4_CNode const root = seL4_CapInitThreadCNode;
seL4_Word const index = _kernel_irq_sel.value();

View File

@ -12,8 +12,7 @@
using namespace Core;
long Irq_object::_associate(Irq_session::Trigger const &irq_trigger,
Irq_session::Polarity const &irq_polarity)
long Irq_object::_associate(Irq_args const & args)
{
enum { IRQ_EDGE = 0, IRQ_LEVEL = 1 };
enum { IRQ_HIGH = 0, IRQ_LOW = 1 };
@ -21,11 +20,11 @@ long Irq_object::_associate(Irq_session::Trigger const &irq_trigger,
seL4_Word level = (_irq < 16) ? IRQ_EDGE : IRQ_LEVEL;
seL4_Word polarity = (_irq < 16) ? IRQ_HIGH : IRQ_LOW;
if (irq_trigger != Irq_session::TRIGGER_UNCHANGED)
level = (irq_trigger == Irq_session::TRIGGER_LEVEL) ? IRQ_LEVEL : IRQ_EDGE;
if (args.trigger() != Irq_session::TRIGGER_UNCHANGED)
level = (args.trigger() == Irq_session::TRIGGER_LEVEL) ? IRQ_LEVEL : IRQ_EDGE;
if (irq_polarity != Irq_session::POLARITY_UNCHANGED)
polarity = (irq_polarity == Irq_session::POLARITY_HIGH) ? IRQ_HIGH : IRQ_LOW;
if (args.polarity() != Irq_session::POLARITY_UNCHANGED)
polarity = (args.polarity() == Irq_session::POLARITY_HIGH) ? IRQ_HIGH : IRQ_LOW;
seL4_CNode const root = seL4_CapInitThreadCNode;
seL4_Word const index = _kernel_irq_sel.value();
@ -33,6 +32,18 @@ long Irq_object::_associate(Irq_session::Trigger const &irq_trigger,
seL4_Word const ioapic = 0;
seL4_Word const pin = _irq ? _irq : 2;
seL4_Word const vector = _irq;
return seL4_IRQControl_GetIOAPIC(seL4_CapIRQControl, root, index, depth,
ioapic, pin, level, polarity, vector);
seL4_Word const handle = 0;
switch (args.type()) {
case Irq_session::TYPE_LEGACY:
return seL4_IRQControl_GetIOAPIC(seL4_CapIRQControl, root, index, depth,
ioapic, pin, level, polarity, vector);
case Irq_session::TYPE_MSI:
case Irq_session::TYPE_MSIX:
return seL4_IRQControl_GetMSI(seL4_CapIRQControl, root, index, depth,
args.pci_bus(), args.pci_dev(),
args.pci_func(), handle, vector);
default:
return seL4_InvalidArgument;
}
}

View File

@ -33,11 +33,14 @@ class Core::Irq_args
long const _irq_number;
long const _bdf;
public:
Irq_args(const char * args)
:
_irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1))
_irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1)),
_bdf(Arg_string::find_arg(args, "bdf").long_value(-1))
{
long irq_trg = Arg_string::find_arg(args, "irq_trigger").long_value(-1);
long irq_pol = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
@ -99,6 +102,10 @@ class Core::Irq_args
Irq_session::Trigger trigger() const { return _irq_trigger; }
Irq_session::Polarity polarity() const { return _irq_polarity; }
Irq_session::Type type() const { return _irq_type; }
unsigned pci_bus() const { return 0xffu & (_bdf >> 8); }
unsigned pci_dev() const { return 0x1fu & (_bdf >> 3); }
unsigned pci_func() const { return 0x07u & _bdf; }
};
#endif /* _CORE__INCLUDE__IRQ_ARGS_H_ */