diff --git a/Makefile b/Makefile index 441b735..7841aca 100644 --- a/Makefile +++ b/Makefile @@ -2,21 +2,22 @@ CC = clang CFLAGS = -Wall -Wextra -g -std=c11 COMMON_SRCS = forth_core.c forth_dict.c forth_words.c forth_interp.c main.c -HOSTED_SRCS = $(COMMON_SRCS) platform_hosted.c -FREESTANDING_SRCS = $(COMMON_SRCS) platform_freestanding.c +LINUX_SRCS = $(COMMON_SRCS) platform_linux.c +KERNEL_SRCS = $(COMMON_SRCS) platform_kernel.c kernel_entry.S +KERNEL_LD = kernel.ld TARGET = forth -FREESTANDING_TARGET = forth_freestanding +KERNEL_TARGET = forth.kernel all: $(TARGET) -$(TARGET): $(HOSTED_SRCS) forth.h - $(CC) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -o $@ $(HOSTED_SRCS) +$(TARGET): $(LINUX_SRCS) forth.h + $(CC) $(CFLAGS) -static -nostdlib -ffreestanding -fno-stack-protector -o $@ $(LINUX_SRCS) -$(FREESTANDING_TARGET): $(FREESTANDING_SRCS) forth.h - $(CC) $(CFLAGS) -ffreestanding -nostdlib -fno-stack-protector -o $@ $(FREESTANDING_SRCS) +$(KERNEL_TARGET): $(KERNEL_SRCS) forth.h $(KERNEL_LD) + $(CC) $(CFLAGS) -ffreestanding -nostdlib -fno-stack-protector -mno-red-zone -o $@ $(KERNEL_SRCS) -T$(KERNEL_LD) -Wl,--build-id=none clean: - rm -f $(TARGET) $(FREESTANDING_TARGET) + rm -f $(TARGET) $(KERNEL_TARGET) .PHONY: all clean diff --git a/kernel.ld b/kernel.ld new file mode 100644 index 0000000..cda9d25 --- /dev/null +++ b/kernel.ld @@ -0,0 +1,30 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x100000; + + .text : ALIGN(4K) + { + *(.multiboot2) + *(.text) + } + + .rodata : ALIGN(4K) + { + *(.rodata) + } + + .data : ALIGN(4K) + { + *(.data) + } + + .bss : ALIGN(4K) + { + __bss_start = .; + *(.bss) + *(COMMON) + __bss_end = .; + } +} diff --git a/kernel_entry.S b/kernel_entry.S new file mode 100644 index 0000000..487384f --- /dev/null +++ b/kernel_entry.S @@ -0,0 +1,98 @@ +# Multiboot2 header and x86_64 long-mode bootstrap + +.section .multiboot2, "a" +.align 8 +multiboot_header: + .long 0xe85250d6 + .long 0 + .long multiboot_header_end - multiboot_header + .long -(0xe85250d6 + 0 + (multiboot_header_end - multiboot_header)) + + .align 8 + .word 0 + .word 0 + .long 8 +multiboot_header_end: + +.section .bss, "aw", @nobits +.align 4096 +pml4: + .space 4096 +pdpt: + .space 4096 +pd: + .space 4096 + +.align 16 +stack_bottom: + .space 16384 +stack_top: + +.section .text +.code32 +.global _start +.type _start, @function +_start: + movl $stack_top, %esp + + movl $pdpt, %eax + orl $0x03, %eax + movl %eax, pml4 + + movl $pd, %eax + orl $0x03, %eax + movl %eax, pdpt + + movl $0x00000083, %eax + movl $pd, %edi + movl $512, %ecx +1: + movl %eax, (%edi) + addl $0x200000, %eax + addl $8, %edi + loop 1b + + movl $pml4, %eax + movl %eax, %cr3 + + movl %cr4, %eax + orl $0x20, %eax + movl %eax, %cr4 + + movl $0xC0000080, %ecx + rdmsr + orl $0x100, %eax + wrmsr + + movl %cr0, %eax + orl $0x80000000, %eax + movl %eax, %cr0 + + lgdt gdt64_pointer + ljmp $0x08, $long_mode_start + +.code64 +long_mode_start: + movabsq $stack_top, %rax + movq %rax, %rsp + + movabsq $__bss_start, %rdi + movabsq $__bss_end, %rcx + subq %rdi, %rcx + xorq %rax, %rax + rep stosb + + call kernel_main + cli +1: + hlt + jmp 1b + +.section .rodata +.align 8 +gdt64: + .quad 0x0000000000000000 + .quad 0x00209A0000000000 +gdt64_pointer: + .word gdt64_pointer - gdt64 - 1 + .quad gdt64 diff --git a/platform_kernel.c b/platform_kernel.c new file mode 100644 index 0000000..fd240ca --- /dev/null +++ b/platform_kernel.c @@ -0,0 +1,142 @@ +#include "forth.h" +#include +#include + +// VGA text-mode buffer +static uint16_t* vga_buffer = (uint16_t*)0xB8000; +static int vga_row = 0; +static int vga_col = 0; + +static void vga_putchar(char c) { + if (c == '\n') { + vga_col = 0; + vga_row++; + } else { + int idx = vga_row * 80 + vga_col; + vga_buffer[idx] = (uint16_t)((0x0F << 8) | (unsigned char)c); + vga_col++; + if (vga_col >= 80) { + vga_col = 0; + vga_row++; + } + } + if (vga_row >= 25) { + vga_row = 0; + vga_col = 0; + } +} + +static inline void outb(uint16_t port, uint8_t val) { + __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); +} + +static inline uint8_t inb(uint16_t port) { + uint8_t ret; + __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static void serial_init(void) { + outb(0x3F8 + 1, 0x00); + outb(0x3F8 + 3, 0x80); + outb(0x3F8 + 0, 0x01); + outb(0x3F8 + 1, 0x00); + outb(0x3F8 + 3, 0x03); + outb(0x3F8 + 2, 0xC7); + outb(0x3F8 + 4, 0x0B); +} + +void forth_putchar(char c) { + vga_putchar(c); + while ((inb(0x3F8 + 5) & 0x20) == 0) { } + outb(0x3F8, (uint8_t)c); +} + +int forth_getchar(void) { + if ((inb(0x3F8 + 5) & 1) == 0) { + return FORTH_EOF; + } + return inb(0x3F8); +} + +void forth_fflush(void) { +} + +void forth_panic(void) { + __asm__ volatile ("cli; hlt"); + __builtin_unreachable(); +} + +int64_t forth_strtoll(const char* str, char** endptr, int base) { + const char* s = str; + int neg = 0; + int64_t val = 0; + while (forth_isspace(*s)) s++; + if (*s == '-') { neg = 1; s++; } + else if (*s == '+') { s++; } + while (*s >= '0' && *s <= '9') { + val = val * base + (*s - '0'); + s++; + } + if (endptr) *endptr = (char*)s; + return neg ? -val : val; +} + +static void print_str(const char* s) { + while (*s) forth_putchar(*s++); +} + +static void print_int(long long v) { + char buf[32]; + int i = 30; + int neg = 0; + if (v < 0) { neg = 1; v = -v; } + buf[31] = '\0'; + if (v == 0) { + buf[i--] = '0'; + } else { + while (v > 0 && i >= 0) { + buf[i--] = '0' + (v % 10); + v /= 10; + } + } + if (neg) buf[i--] = '-'; + print_str(&buf[i + 1]); +} + +void forth_printf(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + while (*fmt) { + if (*fmt == '%' && *(fmt + 1)) { + fmt++; + if (*fmt == 's') { + print_str(va_arg(ap, const char*)); + } else if (*fmt == 'c') { + forth_putchar((char)va_arg(ap, int)); + } else if (*fmt == '%') { + forth_putchar('%'); + } else if (*fmt == 'l') { + if (*(fmt + 1) == 'l' && (*(fmt + 2) == 'd' || *(fmt + 2) == 'i' || *(fmt + 2) == 'u')) { + fmt += 2; + print_int(va_arg(ap, long long)); + } + } else if (*fmt == 'd' || *fmt == 'i' || *fmt == 'u') { + print_int(va_arg(ap, int)); + } else { + forth_putchar('%'); + forth_putchar(*fmt); + } + } else { + forth_putchar(*fmt); + } + fmt++; + } + va_end(ap); +} + +void kernel_main(void) { + serial_init(); + forth_run(); + forth_panic(); +}