From 43e26e583ca92524fd5993cc20b6d84fb9da5d8d Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 20 Nov 2022 18:30:40 +0100 Subject: [PATCH] Calculate the boot timestamp in UNIX time for further usage --- kernel/src/arch/Timer.cpp | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/kernel/src/arch/Timer.cpp b/kernel/src/arch/Timer.cpp index c06b003c..e9694a2c 100644 --- a/kernel/src/arch/Timer.cpp +++ b/kernel/src/arch/Timer.cpp @@ -1,8 +1,58 @@ #include "arch/Timer.h" +#include "arch/Serial.h" +#include "boot/bootboot.h" +#include static u64 timer_ticks = 0; static u64 boot_timestamp; +static int isleap(int year) +{ + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +} + +static int make_yday(int year, int month) +{ + static const short int upto[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + int yd; + + 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 +static 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 int bcd_number_to_decimal(int num) +{ + return ((num >> 4) * 10) + (num & 0xf); +} + +static u64 bootloader_time_to_unix(u8 boottime[8]) +{ + int year = bcd_number_to_decimal(boottime[0]) * 100 + bcd_number_to_decimal(boottime[1]); + int month = bcd_number_to_decimal(boottime[2]); + int day = bcd_number_to_decimal(boottime[3]); + int hour = bcd_number_to_decimal(boottime[4]); + int minute = bcd_number_to_decimal(boottime[5]); + int 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. + Serial::printf("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC\n", day, month, year, hour, minute, second) + .release_value(); + return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second); +} + +extern BOOTBOOT bootboot; + namespace Timer { void tick() @@ -75,6 +125,7 @@ namespace Timer void init() { + boot_timestamp = bootloader_time_to_unix(bootboot.datetime); arch_init(); } } \ No newline at end of file