Add time stuff

This commit is contained in:
mintsuki 2020-04-30 21:19:12 +02:00
parent 6ad7df109b
commit 8db7cdcbd1
7 changed files with 94 additions and 3 deletions

View File

@ -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));
```

Binary file not shown.

View File

@ -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;

View File

@ -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);

44
src/lib/time.c Normal file
View File

@ -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);
}

8
src/lib/time.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __LIB__TIME_H__
#define __LIB__TIME_H__
#include <stdint.h>
uint64_t time(void);
#endif

View File

@ -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;