summaryrefslogtreecommitdiff
path: root/kernel/src/drivers/hpet.cpp
blob: 20e92b828549cc87e946503c283957d3fb04a760 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

#include <cstdint>
#include <drivers/hpet.hpp>

#include <arch/x86_64/interrupts/pit.hpp>

std::uint64_t hpet_base,hpet_clock_nano;
std::uint8_t hpet_is_32_bit = 0;

#include <uacpi/uacpi.h>
#include <uacpi/tables.h>
#include <uacpi/status.h>
#include <uacpi/acpi.h>

#include <etc/logging.hpp>

#include <generic/mm/paging.hpp>

#include <generic/time.hpp>

#include <etc/etc.hpp>

std::uint64_t __hpet_timestamp() {
    return hpet_is_32_bit ? *(volatile uint32_t*)(hpet_base + 0xf0) : *(volatile uint64_t*)(hpet_base + 0xf0);
}

std::uint64_t drivers::hpet::nanocurrent() {
    return __hpet_timestamp() * hpet_clock_nano;
}

extern std::uint16_t KERNEL_GOOD_TIMER;

void drivers::hpet::init() {
    uacpi_table hpet;
    uacpi_status ret = uacpi_table_find_by_signature("HPET",&hpet);
    assert(ret == UACPI_STATUS_OK,"HPET required to get working orange");
    struct acpi_hpet* hpet_table = ((struct acpi_hpet*)hpet.virt_addr);
    hpet_base = (std::uint64_t)Other::toVirt(hpet_table->address.address);
    memory::paging::kernelmap(0,hpet_table->address.address);

    *(volatile std::uint64_t*)(hpet_base + 0x10) |= 1;
    hpet_is_32_bit = (*(volatile uint64_t*)hpet_base & (1 << 13)) ? 0 : 1;
    hpet_clock_nano = (*(volatile uint32_t*)(hpet_base + 4)) / 1000000;

}

void drivers::hpet::sleep(std::uint64_t us) {
    std::uint64_t start = __hpet_timestamp();
    std::uint64_t conv = us * 1000;
    while((__hpet_timestamp() - start) * hpet_clock_nano < conv)
        asm volatile("nop");
}