From 7ded523eb32d037b22c0159f3e493c1529c1a053 Mon Sep 17 00:00:00 2001 From: Jon Feldman Date: Sun, 19 Feb 2017 20:39:03 -0500 Subject: [PATCH] Basic template-ish shit --- Makefile | 44 +++++++++++++++++ common/kernel_main.c | 39 +++++++++++++++ i686/entry.S | 33 +++++++++++++ i686/include/utils.h | 7 +++ i686/link.ld | 43 +++++++++++++++++ i686/utils.c | 43 +++++++++++++++++ include/module.h | 0 include/module_console.h | 24 +++++++++ module/biosvga/module.c | 57 ++++++++++++++++++++++ module/console.c | 102 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 392 insertions(+) create mode 100644 Makefile create mode 100644 common/kernel_main.c create mode 100644 i686/entry.S create mode 100644 i686/include/utils.h create mode 100644 i686/link.ld create mode 100644 i686/utils.c create mode 100644 include/module.h create mode 100644 include/module_console.h create mode 100644 module/biosvga/module.c create mode 100644 module/console.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ee60ab5 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ + # Makefile for JamesM's kernel tutorials. +# The C and C++ rules are already setup by default. +# The only one that needs changing is the assembler +# rule, as we use nasm instead of GNU as. + +TGT=i686 + +SOURCES=$(TGT)/entry.o $(TGT)/utils.o module/biosvga/module.o module/console.o common/kernel_main.o +LDSC=$(TGT)/link.ld + +TGTNAM=$(TGT)-elf +CC=$(TGTNAM)-gcc +AS=$(TGTNAM)-as +CXX=$(TGTNAM)-g++ +LD=$(TGTNAM)-ld +OC=$(TGTNAM)-objcopy +NM=$(TGTNAM)-nm +RL=$(TGTNAM)-ranlib + +CFLAGS=-ffreestanding -std=gnu11 +CPPFLAGS=-Iinclude -I$(TGT)/include +LDFLAGS=-T$(LDSC) +ASFLAGS= +LIBS= + +all: link + +qemu: all + qemu-system-i386 --kernel kernel + +clean: + rm -f $(SOURCES) kernel + +link: $(SOURCES) + $(LD) $(LDFLAGS) -o kernel $(LIBS) $(SOURCES) + +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $< + +%.o: %.cxx + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $< + +%.o: %.S + $(AS) $(ASFLAGS) -c -o $@ $< diff --git a/common/kernel_main.c b/common/kernel_main.c new file mode 100644 index 0000000..308f747 --- /dev/null +++ b/common/kernel_main.c @@ -0,0 +1,39 @@ +#include +#include +#include + +int kernel_main(struct multiboot *mboot_ptr) +{ + console_init(); + + kwrite("1\n"); + kwrite("2\n"); + kwrite("3\n"); + kwrite("4\n"); + kwrite("5\n"); + kwrite("6\n"); + kwrite("7\n"); + kwrite("8\n"); + kwrite("9\n"); + kwrite("10\n"); + kwrite("11\n"); + kwrite("12\n"); + kwrite("13\n"); + kwrite("14\n"); + kwrite("15\n"); + kwrite("16\n"); + kwrite("17\n"); + kwrite("18\n"); + kwrite("19\n"); + kwrite("20\n"); + kwrite("21\n"); + kwrite("22\n"); + kwrite("23\n"); + kwrite("24\n"); + kwrite("25\n"); + kwrite("26\n"); + + console_deinit(); + + return 0xDEADBEEF; +} diff --git a/i686/entry.S b/i686/entry.S new file mode 100644 index 0000000..abb6a38 --- /dev/null +++ b/i686/entry.S @@ -0,0 +1,33 @@ +.set ALIGN, 1<<0 # align loaded modules on page boundaries +.set MEMINFO, 1<<1 # provide memory map +.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field +.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header +.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot + +.section .multiboot +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +.section .bss +.align 16 +stack_bottom: +.skip 16384 # 16 KiB +stack_top: + +.section .text +.global _start +.type _start, @function +_start: + mov $stack_top, %esp + + push %ebx + + call kernel_main + + cli +.halt: hlt + jmp .halt + +.size _start, . - _start diff --git a/i686/include/utils.h b/i686/include/utils.h new file mode 100644 index 0000000..78d311e --- /dev/null +++ b/i686/include/utils.h @@ -0,0 +1,7 @@ +uint8_t inb(uint16_t port); +uint16_t inw(uint16_t port); +uint32_t inl(uint16_t port); + +void outb(uint16_t port, uint8_t val); +void outw(uint16_t port, uint16_t val); +void outl(uint16_t port, uint32_t val); diff --git a/i686/link.ld b/i686/link.ld new file mode 100644 index 0000000..88b0e01 --- /dev/null +++ b/i686/link.ld @@ -0,0 +1,43 @@ +/* The bootloader will look at this image and start execution at the symbol + designated as the entry point. */ +ENTRY(_start) + +/* Tell where the various sections of the object files will be put in the final + kernel image. */ +SECTIONS +{ + /* Begin putting sections at 1 MiB, a conventional place for kernels to be + loaded at by the bootloader. */ + . = 1M; + + /* First put the multiboot header, as it is required to be put very early + early in the image or the bootloader won't recognize the file format. + Next we'll put the .text section. */ + .text BLOCK(4K) : ALIGN(4K) + { + *(.multiboot) + *(.text) + } + + /* Read-only data. */ + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + /* Read-write data (initialized) */ + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + /* Read-write data (uninitialized) and stack */ + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + + /* The compiler may produce other sections, by default it will put them in + a segment with the same name. Simply add stuff here as needed. */ +} diff --git a/i686/utils.c b/i686/utils.c new file mode 100644 index 0000000..dbef878 --- /dev/null +++ b/i686/utils.c @@ -0,0 +1,43 @@ +#include + +void outb(uint16_t port, uint8_t val) +{ + asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) ); +} + +void outw(uint16_t port, uint16_t val) +{ + asm volatile ( "outw %0, %1" : : "a"(val), "Nd"(port) ); +} + +void outl(uint16_t port, uint32_t val) +{ + asm volatile ( "outl %0, %1" : : "a"(val), "Nd"(port) ); +} + +uint8_t inb(uint16_t port) +{ + uint8_t ret; + asm volatile ( "inb %1, %0" + : "=a"(ret) + : "Nd"(port) ); + return ret; +} + +uint16_t inw(uint16_t port) +{ + uint16_t ret; + asm volatile ( "inb %1, %0" + : "=a"(ret) + : "Nd"(port) ); + return ret; +} + +uint32_t inl(uint16_t port) +{ + uint32_t ret; + asm volatile ( "inb %1, %0" + : "=a"(ret) + : "Nd"(port) ); + return ret; +} diff --git a/include/module.h b/include/module.h new file mode 100644 index 0000000..e69de29 diff --git a/include/module_console.h b/include/module_console.h new file mode 100644 index 0000000..895bcb6 --- /dev/null +++ b/include/module_console.h @@ -0,0 +1,24 @@ +typedef void (*console_put_f) (char, char, char, uint16_t, uint16_t); +typedef void (*console_get_f) (char*, char*, char*, uint16_t, uint16_t); +typedef void (*console_cursor_f) (uint16_t, uint16_t); +typedef uint16_t (*console_width_f) (); +typedef uint16_t (*console_height_f) (); +typedef void (*console_refresh_f)(); + +struct console_module { + console_put_f put; + console_get_f get; + console_cursor_f cursor; + console_width_f width; + console_height_f height; + console_refresh_f refresh; +}; + +void console_register_module(struct console_module*); +void console_unregister_module(struct console_module*); +void console_init(); +void console_deinit(); + +void kputc(char); +void kwrite(char*); + diff --git a/module/biosvga/module.c b/module/biosvga/module.c new file mode 100644 index 0000000..bbbaab4 --- /dev/null +++ b/module/biosvga/module.c @@ -0,0 +1,57 @@ +#include +#include +#include + +uint16_t *video_mem = (uint16_t*)0xB8000; + +void biosvga_put(char c, char color_fg, char color_bg, uint16_t x, uint16_t y) { + uint8_t attr = (color_bg << 4) | (color_fg & 0xF); + uint16_t write = (attr << 8) | c; + + video_mem[y * 80 + x] = write; +} + +void biosvga_get(char* c, char* color_fg, char* color_bg, uint16_t x, uint16_t y) { + uint16_t write = video_mem[y * 80 + x]; + *c = (char)(write & 0xFF); + *color_bg = (write << 12) & 0xF; + *color_fg = (write << 8) & 0xF; +} + +void biosvga_cursor(uint16_t x, uint16_t y) { + uint16_t loc = y * 80 + x; + outb(0x3D4, 14); + outb(0x3D5, loc >> 8); + outb(0x3D4, 15); + outb(0x3D5, loc); +} + +uint16_t biosvga_width() { + return 80; +} + +uint16_t biosvga_height() { + return 25; +} + +void biosvga_refresh() { + +} + +struct console_module biosvga_module = { + .put = biosvga_put, + .get = biosvga_get, + .cursor = biosvga_cursor, + .width = biosvga_width, + .height = biosvga_height, + .refresh = biosvga_refresh +}; + +void biosvga_init() { + console_register_module(&biosvga_module); +} + +void biosvga_deinit() { + console_unregister_module(&biosvga_module); + // Stub. +} diff --git a/module/console.c b/module/console.c new file mode 100644 index 0000000..6cc6ae9 --- /dev/null +++ b/module/console.c @@ -0,0 +1,102 @@ +/* This is a generic-ish interface for console drivers. The main reason for this is to abstract printing from what it is +actually printing to; in the future, adding a new backend for framebuffer rendering will be easy, for instance. */ + +#include +#include +#include +#include + +struct console_module *active; +uint16_t x, y, tab_w; + +void biosvga_init(); +void biosvga_deinit(); + +void console_register_module(struct console_module* module) { + active = module; +} + +void console_unregister_module(struct console_module* module) { + if (active == module) + active = NULL; +} + +// TODO - Should this be part of the backend? Scrolling is slow. +void scroll() { + if (y >= active->height()) { + for(int cy = 1; cy <= active->height(); cy++) { + for(int cx = 0; cx <= active->width(); cx++) { + char c = 0; + uint8_t fg = 0, bg = 0; + active->get(&c, &fg, &bg, cx, cy); + active->put(c, 0xf, 0, cx, cy-1); + } + } + --y; + for(int cx = 0; cx < active->width(); cx++) { + active->put(' ', 0xf, 0, cx, y); + } + } +} + +// TODO - Should this be part of the backend? Scrolling is slow. +void clear() { + x = y = 0; + for(int cy = 0; cy < active->height(); cy++) { + for(int cx = 0; cx < active->width(); cx++) { + active->put(' ', 0xf, 0x0, cx, cy); + } + } +} + +void kputc(char c) { + switch(c) { + case '\t': + x += tab_w - (x % tab_w); + break; + case '\b': + --x; + break; + case '\n': + ++y; + case '\r': + x = 0; + break; + case ' ' ... '~': + active->put(c, 0xf, 0x0, x, y); + default: + x += 1; + break; + } + + if (x > active->width()) { + x = 0; + ++y; + } + + scroll(); + active->cursor(x, y); +} + +void kwrite(char* str) { + while(*str != 0) { + kputc(*str); + ++str; + } +} + +void console_init() { + x = y = 0; + tab_w = 4; + + // Temporary + biosvga_init(); + + clear(); +} + +void console_deinit() { + // Temporary + biosvga_deinit(); +} + -- 2.39.5