APIC timer calibration
Now the APIC timer is calibrated against the PIT, and the interval for timer_enable takes a number of microseconds instead of raw ticks and a divisor.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
|
#include "io.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
|
|
||||||
@@ -50,7 +51,46 @@ lapic::lapic(uint32_t *base, isr spurious) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapic::enable_timer(isr vector, uint8_t divisor, uint32_t count, bool repeat)
|
lapic::calibrate_timer()
|
||||||
|
{
|
||||||
|
interrupts_disable();
|
||||||
|
|
||||||
|
log::info(logs::apic, "Calibrating APIC timer...");
|
||||||
|
|
||||||
|
// Set up PIT sleep
|
||||||
|
uint8_t command = 0x30; // channel 0, loybyte/highbyte, mode 0
|
||||||
|
outb(0x43, command);
|
||||||
|
|
||||||
|
const uint32_t initial = -1u;
|
||||||
|
enable_timer_internal(isr::isrIgnore0, 1, initial, false);
|
||||||
|
|
||||||
|
const int iterations = 5;
|
||||||
|
for (int i=0; i<iterations; ++i) {
|
||||||
|
const uint16_t pit_33ms = 39375;
|
||||||
|
uint16_t pit_count = pit_33ms;
|
||||||
|
outb(0x40, pit_count & 0xff);
|
||||||
|
io_wait();
|
||||||
|
outb(0x40, (pit_count >> 8) & 0xff);
|
||||||
|
|
||||||
|
|
||||||
|
while (pit_count <= pit_33ms) {
|
||||||
|
outb(0x43, 0); // latch counter values
|
||||||
|
pit_count =
|
||||||
|
static_cast<uint16_t>(inb(0x40)) |
|
||||||
|
static_cast<uint16_t>(inb(0x40)) << 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t remain = stop_timer();
|
||||||
|
uint32_t ticks_total = initial - remain;
|
||||||
|
m_ticks_per_us = ticks_total / (iterations * 33000);
|
||||||
|
log::info(logs::apic, "APIC timer ticks %d times per nanosecond.", m_ticks_per_us);
|
||||||
|
|
||||||
|
interrupts_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
lapic::enable_timer_internal(isr vector, uint8_t divisor, uint32_t count, bool repeat)
|
||||||
{
|
{
|
||||||
uint32_t divbits = 0;
|
uint32_t divbits = 0;
|
||||||
|
|
||||||
@@ -76,12 +116,28 @@ lapic::enable_timer(isr vector, uint8_t divisor, uint32_t count, bool repeat)
|
|||||||
apic_write(m_base, 0x3e0, divbits);
|
apic_write(m_base, 0x3e0, divbits);
|
||||||
|
|
||||||
reset_timer(count);
|
reset_timer(count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
lapic::enable_timer(isr vector, uint64_t interval, bool repeat)
|
||||||
|
{
|
||||||
|
uint64_t ticks = interval * m_ticks_per_us;
|
||||||
|
|
||||||
|
int divisor = 1;
|
||||||
|
while (ticks > -1u) {
|
||||||
|
ticks /= 2;
|
||||||
|
divisor *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug(logs::apic, "Enabling APIC timer count %ld, divisor %d.", ticks, divisor);
|
||||||
|
return enable_timer_internal(vector, divisor, static_cast<uint32_t>(ticks), repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
lapic::reset_timer(uint32_t count)
|
lapic::reset_timer(uint32_t count)
|
||||||
{
|
{
|
||||||
uint32_t remaining = apic_read(m_base, 0x380);
|
uint32_t remaining = apic_read(m_base, 0x390);
|
||||||
apic_write(m_base, 0x380, count);
|
apic_write(m_base, 0x380, count);
|
||||||
return remaining;
|
return remaining;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ public:
|
|||||||
|
|
||||||
/// Enable interrupts for the LAPIC timer.
|
/// Enable interrupts for the LAPIC timer.
|
||||||
/// \arg vector Interrupt vector the timer should use
|
/// \arg vector Interrupt vector the timer should use
|
||||||
/// \arg divisor The frequency divisor of the bus Hz (power of 2, <= 128)
|
/// \arg interval The timer interval, in microseconds
|
||||||
/// \arg count The count of ticks before an interrupt
|
|
||||||
/// \arg repeat If false, this timer is one-off, otherwise repeating
|
/// \arg repeat If false, this timer is one-off, otherwise repeating
|
||||||
void enable_timer(isr vector, uint8_t divisor, uint32_t count, bool repeat = true);
|
/// \returns The count of ticks the timer is set for
|
||||||
|
uint32_t enable_timer(isr vector, uint64_t interval, bool repeat = true);
|
||||||
|
|
||||||
/// Reset the timer countdown.
|
/// Reset the timer countdown.
|
||||||
/// \arg count The count of ticks before an interrupt, or 0 to stop the timer
|
/// \arg count The count of ticks before an interrupt, or 0 to stop the timer
|
||||||
@@ -55,6 +55,14 @@ public:
|
|||||||
|
|
||||||
void enable(); ///< Enable servicing of interrupts
|
void enable(); ///< Enable servicing of interrupts
|
||||||
void disable(); ///< Disable (temporarily) servicing of interrupts
|
void disable(); ///< Disable (temporarily) servicing of interrupts
|
||||||
|
|
||||||
|
/// Calibrate the timer speed against the PIT
|
||||||
|
void calibrate_timer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t enable_timer_internal(isr vector, uint8_t divisor, uint32_t count, bool repeat);
|
||||||
|
|
||||||
|
uint32_t m_ticks_per_us;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,6 @@ acpi_table_header::validate(uint32_t expected_type) const
|
|||||||
|
|
||||||
void irq2_callback(void *)
|
void irq2_callback(void *)
|
||||||
{
|
{
|
||||||
console *cons = console::get();
|
|
||||||
cons->set_color(11);
|
|
||||||
cons->puts(".");
|
|
||||||
cons->set_color();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq4_callback(void *)
|
void irq4_callback(void *)
|
||||||
@@ -212,8 +208,6 @@ device_manager::load_apic(const acpi_apic *apic)
|
|||||||
p += length;
|
p += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// m_lapic->enable_timer(isr::isrTimer, 128, 3000000);
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < m_ioapics[0]->get_num_gsi(); ++i) {
|
for (uint8_t i = 0; i < m_ioapics[0]->get_num_gsi(); ++i) {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 2: break;
|
case 2: break;
|
||||||
@@ -221,7 +215,6 @@ device_manager::load_apic(const acpi_apic *apic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ioapics[0]->dump_redirs();
|
|
||||||
m_lapic->enable();
|
m_lapic->enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "kutil/memory.h"
|
#include "kutil/memory.h"
|
||||||
|
#include "apic.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -12,6 +13,9 @@
|
|||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
|
static const uint16_t PIC1 = 0x20;
|
||||||
|
static const uint16_t PIC2 = 0xa0;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void _halt();
|
void _halt();
|
||||||
|
|
||||||
@@ -58,12 +62,9 @@ get_irq(unsigned vector)
|
|||||||
static void
|
static void
|
||||||
disable_legacy_pic()
|
disable_legacy_pic()
|
||||||
{
|
{
|
||||||
static const uint16_t PIC1 = 0x20;
|
|
||||||
static const uint16_t PIC2 = 0xa0;
|
|
||||||
|
|
||||||
// Mask all interrupts
|
// Mask all interrupts
|
||||||
outb(0xa1, 0xff);
|
outb(PIC2+1, 0xfc);
|
||||||
outb(0x21, 0xff);
|
outb(PIC1+1, 0xff);
|
||||||
|
|
||||||
// Start initialization sequence
|
// Start initialization sequence
|
||||||
outb(PIC1, 0x11); io_wait();
|
outb(PIC1, 0x11); io_wait();
|
||||||
@@ -71,7 +72,7 @@ disable_legacy_pic()
|
|||||||
|
|
||||||
// Remap into ignore ISRs
|
// Remap into ignore ISRs
|
||||||
outb(PIC1+1, static_cast<uint8_t>(isr::isrIgnore0)); io_wait();
|
outb(PIC1+1, static_cast<uint8_t>(isr::isrIgnore0)); io_wait();
|
||||||
outb(PIC2+1, static_cast<uint8_t>(isr::isrIgnore0)); io_wait();
|
outb(PIC2+1, static_cast<uint8_t>(isr::isrIgnore8)); io_wait();
|
||||||
|
|
||||||
// Tell PICs about each other
|
// Tell PICs about each other
|
||||||
outb(PIC1+1, 0x04); io_wait();
|
outb(PIC1+1, 0x04); io_wait();
|
||||||
@@ -110,29 +111,6 @@ isr_handler(addr_t return_rsp, cpu_state regs)
|
|||||||
console *cons = console::get();
|
console *cons = console::get();
|
||||||
|
|
||||||
switch (static_cast<isr>(regs.interrupt & 0xff)) {
|
switch (static_cast<isr>(regs.interrupt & 0xff)) {
|
||||||
case isr::isrTimer: {
|
|
||||||
scheduler &s = scheduler::get();
|
|
||||||
return_rsp = s.tick(return_rsp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case isr::isrLINT0:
|
|
||||||
cons->puts("\nLINT0\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case isr::isrLINT1:
|
|
||||||
cons->puts("\nLINT1\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case isr::isrIgnore0:
|
|
||||||
case isr::isrIgnore1:
|
|
||||||
case isr::isrIgnore2:
|
|
||||||
case isr::isrIgnore3:
|
|
||||||
case isr::isrIgnore4:
|
|
||||||
case isr::isrIgnore5:
|
|
||||||
case isr::isrIgnore6:
|
|
||||||
case isr::isrIgnore7:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case isr::isrGPFault: {
|
case isr::isrGPFault: {
|
||||||
cons->set_color(9);
|
cons->set_color(9);
|
||||||
@@ -199,6 +177,20 @@ isr_handler(addr_t return_rsp, cpu_state regs)
|
|||||||
_halt();
|
_halt();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isr::isrTimer: {
|
||||||
|
scheduler &s = scheduler::get();
|
||||||
|
return_rsp = s.tick(return_rsp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case isr::isrLINT0:
|
||||||
|
cons->puts("\nLINT0\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case isr::isrLINT1:
|
||||||
|
cons->puts("\nLINT1\n");
|
||||||
|
break;
|
||||||
|
|
||||||
case isr::isrAssert: {
|
case isr::isrAssert: {
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
print_regs(regs);
|
print_regs(regs);
|
||||||
@@ -212,6 +204,31 @@ isr_handler(addr_t return_rsp, cpu_state regs)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isr::isrIgnore0:
|
||||||
|
case isr::isrIgnore1:
|
||||||
|
case isr::isrIgnore2:
|
||||||
|
case isr::isrIgnore3:
|
||||||
|
case isr::isrIgnore4:
|
||||||
|
case isr::isrIgnore5:
|
||||||
|
case isr::isrIgnore6:
|
||||||
|
case isr::isrIgnore7:
|
||||||
|
//cons->printf("\nIGNORED: %02x\n", regs.interrupt);
|
||||||
|
outb(PIC1, 0x20);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case isr::isrIgnore8:
|
||||||
|
case isr::isrIgnore9:
|
||||||
|
case isr::isrIgnoreA:
|
||||||
|
case isr::isrIgnoreB:
|
||||||
|
case isr::isrIgnoreC:
|
||||||
|
case isr::isrIgnoreD:
|
||||||
|
case isr::isrIgnoreE:
|
||||||
|
case isr::isrIgnoreF:
|
||||||
|
//cons->printf("\nIGNORED: %02x\n", regs.interrupt);
|
||||||
|
outb(PIC1, 0x20);
|
||||||
|
outb(PIC2, 0x20);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cons->set_color(9);
|
cons->set_color(9);
|
||||||
cons->printf("\nReceived %02x interrupt:\n",
|
cons->printf("\nReceived %02x interrupt:\n",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "initrd/initrd.h"
|
#include "initrd/initrd.h"
|
||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
#include "kutil/memory.h"
|
#include "kutil/memory.h"
|
||||||
|
#include "apic.h"
|
||||||
#include "block_device.h"
|
#include "block_device.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
@@ -22,7 +23,6 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void kernel_main(popcorn_data *header);
|
void kernel_main(popcorn_data *header);
|
||||||
|
|
||||||
void *__bss_start, *__bss_end;
|
void *__bss_start, *__bss_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ init_console()
|
|||||||
cons->puts(GIT_VERSION " booting...\n");
|
cons->puts(GIT_VERSION " booting...\n");
|
||||||
|
|
||||||
log::init(cons);
|
log::init(cons);
|
||||||
log::enable(logs::apic, log::level::info);
|
log::enable(logs::apic, log::level::debug);
|
||||||
log::enable(logs::device, log::level::info);
|
log::enable(logs::device, log::level::info);
|
||||||
log::enable(logs::driver, log::level::debug);
|
log::enable(logs::driver, log::level::debug);
|
||||||
log::enable(logs::memory, log::level::info);
|
log::enable(logs::memory, log::level::info);
|
||||||
@@ -141,13 +141,17 @@ kernel_main(popcorn_data *header)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
devices->get_lapic()->calibrate_timer();
|
||||||
|
|
||||||
syscall_enable();
|
syscall_enable();
|
||||||
scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic());
|
scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic());
|
||||||
|
|
||||||
|
/*
|
||||||
for (auto &f : ird.files()) {
|
for (auto &f : ird.files()) {
|
||||||
if (f.executable())
|
if (f.executable())
|
||||||
sched->create_process(f.name(), f.data(), f.size());
|
sched->create_process(f.name(), f.data(), f.size());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
sched->start();
|
sched->start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
|
|
||||||
scheduler scheduler::s_instance(nullptr);
|
scheduler scheduler::s_instance(nullptr);
|
||||||
static const uint32_t quantum = 2000000;
|
static const uint64_t quantum_micros = 1000000;
|
||||||
//static const uint32_t quantum = 20000000;
|
//static const uint32_t quantum_micros = 20000000;
|
||||||
|
|
||||||
const int stack_size = 0x1000;
|
const int stack_size = 0x1000;
|
||||||
const uint64_t rflags_noint = 0x002;
|
const uint64_t rflags_noint = 0x002;
|
||||||
@@ -174,7 +174,7 @@ void
|
|||||||
scheduler::start()
|
scheduler::start()
|
||||||
{
|
{
|
||||||
log::info(logs::task, "Starting scheduler.");
|
log::info(logs::task, "Starting scheduler.");
|
||||||
m_apic->enable_timer(isr::isrTimer, 128, quantum, false);
|
m_tick_count = m_apic->enable_timer(isr::isrTimer, quantum_micros, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scheduler::prune(uint64_t now)
|
void scheduler::prune(uint64_t now)
|
||||||
@@ -274,7 +274,7 @@ scheduler::tick(addr_t rsp0)
|
|||||||
// TODO: action based on the task using the whole quantum
|
// TODO: action based on the task using the whole quantum
|
||||||
|
|
||||||
rsp0 = schedule(rsp0);
|
rsp0 = schedule(rsp0);
|
||||||
m_apic->reset_timer(quantum);
|
m_apic->reset_timer(m_tick_count);
|
||||||
return rsp0;
|
return rsp0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ private:
|
|||||||
lapic *m_apic;
|
lapic *m_apic;
|
||||||
|
|
||||||
uint32_t m_next_pid;
|
uint32_t m_next_pid;
|
||||||
|
uint32_t m_tick_count;
|
||||||
|
|
||||||
using process_slab = kutil::slab_allocator<process>;
|
using process_slab = kutil::slab_allocator<process>;
|
||||||
process_slab m_process_allocator;
|
process_slab m_process_allocator;
|
||||||
|
|||||||
Reference in New Issue
Block a user