time
This commit is contained in:
parent
fbf131b5c0
commit
8ad6ef551e
18 changed files with 362 additions and 50 deletions
2
.env
2
.env
|
@ -3,7 +3,7 @@ LD=i386-elf-ld
|
|||
AS=nasm
|
||||
AR=ar
|
||||
|
||||
CFLAGS=-ffreestanding -m32 -O2 -Wall -Wextra -pedantic -DKERNEL_LOG
|
||||
CFLAGS=-ffreestanding -m32 -O2 -Wall -Wextra -pedantic # -DKERNEL_LOG
|
||||
LDFLAGS=-nostdlib
|
||||
|
||||
QEMU=qemu-system-i386
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
/boot
|
||||
/iso
|
||||
/os.iso
|
||||
/kernel/bin
|
||||
/libk/bin
|
||||
|
|
14
Makefile
14
Makefile
|
@ -1,6 +1,6 @@
|
|||
include .env
|
||||
|
||||
.PHONY: all libk kernel
|
||||
.PHONY: all libk kernel clean run
|
||||
|
||||
all: os.iso
|
||||
|
||||
|
@ -11,16 +11,16 @@ kernel:
|
|||
make --directory=kernel
|
||||
|
||||
os.iso: libk kernel
|
||||
rm -fr os.iso
|
||||
mkdir -p boot/grub
|
||||
cp grub.cfg boot/grub
|
||||
cp kernel/bin/kernel.bin boot
|
||||
grub-mkrescue -o os.iso .
|
||||
@rm -fr os.iso
|
||||
@mkdir -p iso/boot/grub
|
||||
cp grub.cfg iso/boot/grub
|
||||
cp kernel/bin/kernel.bin iso/boot
|
||||
grub-mkrescue -o os.iso iso
|
||||
|
||||
clean:
|
||||
make --directory=libk clean
|
||||
make --directory=kernel clean
|
||||
rm -fr boot
|
||||
rm -fr iso
|
||||
rm -fr os.iso
|
||||
|
||||
run:
|
||||
|
|
|
@ -4,7 +4,7 @@ C_SRC = $(shell find src -type f -name "*.c")
|
|||
C_OBJ = $(patsubst %.c,bin/%.o, $(C_SRC))
|
||||
|
||||
ASM_SRC = $(shell find src -type f -name "*.asm")
|
||||
ASM_OBJ = $(patsubst %.asm,bin/%.o, $(ASM_SRC))
|
||||
ASM_OBJ = $(patsubst %.asm,bin/%.asm.o, $(ASM_SRC))
|
||||
|
||||
CFLAGS += -Iinclude -Isrc -I../libk/include -std=gnu17
|
||||
|
||||
|
@ -16,7 +16,7 @@ $(C_OBJ): bin/%.o : %.c
|
|||
@mkdir -p $(@D)
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
$(ASM_OBJ): bin/%.o : %.asm
|
||||
$(ASM_OBJ): bin/%.asm.o : %.asm
|
||||
@mkdir -p $(@D)
|
||||
$(AS) $< -f elf -o $@
|
||||
|
||||
|
|
30
kernel/include/time.h
Normal file
30
kernel/include/time.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct Time {
|
||||
int sec; /// Seconds [0,59]
|
||||
int min; /// Minutes [0,59]
|
||||
int hour; /// Hour [0,23]
|
||||
int mday; /// Day of month [1,31]
|
||||
int mon; /// Month of year [0,11]
|
||||
int year; /// Years since 1900
|
||||
int wday; /// Day of week [0,6] (Sunday = 0)
|
||||
int yday; /// Day of year [0,365]
|
||||
int yn; /// Year number [0,99]
|
||||
int cen; /// Century [19,20]
|
||||
int leap; /// If year is a leap year (True == 1)
|
||||
};
|
||||
|
||||
extern void rtc_update(void);
|
||||
extern void rtc_set_timezone(int offset);
|
||||
extern struct Time *rtc_utctime(void);
|
||||
extern struct Time *rtc_localtime(void);
|
||||
|
||||
/**
|
||||
* Converts the time into a string format
|
||||
* @param time the current time
|
||||
* @param format see manpage for date
|
||||
* @param buf the buffer to store it in
|
||||
*/
|
||||
extern void timetostr(struct Time *time, char *format, char *buf, size_t n);
|
|
@ -4,7 +4,6 @@
|
|||
#include "print.h"
|
||||
#include "tag.h"
|
||||
#include "acpi/acpi.h"
|
||||
#include "graphics/framebuffer.h"
|
||||
#include "memory/memory.h"
|
||||
|
||||
static struct BootInfo info;
|
||||
|
@ -18,12 +17,6 @@ static void read_cmdline(struct BootTag *tag, char *data, uint8_t len) {
|
|||
info.tags[ID_CMDLINE] = *tag;
|
||||
}
|
||||
|
||||
static void read_framebuffer(struct BootTag *tag, uint32_t *data) {
|
||||
debugk("Found framebuffer");
|
||||
tag->data.framebuffer = (struct Framebuffer *) data;
|
||||
info.tags[ID_FRAMEBUFFER] = *tag;;
|
||||
}
|
||||
|
||||
static void read_memorymap(struct BootTag *tag, uint32_t *data) {
|
||||
debugk("Found memorymap");
|
||||
tag->data.memory_map = (struct MemoryMap *) data;
|
||||
|
@ -48,9 +41,6 @@ static uint32_t *read_tag(uint32_t *data) {
|
|||
case ID_CMDLINE:
|
||||
read_cmdline(&tag, (char *)(data + 2), data_len);
|
||||
break;
|
||||
case ID_FRAMEBUFFER:
|
||||
read_framebuffer(&tag, data + 2);
|
||||
break;
|
||||
case iD_MEMORYMAP:
|
||||
read_memorymap(&tag, data + 2);
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "acpi/acpi.h"
|
||||
#include "graphics/framebuffer.h"
|
||||
#include "memory/memory.h"
|
||||
|
||||
#define CMDLINE_MAX 32
|
||||
|
@ -15,7 +14,6 @@ struct BootTag {
|
|||
uint32_t size;
|
||||
union {
|
||||
char cmdline[CMDLINE_MAX];
|
||||
struct Framebuffer *framebuffer;
|
||||
struct MemoryMap *memory_map;
|
||||
struct RootSystemDescriptionPointer *rsdp;
|
||||
} data;
|
||||
|
@ -30,7 +28,6 @@ struct BootInfo {
|
|||
enum BootTagID {
|
||||
ID_CMDLINE = 0,
|
||||
iD_MEMORYMAP = 6,
|
||||
ID_FRAMEBUFFER = 8,
|
||||
ID_RSDP = 14
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ fpu_init:
|
|||
cmp word [test], 0
|
||||
jne no_fpu
|
||||
|
||||
xor eax, 0
|
||||
mov eax, 0
|
||||
ret
|
||||
|
||||
no_fpu:
|
||||
|
|
138
kernel/src/drivers/cmos.c
Normal file
138
kernel/src/drivers/cmos.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
#include "print.h"
|
||||
#include <stdint.h>
|
||||
#include <sys.h>
|
||||
#include <time.h>
|
||||
|
||||
#define CMOS_WRITE_PORT 0x70
|
||||
#define CMOS_READ_PORT 0x71
|
||||
|
||||
#define CMOS_REG_SEC 0x00
|
||||
#define CMOS_REG_MIN 0x02
|
||||
#define CMOS_REG_HOUR 0x04
|
||||
#define CMOS_REG_WDAY 0x06
|
||||
#define CMOS_REG_MDAY 0x07
|
||||
#define CMOS_REG_MON 0x08
|
||||
#define CMOS_REG_YEAR 0x09
|
||||
#define CMOS_REG_CEN 0x32
|
||||
|
||||
static struct Time time;
|
||||
static struct Time localtime;
|
||||
static int cur_offset = 0;
|
||||
|
||||
static uint8_t cmos_read(uint8_t reg) {
|
||||
uint8_t hex, ret;
|
||||
|
||||
outb(CMOS_WRITE_PORT, reg);
|
||||
hex = inb(CMOS_READ_PORT);
|
||||
|
||||
ret = hex & 0x0F;
|
||||
ret += (hex & 0xF0) / 16 * 10;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mday_offset[12] = {
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
||||
};
|
||||
|
||||
static int month_days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
static void update_localtime(void) {
|
||||
|
||||
int change, max;
|
||||
|
||||
// set localtime
|
||||
localtime = time;
|
||||
|
||||
// do we acutally need to do anything
|
||||
if (cur_offset == 0) return;
|
||||
localtime.hour += cur_offset;
|
||||
|
||||
// check if day rolled over
|
||||
change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
|
||||
if (!change) return;
|
||||
|
||||
// roll over day
|
||||
localtime.hour = (localtime.hour + 24) % 24;
|
||||
localtime.wday = (localtime.wday + change + 7) % 7;
|
||||
localtime.mday += change;
|
||||
localtime.yday += change;
|
||||
|
||||
// check if month rolled over
|
||||
max = month_days[localtime.mon];
|
||||
if (localtime.leap && localtime.mon == 1) max++;
|
||||
change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0;
|
||||
if (!change) return;
|
||||
|
||||
// roll over month
|
||||
localtime.mon = (localtime.mon + change + 12) % 12;
|
||||
|
||||
// check if year rolled over
|
||||
max = localtime.leap ? 366 : 365;
|
||||
change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0;
|
||||
if (!change) return;
|
||||
|
||||
// roll over year
|
||||
localtime.yn += change;
|
||||
|
||||
// check if cen rolled over
|
||||
change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0;
|
||||
if (!change) goto year;
|
||||
|
||||
// roll over cen
|
||||
localtime.cen += change;
|
||||
|
||||
|
||||
year:
|
||||
|
||||
localtime.year = localtime.yn + localtime.cen * 100;
|
||||
localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0;
|
||||
|
||||
if (localtime.leap && localtime.yday == -1)
|
||||
localtime.yday = 365;
|
||||
else if (localtime.yday == -1)
|
||||
localtime.yday = 364;
|
||||
else
|
||||
localtime.yday = 0;
|
||||
|
||||
localtime.year -= 1900;
|
||||
|
||||
}
|
||||
|
||||
void rtc_set_timezone(int offset) {
|
||||
cur_offset = offset;
|
||||
}
|
||||
|
||||
void rtc_update(void) {
|
||||
time.sec = cmos_read(CMOS_REG_SEC);
|
||||
time.min = cmos_read(CMOS_REG_MIN);
|
||||
time.hour = cmos_read(CMOS_REG_HOUR);
|
||||
time.wday = cmos_read(CMOS_REG_WDAY) - 1;
|
||||
time.mday = cmos_read(CMOS_REG_MDAY);
|
||||
time.mon = cmos_read(CMOS_REG_MON) - 1;
|
||||
time.yn = cmos_read(CMOS_REG_YEAR);
|
||||
time.cen = 20;
|
||||
|
||||
time.year = time.yn + time.cen * 100;
|
||||
|
||||
time.leap = time.year % 4 == 0 && time.year % 100 != 0;
|
||||
|
||||
time.yday = mday_offset[time.mon] + time.mday;
|
||||
|
||||
if (time.leap && time.mon > 2)
|
||||
time.yday++;
|
||||
|
||||
time.year -= 1900;
|
||||
|
||||
update_localtime();
|
||||
}
|
||||
|
||||
struct Time *rtc_utctime(void) {
|
||||
return &time;
|
||||
}
|
||||
|
||||
struct Time *rtc_localtime(void) {
|
||||
return &localtime;
|
||||
}
|
0
kernel/src/drivers/vga.c
Normal file
0
kernel/src/drivers/vga.c
Normal file
0
kernel/src/drivers/vga.h
Normal file
0
kernel/src/drivers/vga.h
Normal file
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct Framebuffer {
|
||||
uint64_t addr;
|
||||
uint32_t pitch;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t depth;
|
||||
uint8_t type;
|
||||
uint8_t reserved;
|
||||
// struct FramebufferPallete palettes[];
|
||||
|
||||
} __attribute__ ((packed));
|
|
@ -9,25 +9,35 @@
|
|||
#include "acpi/acpi.h"
|
||||
#include "drivers/ps2kb.h"
|
||||
#include "drivers/ps2mouse.h"
|
||||
#include "time.h"
|
||||
#include "tty/color.h"
|
||||
#include "idt.h"
|
||||
#include "pic.h"
|
||||
#include "tty/term.h"
|
||||
|
||||
static int timer = 0;
|
||||
#define WIDTH 30
|
||||
static char buf[WIDTH];
|
||||
static int timer = -1;
|
||||
|
||||
void idt_pic_eoi(uint8_t exception) {
|
||||
pic_eoi(exception - PIC_REMAP_OFFSET);
|
||||
}
|
||||
|
||||
void idt_pic_timer(void) {
|
||||
uint32_t state = term_save();
|
||||
term_setfg(VGA_LIGHT_GREEN);
|
||||
term_setpos(60, 0);
|
||||
puts(" ");
|
||||
term_setpos(60, 0);
|
||||
printk("%d", timer);
|
||||
|
||||
timer += 1;
|
||||
if (timer % 20 != 0) return;
|
||||
|
||||
uint32_t state = term_save();
|
||||
|
||||
term_setfg(VGA_LIGHT_GREEN);
|
||||
term_setpos(TERM_W - WIDTH - 1, 0);
|
||||
for (size_t i = 0; i < WIDTH; i++) putchar(' ');
|
||||
term_setpos(TERM_W - WIDTH - 1, 0);
|
||||
|
||||
timetostr(rtc_localtime(), "%a %b %d %Y %H:%M:%S", buf, WIDTH);
|
||||
printk("%s", buf);
|
||||
|
||||
term_load(state);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "drivers/ps2mouse.h"
|
||||
#include "interrupt/idt.h"
|
||||
#include "interrupt/pic.h"
|
||||
#include "time.h"
|
||||
#include "tty/cursor.h"
|
||||
#include "tty/term.h"
|
||||
|
||||
|
@ -21,6 +22,9 @@ void kernel_main(void* boot_info) {
|
|||
term_init();
|
||||
cursor_enable();
|
||||
|
||||
rtc_set_timezone(-4);
|
||||
rtc_update();
|
||||
|
||||
idt_init();
|
||||
pic_remap(PIC_REMAP_OFFSET);
|
||||
|
||||
|
@ -64,5 +68,8 @@ void kernel_main(void* boot_info) {
|
|||
y = fclamp(y, 0, TERM_H);
|
||||
printk(" x%d y%d\n", (int)x, (int)y);
|
||||
}
|
||||
}
|
||||
|
||||
term_flush();
|
||||
rtc_update();
|
||||
}
|
||||
}
|
||||
|
|
146
kernel/src/print/time.c
Normal file
146
kernel/src/print/time.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static char* ABB_WEEKDAY[7] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
|
||||
static char* FULL_WEEKDAY[7] = {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturady"
|
||||
};
|
||||
|
||||
static char* ABB_MONTH[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
static char* FULL_MONTH[12] = {
|
||||
"January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
|
||||
};
|
||||
|
||||
static char *write_num(unsigned int num, unsigned int pad, char *buf, size_t n) {
|
||||
size_t digits = 1;
|
||||
unsigned int x = num;
|
||||
|
||||
while (x /= 10, x > 0) digits++;
|
||||
if (pad == 0) pad = digits;
|
||||
|
||||
for (size_t i = 0; i < pad; i++) {
|
||||
|
||||
size_t digit;
|
||||
if (i >= digits) {
|
||||
digit = 0;
|
||||
} else {
|
||||
digit = num % 10;
|
||||
num /= 10;
|
||||
}
|
||||
|
||||
if (pad - i - 1 >= n) continue;
|
||||
buf[pad - i - 1] = '0' + digit;
|
||||
|
||||
}
|
||||
|
||||
if (pad > n) pad = n;
|
||||
|
||||
return buf + pad;
|
||||
}
|
||||
|
||||
void timetostr(struct Time *time, char *format, char *buf, size_t n) {
|
||||
char *index = buf;
|
||||
char c;
|
||||
int space;
|
||||
|
||||
while (
|
||||
c = *format++,
|
||||
space = (buf + n) - index,
|
||||
c != '\0' && space > 0
|
||||
) {
|
||||
if (c != '%') {
|
||||
*index++ = c;
|
||||
continue;
|
||||
} else {
|
||||
c = *format++;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '%':
|
||||
*index++ = '%';
|
||||
break;
|
||||
case 'a':
|
||||
index = strncpy(index, ABB_WEEKDAY[time->wday], space);
|
||||
break;
|
||||
case 'A':
|
||||
index = strncpy(index, FULL_WEEKDAY[time->wday], space);
|
||||
break;
|
||||
case 'b':
|
||||
case 'h':
|
||||
index = strncpy(index, ABB_MONTH[time->mon], space);
|
||||
break;
|
||||
case 'B':
|
||||
index = strncpy(index, FULL_MONTH[time->mon], space);
|
||||
break;
|
||||
case 'C':
|
||||
index = write_num(time->cen, 0, index, space);
|
||||
break;
|
||||
case 'd':
|
||||
index = write_num(time->mday, 2, index, space);
|
||||
break;
|
||||
case 'H':
|
||||
index = write_num(time->hour, 2, index, space);
|
||||
break;
|
||||
case 'I':
|
||||
index = write_num((time->hour + 12) % 12 + 1, 2, index, space);
|
||||
break;
|
||||
case 'j':
|
||||
index = write_num(time->yday, 3, index, space);
|
||||
break;
|
||||
case 'm':
|
||||
index = write_num(time->mon + 1, 2, index, space);
|
||||
break;
|
||||
case 'M':
|
||||
index = write_num(time->min, 2, index, space);
|
||||
break;
|
||||
case 'n':
|
||||
*index++ = '\n';
|
||||
break;
|
||||
case 'p':
|
||||
index = strncpy(index, time->hour > 11 ? "PM" : "AM", space);
|
||||
break;
|
||||
case 'P':
|
||||
index = strncpy(index, time->hour > 11 ? "pm" : "am", space);
|
||||
break;
|
||||
case 'q':
|
||||
index = write_num((time->mon + 3) / 3, 0, index, space);
|
||||
break;
|
||||
case 'S':
|
||||
index = write_num(time->sec, 2, index, space);
|
||||
break;
|
||||
case 't':
|
||||
*index++ = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
index = write_num(((time->wday + 1 )% 7) + 1, 0, index, space);
|
||||
break;
|
||||
case 'w':
|
||||
index = write_num(time->wday, 0, index, space);
|
||||
break;
|
||||
case 'y':
|
||||
index = write_num(time->yn, 2, index, space);
|
||||
break;
|
||||
case 'Y':
|
||||
index = write_num(time->year + 1900, 0, index, space);
|
||||
break;
|
||||
default: {
|
||||
char b[3] = {'%', c, '\0'};
|
||||
index = strncpy(index, b, space);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (space < 1)
|
||||
buf[n - 1] = '\0';
|
||||
else
|
||||
*index = '\0';
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
#include "color.h"
|
||||
#include "cursor.h"
|
||||
|
||||
uint16_t *buffer;
|
||||
uint16_t buffer[TERM_W * TERM_H * sizeof(uint16_t)];
|
||||
uint16_t *front;
|
||||
uint8_t x, y;
|
||||
uint8_t color;
|
||||
|
||||
|
@ -27,7 +28,7 @@ static void term_clear_line(int y) {
|
|||
void term_init (void) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
buffer = (uint16_t*) 0xb8000;
|
||||
front = (uint16_t*) 0xb8000;
|
||||
term_setfg(VGA_WHITE);
|
||||
term_setbg(VGA_BLACK);
|
||||
term_clear();
|
||||
|
@ -129,3 +130,9 @@ void putchar(int c) {
|
|||
bool term_newline(void) {
|
||||
return x == 0;
|
||||
}
|
||||
|
||||
void term_flush(void) {
|
||||
int_disable();
|
||||
memcpy(front, buffer, TERM_W * TERM_H * sizeof(uint16_t));
|
||||
int_enable();
|
||||
}
|
||||
|
|
|
@ -25,3 +25,5 @@ uint16_t term_save_col(void);
|
|||
void term_load_col(uint16_t color);
|
||||
|
||||
bool term_newline(void);
|
||||
|
||||
void term_flush(void);
|
||||
|
|
Loading…
Reference in a new issue