summaryrefslogtreecommitdiff
path: root/kernel/src/arch/x86_64/cpu/lapic.cpp
blob: da98bfdf2cc4c88e0849d78bc1fa7dc1f0cb409c (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
55
56
57
58
59
60
61
#include <cstdint>
#include <arch/x86_64/cpu/lapic.hpp>
#include <arch/x86_64/assembly.hpp>
#include <generic/time.hpp>

std::uint32_t x86_64::lapic::id() {
    if(is_x2apic) {
        return read(0x20);
    } else {
        return read(0x20) >> 24;
    }
}

void x86_64::lapic::eoi() {
    write(0xB0,0);
}

void x86_64::lapic::tick(std::uint64_t tick) { 
    write(0x380,tick);
}

void x86_64::lapic::off() {
    uint32_t icr_low = (0x3 << 18) | (0x5 << 8) | (1 << 14);
    write(0x300, icr_low); 
}

std::uint64_t x86_64::lapic::init(std::uint32_t us) {
    std::uint32_t a,b,c,d;
    assembly::cpuid(1,0,&a,&b,&c,&d);

    static bool is_print = 0;

    if(c & (1 << 21)) {
                            // x2apic present
        if(!is_print) log("x2apic", "enabling x2apic (base is 0x%p)",0x800);
        assembly::wrmsr(0x1B,assembly::rdmsr(0x1B) | (1 << 10) | (1 << 11));
        is_x2apic = 1;
    } else {
        assembly::wrmsr(0x1B,assembly::rdmsr(0x1B));
    }

                        
    paging::map_range(gobject::kernel_root,assembly::rdmsr(0x1B) & 0xFFFFF000,(assembly::rdmsr(0x1B) & 0xFFFFF000) + etc::hhdm(),PAGE_SIZE, PAGING_PRESENT | PAGING_RW);
    write(0xf0,0xff | 0x100);
    write(0x3e0,1);
    write(0x320,32 | (1 << 16));
    write(0x380,0xFFFFFFFF);
    time::timer->sleep(us);
    std::uint64_t ticks = 0xFFFFFFFF - read(0x390);
    write(0x320, 32 | (1 << 17));
    write(0x3e0,1);
    write(0x380,ticks);

    if(!is_lapic_init) {
        if(!is_print) log("lapic", "calibration time is %lli, ticks %lli",us,ticks);
        is_print = 1;
        is_lapic_init = 1;
    }

    return ticks;
}