:: limine / common / lib / time.c 2.0 KB raw

1
#include <stddef.h>
2
#include <stdint.h>
3
#include <lib/time.h>
4
#if defined (BIOS)
5
#  include <lib/real.h>
6
#elif defined (UEFI)
7
#  include <efi.h>
8
#endif
9
#include <lib/misc.h>
10
11
// Julian date calculation from https://en.wikipedia.org/wiki/Julian_day
12
static int get_jdn(int days, int months, int years) {
13
    return (1461 * (years + 4800 + (months - 14)/12))/4 + (367 *
14
           (months - 2 - 12 * ((months - 14)/12)))/12 -
15
           (3 * ((years + 4900 + (months - 14)/12)/100))/4
16
           + days - 32075;
17
}
18
19
static uint64_t get_unix_epoch(uint8_t seconds, uint8_t minutes, uint8_t  hours,
20
                               uint8_t days,    uint8_t months,  uint16_t years) {
21
    uint64_t jdn_current = get_jdn(days, months, years);
22
    uint64_t jdn_1970    = get_jdn(1, 1, 1970);
23
24
    uint64_t jdn_diff = jdn_current - jdn_1970;
25
26
    return (jdn_diff * (60 * 60 * 24)) + hours * 3600 + minutes * 60 + seconds;
27
}
28
29
#if defined (BIOS)
30
uint64_t time(void) {
31
    struct rm_regs r;
32
33
again:
34
    r = (struct rm_regs){0};
35
    r.eax = 0x0400;
36
    rm_int(0x1a, &r, &r);
37
38
    uint8_t  day    = bcd_to_int( r.edx & 0x00ff);
39
    uint8_t  month  = bcd_to_int((r.edx & 0xff00) >> 8);
40
    uint16_t year   = bcd_to_int( r.ecx & 0x00ff) +
41
    /* century */     bcd_to_int((r.ecx & 0xff00) >> 8) * 100;
42
43
    r = (struct rm_regs){0};
44
    r.eax = 0x0200;
45
    rm_int(0x1a, &r, &r);
46
47
    uint8_t second  = bcd_to_int((r.edx & 0xff00) >> 8);
48
    uint8_t minute  = bcd_to_int( r.ecx & 0x00ff);
49
    uint8_t hour    = bcd_to_int((r.ecx & 0xff00) >> 8);
50
51
    // Check RTC day wraparound
52
    r = (struct rm_regs){0};
53
    r.eax = 0x0400;
54
    rm_int(0x1a, &r, &r);
55
    if (bcd_to_int(r.edx & 0x00ff) != day) {
56
        goto again;
57
    }
58
59
    return get_unix_epoch(second, minute, hour, day, month, year);
60
}
61
#endif
62
63
#if defined (UEFI)
64
uint64_t time(void) {
65
    EFI_TIME time;
66
    EFI_STATUS status = gRT->GetTime(&time, NULL);
67
68
    if (status != 0) {
69
        return 0;
70
    }
71
72
    return get_unix_epoch(time.Second, time.Minute, time.Hour,
73
                          time.Day, time.Month, time.Year);
74
}
75
#endif
tab: 248 wrap: offon