2015-02-06 17:29:30 +01:00
|
|
|
/*
|
|
|
|
* \brief Programmable interrupt controller for core
|
2015-03-13 09:20:28 +01:00
|
|
|
* \author Reto Buerki
|
2018-08-01 15:46:06 +02:00
|
|
|
* \author Alexander Boettcher
|
2015-03-13 09:20:28 +01:00
|
|
|
* \date 2015-02-17
|
2015-02-06 17:29:30 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2018-08-01 15:46:06 +02:00
|
|
|
* Copyright (C) 2015-2018 Genode Labs GmbH
|
2015-02-06 17:29:30 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-02-06 17:29:30 +01:00
|
|
|
*/
|
|
|
|
|
2017-04-12 10:06:29 +02:00
|
|
|
#ifndef _CORE__SPEC__X86_64__PIC_H_
|
|
|
|
#define _CORE__SPEC__X86_64__PIC_H_
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2015-03-20 12:22:34 +01:00
|
|
|
/* Genode includes */
|
2015-02-17 09:03:12 +01:00
|
|
|
#include <util/mmio.h>
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2015-03-20 12:22:34 +01:00
|
|
|
/* core includes */
|
|
|
|
#include <board.h>
|
|
|
|
|
2015-02-06 17:29:30 +01:00
|
|
|
namespace Genode
|
|
|
|
{
|
2015-04-29 13:05:41 +02:00
|
|
|
/*
|
|
|
|
* Redirection table entry
|
|
|
|
*/
|
|
|
|
struct Irte;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IO advanced programmable interrupt controller
|
|
|
|
*/
|
|
|
|
class Ioapic;
|
|
|
|
|
2015-02-06 17:29:30 +01:00
|
|
|
/**
|
|
|
|
* Programmable interrupt controller for core
|
|
|
|
*/
|
|
|
|
class Pic;
|
2015-05-16 02:34:45 +02:00
|
|
|
|
|
|
|
enum { IRQ_COUNT = 256 };
|
2015-02-06 17:29:30 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 13:05:41 +02:00
|
|
|
struct Genode::Irte : Register<64>
|
|
|
|
{
|
|
|
|
struct Pol : Bitfield<13, 1> { };
|
|
|
|
struct Trg : Bitfield<15, 1> { };
|
|
|
|
struct Mask : Bitfield<16, 1> { };
|
|
|
|
};
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2015-04-29 13:05:41 +02:00
|
|
|
class Genode::Ioapic : public Mmio
|
2015-02-06 17:29:30 +01:00
|
|
|
{
|
2015-02-17 09:03:12 +01:00
|
|
|
private:
|
|
|
|
|
hw_x86_64: Do not mask edge-triggered interrupts
Do not mask edge-triggered interrupts to avoid losing them while masked,
see Intel 82093AA I/O Advanced Programmable Interrupt Controller
(IOAPIC) specification, section 3.4.2, "Interrupt Mask":
"When this bit is 1, the interrupt signal is masked. Edge-sensitive
interrupts signaled on a masked interrupt pin are ignored (i.e., not
delivered or held pending)"
Or to quote Linus Torvalds on the subject:
"Now, edge-triggered interrupts are a _lot_ harder to mask, because the
Intel APIC is an unbelievable piece of sh*t, and has the edge-detect
logic _before_ the mask logic, so if a edge happens _while_ the device
is masked, you'll never ever see the edge ever again (unmasking will not
cause a new edge, so you simply lost the interrupt)."
So when you "mask" an edge-triggered IRQ, you can't really mask it at
all, because if you did that, you'd lose it forever if the IRQ comes in
while you masked it. Instead, we're supposed to leave it active, and set
a flag, and IF the IRQ comes in, we just remember it, and mask it at
that point instead, and then on unmasking, we have to replay it by
sending a self-IPI." [1]
[1] - http://yarchive.net/comp/linux/edge_triggered_interrupts.html
Ref #1448
2015-03-20 14:25:07 +01:00
|
|
|
enum { REMAP_BASE = Board::VECTOR_REMAP_BASE };
|
|
|
|
|
2017-08-07 15:14:30 +02:00
|
|
|
/* Number of Redirection Table entries */
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
unsigned _irte_count = 0;
|
2015-04-29 13:05:41 +02:00
|
|
|
|
|
|
|
enum {
|
|
|
|
/* Register selectors */
|
|
|
|
IOAPICVER = 0x01,
|
|
|
|
IOREDTBL = 0x10,
|
2015-05-16 02:34:45 +02:00
|
|
|
|
|
|
|
/* IRQ modes */
|
|
|
|
TRIGGER_EDGE = 0,
|
|
|
|
TRIGGER_LEVEL = 1,
|
|
|
|
POLARITY_HIGH = 0,
|
|
|
|
POLARITY_LOW = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IRQ mode specifies trigger mode and polarity of an IRQ
|
|
|
|
*/
|
|
|
|
struct Irq_mode
|
|
|
|
{
|
|
|
|
unsigned trigger_mode;
|
|
|
|
unsigned polarity;
|
2015-04-29 13:05:41 +02:00
|
|
|
};
|
|
|
|
|
2015-05-16 02:34:45 +02:00
|
|
|
static Irq_mode _irq_mode[IRQ_COUNT];
|
|
|
|
|
2015-05-12 22:23:57 +02:00
|
|
|
/**
|
|
|
|
* Return whether 'irq' is an edge-triggered interrupt
|
|
|
|
*/
|
|
|
|
bool _edge_triggered(unsigned const irq)
|
|
|
|
{
|
2015-05-16 02:34:45 +02:00
|
|
|
return _irq_mode[irq].trigger_mode == TRIGGER_EDGE;
|
|
|
|
}
|
2015-05-12 22:07:32 +02:00
|
|
|
|
2015-05-16 02:34:45 +02:00
|
|
|
/**
|
|
|
|
* Update IRT entry of given IRQ
|
|
|
|
*
|
|
|
|
* Note: The polarity and trigger flags are located in the lower
|
|
|
|
* 32 bits so only the necessary half of the IRT entry is
|
|
|
|
* updated.
|
|
|
|
*/
|
2016-11-07 18:00:24 +01:00
|
|
|
void _update_irt_entry(unsigned irq);
|
2015-05-12 22:23:57 +02:00
|
|
|
|
2015-04-29 13:05:41 +02:00
|
|
|
/**
|
|
|
|
* Create redirection table entry for given IRQ
|
|
|
|
*/
|
2016-11-07 18:00:24 +01:00
|
|
|
Irte::access_t _create_irt_entry(unsigned const irq);
|
2015-04-29 13:05:41 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2016-11-07 18:00:24 +01:00
|
|
|
Ioapic();
|
2015-04-29 13:05:41 +02:00
|
|
|
|
2015-05-16 02:34:45 +02:00
|
|
|
/**
|
|
|
|
* Set/unset mask bit of IRTE for given vector
|
|
|
|
*
|
|
|
|
* \param vector targeted vector
|
|
|
|
* \param set whether to set or to unset the mask bit
|
|
|
|
*/
|
2016-11-07 18:00:24 +01:00
|
|
|
void toggle_mask(unsigned const vector, bool const set);
|
2015-04-29 13:05:41 +02:00
|
|
|
|
2015-05-16 02:34:45 +02:00
|
|
|
/**
|
|
|
|
* Setup mode of an IRQ to specified trigger mode and polarity
|
|
|
|
*
|
|
|
|
* \param irq_number ID of targeted interrupt
|
|
|
|
* \param trigger new interrupt trigger mode
|
|
|
|
* \param polarity new interrupt polarity setting
|
|
|
|
*/
|
|
|
|
void setup_irq_mode(unsigned irq_number, unsigned trigger,
|
|
|
|
unsigned polarity);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Registers
|
|
|
|
*/
|
|
|
|
|
2015-04-29 13:05:41 +02:00
|
|
|
struct Ioregsel : Register<0x00, 32> { };
|
2017-08-07 15:14:30 +02:00
|
|
|
struct Iowin : Register<0x10, 32>
|
|
|
|
{
|
|
|
|
struct Maximum_redirection_entry : Bitfield<16, 8> { };
|
|
|
|
};
|
2015-04-29 13:05:41 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class Genode::Pic : public Mmio
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2015-05-16 02:34:45 +02:00
|
|
|
/*
|
|
|
|
* Registers
|
|
|
|
*/
|
|
|
|
|
2018-08-01 15:46:06 +02:00
|
|
|
struct Id : Register<0x020, 32> { };
|
2015-02-17 09:03:12 +01:00
|
|
|
struct EOI : Register<0x0b0, 32, true> { };
|
|
|
|
struct Svr : Register<0x0f0, 32>
|
|
|
|
{
|
|
|
|
struct APIC_enable : Bitfield<8, 1> { };
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
2015-05-16 02:34:45 +02:00
|
|
|
* ISR register, see Intel SDM Vol. 3A, section 10.8.4.
|
|
|
|
*
|
|
|
|
* Each of the 8 32-bit ISR values is followed by 12 bytes of padding.
|
2015-02-17 09:03:12 +01:00
|
|
|
*/
|
|
|
|
struct Isr : Register_array<0x100, 32, 8 * 4, 32> { };
|
|
|
|
|
2018-08-01 15:46:06 +02:00
|
|
|
/*
|
|
|
|
* Interrupt control register
|
|
|
|
*/
|
|
|
|
struct Icr_low : Register<0x300, 32, true> {
|
|
|
|
struct Vector : Bitfield< 0, 8> { };
|
|
|
|
struct Delivery_status : Bitfield<12, 1> { };
|
|
|
|
struct Level_assert : Bitfield<14, 1> { };
|
|
|
|
};
|
|
|
|
struct Icr_high : Register<0x310, 32, true> {
|
|
|
|
struct Destination : Bitfield<24, 8> { };
|
|
|
|
};
|
|
|
|
|
2015-02-17 09:03:12 +01:00
|
|
|
/**
|
|
|
|
* Determine lowest pending interrupt in ISR register
|
|
|
|
*
|
|
|
|
* \return index of first ISR bit set starting at index one, zero if no
|
|
|
|
* bit is set.
|
|
|
|
*/
|
2016-11-07 18:00:24 +01:00
|
|
|
inline unsigned get_lowest_bit(void);
|
2015-02-17 09:03:12 +01:00
|
|
|
|
2018-08-01 15:46:06 +02:00
|
|
|
/**
|
|
|
|
* Mapping of our logical boot CPUs to the local APIC IDs
|
|
|
|
*/
|
|
|
|
static uint8_t lapic_ids[NR_OF_CPUS];
|
|
|
|
|
2015-02-06 17:29:30 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/*
|
|
|
|
* FIXME: dummy ipi value on non-SMP platform, should be removed
|
2015-02-17 09:03:12 +01:00
|
|
|
* when SMP is an aspect of CPUs only compiled where
|
|
|
|
* necessary
|
2015-02-06 17:29:30 +01:00
|
|
|
*/
|
|
|
|
IPI = 255,
|
2015-05-16 02:34:45 +02:00
|
|
|
NR_OF_IRQ = IRQ_COUNT,
|
2015-02-06 17:29:30 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2015-02-17 09:03:12 +01:00
|
|
|
Pic();
|
2015-02-06 17:29:30 +01:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Ioapic ioapic { };
|
2015-05-16 02:34:45 +02:00
|
|
|
|
2015-02-17 09:03:12 +01:00
|
|
|
bool take_request(unsigned &irq);
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2015-02-17 09:03:12 +01:00
|
|
|
void finish_request();
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2015-02-17 09:03:12 +01:00
|
|
|
void unmask(unsigned const i, unsigned);
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2015-02-17 09:03:12 +01:00
|
|
|
void mask(unsigned const i);
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2018-08-01 15:46:06 +02:00
|
|
|
void store_apic_id(unsigned const cpu_id) {
|
|
|
|
Id::access_t const lapic_id = read<Id>();
|
|
|
|
lapic_ids[cpu_id] = (lapic_id >> 24) & 0xff;
|
|
|
|
}
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2018-08-01 15:46:06 +02:00
|
|
|
void send_ipi(unsigned const);
|
2015-02-06 17:29:30 +01:00
|
|
|
};
|
|
|
|
|
2016-11-07 18:00:24 +01:00
|
|
|
namespace Kernel { using Genode::Pic; }
|
2015-02-06 17:29:30 +01:00
|
|
|
|
2017-04-12 10:06:29 +02:00
|
|
|
#endif /* _CORE__SPEC__X86_64__PIC_H_ */
|