diff --git a/README b/README index eb76f76..e81e2d2 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ kern. ===== -_Idk why i called it that it was 3am and i needed sleep._ +Idk why i called it that it was 3am and i needed sleep. !! WARNING !! Kern is broken at the moment. The last working commit is: '11feab5' @@ -13,8 +13,6 @@ Kern is a 32-bit OS based on the x86 architecture written in NASM Assembly and C I'm working on a basic command line as well as a custom unix-esque filesystem. It has a simple shell with some commands (use 'help' for a list of available ones). -Since there's always more to do, here are the TODO. - Features -------- * Shell diff --git a/boot/makefile b/boot/makefile index e69de29..e52c5f7 100644 --- a/boot/makefile +++ b/boot/makefile @@ -0,0 +1,7 @@ +.PHONY: all clean + +all: + @echo "TODO: Write this makefile..." + +clean: + diff --git a/defaults.mk b/defaults.mk index 2b93e63..ef3385c 100644 --- a/defaults.mk +++ b/defaults.mk @@ -1,3 +1,30 @@ # # kern. makefile defaults # + +# Tools +HOSTCC = cc +CC = i686-elf-gcc +LD = i686-elf-ld +AS = nasm +MAKE = make + +# Flags +CFLAGS = -Wall -Wextra -Wpedantic -Wno-pointer-arith\ + -ffreestanding -fno-stack-protector -fno-builtin -fno-pie -fcommon\ + -O2 -std=c17 -nostdinc -nostdlib -z notext -march=i386 +LDFLAGS = -melf_i386 +ASFLAGS = + +# Directories +KERNEL_DIR = ./kernel +BOOT_DIR = ./boot +LIBC_DIR = ./libc +USER_DIR = ./user + +# Modules +MODULES = $(KERNEL_DIR) \ + $(BOOT_DIR) \ + $(LIBC_DIR) \ + $(USER_DIR) + diff --git a/docs/modules.txt b/docs/modules.txt index 8befa4a..c1a6032 100644 --- a/docs/modules.txt +++ b/docs/modules.txt @@ -7,8 +7,10 @@ Independant Modules * Each MAY have their own internal independant submodules (eg. userspace programs in 'usr/') * A module MAY be dependant on it's own submodules, but it's submodules MUST be independant of each other * Each MUST have a makefile in their directory (eg. 'libc/makefile') +* Each module makefile MUST implement the 'all' and 'clean' targets * Each module MUST be listed in the 'make.defaults' directory * Each module MUST be self-contained and independentally compilable +* A module SHOULD output binaries into the 'bin/' directory kern (Root "module", is dependant on all of it's submodules) |- boot diff --git a/kernel/header.c b/kernel/header.c new file mode 100644 index 0000000..97ebefe --- /dev/null +++ b/kernel/header.c @@ -0,0 +1,15 @@ +#include "multiboot.h" + +#define FLAGS (MBH_PAGE_ALIGN | MBH_GRAPH_INFO) + +__attribute__ ((section(".multiboot"))) +struct multiboot_header mbh = { + .magic = HEAD_MAGIC, + .flags = FLAGS, + .checksum = -(HEAD_MAGIC + FLAGS), + // We don't need the a.out format fields + .mode_type = 0, + .width = 1920, + .height = 1080, + .depth = 32, +}; diff --git a/kernel/kernel.c b/kernel/kernel.c new file mode 100644 index 0000000..b8f2161 --- /dev/null +++ b/kernel/kernel.c @@ -0,0 +1,200 @@ +#include "stdint.h" +#include "multiboot.h" + +/* Constants */ +#define COLS 80 +#define ROWS 24 +#define ATTR 0x0f +#define VID_MEM 0xb8000 + +/* Variables */ +static int xpos; +static int ypos; +static uint8_t* video; + +/* Forward Declarations */ +void cls(void); +void itoa(char* buf, int base, int d); +void putc(int c); +void printf(const char* fmt, ...); + +/* Entry Point */ +void kmain(void) { + uint32_t magic, addr; + __asm__ volatile ("movl %%eax, %0; movl %%ebx, %1" : "=m"(magic), "=m"(addr)); + struct multiboot_info* mbi; + video = (uint8_t*)VID_MEM; + + // Clear Screen + cls(); + + // Didn't boot with Multiboot + if (magic != BOOT_MAGIC) { + printf("Invalid Magic Number: 0x%x\n", magic); + while (1); + } + + mbi = (struct multiboot_info*)addr; + + printf("flags: 0x%x\n", mbi->flags); + + if (mbi->flags & MBI_MEMORY) { + printf("mem_lower: %ukB, mem_upper: %ukB\n", + mbi->mem_lower, mbi->mem_upper); + } + + if (mbi->flags & MBI_BOOT_DEV) { + printf("boot_device: 0x%x\n", mbi->boot_device); + } + + if (mbi->flags & MBI_CMDLINE) { + printf("cmdline: %s\n", mbi->cmdline); + } + + if (mbi->flags & MBI_MODS) { + printf("mods_count: %d, mods_addr: 0x%x\n", + mbi->mods_count, mbi->mods_addr); + + struct multiboot_module* mod = + (struct multiboot_module*)mbi->mods_addr; + + for (size_t i = 0; i < mbi->mods_count; i++) { + printf(" start 0x%x, end: 0x%x, cmdline: %s\n", + mod->start, mod->end, mod->cmdline); + mod++; + } + } + + if (mbi->flags & MBI_SYMBOLS && + mbi->flags & MBI_ELF_HEAD) { + printf("Flag SYMBOLS and ELF HEADER are both set!\n"); + while (1); + } + + if (mbi->flags & MBI_MEMMAP) { + printf("mmap_addr: 0x%x, mmap_length: 0x%x\n", + mbi->mmap_addr, mbi->mmap_length); + + struct multiboot_memmap* mmap = + (struct multiboot_memmap*)mbi->mmap_addr; + + while ((uint32_t)mmap < mbi->mmap_addr + mbi->mmap_length) { + printf( " size: 0x%x, base: 0x%08x, " + "length: 0x%08x, type: 0x%x\n", + mmap->size, mmap->base, mmap->len, mmap->type); + + mmap = (struct multiboot_memmap*) + ((uint32_t)mmap + mmap->size + (sizeof(mmap->size))); + } + } + + while (1); +} + +void cls(void) { + for (int i = 0; i < COLS * ROWS * 2; i++) video[i] = 0; + xpos = 0; + ypos = 0; +} + +void itoa(char* buf, int base, int d) { + char* p = buf; + char* p1; + char* p2; + uint32_t ud = d; + int divisor = 10; + + if (base == 'd' && d < 0) { + *p++ = '-'; + buf++; + ud = -d; + } else if (base == 'x') divisor = 16; + + do { + int remainder = ud % divisor; + *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; + } while (ud /= divisor); + + *p = 0; + + p1 = buf; + p2 = p - 1; + while (p1 < p2) { + char tmp = *p1; + *p1 = *p2; + *p2 = tmp; + p1++; + p2--; + } +} + +/* Put the character C on the screen. */ +void putc(int c) { + if (c == '\n' || c == '\r') { + newline: + xpos = 0; + ypos++; + if (ypos >= ROWS) + ypos = 0; + return; + } + + video[(xpos + ypos * COLS) * 2] = c & 0xFF; + video[(xpos + ypos * COLS) * 2 + 1] = ATTR; + + xpos++; + if (xpos >= COLS) + goto newline; +} + +void printf(const char *format, ...) { + char** arg = (char**)&format; + int c; + char buf[20]; + + arg++; + + while ((c = *format++) != 0) { + if (c != '%') { + putc (c); + continue; + } + + char *p, *p2; + int pad0 = 0, pad = 0; + + c = *format++; + + if (c == '0') { + pad0 = 1; + c = *format++; + } + + if (c >= '0' && c <= '9') { + pad = c - '0'; + c = *format++; + } + + switch (c) { + case 'd': + case 'u': + case 'x': + itoa(buf, c, *((int *) arg++)); + p = buf; + goto string; + break; + case 's': + p = *arg++; + if (! p) p = "(null)"; + string: + for (p2 = p; *p2; p2++); + for (; p2 < p + pad; p2++) putc (pad0 ? '0' : ' '); + while (*p) putc (*p++); + break; + default: + putc(*((int *) arg++)); + break; + } + } +} + diff --git a/kernel/linker.ld b/kernel/linker.ld new file mode 100644 index 0000000..b036efa --- /dev/null +++ b/kernel/linker.ld @@ -0,0 +1,43 @@ +OUTPUT_FORMAT(elf32-i386) +ENTRY(kmain) + +SECTIONS { + . = 0x00100000; + + /* Multiboot Header */ + .multiboot ALIGN(4) : { + *(.multiboot) + } + + /* Kernel Code */ + .text ALIGN(4) : { + *(.text) + *(.text.*) + } + + /* Read-Only Data */ + .rodata ALIGN(4) : { + *(.rodata) + *(.rodata.*) + } + + /* Read/Write Data */ + .data ALIGN(4) : { + *(.data) + *(.data.*) + } + + /* BSS Section */ + .bss ALIGN(4) : { + *(COMMON) + *(.bss) + *(.bss.*) + } + + /* Discarded Sections */ + /DISCARD/ : { + *(.note) + *(.note.*) + *(.comment) + } +} diff --git a/kernel/makefile b/kernel/makefile new file mode 100644 index 0000000..298064b --- /dev/null +++ b/kernel/makefile @@ -0,0 +1,19 @@ +include defaults.mk + +SRCS = $(shell find $(SRC) -name '**.c') +OBJS = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS)) +LINKER = $(SRC)/linker.ld +OUT = $(BIN)/kernel.elf + +.PHONY: all clean + +all: $(OUT) +$(OUT): $(OBJS) + $(LD) $(LDFLAGS) -T $(LINKER) -o $@ $^ + +$(BIN)/%.o: $(SRC)/%.c + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -fr $(BIN) + diff --git a/kernel/multiboot.h b/kernel/multiboot.h new file mode 100644 index 0000000..e79a12b --- /dev/null +++ b/kernel/multiboot.h @@ -0,0 +1,96 @@ +#ifndef _MULTIBOOT_H +#define _MULTIBOOT_H + +#include "stdint.h" + +#define __packed __attribute__ ((packed)) + +#define HEAD_MAGIC 0x1BADB002 +#define BOOT_MAGIC 0x2BADB002 + +// Multiboot Header Flags +enum { + MBH_PAGE_ALIGN = (1<<0), + MBH_MEMORY_INFO = (1<<1), + MBH_GRAPH_INFO = (1<<2), + MBH_ADDR_FIELDS = (1<<16), +}; + +struct multiboot_header { + uint32_t magic; + uint32_t flags; + uint32_t checksum; + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; + uint32_t mode_type; + uint32_t width; + uint32_t height; + uint32_t depth; +} __packed; + +// Multiboot Info Flags +enum { + MBI_MEMORY = (1<<0), + MBI_BOOT_DEV = (1<<1), + MBI_CMDLINE = (1<<2), + MBI_MODS = (1<<3), + MBI_SYMBOLS = (1<<4), + MBI_ELF_HEAD = (1<<5), + MBI_MEMMAP = (1<<6), + MBI_DRIVES = (1<<7), + MBI_CONF_TAB = (1<<8), + MBI_BOOTLD_NAME = (1<<9), + MBI_APM_TABLE = (1<<10), + MBI_VBE_TABLE = (1<<11), + MBI_FB_TABLE = (1<<12), +}; + +struct multiboot_info { + uint32_t flags; + uint32_t mem_lower; + uint32_t mem_upper; + uint32_t boot_device; + uint32_t cmdline; + uint32_t mods_count; + uint32_t mods_addr; + uint32_t syms[4]; + uint32_t mmap_length; + uint32_t mmap_addr; + uint32_t drives_length; + uint32_t drives_addr; + uint32_t config_table; + uint32_t bootloader_name; + uint32_t apm_table; + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint32_t vbe_mode; + uint32_t vbe_interface_seg; + uint32_t vbe_interface_off; + uint32_t vbe_interface_len; + uint32_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint32_t framebuffer_bpp; + uint32_t framebuffer_type; + uint32_t color_info; +} __packed; + +struct multiboot_module { + uint32_t start; + uint32_t end; + uint32_t cmdline; + uint32_t __reserved; +} __packed; + +struct multiboot_memmap { + uint32_t size; + uint64_t base; + uint64_t len; + uint32_t type; +} __packed; + +#endif diff --git a/kernel/stdint.h b/kernel/stdint.h new file mode 100644 index 0000000..c76ac94 --- /dev/null +++ b/kernel/stdint.h @@ -0,0 +1,23 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#define NULL ((void*)0) + +// Naitive width +typedef unsigned int size_t; +typedef signed int ssize_t; + +// Signed ints +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +// Unsigned ints +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + + +#endif diff --git a/libc/include/ctype.h b/libc/include/ctype.h index 3cf0133..b0fd212 100644 --- a/libc/include/ctype.h +++ b/libc/include/ctype.h @@ -1,17 +1,19 @@ #ifndef _CTYPE_H #define _CTYPE_H -/* Bitfield values - Property | Bit - ------------|----- - Digit | 0 - Letter | 1 - Lowercase | 2 - Punct | 3 - Space | 4 - Control | 5 - Printable | 6 - Hex digit | 7 +/* + * Bitfield values + * + * Property | Bit + * ------------|----- + * Digit | 0 + * Letter | 1 + * Lowercase | 2 + * Punct | 3 + * Space | 4 + * Control | 5 + * Printable | 6 + * Hex digit | 7 */ #define _DIGIT_MASK (1<<0) #define _ALPHA_MASK (1<<1) diff --git a/libc/makefile b/libc/makefile index 1111e3a..e52c5f7 100644 --- a/libc/makefile +++ b/libc/makefile @@ -1,14 +1,7 @@ -# -# C Standard library -# +.PHONY: all clean -include make.defaults +all: + @echo "TODO: Write this makefile..." -$(LIBC): $(LIBC_SRC) - @echo "Building $(LIBC)..." - for f in $(LIBC_SRC); do\ - filename=$$(basename $$f .c);\ - $(CC) $(CFLAGS) -I$(LIBC_INC) -o $(BIN)/libc/$$filename.o -c $$f;\ - done - $(LD) $(LDFLAGS) -r -o $(LIBC) $(BIN)/libc/**.o +clean: diff --git a/makefile b/makefile index 783347c..88492b1 100644 --- a/makefile +++ b/makefile @@ -3,7 +3,38 @@ # (c) 2023-2025 Tomas Kubecek # +export VERSION = 0.3.0 + +# Configurable variables include defaults.mk +BIN = ./bin +IMG = ./kern.img +.PHONY: all clean qemu msg $(MODULES) + +all: msg $(IMG) +$(IMG): $(MODULES) + @echo "\nDone!\n" + +# Build each module +$(MODULES): + mkdir -p $(BIN)/$@ + $(MAKE) BIN=$(BIN)/$@ SRC=$@ -f $@/makefile all + +clean: + for m in $(MODULES); do $(MAKE) BIN=$(BIN)/$$m SRC=$$m -C . -f $$m/makefile clean; done + rm -fr $(BIN) + rm -fr $(IMG) + +msg: + @echo "\x1b[36mBuilding \x1b[1mkern.\x1b[22m V$(VERSION)\x1b[0m\n" + +# Core Audio only works on MacOS +qemu: + qemu-system-x86_64\ + -drive format=raw,file=$(IMG),index=0,media=disk\ + -m 256M -accel tcg -monitor stdio\ + -rtc base=localtime,clock=host,driftfix=slew\ + -audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 diff --git a/user/makefile b/user/makefile new file mode 100644 index 0000000..e52c5f7 --- /dev/null +++ b/user/makefile @@ -0,0 +1,7 @@ +.PHONY: all clean + +all: + @echo "TODO: Write this makefile..." + +clean: +