]> Chaos Git - misc/eidos.git/commitdiff
Basic template-ish shit
authorJon Feldman <chaos.kagami@gmail.com>
Mon, 20 Feb 2017 01:39:03 +0000 (20:39 -0500)
committerJon Feldman <chaos.kagami@gmail.com>
Mon, 20 Feb 2017 01:39:03 +0000 (20:39 -0500)
Makefile [new file with mode: 0644]
common/kernel_main.c [new file with mode: 0644]
i686/entry.S [new file with mode: 0644]
i686/include/utils.h [new file with mode: 0644]
i686/link.ld [new file with mode: 0644]
i686/utils.c [new file with mode: 0644]
include/module.h [new file with mode: 0644]
include/module_console.h [new file with mode: 0644]
module/biosvga/module.c [new file with mode: 0644]
module/console.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..308f747
--- /dev/null
@@ -0,0 +1,39 @@
+#include <stdint.h>
+#include <module.h>
+#include <module_console.h>
+
+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 (file)
index 0000000..abb6a38
--- /dev/null
@@ -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 (file)
index 0000000..78d311e
--- /dev/null
@@ -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 (file)
index 0000000..88b0e01
--- /dev/null
@@ -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 (file)
index 0000000..dbef878
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdint.h>
+
+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 (file)
index 0000000..e69de29
diff --git a/include/module_console.h b/include/module_console.h
new file mode 100644 (file)
index 0000000..895bcb6
--- /dev/null
@@ -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 (file)
index 0000000..bbbaab4
--- /dev/null
@@ -0,0 +1,57 @@
+#include <stdint.h>
+#include <module.h>
+#include <module_console.h>
+
+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 (file)
index 0000000..6cc6ae9
--- /dev/null
@@ -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 <stdint.h>
+#include <stddef.h>
+#include <module.h>
+#include <module_console.h>
+
+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();
+}
+