summaryrefslogtreecommitdiff
path: root/kernel/src/drivers/kvmtimer.cpp
blob: 302e03d40890dcc33347a428f8c956f8a989c390 (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
53
54

#include <cstdint>

#include <drivers/kvmtimer.hpp>
#include <generic/time.hpp>
#include <etc/assembly.hpp>
#include <etc/etc.hpp>

#include <etc/logging.hpp>

#include <generic/mm/pmm.hpp>

struct pvclock_vcpu_time_info* kvmclock_info;

extern std::uint16_t KERNEL_GOOD_TIMER;

void drivers::kvmclock::init() {

    std::uint32_t a,b,c,d;

    __cpuid(0x40000000,0,&a,&b,&c,&d);
    if(b != 0x4b4d564b || d != 0x4d || c != 0x564b4d56)
        return;

    __cpuid(0x40000001,0,&a,&b,&c,&d);
    if(!(a & (1 << 3)))
        return;

    KERNEL_GOOD_TIMER = KVM_TIMER;

    kvmclock_info = (struct pvclock_vcpu_time_info*)memory::pmm::_virtual::alloc(4096);

    __wrmsr(0x4b564d01,(std::uint64_t)Other::toPhys(kvmclock_info) | 1);
    Log::Display(LEVEL_MESSAGE_OK,"KVMClock initializied\n");

}

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

std::uint64_t drivers::kvmclock::currentnano() {
    std::uint64_t time0 = __rdtsc() - kvmclock_info->tsc_timestamp;
    if(kvmclock_info->tsc_shift >= 0)
        time0 <<= kvmclock_info->tsc_shift;
    else
        time0 >>= -kvmclock_info->tsc_shift;
    time0 = (time0 * kvmclock_info->tsc_to_system_mul) >> 32;
    time0 = time0 + kvmclock_info->system_time;
    return time0;
}