Instead of many timer interrupts and decrementing a process' remaining quanta, change to setting a single timer for when a process should be preempted. If it uses its whole timeslice, demote it. If it uses less than half before blocking, promote it. Determine timeslice based on priority as well. This change also required changing the apic timer interface to be purely interval (in microseconds) based instead of its previous interval/tick hybrid.
119 lines
3.4 KiB
C++
119 lines
3.4 KiB
C++
#pragma once
|
|
/// \file apic.h
|
|
/// Classes to control both local and I/O APICs.
|
|
|
|
#include <stdint.h>
|
|
|
|
enum class isr : uint8_t;
|
|
|
|
|
|
/// Base class for other APIC types
|
|
class apic
|
|
{
|
|
public:
|
|
/// Constructor
|
|
/// \arg base Base virtual address of the APIC's MMIO registers
|
|
apic(uint32_t *base);
|
|
|
|
protected:
|
|
uint32_t *m_base;
|
|
};
|
|
|
|
|
|
/// Controller for processor-local APICs
|
|
class lapic :
|
|
public apic
|
|
{
|
|
public:
|
|
/// Constructor
|
|
/// \arg base Base virtual address of the APIC's MMIO registers
|
|
/// \arg spurious Vector of the spurious interrupt handler
|
|
lapic(uint32_t *base, isr spurious);
|
|
|
|
/// Enable interrupts for the LAPIC timer.
|
|
/// \arg vector Interrupt vector the timer should use
|
|
/// \arg repeat If false, this timer is one-off, otherwise repeating
|
|
void enable_timer(isr vector, bool repeat = true);
|
|
|
|
/// Reset the timer countdown.
|
|
/// \arg interval The interval in us before an interrupt, or 0 to stop the timer
|
|
/// \returns The interval in us that was remaining before reset
|
|
uint32_t reset_timer(uint64_t interval);
|
|
|
|
/// Stop the timer.
|
|
/// \returns The interval in us remaining before an interrupt was to happen
|
|
inline uint32_t stop_timer() { return reset_timer(0); }
|
|
|
|
/// Enable interrupts for the LAPIC LINT0 pin.
|
|
/// \arg num Local interrupt number (0 or 1)
|
|
/// \arg vector Interrupt vector LINT0 should use
|
|
/// \arg nmi Whether this interrupt is NMI delivery mode
|
|
/// \arg flags Flags for mode/polarity (ACPI MPS INTI flags)
|
|
void enable_lint(uint8_t num, isr vector, bool nmi, uint16_t flags);
|
|
|
|
void enable(); ///< Enable servicing of interrupts
|
|
void disable(); ///< Disable (temporarily) servicing of interrupts
|
|
|
|
/// Calibrate the timer speed against the PIT
|
|
void calibrate_timer();
|
|
|
|
private:
|
|
inline uint64_t ticks_to_us(uint32_t ticks) const {
|
|
return static_cast<uint64_t>(ticks) / m_ticks_per_us;
|
|
}
|
|
|
|
inline uint64_t us_to_ticks(uint64_t interval) const {
|
|
return interval * m_ticks_per_us;
|
|
}
|
|
|
|
void set_divisor(uint8_t divisor);
|
|
void set_repeat(bool repeat);
|
|
uint32_t enable_timer_internal(isr vector, uint8_t divisor, uint32_t count, bool repeat);
|
|
|
|
uint32_t m_divisor;
|
|
uint32_t m_ticks_per_us;
|
|
};
|
|
|
|
|
|
/// Controller for I/O APICs
|
|
class ioapic :
|
|
public apic
|
|
{
|
|
public:
|
|
/// Constructor
|
|
/// \arg base Base virtual address of the APIC's MMIO registers
|
|
/// \arg base_gsi Starting global system interrupt number of this IOAPIC
|
|
ioapic(uint32_t *base, uint32_t base_gsi);
|
|
|
|
uint32_t get_base_gsi() const { return m_base_gsi; }
|
|
uint32_t get_num_gsi() const { return m_num_gsi; }
|
|
|
|
/// Set a redirection entry.
|
|
/// TODO: pick CPU
|
|
/// \arg source Source interrupt number
|
|
/// \arg vector Interrupt vector that should be used
|
|
/// \arg flags Flags for mode/polarity (ACPI MPS INTI flags)
|
|
/// \arg masked Whether the iterrupt should be suppressed
|
|
void redirect(uint8_t irq, isr vector, uint16_t flags, bool masked);
|
|
|
|
/// Mask or unmask an interrupt to stop/start having it sent to the CPU
|
|
/// \arg irq The IOAPIC-local irq number
|
|
/// \arg masked Whether to suppress this interrupt
|
|
void mask(uint8_t irq, bool masked);
|
|
|
|
/// Mask all interrupts on this IOAPIC.
|
|
void mask_all() { for(int i=0; i<m_num_gsi; ++i) mask(i, true); }
|
|
|
|
/// Unmask all interrupts on this IOAPIC.
|
|
void unmask_all() { for(int i=0; i<m_num_gsi; ++i) mask(i, false); }
|
|
|
|
void dump_redirs() const;
|
|
|
|
private:
|
|
uint32_t m_base_gsi;
|
|
uint32_t m_num_gsi;
|
|
|
|
uint8_t m_id;
|
|
uint8_t m_version;
|
|
};
|