mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-16 07:27:35 +00:00
parent
5006b009cb
commit
c767c2b129
@ -379,6 +379,12 @@ class Driver::Device : private List_model<Device>::Element
|
||||
fn(idx++, ipr.range, ipr.bar); });
|
||||
}
|
||||
|
||||
template <typename FN> void for_each_property(FN const & fn) const
|
||||
{
|
||||
_property_list.for_each([&] (Property const & p) {
|
||||
fn(p.name, p.value); });
|
||||
}
|
||||
|
||||
template <typename FN> void for_pci_config(FN const & fn) const
|
||||
{
|
||||
/*
|
||||
|
108
repos/pc/src/driver/platform/pc/ioapic.cc
Normal file
108
repos/pc/src/driver/platform/pc/ioapic.cc
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* \brief IOAPIC implementation
|
||||
* \author Johannes Schlatow
|
||||
* \date 2024-03-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
/* local includes */
|
||||
#include <ioapic.h>
|
||||
|
||||
unsigned Driver::Ioapic::_read_max_entries()
|
||||
{
|
||||
write<Ioregsel>(Ioregsel::IOAPICVER);
|
||||
return read<Iowin::Maximum_entries>() + 1;
|
||||
}
|
||||
|
||||
|
||||
bool Driver::Ioapic::handles_irq(unsigned irq)
|
||||
{
|
||||
if (irq < _irq_start || irq >= _irq_start + _max_entries)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets remapping bit and destination index in IOAPIC redirection table.
|
||||
*
|
||||
* Note: Expected to be called only if handles_irq() returned true.
|
||||
*/
|
||||
void Driver::Ioapic::remap_irq(unsigned from, unsigned to)
|
||||
{
|
||||
const unsigned idx = from - _irq_start;
|
||||
|
||||
/* read upper 32 bit */
|
||||
write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx + 1);
|
||||
Irte::access_t irte { read<Iowin>() };
|
||||
irte <<= 32;
|
||||
|
||||
/* read lower 32 bit */
|
||||
write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx);
|
||||
irte |= read<Iowin>();
|
||||
|
||||
/* remap entry */
|
||||
Irte::Remap::set(irte, 1);
|
||||
Irte::Index::set(irte, to & 0xFF);
|
||||
|
||||
/* write upper 32 bit */
|
||||
write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx + 1);
|
||||
write<Iowin>((Iowin::access_t)(irte >> 32));
|
||||
|
||||
/* write lower 32 bit */
|
||||
write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx);
|
||||
write<Iowin>((Iowin::access_t)(irte & 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads and returns IRQ configuration from IOAPIC redirection table.
|
||||
*
|
||||
* Note: Expected to be called only if handles_irq() returned true.
|
||||
*/
|
||||
Driver::Ioapic::Irq_config Driver::Ioapic::irq_config(unsigned irq)
|
||||
{
|
||||
const unsigned idx = irq - _irq_start;
|
||||
|
||||
/* read upper 32 bit */
|
||||
write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx + 1);
|
||||
Irte::access_t irte { read<Iowin>() };
|
||||
irte <<= 32;
|
||||
|
||||
/* read lower 32 bit */
|
||||
write<Ioregsel>(Ioregsel::IOREDTBL + 2 * idx);
|
||||
irte |= read<Iowin>();
|
||||
|
||||
/* extract trigger mode */
|
||||
Irq_session::Trigger trigger { Irq_session::TRIGGER_UNCHANGED };
|
||||
switch (Irte::Trigger_mode::get(irte)) {
|
||||
case Irte::Trigger_mode::EDGE:
|
||||
trigger = Irq_session::TRIGGER_EDGE;
|
||||
break;
|
||||
case Irte::Trigger_mode::LEVEL:
|
||||
trigger = Irq_session::TRIGGER_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* extract destination mode */
|
||||
Irq_config::Mode mode { Irq_config::Mode::INVALID };
|
||||
switch (Irte::Destination_mode::get(irte)) {
|
||||
case Irte::Destination_mode::PHYSICAL:
|
||||
mode = Irq_config::Mode::PHYSICAL;
|
||||
break;
|
||||
case Irte::Destination_mode::LOGICAL:
|
||||
mode = Irq_config::Mode::LOGICAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return { mode, trigger,
|
||||
Irte::Vector::get(irte),
|
||||
Irte::Destination::get(irte) };
|
||||
}
|
152
repos/pc/src/driver/platform/pc/ioapic.h
Normal file
152
repos/pc/src/driver/platform/pc/ioapic.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* \brief IOAPIC implementation
|
||||
* \author Johannes Schlatow
|
||||
* \date 2024-03-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 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 _SRC__DRIVERS__PLATFORM__PC__IOAPIC_H_
|
||||
#define _SRC__DRIVERS__PLATFORM__PC__IOAPIC_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/attached_mmio.h>
|
||||
#include <util/register_set.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
/* Platform-driver includes */
|
||||
#include <device.h>
|
||||
#include <irq_controller.h>
|
||||
|
||||
namespace Driver {
|
||||
using namespace Genode;
|
||||
|
||||
class Ioapic;
|
||||
class Ioapic_factory;
|
||||
}
|
||||
|
||||
|
||||
class Driver::Ioapic : private Attached_mmio<0x1000>,
|
||||
public Driver::Irq_controller
|
||||
{
|
||||
private:
|
||||
|
||||
Env & _env;
|
||||
unsigned _irq_start;
|
||||
unsigned _max_entries;
|
||||
|
||||
/**
|
||||
* Registers
|
||||
*/
|
||||
|
||||
struct Ioregsel : Register<0x00, 32> {
|
||||
enum {
|
||||
IOAPICVER = 0x01,
|
||||
IOREDTBL = 0x10
|
||||
};
|
||||
};
|
||||
|
||||
struct Iowin : Register<0x10, 32> {
|
||||
struct Maximum_entries : Bitfield<16, 8> { };
|
||||
};
|
||||
|
||||
struct Irte : Genode::Register<64> {
|
||||
struct Index_15 : Bitfield<11, 1> { };
|
||||
struct Remap : Bitfield<48, 1> { };
|
||||
struct Index_0_14 : Bitfield<49, 15> { };
|
||||
struct Index : Bitset_2<Index_0_14, Index_15> { };
|
||||
|
||||
struct Vector : Bitfield<0,8> { };
|
||||
struct Trigger_mode : Bitfield<15,1> {
|
||||
enum { EDGE = 0, LEVEL = 1 }; };
|
||||
|
||||
struct Destination_mode : Bitfield<11,1> {
|
||||
enum { PHYSICAL = 0, LOGICAL = 1 }; };
|
||||
|
||||
struct Destination : Bitfield<56,8> { };
|
||||
};
|
||||
|
||||
unsigned _read_max_entries();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Irq_controller interface
|
||||
*/
|
||||
void remap_irq(unsigned, unsigned) override;
|
||||
bool handles_irq(unsigned) override;
|
||||
Irq_config irq_config(unsigned) override;
|
||||
|
||||
/**
|
||||
* Constructor/Destructor
|
||||
*/
|
||||
|
||||
Ioapic(Env & env,
|
||||
Registry<Irq_controller> & irq_controller_registry,
|
||||
Device::Name const & name,
|
||||
Device::Name const & iommu_name,
|
||||
Pci::Bdf const & bdf,
|
||||
Device::Io_mem::Range range,
|
||||
unsigned irq_start)
|
||||
: Attached_mmio(env, {(char *)range.start, range.size}),
|
||||
Driver::Irq_controller(irq_controller_registry, name, iommu_name, bdf),
|
||||
_env(env), _irq_start(irq_start), _max_entries(_read_max_entries())
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
class Driver::Ioapic_factory : public Driver::Irq_controller_factory
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Env & _env;
|
||||
|
||||
public:
|
||||
|
||||
Ioapic_factory(Genode::Env & env, Registry<Irq_controller_factory> & registry)
|
||||
: Driver::Irq_controller_factory(registry, Device::Type { "ioapic" }),
|
||||
_env(env)
|
||||
{ }
|
||||
|
||||
void create(Allocator & alloc, Registry<Irq_controller> & irq_controller_registry, Device const & device) override
|
||||
{
|
||||
using Range = Device::Io_mem::Range;
|
||||
using Property = Device::Property;
|
||||
|
||||
/* evaluate properties (remapping support, base IRQ, routing id) */
|
||||
bool remap { false };
|
||||
unsigned irq_start { 0 };
|
||||
Pci::rid_t rid { 0 };
|
||||
device.for_each_property([&] (Property::Name const & name, Property::Value const & value) {
|
||||
if (name == "remapping")
|
||||
ascii_to(value.string(), remap);
|
||||
else if (name == "irq_start")
|
||||
ascii_to(value.string(), irq_start);
|
||||
else if (name == "routing_id")
|
||||
ascii_to(value.string(), rid);
|
||||
});
|
||||
|
||||
/* ignore IOAPIC devices without remapping support */
|
||||
if (!remap)
|
||||
return;
|
||||
|
||||
unsigned iommu_idx = 0;
|
||||
device.for_each_io_mmu([&] (Device::Io_mmu const & iommu) {
|
||||
if (iommu_idx++) return;
|
||||
|
||||
device.for_each_io_mem([&] (unsigned idx, Range range, Device::Pci_bar, bool)
|
||||
{
|
||||
if (idx == 0)
|
||||
new (alloc) Ioapic(_env, irq_controller_registry, device.name(),
|
||||
iommu.name, Pci::Bdf::bdf(rid), range, irq_start);
|
||||
});
|
||||
}, [] () { /* empty fn */ });
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__DRIVERS__PLATFORM__PC__IOAPIC_H_ */
|
@ -16,6 +16,7 @@
|
||||
#include <common.h>
|
||||
#include <pci.h>
|
||||
#include <intel/io_mmu.h>
|
||||
#include <ioapic.h>
|
||||
|
||||
namespace Driver { struct Main; };
|
||||
|
||||
@ -33,6 +34,7 @@ struct Driver::Main
|
||||
&Main::_system_update };
|
||||
|
||||
Intel::Io_mmu_factory _intel_iommu { _env, _common.io_mmu_factories() };
|
||||
Ioapic_factory _ioapic_factory { _env, _common.irq_controller_factories() };
|
||||
|
||||
void _handle_config();
|
||||
void _suspend(String<8>);
|
||||
@ -51,6 +53,7 @@ struct Driver::Main
|
||||
_system_update();
|
||||
|
||||
_common.acquire_io_mmu_devices();
|
||||
_common.acquire_irq_controller();
|
||||
_common.announce_service();
|
||||
}
|
||||
};
|
||||
|
@ -9,7 +9,9 @@ SRC_CC += intel/managed_root_table.cc
|
||||
SRC_CC += intel/io_mmu.cc
|
||||
SRC_CC += intel/page_table.cc
|
||||
SRC_CC += intel/default_mappings.cc
|
||||
SRC_CC += ioapic.cc
|
||||
|
||||
INC_DIR += $(PRG_DIR)/../../
|
||||
|
||||
vpath intel/%.cc $(PRG_DIR)/../../
|
||||
vpath ioapic.cc $(PRG_DIR)/../../
|
||||
|
Loading…
x
Reference in New Issue
Block a user