aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2014-11-30 19:58:32 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2014-11-30 19:58:32 +0100
commit54e7efbbd0e0c88d99bb6bddb82e9fc8d90eae50 (patch)
tree178f0d423d1708cbddf89c0e4c510a2022fa7eda
parentbee97e0b630976b96798246a3ef4eea8964099cf (diff)
downloadmacroscope-54e7efbbd0e0c88d99bb6bddb82e9fc8d90eae50.tar.gz
macroscope-54e7efbbd0e0c88d99bb6bddb82e9fc8d90eae50.zip
Add debug output and a few elementary stdlib functions.
-rw-r--r--kernel/Makefile19
-rw-r--r--kernel/config.h27
-rw-r--r--kernel/include/dbglog.h7
-rw-r--r--kernel/include/multiboot.h6
-rw-r--r--kernel/include/printf.h8
-rw-r--r--kernel/include/stdlib.h7
-rw-r--r--kernel/include/sys.h14
-rw-r--r--kernel/l0/dbglog.c151
-rw-r--r--kernel/l0/kmain.c132
-rw-r--r--kernel/l0/sys.c44
-rw-r--r--kernel/lib/printf.c105
-rw-r--r--kernel/lib/stdlib.c8
12 files changed, 398 insertions, 130 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 7a29c9e..6e973dd 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -3,15 +3,18 @@ AS = nasm
ASFLAGS = -felf
CC = i586-elf-gcc
-CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I ./include
+CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include
+# CXX = i586-elf-g++
+# CXFLAGS = -ffreestanding -O2 -Wall -Wextra -I . -I ./include -fno-exceptions -fno-rtti
LD = i586-elf-gcc
LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -lgcc
-OBJ = l0/loader.o l0/kmain.o
+OBJ = lib/stdlib.o lib/printf.o l0/loader.o l0/kmain.o l0/dbglog.o l0/sys.o
+OUT = kernel.bin
-all: kernel.bin
+all: $(OUT)
-kernel.bin: $(OBJ)
+$(OUT): $(OBJ)
$(LD) $(LDFLAGS) -o $@ $^
%.o: %.s
@@ -19,3 +22,11 @@ kernel.bin: $(OBJ)
%.o: %.c
$(CC) -c $< -o $@ $(CFLAGS)
+
+# %.o: %.cpp
+# $(CXX) -c $< -o $@ $(CXFLAGS)
+
+clean:
+ rm */*.o || true
+mrproper: clean
+ rm $(OUT)
diff --git a/kernel/config.h b/kernel/config.h
new file mode 100644
index 0000000..5ea242e
--- /dev/null
+++ b/kernel/config.h
@@ -0,0 +1,27 @@
+#if !defined(__cplusplus)
+#include <stdbool.h>
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if defined(__linux__)
+#error "This kernel needs to be compiled with a cross-compiler."
+#endif
+
+#if !defined(__i386__)
+#error "This kernel needs to be compiled with a ix86-elf compiler"
+#endif
+
+
+extern char k_highhalf_addr; // defined in linker script : 0xC0000000
+#define K_HIGHHALF_ADDR ((void*)&k_highhalf_addr)
+
+#define OS_NAME "Macroscope"
+#define OS_VERSION "0.0.1"
+
+// Comment to disable either form of debug log output
+#define DBGLOG_TO_SERIAL
+#define DBGLOG_TO_SCREEN
+
+
diff --git a/kernel/include/dbglog.h b/kernel/include/dbglog.h
new file mode 100644
index 0000000..c8904c6
--- /dev/null
+++ b/kernel/include/dbglog.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <config.h>
+
+void dbglog_setup();
+void dbg_print(const char* str);
+void dbg_printf(const char* format, ...);
diff --git a/kernel/include/multiboot.h b/kernel/include/multiboot.h
index 908274c..8fd9dee 100644
--- a/kernel/include/multiboot.h
+++ b/kernel/include/multiboot.h
@@ -1,5 +1,5 @@
-#ifndef HDR_MULTIBOOT
-#define HDR_MULTIBOOT
+#pragma once
+
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
@@ -60,5 +60,3 @@ struct memory_map_t {
unsigned long type;
};
-#endif
-
diff --git a/kernel/include/printf.h b/kernel/include/printf.h
new file mode 100644
index 0000000..4569827
--- /dev/null
+++ b/kernel/include/printf.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+int snprintf(char* s, size_t n, const char* format, ...);
+int vsnprintf(char* s, size_t n, const char* format, va_list arg);
+
diff --git a/kernel/include/stdlib.h b/kernel/include/stdlib.h
new file mode 100644
index 0000000..601e7c4
--- /dev/null
+++ b/kernel/include/stdlib.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+size_t strlen(const char*);
+
diff --git a/kernel/include/sys.h b/kernel/include/sys.h
new file mode 100644
index 0000000..b76ca26
--- /dev/null
+++ b/kernel/include/sys.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <config.h>
+
+void outb(uint16_t port, uint8_t value);
+void outw(uint16_t port, uint16_t value);
+uint8_t inb(uint16_t port);
+uint16_t inw(uint16_t port);
+
+
+#define PANIC(s) panic(s, __FILE__, __LINE__);
+#define ASSERT(s) { if (!(s)) panic_assert(#s, __FILE__, __LINE__); }
+void panic(const char* message, const char* file, int line);
+void panic_assert(const char* assertion, const char* file, int line);
diff --git a/kernel/l0/dbglog.c b/kernel/l0/dbglog.c
new file mode 100644
index 0000000..0285002
--- /dev/null
+++ b/kernel/l0/dbglog.c
@@ -0,0 +1,151 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <printf.h>
+#include <dbglog.h>
+#include <config.h>
+#include <sys.h>
+
+// ==================================================================
+
+#ifdef DBGLOG_TO_SCREEN
+
+static const size_t VGA_WIDTH = 80;
+static const size_t VGA_HEIGHT = 25;
+
+static uint8_t vga_color = 7;
+static uint16_t* vga_buffer = 0;
+static uint16_t vga_row = 0, vga_column = 0;
+
+static uint16_t make_vgaentry(char c, uint8_t color) {
+ uint16_t c16 = c;
+ uint16_t color16 = color;
+ return c16 | color16 << 8;
+}
+
+static void vga_putentryat(char c, uint8_t color, size_t x, size_t y) {
+ const size_t index = y * VGA_WIDTH + x;
+ vga_buffer[index] = make_vgaentry(c, color);
+}
+
+static void vga_update_cursor() {
+ uint16_t cursor_location = vga_row * 80 + vga_column;
+ outb(0x3D4, 14); //Sending high cursor byte
+ outb(0x3D5, cursor_location >> 8);
+ outb(0x3D4, 15); //Sending high cursor byte
+ outb(0x3D5, cursor_location);
+}
+
+static void vga_init() {
+ vga_row = 0;
+ vga_column = 0;
+ vga_buffer = (uint16_t*) (&k_highhalf_addr + 0xB8000);
+
+ for (size_t y = 0; y < VGA_HEIGHT; y++) {
+ for (size_t x = 0; x < VGA_WIDTH; x++) {
+ vga_putentryat(' ', vga_color, x, y);
+ }
+ }
+
+ vga_update_cursor();
+}
+
+static void vga_scroll() {
+ for (size_t i = 0; i < VGA_WIDTH * (VGA_HEIGHT - 1); i++) {
+ vga_buffer[i] = vga_buffer[i + VGA_WIDTH];
+ }
+ for (size_t x = 0; x < VGA_WIDTH; x++) {
+ vga_putentryat(' ', vga_color, x, VGA_HEIGHT - 1);
+ }
+ vga_row--;
+}
+
+static void vga_newline() {
+ vga_column = 0;
+ if (++vga_row == VGA_HEIGHT) {
+ vga_scroll();
+ }
+}
+
+static void vga_putc(char c) {
+ if (c == '\n') {
+ vga_newline();
+ } else if (c == '\t') {
+ vga_putc(' ');
+ while (vga_column % 4 != 0) vga_putc(' ');
+ } else {
+ vga_putentryat(c, vga_color, vga_column, vga_row);
+ if (++vga_column == VGA_WIDTH) {
+ vga_newline();
+ }
+ }
+}
+
+static void vga_puts(const char* data) {
+ size_t datalen = strlen(data);
+ for (size_t i = 0; i < datalen; i++)
+ vga_putc(data[i]);
+
+ vga_update_cursor();
+}
+
+#endif // DBGLOG_TO_SCREEN
+
+// ==================================================================
+
+#ifdef DBGLOG_TO_SERIAL
+
+#define SER_PORT 0x3F8 // COM1
+
+static void serial_init() {
+ outb(SER_PORT + 1, 0x00); // disable interrupts
+ outb(SER_PORT + 3, 0x80); // set baud rate
+ outb(SER_PORT + 0, 0x03); // set divisor to 3 (38400 baud)
+ outb(SER_PORT + 1, 0x00);
+ outb(SER_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outb(SER_PORT + 2, 0xC7); // enable FIFO, clear them, with 14-byte threshold
+}
+
+static void serial_putc(const char c) {
+ while (!(inb(SER_PORT + 5) & 0x20));
+ outb(SER_PORT, c);
+}
+
+static void serial_puts(const char *c) {
+ while (*c) {
+ serial_putc(*c);
+ c++;
+ }
+}
+
+#endif // DBGLOG_TO_SERIAL
+
+// ==================================================================
+
+void dbglog_setup() {
+#ifdef DBGLOG_TO_SCREEN
+ vga_init();
+#endif
+#ifdef DBGLOG_TO_SERIAL
+ serial_init();
+#endif
+}
+
+void dbg_print(const char* str) {
+#ifdef DBGLOG_TO_SCREEN
+ vga_puts(str);
+#endif
+#ifdef DBGLOG_TO_SERIAL
+ serial_puts(str);
+#endif
+}
+
+void dbg_printf(const char* fmt, ...) {
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, 256, fmt, ap);
+ va_end(ap);
+
+ dbg_print(buffer);
+}
diff --git a/kernel/l0/kmain.c b/kernel/l0/kmain.c
index 9139856..74945e4 100644
--- a/kernel/l0/kmain.c
+++ b/kernel/l0/kmain.c
@@ -1,126 +1,14 @@
-#if !defined(__cplusplus)
-#include <stdbool.h> /* C doesn't have booleans by default. */
-#endif
-#include <stddef.h>
-#include <stdint.h>
+#include <multiboot.h>
+#include <config.h>
+#include <dbglog.h>
+#include <sys.h>
-/* Check if the compiler thinks if we are targeting the wrong operating system. */
-#if defined(__linux__)
-#error "You are not using a cross-compiler, you will most certainly run into trouble"
-#endif
-
-/* This tutorial will only work for the 32-bit ix86 targets. */
-#if !defined(__i386__)
-#error "This tutorial needs to be compiled with a ix86-elf compiler"
-#endif
+void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) {
+ dbglog_setup();
-#include "multiboot.h"
-
-extern void k_highhalf_addr;
+ dbg_printf("Hello, kernel World!\n");
+ dbg_printf("This is %s, version %s.\n", OS_NAME, OS_VERSION);
-/* Hardware text mode color constants. */
-enum vga_color
-{
- COLOR_BLACK = 0,
- COLOR_BLUE = 1,
- COLOR_GREEN = 2,
- COLOR_CYAN = 3,
- COLOR_RED = 4,
- COLOR_MAGENTA = 5,
- COLOR_BROWN = 6,
- COLOR_LIGHT_GREY = 7,
- COLOR_DARK_GREY = 8,
- COLOR_LIGHT_BLUE = 9,
- COLOR_LIGHT_GREEN = 10,
- COLOR_LIGHT_CYAN = 11,
- COLOR_LIGHT_RED = 12,
- COLOR_LIGHT_MAGENTA = 13,
- COLOR_LIGHT_BROWN = 14,
- COLOR_WHITE = 15,
-};
-
-uint8_t make_color(enum vga_color fg, enum vga_color bg)
-{
- return fg | bg << 4;
-}
-
-uint16_t make_vgaentry(char c, uint8_t color)
-{
- uint16_t c16 = c;
- uint16_t color16 = color;
- return c16 | color16 << 8;
-}
-
-size_t strlen(const char* str)
-{
- size_t ret = 0;
- while ( str[ret] != 0 )
- ret++;
- return ret;
-}
-
-static const size_t VGA_WIDTH = 80;
-static const size_t VGA_HEIGHT = 25;
-
-size_t terminal_row;
-size_t terminal_column;
-uint8_t terminal_color;
-uint16_t* terminal_buffer;
-
-void terminal_initialize()
-{
- terminal_row = 0;
- terminal_column = 0;
- terminal_color = make_color(COLOR_LIGHT_GREY, COLOR_BLACK);
- terminal_buffer = (uint16_t*) (&k_highhalf_addr + 0xB8000);
- for ( size_t y = 0; y < VGA_HEIGHT; y++ )
- {
- for ( size_t x = 0; x < VGA_WIDTH; x++ )
- {
- const size_t index = y * VGA_WIDTH + x;
- terminal_buffer[index] = make_vgaentry(' ', terminal_color);
- }
- }
-}
-
-void terminal_setcolor(uint8_t color)
-{
- terminal_color = color;
-}
-
-void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
-{
- const size_t index = y * VGA_WIDTH + x;
- terminal_buffer[index] = make_vgaentry(c, color);
-}
-
-void terminal_putchar(char c)
-{
- terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
- if ( ++terminal_column == VGA_WIDTH )
- {
- terminal_column = 0;
- if ( ++terminal_row == VGA_HEIGHT )
- {
- terminal_row = 0;
- }
- }
-}
-
-void terminal_writestring(const char* data)
-{
- size_t datalen = strlen(data);
- for ( size_t i = 0; i < datalen; i++ )
- terminal_putchar(data[i]);
-}
-
-#if defined(__cplusplus)
-extern "C" /* Use C linkage for kernel_main. */
-#endif
-void kmain(struct multiboot_info_t *mbd, int32_t mb_magic)
-{
- terminal_initialize();
- /* Since there is no support for newlines in terminal_putchar yet, \n will
- produce some VGA specific character instead. This is normal. */
- terminal_writestring("Hello, kernel World!\n");
+ PANIC("Reached kmain end! Falling off the edge.");
}
+
diff --git a/kernel/l0/sys.c b/kernel/l0/sys.c
new file mode 100644
index 0000000..f6a9900
--- /dev/null
+++ b/kernel/l0/sys.c
@@ -0,0 +1,44 @@
+#include <sys.h>
+#include <dbglog.h>
+
+
+// C wrappers for inb/outb/inw/outw
+
+void outb(uint16_t port, uint8_t value) {
+ asm volatile("outb %1, %0" : : "dN"(port), "a"(value));
+}
+
+void outw(uint16_t port, uint16_t value) {
+ asm volatile("outw %1, %0" : : "dN"(port), "a"(value));
+}
+
+uint8_t inb(uint16_t port) {
+ uint8_t ret;
+ asm volatile("inb %1, %0" : "=a"(ret) : "dN"(port));
+ return ret;
+}
+
+uint16_t inw(uint16_t port) {
+ uint16_t ret;
+ asm volatile("inw %1, %0" : "=a"(ret) : "dN"(port));
+ return ret;
+}
+
+// Kernel panic and kernel assert failure
+
+static void panic_do(const char* type, const char *msg, const char* file, int line) {
+ asm volatile("cli;");
+ dbg_printf("/\n| %s:\t%s\n", type, msg);
+ dbg_printf("| File: \t%s:%i\n", file, line);
+ dbg_printf("| System halted -_-'\n");
+ dbg_printf("\\---------------------------------------------------------/");
+ asm volatile("hlt");
+}
+
+void panic(const char* message, const char* file, int line) {
+ panic_do("PANIC", message, file, line);
+}
+
+void panic_assert(const char* assertion, const char* file, int line) {
+ panic_do("ASSERT FAILED", assertion, file, line);
+}
diff --git a/kernel/lib/printf.c b/kernel/lib/printf.c
new file mode 100644
index 0000000..fdf474d
--- /dev/null
+++ b/kernel/lib/printf.c
@@ -0,0 +1,105 @@
+#include <printf.h>
+#include <stdarg.h>
+
+int snprintf(char * buff, size_t len, const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ len = vsnprintf(buff, len, format, ap);
+ va_end(ap);
+
+ return len;
+}
+
+int vsnprintf(char *buff, size_t len, const char* format, va_list ap){
+ size_t i, result;
+
+ if (!buff || !format)
+ return -1;
+
+#define PUTCHAR(thechar) \
+ do { \
+ if (result < len-1) \
+ *buff++ = (thechar); \
+ result++; \
+ } while (0)
+
+ result = 0;
+ for(i = 0; format[i] != '\0' ; i++) {
+ if (format[i] == '%') {
+ i++;
+ switch(format[i]) {
+ case '%':
+ PUTCHAR('%');
+ break;
+
+ case 'i':;
+ case 'd': {
+ int integer = va_arg(ap,int);
+ int cpt2 = 0;
+ char buff_int[16];
+
+ if (integer<0)
+ PUTCHAR('-');
+
+ do {
+ int m10 = integer%10;
+ m10 = (m10 < 0)? -m10:m10;
+ buff_int[cpt2++] = (char)('0'+ m10);
+ integer = integer/10;
+ } while(integer != 0);
+
+ for(cpt2 = cpt2 - 1; cpt2 >= 0; cpt2--)
+ PUTCHAR(buff_int[cpt2]);
+
+ break;
+ }
+ case 'c': {
+ int value = va_arg(ap,int);
+ PUTCHAR((char)value);
+ break;
+ }
+ case 's': {
+ char *string = va_arg(ap,char *);
+ if (!string)
+ string = "(null)";
+ for(; *string != '\0' ; string++)
+ PUTCHAR(*string);
+ break;
+ }
+ case 'x': {
+ unsigned int hexa = va_arg(ap,int);
+ unsigned int nb;
+ int j, had_nonzero = 0;
+ for(j = 0; j < 8; j++)
+ {
+ nb = (unsigned int)(hexa << (j*4));
+ nb = (nb >> 28) & 0xf;
+ // Skip the leading zeros
+ if (nb == 0) {
+ if (had_nonzero)
+ PUTCHAR('0');
+ } else {
+ had_nonzero = 1;
+ if (nb < 10)
+ PUTCHAR('0'+nb);
+ else
+ PUTCHAR('a'+(nb-10));
+ }
+ }
+ if (!had_nonzero)
+ PUTCHAR('0');
+ break;
+ }
+ default:
+ PUTCHAR('%');
+ PUTCHAR(format[i]);
+ }
+ } else {
+ PUTCHAR(format[i]);
+ }
+ }
+
+ *buff = '\0';
+ return result;
+}
diff --git a/kernel/lib/stdlib.c b/kernel/lib/stdlib.c
new file mode 100644
index 0000000..6710da2
--- /dev/null
+++ b/kernel/lib/stdlib.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+
+size_t strlen(const char* str) {
+ size_t ret = 0;
+ while (str[ret] != 0)
+ ret++;
+ return ret;
+}