Files
jsix/src/kernel/idt.h
Justin C. Miller 5c3943bf38 [kernel] Make grabbing an IST stack atomic
In the beginning of the interrupt handler, we had previously checked if
the current handler had grabbed an IST stack from the IDT/TSS. If it
was, it saved this value and set it to 0 in the IDT, then restored it at
the end.

Now this is an atomic action. This is unlikely to make a difference
unless the interrupt handler is itself interrupted by an exception
before being able to swap the IDT value, but such a situation is now
impossible.
2022-03-13 17:49:29 -07:00

82 lines
2.5 KiB
C++

#pragma once
/// \file idt.h
/// Definitions relating to a CPU's IDT table
#include <stdint.h>
#include "assert.h"
class IDT
{
public:
IDT();
/// Get the currently running CPU's IDT
static IDT & current();
/// Set the global NMI handler. Must happen before creating
/// any IDTs.
static void set_nmi_handler(uintptr_t address);
/// Install this IDT to the current CPU
void install() const;
/// Add the IST entries listed in the ISR table into the IDT.
/// This can't be done until after memory is set up so the
/// stacks can be created.
void add_ist_entries();
/// Get the IST entry used by an entry, clearing it in the process.
/// \arg i Which IDT entry to look in
/// \returns The IST index used by entry i, or 0 for none
inline uint8_t get_ist(uint8_t i) {
return __atomic_exchange_n(&m_entries[i].ist, 0, __ATOMIC_SEQ_CST);
}
/// Restore the IST entry used by an entry when done using it.
/// \arg i Which IDT entry to restore
/// \arg ist The IST index for entry i, or 0 for none
inline void return_ist(uint8_t i, uint8_t ist) {
if (!ist) return;
uint8_t expected = 0;
bool result = __atomic_compare_exchange_n(
&m_entries[i].ist, &expected, ist,
false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
kassert(result, "Tried to overwrite a non-zero IST value in IDT");
}
/// Set the IST entry used by an entry. This should not be called
/// by interrupt handlers.
/// \arg i Which IDT entry to set
/// \arg ist The IST index for entry i, or 0 for none
inline void set_ist(uint8_t i, uint8_t ist) { m_entries[i].ist = ist; }
/// Get the IST entries that are used by this table, as a bitmap
static uint8_t used_ist_entries();
/// Dump debug information about the IDT to the console.
/// \arg index Which entry to print, or -1 for all entries
void dump(unsigned index = -1) const;
private:
void set(uint8_t i, void (*handler)(), uint16_t selector, uint8_t flags);
struct descriptor
{
uint16_t base_low;
uint16_t selector;
uint8_t ist;
uint8_t flags;
uint16_t base_mid;
uint32_t base_high;
uint32_t reserved; // must be zero
} __attribute__ ((packed, aligned(16)));
struct ptr
{
uint16_t limit;
descriptor *base;
} __attribute__ ((packed, aligned(4)));
descriptor m_entries[256];
ptr m_ptr;
};