more stuff
This commit is contained in:
+2
-2
@@ -15,7 +15,7 @@ static bool use_hpet = true;
|
||||
static void hpet_option(bool use) {
|
||||
use_hpet = use;
|
||||
}
|
||||
CMDLINE_OPTION("hpet", hpet_option);
|
||||
CMDLINE_OPTION("x86_64.hpet", "Enable High Precision Event Timer clock", hpet_option);
|
||||
|
||||
struct hpet {
|
||||
struct clock clock;
|
||||
@@ -64,7 +64,7 @@ void hpet_init() {
|
||||
hpet_clock.regs = (void*)vaddr;
|
||||
|
||||
uacpi_table_unref(&table);
|
||||
log("x86_64/hpet", "HPET registers mapped at %p\n", hpet_clock.regs);
|
||||
log("x86_64/hpet: HPET registers mapped at %p\n", hpet_clock.regs);
|
||||
|
||||
mmio_write64(hpet_clock.regs + HPET_CFG, mmio_read64(hpet_clock.regs + HPET_CFG) | 1);
|
||||
|
||||
|
||||
+3
-4
@@ -5,6 +5,7 @@
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <arch/sched.h>
|
||||
#include <bits/sched.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -36,6 +37,7 @@ void interrupt_handler(struct arch_context* ctx) {
|
||||
bool old = irq_set_interrupted(true);
|
||||
|
||||
uint64_t isr = ctx->isr;
|
||||
|
||||
switch (isr) {
|
||||
case IDT_PF:
|
||||
uint64_t cr2;
|
||||
@@ -48,13 +50,10 @@ void interrupt_handler(struct arch_context* ctx) {
|
||||
sched_reschedule(&cpu->sched);
|
||||
}
|
||||
break;
|
||||
case 0x20 ...(0x20 + ARRAY_SIZE(cpu->arch.irq_lines)):
|
||||
default:
|
||||
struct irq_line* line = cpu->arch.irq_lines[isr - 0x20];
|
||||
assert(line, "Unhandled interrupt on ISR %lu\n", isr);
|
||||
// TODO: irq_raise(line);
|
||||
break;
|
||||
default:
|
||||
panic("Unhandled exception on ISR %lu\n", isr);
|
||||
}
|
||||
|
||||
irq_set_interrupted(old);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <zinnia/pmap.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/vma.h>
|
||||
#include <arch/sched.h>
|
||||
#include <bits/sched.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
+43
-13
@@ -1,17 +1,52 @@
|
||||
#include <zinnia/clock.h>
|
||||
#include <zinnia/cmdline.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <stdint.h>
|
||||
#include <x86_64/asm.h>
|
||||
#include <x86_64/defs.h>
|
||||
|
||||
static bool use_tsc = true;
|
||||
static void tsc_option(bool opt) {
|
||||
use_tsc = opt;
|
||||
}
|
||||
CMDLINE_OPTION("x86_64.tsc", "Enable timestamp counter", tsc_option);
|
||||
|
||||
constexpr uint64_t nanos_per_sec = 1'000'000'000;
|
||||
static uint64_t tsc_freq = 0;
|
||||
static uint64_t tsc_base_cycles = 0;
|
||||
|
||||
static uint64_t cycles_to_ns(uint64_t cycles, uint64_t freq) {
|
||||
uint64_t seconds = cycles / freq;
|
||||
uint64_t remaining_cycles = cycles % freq;
|
||||
uint64_t fractional_ns = (uint64_t)((__uint128_t)remaining_cycles * (__uint128_t)nanos_per_sec / (__uint128_t)freq);
|
||||
uint64_t ns = seconds * nanos_per_sec + fractional_ns;
|
||||
|
||||
return MIN(ns, UINT64_MAX);
|
||||
}
|
||||
|
||||
static void tsc_reset(struct clock* clock) {
|
||||
tsc_base_cycles = asm_rdtsc();
|
||||
}
|
||||
|
||||
static uint64_t tsc_get_elapsed_ns(struct clock* clock) {
|
||||
uint64_t cycles = asm_rdtsc() - tsc_base_cycles;
|
||||
return cycles_to_ns(cycles, tsc_freq);
|
||||
}
|
||||
|
||||
static struct clock tsc_clock = {
|
||||
.name = "tsc",
|
||||
.priority = 255,
|
||||
.reset = tsc_reset,
|
||||
.get_elapsed_ns = tsc_get_elapsed_ns,
|
||||
};
|
||||
|
||||
void tsc_init() {
|
||||
if (!use_tsc)
|
||||
return;
|
||||
|
||||
if (!(asm_cpuid(1, 0).edx & CPUID_1D_TSC) || !(asm_cpuid(0x8000'0007, 0).edx & (1 << 8))) {
|
||||
log("x86_64/tsc", "No invariant TSC detected!\n");
|
||||
log("x86_64/tsc: No invariant TSC detected!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,33 +57,28 @@ void tsc_init() {
|
||||
tsc_leaf = asm_cpuid(0x15, 0);
|
||||
}
|
||||
|
||||
uint64_t freq = 0;
|
||||
if (clock_available()) {
|
||||
// Calibrate using existing clock.
|
||||
uint64_t t1 = asm_rdtsc();
|
||||
clock_spin_ns(10'000'000);
|
||||
uint64_t t2 = asm_rdtsc();
|
||||
freq = (t2 - t1) * 100;
|
||||
tsc_freq = (t2 - t1) * 100;
|
||||
} else if (has_tsc_leaf) {
|
||||
// If we have no timer (yet), the only way we can calibrate the TSC is if CPUID gives us the frequency.
|
||||
// On a normal system, this should usually never be called and is a last resort
|
||||
// since at this point we have at least the HPET timer.
|
||||
if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) {
|
||||
log("x86_64/tsc", "Calibrating TSC using CPUID 0x15");
|
||||
freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
|
||||
log("x86_64/tsc: Calibrating TSC using CPUID 0x15");
|
||||
tsc_freq = tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
|
||||
} else {
|
||||
log("x86_64/tsc", "Unable to calibrate TSC using CPUID frequency information");
|
||||
log("x86_64/tsc: Unable to calibrate TSC using CPUID frequency information");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
log("x86_64/tsc", "Unable to calibrate the TSC without a clock or static frequency info!\n");
|
||||
log("x86_64/tsc: Unable to calibrate the TSC without a clock or static frequency info!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
log("x86_64/tsc", "Timer frequency is %lu MHz\n", freq / 1'000'000);
|
||||
log("x86_64/tsc: Timer frequency is %lu MHz\n", tsc_freq / 1'000'000);
|
||||
clock_switch(&tsc_clock);
|
||||
}
|
||||
|
||||
static void tsc_option(bool opt) {
|
||||
use_tsc = opt;
|
||||
}
|
||||
CMDLINE_OPTION("x86_64.tsc", tsc_option);
|
||||
|
||||
Reference in New Issue
Block a user