Fix user apps randomly crashing (APIC, GDT layout, syscall entry)
All checks were successful
Build documentation / build-and-deploy (push) Successful in 23s
All checks were successful
Build documentation / build-and-deploy (push) Successful in 23s
This commit is contained in:
@@ -30,46 +30,87 @@ static uint64_t hpet_period_fs;
|
||||
/* Lock, which protects concurrent access. See amd64/smp.c */
|
||||
static spin_lock_t hpet_lock = SPIN_LOCK_INIT;
|
||||
|
||||
/* Read a HPET register. Assumes caller holds \ref hpet_lock */
|
||||
static uint64_t amd64_hpet_read (uint32_t reg) {
|
||||
/* Read a HPET register. Assumes caller holds hpet_lock */
|
||||
static uint64_t amd64_hpet_read64 (uint32_t reg) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
uintptr_t hpet_vaddr = hpet_paddr + (uintptr_t)hhdm->offset;
|
||||
return (hpet_32bits ? *(volatile uint32_t*)(hpet_vaddr + reg)
|
||||
: *(volatile uint64_t*)(hpet_vaddr + reg));
|
||||
return *(volatile uint64_t*)(hpet_vaddr + reg);
|
||||
}
|
||||
|
||||
/* Write a HPET register. Assumes caller holds \ref hpet_lock */
|
||||
static void amd64_hpet_write (uint32_t reg, uint64_t value) {
|
||||
static uint32_t amd64_hpet_read32 (uint32_t reg) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
uintptr_t hpet_vaddr = hpet_paddr + (uintptr_t)hhdm->offset;
|
||||
if (hpet_32bits)
|
||||
*(volatile uint32_t*)(hpet_vaddr + reg) = (value & 0xFFFFFFFF);
|
||||
else
|
||||
*(volatile uint64_t*)(hpet_vaddr + reg) = value;
|
||||
return *(volatile uint32_t*)(hpet_vaddr + reg);
|
||||
}
|
||||
|
||||
/* Read current value of \ref HPET_MCVR register. */
|
||||
static uint64_t amd64_hpet_timestamp (void) { return amd64_hpet_read (HPET_MCVR); }
|
||||
/* Write a HPET register. Assumes caller holds hpet_lock */
|
||||
static void amd64_hpet_write64 (uint32_t reg, uint64_t value) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
uintptr_t hpet_vaddr = hpet_paddr + (uintptr_t)hhdm->offset;
|
||||
*(volatile uint64_t*)(hpet_vaddr + reg) = value;
|
||||
}
|
||||
|
||||
static void amd64_hpet_write32 (uint32_t reg, uint32_t value) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
uintptr_t hpet_vaddr = hpet_paddr + (uintptr_t)hhdm->offset;
|
||||
*(volatile uint32_t*)(hpet_vaddr + reg) = value;
|
||||
}
|
||||
|
||||
/* Read current value of HPET_MCVR register. */
|
||||
|
||||
static uint64_t amd64_hpet_read_counter (void) {
|
||||
uint64_t value;
|
||||
|
||||
spin_lock (&hpet_lock);
|
||||
|
||||
if (!hpet_32bits)
|
||||
value = amd64_hpet_read64 (HPET_MCVR);
|
||||
else {
|
||||
uint32_t hi1, lo, hi2;
|
||||
do {
|
||||
hi1 = amd64_hpet_read32 (HPET_MCVR + 4);
|
||||
lo = amd64_hpet_read32 (HPET_MCVR + 0);
|
||||
hi2 = amd64_hpet_read32 (HPET_MCVR + 4);
|
||||
} while (hi1 != hi2);
|
||||
|
||||
value = ((uint64_t)hi1 << 32) | lo;
|
||||
}
|
||||
|
||||
spin_unlock (&hpet_lock);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void amd64_hpet_write_counter (uint64_t value) {
|
||||
spin_lock (&hpet_lock);
|
||||
|
||||
if (!hpet_32bits)
|
||||
amd64_hpet_write64 (HPET_MCVR, value);
|
||||
else {
|
||||
amd64_hpet_write32 (HPET_MCVR, (uint32_t)value);
|
||||
amd64_hpet_write32 (HPET_MCVR + 4, (uint32_t)(value >> 32));
|
||||
}
|
||||
|
||||
spin_unlock (&hpet_lock);
|
||||
}
|
||||
|
||||
/* Sleep for a given amount of microseconds. This time can last longer due to \ref hpet_lock being
|
||||
* held. */
|
||||
void amd64_hpet_sleep_micro (uint64_t us) {
|
||||
spin_lock (&hpet_lock);
|
||||
if (hpet_period_fs == 0)
|
||||
return;
|
||||
|
||||
uint64_t start = amd64_hpet_timestamp ();
|
||||
uint64_t target_fs = us * 1000000000ULL;
|
||||
uint64_t ticks_to_wait = (us * 1000ULL) / (hpet_period_fs / 1000000ULL);
|
||||
uint64_t start = amd64_hpet_read_counter ();
|
||||
|
||||
for (;;) {
|
||||
uint64_t current = amd64_hpet_timestamp ();
|
||||
uint64_t dt = current - start;
|
||||
uint64_t now = amd64_hpet_read_counter ();
|
||||
|
||||
if ((dt * hpet_period_fs) >= target_fs)
|
||||
if ((now - start) >= ticks_to_wait)
|
||||
break;
|
||||
|
||||
__asm__ volatile ("pause" ::: "memory");
|
||||
}
|
||||
|
||||
spin_unlock (&hpet_lock);
|
||||
}
|
||||
|
||||
/* Initialize HPET */
|
||||
@@ -88,19 +129,12 @@ void amd64_hpet_init (void) {
|
||||
mm_map_kernel_page (hpet_paddr, (uintptr_t)hhdm->offset + hpet_paddr,
|
||||
MM_PG_PRESENT | MM_PG_RW | MM_PD_RELOAD);
|
||||
|
||||
hpet_32bits = (amd64_hpet_read (HPET_GCIDR) & (1 << 13)) ? 0 : 1;
|
||||
uint64_t caps = amd64_hpet_read64 (HPET_GCIDR);
|
||||
hpet_32bits = (caps & (1 << 13)) ? 0 : 1;
|
||||
|
||||
/* reset */
|
||||
amd64_hpet_write (HPET_GCR, 0);
|
||||
amd64_hpet_write (HPET_MCVR, 0);
|
||||
amd64_hpet_write (HPET_GCR, 1);
|
||||
hpet_period_fs = (uint32_t)(caps >> 32);
|
||||
|
||||
uint64_t gcidr = amd64_hpet_read (HPET_GCIDR);
|
||||
if (hpet_32bits) {
|
||||
uint32_t low = (uint32_t)gcidr;
|
||||
uint32_t high = (uint32_t)amd64_hpet_read (HPET_GCIDR + 4);
|
||||
gcidr = (((uint64_t)high << 32) | low);
|
||||
}
|
||||
|
||||
hpet_period_fs = (gcidr >> 32);
|
||||
amd64_hpet_write64 (HPET_GCR, 0);
|
||||
amd64_hpet_write_counter (0);
|
||||
amd64_hpet_write64 (HPET_GCR, 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user