genode/repos/base-hw/src/core/spec/x86_64/pic.h

224 lines
4.5 KiB
C++

/*
* \brief Programmable interrupt controller for core
* \author Reto Buerki
* \author Alexander Boettcher
* \date 2015-02-17
*/
/*
* Copyright (C) 2015-2018 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 _CORE__SPEC__X86_64__PIC_H_
#define _CORE__SPEC__X86_64__PIC_H_
/* Genode includes */
#include <util/mmio.h>
/* core includes */
#include <board.h>
namespace Board
{
/*
* Redirection table entry
*/
struct Irte;
/**
* IO advanced programmable interrupt controller
*/
class Ioapic;
/**
* Programmable interrupt controller for core
*/
class Pic;
enum { IRQ_COUNT = 256 };
}
struct Board::Irte : Genode::Register<64>
{
struct Pol : Bitfield<13, 1> { };
struct Trg : Bitfield<15, 1> { };
struct Mask : Bitfield<16, 1> { };
};
class Board::Ioapic : public Genode::Mmio
{
private:
/* Number of Redirection Table entries */
unsigned _irte_count = 0;
enum {
/* Register selectors */
IOAPICVER = 0x01,
IOREDTBL = 0x10,
/* 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;
};
static Irq_mode _irq_mode[IRQ_COUNT];
/**
* Return whether 'irq' is an edge-triggered interrupt
*/
bool _edge_triggered(unsigned const irq)
{
return _irq_mode[irq].trigger_mode == TRIGGER_EDGE;
}
/**
* 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.
*/
void _update_irt_entry(unsigned irq);
/**
* Create redirection table entry for given IRQ
*/
Irte::access_t _create_irt_entry(unsigned const irq);
public:
Ioapic();
/**
* Set/unset mask bit of IRTE for given vector
*
* \param vector targeted vector
* \param set whether to set or to unset the mask bit
*/
void toggle_mask(unsigned const vector, bool const set);
/**
* 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 irq_mode(unsigned irq_number, unsigned trigger,
unsigned polarity);
/*
* Registers
*/
struct Ioregsel : Register<0x00, 32> { };
struct Iowin : Register<0x10, 32>
{
struct Maximum_redirection_entry : Bitfield<16, 8> { };
};
};
class Board::Pic : public Genode::Mmio
{
private:
/*
* Registers
*/
struct Id : Register<0x020, 32> { };
struct EOI : Register<0x0b0, 32, true> { };
struct Svr : Register<0x0f0, 32>
{
struct APIC_enable : Bitfield<8, 1> { };
};
/*
* 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.
*/
struct Isr : Register_array<0x100, 32, 8 * 4, 32> { };
/*
* 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> { };
};
/**
* Determine lowest pending interrupt in ISR register
*
* \return index of first ISR bit set starting at index one, zero if no
* bit is set.
*/
inline unsigned get_lowest_bit(void);
/**
* Mapping of our logical boot CPUs to the local APIC IDs
*/
static Genode::uint8_t lapic_ids[NR_OF_CPUS];
public:
enum {
/*
* FIXME: dummy ipi value on non-SMP platform, should be removed
* when SMP is an aspect of CPUs only compiled where
* necessary
*/
IPI = 255,
NR_OF_IRQ = IRQ_COUNT,
};
/**
* Constructor
*/
Pic();
Ioapic ioapic { };
bool take_request(unsigned &irq);
void finish_request();
void unmask(unsigned const i, unsigned);
void mask(unsigned const i);
void irq_mode(unsigned irq, unsigned trigger, unsigned polarity);
void store_apic_id(unsigned const cpu_id)
{
if (cpu_id < NR_OF_CPUS) {
Id::access_t const lapic_id = read<Id>();
lapic_ids[cpu_id] = (lapic_id >> 24) & 0xff;
}
}
void send_ipi(unsigned const);
};
#endif /* _CORE__SPEC__X86_64__PIC_H_ */