λ

furix

cute os

settings

arch/x86_64/ioapic.c

1780 bytes raw

#include <ioapic.h>

#include <io.h>
#include <types.h>

/* IO-APIC indirect register file */
#define IOAPIC_REGSEL 0x00
#define IOAPIC_WINDOW 0x10

#define REG_ID 0x00
#define REG_VER 0x01
#define REG_REDIR 0x10

/* bit 16 of a redirection entry masks that input */
#define REDIR_MASKED (1u << 16)

/* redirection entry count lives in the version register's bits 23:16 */
#define IOAPIC_MAX_ENTRIES 24

static volatile uint32_t *ioapic(void) {
  return (volatile uint32_t *)(uint64_t)IOAPIC_DEFAULT_BASE;
}

static uint32_t ioapic_read(uint32_t reg) {
  /*
   * index-then-read: writing the register number to REGSEL selects it, and the
   * selected register is then read from WINDOW.
   */
  *ioapic() = reg;
  return *(volatile uint32_t *)((uint64_t)IOAPIC_DEFAULT_BASE + IOAPIC_WINDOW);
}

static void ioapic_write(uint32_t reg, uint32_t value) {
  *ioapic() = reg;
  *(volatile uint32_t *)((uint64_t)IOAPIC_DEFAULT_BASE + IOAPIC_WINDOW) = value;
}

void ioapic_disarm(void) {
  uint32_t entries;
  uint32_t i;

  /*
   * mask first, before trusting the version register. entries are masked one
   * at a time, so if anything is already routed it stops as soon as we reach
   * it.
   */
  for (i = 0; i < IOAPIC_MAX_ENTRIES; i++) {
    uint32_t entry = ioapic_read(REG_REDIR + 2 * i);

    ioapic_write(REG_REDIR + 2 * i, entry | REDIR_MASKED);
  }

  /* the version register encodes the entry count in bits 23:16 */
  entries = (ioapic_read(REG_VER) >> 16) & 0xFF;

  if (entries == 0 || entries > IOAPIC_MAX_ENTRIES) {
    /* no usable count: mask everything the array can hold */
    entries = IOAPIC_MAX_ENTRIES;
  }

  for (i = 0; i < entries; i++) {
    uint32_t entry = ioapic_read(REG_REDIR + 2 * i);

    ioapic_write(REG_REDIR + 2 * i, entry | REDIR_MASKED);
  }
}