diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6cd758c --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +ASM ?= nasm +CC := i686-elf-gcc +GDB := i686-elf-gdb +LD := i686-elf-ld + +C_FILES = $(shell find src/ -type f -name '*.c') +CO_FILES = $(patsubst src/%.c, obj/%.o, $(C_FILES)) +ASM_FILES = $(shell find src/kernel/ -type f -name '*.asm') +AO_FILES = $(patsubst src/kernel/%.asm, obj/kernel/%.o, $(ASM_FILES)) + +KERNEL_O_FILES = ${CO_FILES} ${AO_FILES} + +iso: bin/shade.iso + +obj/boot.o: src/boot.asm + $(ASM) -felf32 $^ -o $@ + +bin/shade.bin: obj/boot.o ${KERNEL_O_FILES} + mkdir -p bin + $(CC) -T src/linker.ld -ffreestanding -O2 -nostdlib $^ -o $@ -lgcc + grub-file --is-x86-multiboot bin/shade.bin + +bin/shade.iso: bin/shade.bin + mkdir -p isodir/boot/grub + cp bin/shade.bin isodir/boot/shade.bin + cp src/iso/grub.cfg isodir/boot/grub/grub.cfg + grub-mkrescue -o bin/shade.iso isodir + rm -rf isodir + +obj/%.o: src/%.c + mkdir -p "$(@D)" + $(CC) -ffreestanding -O2 -Wall -Wextra -c $< -o $@ + +obj/%.o: src/%.asm + mkdir -p "$(@D)" + $(ASM) -f elf $< -o $@ + + +run: clean bin/shade.iso + qemu-system-x86_64 -hdd bin/shade.iso + +debug: clean bin/shade.iso bin/shade.bin + qemu-system-x86_64 -s -S -hdd bin/shade.iso & + ${GDB} os-image.bin -ex "symbol-file bin/shade.bin" -ex "target remote localhost:1234" + + +clean: + find obj -type f -name '*.o' -exec rm {} + + find obj -type f -name '*.bin' -exec rm {} + + find bin -type f -name '*.o' -exec rm {} + + find bin -type f -name '*.bin' -exec rm {} + + find . -type f -name '*.dis' -exec rm {} + + rm -f kernel.elf + rm -rf isodir \ No newline at end of file diff --git a/bin/shade.bin b/bin/shade.bin new file mode 100755 index 0000000..b755599 Binary files /dev/null and b/bin/shade.bin differ diff --git a/bin/shade.iso b/bin/shade.iso new file mode 100644 index 0000000..080a0ab Binary files /dev/null and b/bin/shade.iso differ diff --git a/obj/boot.o b/obj/boot.o new file mode 100644 index 0000000..8b05e99 Binary files /dev/null and b/obj/boot.o differ diff --git a/obj/kernel/kernel.o b/obj/kernel/kernel.o new file mode 100644 index 0000000..0c6d63b Binary files /dev/null and b/obj/kernel/kernel.o differ diff --git a/obj/kernel/platform/drivers/ports.o b/obj/kernel/platform/drivers/ports.o new file mode 100644 index 0000000..a5820f9 Binary files /dev/null and b/obj/kernel/platform/drivers/ports.o differ diff --git a/obj/kernel/print.o b/obj/kernel/print.o new file mode 100644 index 0000000..30f77e5 Binary files /dev/null and b/obj/kernel/print.o differ diff --git a/obj/kernel/strings.o b/obj/kernel/strings.o new file mode 100644 index 0000000..b0718e1 Binary files /dev/null and b/obj/kernel/strings.o differ diff --git a/obj/kernel/util.o b/obj/kernel/util.o new file mode 100644 index 0000000..ddd8515 Binary files /dev/null and b/obj/kernel/util.o differ diff --git a/src/boot.asm b/src/boot.asm new file mode 100644 index 0000000..a265974 --- /dev/null +++ b/src/boot.asm @@ -0,0 +1,38 @@ +; Declare constants for the multiboot header. +MBALIGN equ 1 << 0 ; align loaded modules on page boundaries +MEMINFO equ 1 << 1 ; provide memory map +FLAGS equ MBALIGN | MEMINFO ; this is the Multiboot 'flag' field +MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header +CHECKSUM equ -(MAGIC + FLAGS) ; checksum of above, to prove we are multiboot + +section .multiboot +align 4 + dd MAGIC + dd FLAGS + dd CHECKSUM + +section .bss +align 16 + +stack_bottom: +resb 16384 +stack_top: + +; _start = entry to kernel +; Since the bootloader will be gone, it doesn't make sense to return from this +section .text + +global _start:function (_start.end - _start) +_start: + ; 32bit protected mode, no int, no paging + mov esp, stack_top ; Initialize stack + + extern kmain + call kmain + + cli ; Turn off interrupts in case they are on +.hang: + hlt ; Totally halt the cpu + jmp .hang ; If the cpu un-halts for some reason, halt again + +.end: \ No newline at end of file diff --git a/src/iso/grub.cfg b/src/iso/grub.cfg new file mode 100644 index 0000000..d6d553e --- /dev/null +++ b/src/iso/grub.cfg @@ -0,0 +1,3 @@ +menuentry "shadeOS Dev Build" { + multiboot /boot/shade.bin +} \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c new file mode 100644 index 0000000..33df331 --- /dev/null +++ b/src/kernel/kernel.c @@ -0,0 +1,55 @@ +#include "./platform/drivers/ports.h" +#include "print.h" +#include "./platform/types.h" +//#include "./platform/interrupts/int.h" + +void dummy_test_entrypoint() {} + +void kernel_welcome() { + print_str("Welcome to "); + print_set_color(PRINT_COLOR_CYAN, PRINT_COLOR_BLACK); + print_str("Shade"); + print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); + print_str("!\n"); + + print_str("shadeOS kernel version "); + + print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK); + print_str("0.2.2"); + + print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); + print_newline(); + + print_str("Running on "); + + print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK); + print_str("shade-development"); + + print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); + + print_newline(); +} + +// kMain +void kmain() { + // Initialize screen buffer + struct Char* buffer = (struct Char*) 0xb8000; + + clear_all(); // Clear screen + set_cursor_pos(0, 0); // Set cursor position + print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); // Set print color + + // welcome messages + kernel_msg_ok("Initialized display successfully\n"); + kernel_welcome(); + + print_str("Copyright (c) e3team 2022. All rights reserved.\n"); + print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n"); + print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n"); +/* + idt_init(); + kernel_msg_ok("Interrupts initialized"); + + __asm__ __volatile__("int $2"); +*/ +} \ No newline at end of file diff --git a/src/kernel/platform/drivers/ports.c b/src/kernel/platform/drivers/ports.c new file mode 100644 index 0000000..34a48db --- /dev/null +++ b/src/kernel/platform/drivers/ports.c @@ -0,0 +1,26 @@ +/* + * Read 1 byte from specified port + */ +unsigned char port_byte_in(unsigned short port) { + unsigned char result; + // source and dest are backwards. + // "=a (result)" set the C variable to the value of register e'a'x + // '"d" (port) map the C variable port into e'd'x register + __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); +} + +void port_byte_out(unsigned short port, unsigned char data) { + // both regs are C vars, nothing is returned, so no '=' in asm syntax + // comma because two vars in input area and none in return area + __asm__("out %%al, %%dx" : : "a" (data), "d" (port)); +} + +unsigned short port_word_in(unsigned short port) { + unsigned short result; + __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port)); + return result; +} + +void port_word_out(unsigned short port, unsigned short data) { + __asm__("out %%ax, %%dx" : : "a" (data), "d" (port)); +} \ No newline at end of file diff --git a/src/kernel/platform/drivers/ports.h b/src/kernel/platform/drivers/ports.h new file mode 100644 index 0000000..d616f0e --- /dev/null +++ b/src/kernel/platform/drivers/ports.h @@ -0,0 +1,4 @@ +unsigned char port_byte_in(unsigned short port); +void port_byte_out(unsigned short port, unsigned char data); +unsigned short port_word_in(unsigned short port); +void port_word_out(unsigned short port, unsigned short data); \ No newline at end of file diff --git a/src/kernel/platform/types.h b/src/kernel/platform/types.h new file mode 100644 index 0000000..e18f414 --- /dev/null +++ b/src/kernel/platform/types.h @@ -0,0 +1,18 @@ +#ifndef TYPES_H +#define TYPES_H + +typedef unsigned int u32; +typedef int i32; +typedef unsigned short u16; +typedef short i16; +typedef unsigned char u8; +typedef char i8; + +#define high16(i32) (i32 & 0xffff) +#define low16(i32) ((i32>>16) & 0xffff) + +#define TRUE 1 +#define FALSE 0 +#define NULL 0 + +#endif \ No newline at end of file diff --git a/src/kernel/print.c b/src/kernel/print.c new file mode 100644 index 0000000..014de03 --- /dev/null +++ b/src/kernel/print.c @@ -0,0 +1,110 @@ +#include "print.h" +#include "./platform/drivers/ports.h" + +int row = 0; +int col = 0; +char color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4; + +void clear_row(int row) { + struct Char* buffer = (struct Char*) 0xb8000; + + struct Char empty = (struct Char) { + character: ' ', + color: color, + }; + + for (int x = 0; x < NUM_COLS; x++) { + buffer[x + NUM_COLS * row] = empty; + } + set_cursor_pos(col, row); +} + +void clear_all() { + for (int i = 0; i < NUM_ROWS; i++) { + clear_row(i); + } + set_cursor_pos(col, row); +} + +void print_newline() { + struct Char* buffer = (struct Char*) 0xb8000; + + col = 0; + + if (row < NUM_ROWS - 1) { + row++; + return; + } + + for (int row = 1; row < NUM_ROWS; row++) { + for (int col = 0; col < NUM_COLS; col++) { + struct Char character = buffer[col + NUM_COLS * row]; + buffer[col + NUM_COLS * (row - 1)] = character; + } + } + + clear_row(NUM_COLS - 1); + set_cursor_pos(col, row); +} + +void print_char(char character) { + struct Char* buffer = (struct Char*) 0xb8000; + + if (character == '\n') { + print_newline(); + return; + } + + if (col > NUM_COLS) { + print_newline(); + } + + struct Char cr = (struct Char) { + character: character, + color: color, + }; + buffer[col + NUM_COLS * row] = cr; + + col++; + set_cursor_pos(col, row); +} + +void print_str(char* str) { + for (int i = 0; 1; i++) { + char character = (char) str[i]; + + if (character == '\0') { + return; + } + + print_char(character); + } +} + +void print_set_color(char foreground, char background) { + color = foreground + (background << 4); +} + +void set_cursor_pos(int col, int row) { + int offset = col + NUM_COLS * row; + port_byte_out(REG_SCREEN_CTRL, 14); + port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8)); + port_byte_out(REG_SCREEN_CTRL, 15); + port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff)); +} + +void kernel_msg_ok(char* msg) { + char ok_p1[] = "[ "; + char ok_p2[] = "OK "; + char ok_p3[] = "] "; + + print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); + print_str(ok_p1); + + print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK); + print_str(ok_p2); + + print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); + print_str(ok_p3); + print_str(msg); +} \ No newline at end of file diff --git a/src/kernel/print.h b/src/kernel/print.h new file mode 100644 index 0000000..edd8a9e --- /dev/null +++ b/src/kernel/print.h @@ -0,0 +1,44 @@ +#ifndef PRINT_H +#define PRINT_H +#define REG_SCREEN_CTRL 0x3d4 +#define REG_SCREEN_DATA 0x3d5 + +enum { + PRINT_COLOR_BLACK = 0, + PRINT_COLOR_BLUE = 1, + PRINT_COLOR_GREEN = 2, + PRINT_COLOR_CYAN = 3, + PRINT_COLOR_RED = 4, + PRINT_COLOR_MAGENTA = 5, + PRINT_COLOR_BROWN = 6, + PRINT_COLOR_LIGHT_GRAY = 7, + PRINT_COLOR_DARK_GRAY = 8, + PRINT_COLOR_LIGHT_BLUE = 9, + PRINT_COLOR_LIGHT_GREEN = 10, + PRINT_COLOR_LIGHT_CYAN = 11, + PRINT_COLOR_LIGHT_RED = 12, + PRINT_COLOR_PINK = 13, + PRINT_COLOR_YELLOW = 14, + PRINT_COLOR_WHITE = 15, +}; + +const static int NUM_COLS = 80; +const static int NUM_ROWS = 25; + +struct Char { + char character; + char color; +}; + +void clear_row(int row); +void clear_all(); + +void print_newline(); +void print_char(char character); +void print_set_color(char foreground, char background); +void print_str(char* str); + +void set_cursor_pos(int col, int row); + +void kernel_msg_ok(char* msg); +#endif \ No newline at end of file diff --git a/src/kernel/strings.c b/src/kernel/strings.c new file mode 100644 index 0000000..79897f8 --- /dev/null +++ b/src/kernel/strings.c @@ -0,0 +1,48 @@ +#include "strings.h" +#include "./platform/types.h" + +void itoa(int n, char str[]) { + int i, sign; + if ((sign = n) < 0) n = -n; + i = 0; + do { + str[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + + if (sign < 0) str[i++] = '-'; + str[i] = '\0'; + + strrev(str); +} + +/* K&R */ +void strrev(char s[]) { + int c, i, j; + for (i = 0, j = strlen(s)-1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +/* K&R */ +int strlen(char s[]) { + int i = 0; + while (s[i] != '\0') ++i; + return i; +} + +char* strcpy(char* strDest, const char* strSrc) { + if ( (strDest == NULL) || (strSrc == NULL) ) { + return NULL; + } + char* strDestCopy = strDest; + while ((*strDest++=*strSrc++)!='\0'); + return strDestCopy; +} + +char* strcnc(char* str1, char* str2) { + char* str_dest; + strcpy(str_dest, str1); + strcpy(str_dest, str2); +} \ No newline at end of file diff --git a/src/kernel/strings.h b/src/kernel/strings.h new file mode 100644 index 0000000..ee4402a --- /dev/null +++ b/src/kernel/strings.h @@ -0,0 +1,10 @@ +#ifndef STRINGS_H +#define STRINGS_H + +void itoa(int n, char str[]); +void strrev(char s[]); +int strlen(char s[]); +char* strcpy(char* strDest, const char* strSrc); +char* strcnc(char* str1, char* str2); + +#endif \ No newline at end of file diff --git a/src/kernel/util.c b/src/kernel/util.c new file mode 100644 index 0000000..e945d94 --- /dev/null +++ b/src/kernel/util.c @@ -0,0 +1,25 @@ +#include "util.h" + +void memcpy(char *source, char *dest, int nbytes) { + int i; + for (i = 0; i < nbytes; i++) { + *(dest + i) = *(source + i); + } +} + +void memset(char *dest, char val, int len) { + char *temp = (char *)dest; + for(; len !=0; len--) *temp++ = val; +} + +void int_to_ascii(int n, char str[]) { + int i, sign; + if ((sign = n) < 0) n = -n; + i = 0; + do { + str[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + + if (sign < 0) str[i++] = '-'; + str[i] = '\0'; +} \ No newline at end of file diff --git a/src/kernel/util.h b/src/kernel/util.h new file mode 100644 index 0000000..889ccb0 --- /dev/null +++ b/src/kernel/util.h @@ -0,0 +1,8 @@ +#ifndef UTIL_H +#define UTIL_H + +void memcpy(char *source, char *dest, int nbytes); +void memset(char *dest, char val, int len); +void int_to_ascii(int n, char str[]); + +#endif \ No newline at end of file diff --git a/src/linker.ld b/src/linker.ld new file mode 100644 index 0000000..dfc6a97 --- /dev/null +++ b/src/linker.ld @@ -0,0 +1,32 @@ +ENTRY(_start) + +SECTIONS +{ + . = 1M; + + /* MB header */ + .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) + } +} \ No newline at end of file