Luna/kernel/src/arch/Timer.cpp

140 lines
3.6 KiB
C++
Raw Normal View History

2022-11-19 19:01:01 +00:00
#include "arch/Timer.h"
2022-11-30 16:16:36 +00:00
#include "Log.h"
#include "arch/Serial.h"
#include "boot/bootboot.h"
2022-11-19 19:01:01 +00:00
static u64 timer_ticks = 0;
static u64 boot_timestamp;
static inline constexpr bool isleap(u32 year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
static constexpr u32 make_yday(u32 year, u32 month)
{
constexpr u16 upto[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
u32 yd = upto[month - 1];
if (month > 2 && isleap(year)) yd++;
return yd;
}
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16
2022-12-05 15:43:52 +00:00
static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec)
{
return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
}
// The bootloader encodes the date and time in Binary-Coded Decimal (BCD), which represents decimal digits using
// hexadecimal digits. For example, BCD 0x22 is 22 in decimal.
// https://gitlab.com/bztsrc/bootboot/-/blob/master/bootboot_spec_1st_ed.pdf, page 15.
static inline constexpr u32 bcd_number_to_decimal(u32 num)
{
return ((num >> 4) * 10) + (num & 0xf);
}
static u64 bootloader_time_to_unix(const u8 boottime[8])
{
const u32 year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]);
const u32 month = bcd_number_to_decimal(boottime[2]);
const u32 day = bcd_number_to_decimal(boottime[3]);
const u32 hour = bcd_number_to_decimal(boottime[4]);
const u32 minute = bcd_number_to_decimal(boottime[5]);
const u32 second = bcd_number_to_decimal(boottime[6]);
// "The last byte can store 1/100th second precision, but in lack of support on most platforms, it is 0x00".
// Therefore, let's not rely on it.
2022-12-05 15:41:39 +00:00
kinfoln("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC", day, month, year, hour, minute, second);
return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second);
}
extern const BOOTBOOT bootboot;
2022-11-19 19:01:01 +00:00
namespace Timer
{
void tick()
{
timer_ticks++;
}
2022-12-07 13:31:40 +00:00
usize raw_ticks()
{
return timer_ticks;
}
2022-11-19 19:01:01 +00:00
usize ticks()
{
return ticks_ms() / 1000;
}
usize ticks_ms()
{
return timer_ticks / ARCH_TIMER_FREQ;
}
usize ticks_us() // We want a bit of precision; if there are 10 ticks/ms, do not return the truncated ms value *
// 1000, but ticks * 100 (1000/10), which is more precise
{
if constexpr (ARCH_TIMER_FREQ > 1000) return timer_ticks / (ARCH_TIMER_FREQ / 1000);
else
return timer_ticks * (1000 / ARCH_TIMER_FREQ);
2022-11-19 19:01:01 +00:00
}
usize ticks_ns()
{
return ticks_us() * 1000;
}
usize boot()
{
return boot_timestamp;
}
usize boot_ms()
{
return boot_timestamp * MS_PER_SECOND;
}
usize boot_us()
{
return boot_timestamp * US_PER_SECOND;
}
usize boot_ns()
{
return boot_timestamp * NS_PER_SECOND;
}
usize clock()
{
return boot() + ticks();
}
usize clock_ms()
{
return boot_ms() + ticks_ms();
}
usize clock_us()
{
return boot_us() + ticks_us();
}
usize clock_ns()
{
return boot_ns() + ticks_ns();
}
void init()
{
boot_timestamp = bootloader_time_to_unix(bootboot.datetime);
2022-11-19 19:01:01 +00:00
arch_init();
}
2022-12-07 11:15:30 +00:00
}
bool should_invoke_scheduler()
{
2022-12-07 13:31:40 +00:00
// FIXME: Modulo is SLOW. We're calling this every tick.
2022-12-07 11:15:30 +00:00
return (timer_ticks % ARCH_TIMER_FREQ) == 0;
2022-11-19 19:01:01 +00:00
}