pc99: only access real IOAPIC registers

IOAPICS can have varying numbers of lines attached. The actual number
can be accessed in the top 16 bits of the version register.

Rather than assuming fixed 24 lines per IRQ, read the actual number and
use that. We still bound that value by 24 and abort initialization if
the bound is not met. As all current IOAPICS have at most 24 IRQ lines,
this will not trigger on current hardware.

Signed-off-by: Peter Chubb <peter.chubb@unsw.edu.au>
This commit is contained in:
Peter Chubb 2022-07-29 12:17:19 +10:00 committed by Gerwin Klein
parent bf2134e6de
commit ecec5e4afb

View file

@ -15,6 +15,7 @@
#define IOAPIC_WINDOW 0x10
#define IOAPIC_REG_IOAPICID 0x00
#define IOAPIC_REG_IOAPICVER 0x01
#define IOAPIC_REG_IOREDTBL 0x10
#define IOREDTBL_LOW(reg) (IOAPIC_REG_IOREDTBL + (reg) * 2)
@ -32,9 +33,17 @@
#define IOREDTBL_HIGH_RESERVED_BITS 24
/* Cache what we believe is in the low word of the IOREDTBL. This
* has all the state of trigger modes etc etc */
/*
* Cache what we believe is in the low word of the IOREDTBL. This
* has all the state of trigger modes etc etc.
* IOAPIC_IRQ_LINES is the upper bound on the number of lines
* per IOAPIC.
*/
static uint32_t ioredtbl_state[IOAPIC_IRQ_LINES * MAX(1, CONFIG_MAX_NUM_IOAPIC)];
/*
* The number of IRQ lines for each IOAPIC
*/
static uint8_t ioapic_nirqs[MAX(1, CONFIG_MAX_NUM_IOAPIC)];
/* Number of IOAPICs in the system */
static uint32_t num_ioapics = 0;
@ -52,12 +61,28 @@ static uint32_t ioapic_read(uint32_t ioapic, word_t reg)
static void single_ioapic_init(word_t ioapic, cpu_id_t delivery_cpu)
{
uint32_t i;
uint32_t nirqs;
ioapic_write(ioapic, IOAPIC_REGSEL, IOAPIC_REG_IOAPICVER);
nirqs = (ioapic_read(ioapic, IOAPIC_WINDOW) >> 16) + 1;
ioapic_nirqs[ioapic] = nirqs;
/*
* All current implementations have 24 or fewer lines
* Protect against the future one that may have more
*/
if (nirqs > IOAPIC_IRQ_LINES) {
userError("%s: ioapic %lu has %u IRQs,\n"
"which is greater than the max handled (%u)\n",
__func__, ioapic, nirqs, IOAPIC_IRQ_LINES);
halt();
}
/* Mask all the IRQs. In doing so we happen to set
* the vector to 0, which we can assert against in
* mask_interrupt to ensure a vector is assigned
* before we unmask */
for (i = 0; i < IOAPIC_IRQ_LINES; i++) {
for (i = 0; i < nirqs; i++) {
/* Send to desired cpu */
ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_HIGH(i));
ioapic_write(ioapic, IOAPIC_WINDOW, (ioapic_read(ioapic,
@ -87,7 +112,7 @@ void ioapic_init(uint32_t num_nodes, cpu_id_t *cpu_list, uint32_t num_ioapic)
void ioapic_mask(bool_t mask, uint32_t ioapic, uint32_t pin)
{
int index = ioapic * IOAPIC_IRQ_LINES + pin;
if (ioapic >= num_ioapics || pin >= IOAPIC_IRQ_LINES) {
if (ioapic >= num_ioapics || pin >= ioapic_nirqs[ioapic]) {
/* silently ignore requests to non existent parts of the interrupt space */
return;
}
@ -118,11 +143,11 @@ exception_t ioapic_decode_map_pin_to_vector(word_t ioapic, word_t pin, word_t le
current_syscall_error.rangeErrorMax = num_ioapics - 1;
return EXCEPTION_SYSCALL_ERROR;
}
if (pin >= IOAPIC_IRQ_LINES) {
userError("Invalid IOAPIC pin %ld, there are %d pins", (long)pin, IOAPIC_IRQ_LINES);
if (pin >= ioapic_nirqs[ioapic]) {
userError("Invalid IOAPIC pin %ld, there are %d pins", (long)pin, ioapic_nirqs[ioapic]);
current_syscall_error.type = seL4_RangeError;
current_syscall_error.rangeErrorMin = 0;
current_syscall_error.rangeErrorMax = IOAPIC_IRQ_LINES - 1;
current_syscall_error.rangeErrorMax = ioapic_nirqs[ioapic] - 1;
return EXCEPTION_SYSCALL_ERROR;
}