diff --git a/.env b/.env index ab3cca2..8884d6d 100644 --- a/.env +++ b/.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 diff --git a/.gitignore b/.gitignore index bf6638d..34dd279 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/boot +/iso /os.iso /kernel/bin /libk/bin diff --git a/Makefile b/Makefile index c684312..c9fd3aa 100644 --- a/Makefile +++ b/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: diff --git a/kernel/Makefile b/kernel/Makefile index 999498b..d4cbdf4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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 $@ diff --git a/kernel/include/time.h b/kernel/include/time.h new file mode 100644 index 0000000..783d96f --- /dev/null +++ b/kernel/include/time.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +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); diff --git a/kernel/src/boot/tag.c b/kernel/src/boot/tag.c index 22ea758..d4dd0c9 100644 --- a/kernel/src/boot/tag.c +++ b/kernel/src/boot/tag.c @@ -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; diff --git a/kernel/src/boot/tag.h b/kernel/src/boot/tag.h index f9853e5..a81e443 100644 --- a/kernel/src/boot/tag.h +++ b/kernel/src/boot/tag.h @@ -4,7 +4,6 @@ #include #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 }; diff --git a/kernel/src/cpu/fpu.asm b/kernel/src/cpu/fpu.asm index e49ab6f..d03feba 100644 --- a/kernel/src/cpu/fpu.asm +++ b/kernel/src/cpu/fpu.asm @@ -9,7 +9,7 @@ fpu_init: cmp word [test], 0 jne no_fpu - xor eax, 0 + mov eax, 0 ret no_fpu: diff --git a/kernel/src/drivers/cmos.c b/kernel/src/drivers/cmos.c new file mode 100644 index 0000000..5ac12c3 --- /dev/null +++ b/kernel/src/drivers/cmos.c @@ -0,0 +1,138 @@ +#include "print.h" +#include +#include +#include + +#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; +} diff --git a/kernel/src/drivers/vga.c b/kernel/src/drivers/vga.c new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/drivers/vga.h b/kernel/src/drivers/vga.h new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/graphics/framebuffer.h b/kernel/src/graphics/framebuffer.h deleted file mode 100644 index c3b0dc6..0000000 --- a/kernel/src/graphics/framebuffer.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -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)); diff --git a/kernel/src/interrupt/isr.asm b/kernel/src/interrupt/idt.asm similarity index 100% rename from kernel/src/interrupt/isr.asm rename to kernel/src/interrupt/idt.asm diff --git a/kernel/src/interrupt/idt.c b/kernel/src/interrupt/idt.c index 6df3793..aaa7034 100644 --- a/kernel/src/interrupt/idt.c +++ b/kernel/src/interrupt/idt.c @@ -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); } diff --git a/kernel/src/main.c b/kernel/src/main.c index 2a04c24..7c0f221 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -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(); + } } diff --git a/kernel/src/print/time.c b/kernel/src/print/time.c new file mode 100644 index 0000000..7f52a98 --- /dev/null +++ b/kernel/src/print/time.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include + +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'; +} diff --git a/kernel/src/tty/term.c b/kernel/src/tty/term.c index 4f75788..231d38b 100644 --- a/kernel/src/tty/term.c +++ b/kernel/src/tty/term.c @@ -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(); +} diff --git a/kernel/src/tty/term.h b/kernel/src/tty/term.h index f6eb555..ceda255 100644 --- a/kernel/src/tty/term.h +++ b/kernel/src/tty/term.h @@ -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);