Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
apic_timer.c
Go to the documentation of this file.
1#include <hal/cpu/core.h>
2#include "hal/cpu/cpuid.h"
3#include "hal/cpu/interrupt.h"
4#include "hal/cpu/msr.h"
5#include "hal/timer/timer.h"
6#include "init/init.h"
7#include "libk/io.h"
8#include "libk/serial.h"
9#include <hal/acpi/hpet.h>
10#include <hal/apic/apic.h>
11
13
16
18
20 uint32_t eax, edx;
21 __asm__ volatile("rdtsc" : "=a"(eax), "=d"(edx));
22 return ((uint64_t) edx << 32) | eax;
23}
24
25// static void calibrate_tsmc_backend(interrupt_stack_frame_t* _) {
26// tsmc_calibrated = 1;
27// }
28
29// static boolean_t vxAPICIsTSMCSupported() {
30// uint32_t eax, ebx, ecx, edx;
31// cpuid(1, 0, &eax, &ebx, &ecx, &edx);
32// return (ecx & (1 << 24)) != 0;
33// }
34
36 uint32_t edx, unused;
37 cpuid(0x80000007, 0, &unused, &unused, &unused, &edx);
38 return edx & (1 << 8);
39}
40
42
43 for (uint64_t i = 0; i < 5; i++) {
45
46 LOG2_DEBUG("APIC_TIMER", "[APIC] calibrating core %d....",
47 get_current_core_data()->core_id);
49 // TODO: buat utility untuk handle ini
50 // hpet_write(HPET_MAIN_COUNT, 0);
52
53 time_counter_t counter = {0};
54 init_timer_counter(&counter);
55 // LOG2_INFO("APIC TIMER", "ok");
56
59
60 // Tunggu 1000 us (1ms) — pakai integer, bukan 1e3
61 while (get_timer_counter_count(&counter) < 1000)
62 ;
63
64 // us → ns: bagi 1000, bukan kali 1e-3
65 uint64_t elapsed_time_us =
66 get_timer_counter_count_ns(&counter) / 1000;
67
68 uint64_t elapsed_test =
69 0xFFFFFFFF - apic_read(TIMER_CURRENT_COUNT);
70
71 // error_ratio = 1 / elapsed_time_us dalam integer tidak berguna
72 // (selalu 0 karena integer division)
73 // Ganti: hitung ticks per us langsung
74 // elapsed_test ticks terjadi dalam elapsed_time_us us
75 // ticks per us = elapsed_test / elapsed_time_us
76 uint64_t ticks_per_us = 0;
77 if (elapsed_time_us > 0)
78 ticks_per_us = elapsed_test / elapsed_time_us;
79
80 // Running average
82 (calibrated_ticks_1ns * i + ticks_per_us) / (i + 1);
83 }
84
85 LOG2_DEBUG("APIC_TIMER", "[APIC] calibrated apic timer 1ms done.");
86}
87
88// static void vxAPICTimerCalibrationUsingPIT() {
89// outb((0x43), 0b00010100);
90// uint16_t reload_value = (uint16_t) (1193182 / 20);
91// outb((0X40), reload_value & 0xFF);
92// outb((0X40), (reload_value >> 8) & 0xFF);
93
94// serial_trace("PIT Reload Value : %d\n", reload_value);
95// apic_write(TIMER_INITIAL_COUNT, 0xFFFFFFFF);
96// apic_write(TIMER_DIVIDE_CONFIG, 0x3);
97// apic_write(LVT_TIMER, 0x20000 | 48);
98
99// uint32_t __start = apic_read(0x390);
100// serial_trace("APIC Timer Start : %d\n", __start);
101
102// uint16_t pit_status;
103// do {
104// outb(0x43, 0x00);
105// pit_status = inb(0x40);
106// pit_status |= inb(0x40) << 8;
107// } while ((pit_status & 0x20) == 0);
108
109// uint32_t __end = apic_read(0x390);
110// serial_trace("APIC Timer End : %d\n", __end);
111// uint32_t freq = (__start - __end) * 20;
112// calibrated_ticks_1ns = freq;
113// serial_trace("APIC Timer Frequency : %d\n", freq);
114// }
115
116// static void vxTSCTimerCalibration() {
117// uint64_t tick_ns = vxHPETMinTickNs();
118
119// if (!vxAPICIsTSMCSupported()) {
120// LOG_DEBUG("APIC_TIMER", "TSMC is Not supported");
121// return;
122// }
123
124// hpet_disable();
125// // TODO: buat utility untuk handle ini
126// // hpet_write(HPET_MAIN_COUNT, 0);
127// hpet_enable();
128
129// uint64_t hpet_tickss = ms2ns(1) / tick_ns;
130// uint64_t hpet_start = vxHPETGetMainCount();
131// uint64_t tsc_start = vxAPICReadTSC();
132
133// while ((vxHPETGetMainCount() - hpet_start) < hpet_tickss)
134// ;
135
136// uint64_t tsc_end = vxAPICReadTSC();
137
138// // Sebelum: (tsc_end - tsc_start) / 1e6 → FPU/SSE
139// // tsc_end - tsc_start = ticks selama 1ms
140// // freq per ms = ticks / 1ms
141// // bagi 1000 untuk dapat per us, bagi 1000000 untuk per ns
142// // calibrated_tsmc_freq_1ms = ticks per ms, simpan apa adanya
143// calibrated_tsmc_freq_1ms = (tsc_end - tsc_start);
144
145// LOG_DEBUG("APIC_TIMER", "[APIC] calibrated TSC timer 1ms done.");
146// }
147
149 if (get_current_core_cpuid() == 0) {
151 } else {
152 while (__atomic_load_n(&calibrated_ticks_1ns, __ATOMIC_ACQUIRE)
153 == 0)
154 __asm__ volatile("pause");
155 }
156}
157
158#define APIC_TIMER_MASKED (1 << 16)
159
160#define APIC_TIMER_MIN_VECTOR 0x20
161
164 LOG_ERROR("APIC_TIMER", "Invalid timer type: 0x%x", type);
165 return;
166 }
167
169 LOG_ERROR("APIC_TIMER", "Invalid vector: 0x%x", vector);
170 return;
171 }
172
173 if (interval_us == 0) {
174 LOG_ERROR("APIC_TIMER", "Interval must be > 0");
175 return;
176 }
177
178 if (calibrated_ticks_1ns == 0) {
179 LOG_ERROR("APIC_TIMER", "APIC timer not calibrated");
180 return;
181 }
182
183 // calibrated_ticks_1ns = ticks per us (hasil kalibrasi baru)
184 // count = ticks per us * interval_us
185 uint64_t count = calibrated_ticks_1ns * interval_us;
186
187 if (count > 0xFFFFFFFF) {
188 LOG_WARN("APIC_TIMER", "Interval too long, truncated");
189 count = 0xFFFFFFFF;
190 }
191
193
194 uint32_t lvt = (vector & 0xFF) | type | APIC_TIMER_MASKED;
195 apic_write(LVT_TIMER, lvt);
196
197 lvt = apic_read(LVT_TIMER);
200}
201
204
205 // Sebelum: calibrated_tsmc_freq_1ms * freq_us → double
206 // calibrated_tsmc_freq_1ms = ticks per 1ms = ticks per 1000us
207 // ticks per us = calibrated_tsmc_freq_1ms / 1000
208 // tsc_delta = (calibrated_tsmc_freq_1ms / 1000) * freq_us
209 // Gunakan urutan perkalian dulu untuk hindari precision loss
210 const uint64_t tsc_delta = (calibrated_tsmc_freq_1ms * freq_us) / 1000;
211
212 const uint64_t deadline = vxAPICReadTSC() + tsc_delta;
213 vxWRSR(0x6E0, deadline);
214}
uint8_t x2_apic_supported
Definition apic.c:16
void apic_write(uint32_t reg, uint32_t value)
Definition apic.c:40
uint32_t apic_read(uint32_t reg)
Definition apic.c:49
#define APIC_TIMER_DEADLINE
Definition apic.h:23
#define APIC_TIMER_PERIOD
Definition apic.h:21
#define TIMER_DIVIDE_CONFIG
Definition apic.h:19
#define TIMER_INITIAL_COUNT
Definition apic.h:18
#define LVT_TIMER
Definition apic.h:17
#define TIMER_CURRENT_COUNT
Definition apic.h:20
#define APIC_TIMER_ONE_SHOT
Definition apic.h:22
#define APIC_TIMER_MASKED
Definition apic_timer.c:158
void vxAPICCreateTimer(uint32_t type, uint64_t interval_us, uint16_t vector)
Definition apic_timer.c:162
void vxInitializeAPICTimer()
Definition apic_timer.c:148
void vxAPICCreateDeadlineTimer(const uint8_t vector, const uint64_t freq_us)
Definition apic_timer.c:202
static uint64_t calibrated_tsmc_freq_1ms
Definition apic_timer.c:15
static void vxAPICTimerCalibrationUsingHPET()
Definition apic_timer.c:41
bool vxTSChasInvariant(void)
Definition apic_timer.c:35
static uint64_t vxAPICReadTSC()
Definition apic_timer.c:19
static uint64_t calibrated_ticks_1ns
Definition apic_timer.c:14
int count
Definition cache.h:2
each_core_data * get_current_core_data(void)
Definition core.c:54
void cpuid(uint32_t leaf, uint32_t subleaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
Definition cpuid.c:4
void hpet_disable()
Definition hpet.c:32
void hpet_enable()
Definition hpet.c:26
uint8_t get_current_core_cpuid()
void vxWRSR(uint32_t msr, uint64_t value)
Definition msr.c:3
#define LOG_ERROR(mod, fmt,...)
Definition serial.h:25
#define LOG_WARN(mod, fmt,...)
Definition serial.h:27
#define LOG2_DEBUG(mod, fmt,...)
Definition serial.h:35
uint64_t get_timer_counter_count_ns(time_counter_t *counter)
Definition timer.c:69
void init_timer_counter(time_counter_t *counter)
Definition timer.c:56
uint64_t get_timer_counter_count(time_counter_t *counter)
Definition timer.c:60
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
unsigned long uint64_t
Definition type.h:25
unsigned char uint8_t
Definition type.h:7
#define vector(T)
Definition vector.h:11
uint8_t type
Definition vnode.h:2