:: commit 8db7cdcbd18176c3d0f3b576211922a0837d417b

mintsuki <mintsuki@protonmail.com> — 2020-04-30 19:19

parents: 6ad7df109b

Add time stuff

diff --git a/STIVALE.md b/STIVALE.md
index e6f20d84..b475c226 100644
--- a/STIVALE.md
+++ b/STIVALE.md
@@ -2,15 +2,18 @@
 
 The stivale boot protocol aims to be a *simple* to implement protocol which
 provides the kernel with most of the features one may need in a *modern*
-x86_64 context.
+x86_64 context (although 32-bit x86 is also supported).
 
 ## General information
 
 In order to have a stivale compliant kernel, one must have a kernel executable
-in the `elf64` format and have a `.stivalehdr` section (described below).
+in the `elf64` or `elf32` format and have a `.stivalehdr` section (described below).
 Other executable formats are not supported.
 
-stivale natively supports and encourages higher half kernels.
+stivale will recognise whether the ELF file is 32-bit or 64-bit and load the kernel
+into the appropriate CPU mode.
+
+stivale natively supports (only for 64-bit kernels) and encourages higher half kernels.
 The kernel can load itself at `0xffffffff80100000` (as defined in the linker script)
 and the bootloader will take care of everything, no AT linker script directives needed.
 
@@ -27,6 +30,8 @@ The kernel MUST NOT request to load itself at an address lower than `0x100000`
 
 ## Kernel entry machine state
 
+### 64-bit kernel
+
 `rip` will be the entry point as defined in the ELF file.
 
 At entry, the bootloader will have setup paging such that there is a 4GiB identity
@@ -58,6 +63,29 @@ The A20 gate is enabled.
 
 `rdi` will point to the stivale structure (described below).
 
+### 32-bit kernel
+
+`eip` will be the entry point as defined in the ELF file.
+
+At entry all segment registers are loaded as 32 bit code/data segments.
+All segment bases are `0x00000000` and all limits are `0xffffffff`.
+
+DO NOT reload segment registers or rely on the provided GDT. The kernel MUST load
+its own GDT as soon as possible and not rely on the bootloader's.
+
+The IDT is in an undefined state. Kernel must load its own.
+
+IF flag, VM flag, and direction flag are cleared on entry. Other flags undefined.
+
+PE is enabled (`cr0`).
+
+The A20 gate is enabled.
+
+`esp` is set to the requested stack as per stivale header.
+
+A pointer to the stivale structure (described below) is pushed onto this stack
+before the entry point is called.
+
 ## stivale header (.stivalehdr)
 
 The kernel executable shall have a section `.stivalehdr` which will contain
@@ -96,6 +124,7 @@ struct stivale_struct {
     uint64_t rsdp;                  // Pointer to the ACPI RSDP structure
     uint64_t module_count;          // Count of modules that stivale loaded according to config
     uint64_t modules;               // Pointer to the first entry in the linked list of modules (described below)
+    uint64_t epoch;                 // UNIX epoch at boot, read from system RTC
 } __attribute__((packed));
 ```
 
diff --git a/qloader2.bin b/qloader2.bin
index a1ea8530..185ecb8f 100644
Binary files a/qloader2.bin and b/qloader2.bin differ
diff --git a/src/lib/blib.c b/src/lib/blib.c
index 3d0c7678..53821780 100644
--- a/src/lib/blib.c
+++ b/src/lib/blib.c
@@ -8,6 +8,10 @@
 #include <lib/real.h>
 #include <lib/cio.h>
 
+uint8_t bcd_to_int(uint8_t val) {
+    return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
+}
+
 int cpuid(uint32_t leaf, uint32_t subleaf,
           uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
     uint32_t cpuid_max;
diff --git a/src/lib/blib.h b/src/lib/blib.h
index 781366aa..a69d6d90 100644
--- a/src/lib/blib.h
+++ b/src/lib/blib.h
@@ -4,6 +4,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+uint8_t bcd_to_int(uint8_t val);
+
 int cpuid(uint32_t leaf, uint32_t subleaf,
           uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
 
diff --git a/src/lib/time.c b/src/lib/time.c
new file mode 100644
index 00000000..7120dc95
--- /dev/null
+++ b/src/lib/time.c
@@ -0,0 +1,44 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <lib/time.h>
+#include <lib/real.h>
+#include <lib/blib.h>
+
+// Julian date calculation from https://en.wikipedia.org/wiki/Julian_day
+static uint64_t get_jdn(uint8_t days, uint8_t months, uint16_t years) {
+    return (1461 * (years + 4800 + (months - 14)/12))/4 + (367 *
+           (months - 2 - 12 * ((months - 14)/12)))/12 -
+           (3 * ((years + 4900 + (months - 14)/12)/100))/4
+           + days - 32075;
+}
+
+static uint64_t get_unix_epoch(uint8_t seconds, uint8_t minutes, uint8_t  hours,
+                               uint8_t days,    uint8_t months,  uint16_t years) {
+    uint64_t jdn_current = get_jdn(days, months, years);
+    uint64_t jdn_1970    = get_jdn(1, 1, 1970);
+
+    uint64_t jdn_diff = jdn_current - jdn_1970;
+
+    return (jdn_diff * (60 * 60 * 24)) + hours * 3600 + minutes * 60 + seconds;
+}
+
+uint64_t time(void) {
+    struct rm_regs r = {0};
+
+    r.eax = 0x0400;
+    rm_int(0x1a, &r, &r);
+
+    uint8_t  day    = bcd_to_int( r.edx & 0x00ff);
+    uint8_t  month  = bcd_to_int((r.edx & 0xff00) >> 8);
+    uint16_t year   = bcd_to_int( r.ecx & 0x00ff) +
+    /* century */     bcd_to_int((r.ecx & 0xff00) >> 8) * 100;
+
+    r.eax = 0x0200;
+    rm_int(0x1a, &r, &r);
+
+    uint8_t second  = bcd_to_int((r.edx & 0xff00) >> 8);
+    uint8_t minute  = bcd_to_int( r.ecx & 0x00ff);
+    uint8_t hour    = bcd_to_int((r.ecx & 0xff00) >> 8);
+
+    return get_unix_epoch(second, minute, hour, day, month, year);
+}
diff --git a/src/lib/time.h b/src/lib/time.h
new file mode 100644
index 00000000..60da1a3d
--- /dev/null
+++ b/src/lib/time.h
@@ -0,0 +1,8 @@
+#ifndef __LIB__TIME_H__
+#define __LIB__TIME_H__
+
+#include <stdint.h>
+
+uint64_t time(void);
+
+#endif
diff --git a/src/protos/stivale.c b/src/protos/stivale.c
index 2fa9bcf6..148f69eb 100644
--- a/src/protos/stivale.c
+++ b/src/protos/stivale.c
@@ -6,6 +6,7 @@
 #include <lib/acpi.h>
 #include <lib/e820.h>
 #include <lib/config.h>
+#include <lib/time.h>
 #include <drivers/vbe.h>
 #include <drivers/vga_textmode.h>
 #include <fs/file.h>
@@ -39,6 +40,7 @@ struct stivale_struct {
     uint64_t rsdp;
     uint64_t module_count;
     uint64_t modules;
+    uint64_t epoch;
 } __attribute__((packed));
 
 struct stivale_struct stivale_struct = {0};
@@ -146,6 +148,8 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
 
     stivale_struct.cmdline = (uint64_t)(size_t)cmdline;
 
+    stivale_struct.epoch = time();
+
     stivale_struct.framebuffer_width  = stivale_hdr.framebuffer_width;
     stivale_struct.framebuffer_height = stivale_hdr.framebuffer_height;
     stivale_struct.framebuffer_bpp    = stivale_hdr.framebuffer_bpp;
tab: 248 wrap: offon