From 8cf8be522133548ee25fdcb0258ddf3950a68bcf Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Mon, 8 Dec 2025 22:25:48 +0800 Subject: The start of the project -- A MicroDOS feat: Initial bare-metal RISC-V boot with UART --- Makefile | 61 +++++++++++++++++++++++++++++++++++++++++ build/kernel.elf | Bin 0 -> 6616 bytes build/src/boot/entry.d | 1 + build/src/boot/entry.o | Bin 0 -> 2024 bytes build/src/drivers/uart.d | 2 ++ build/src/drivers/uart.o | Bin 0 -> 2688 bytes build/src/kernel/main.d | 1 + build/src/kernel/main.o | Bin 0 -> 3344 bytes include/common/types.h | 14 ++++++++++ include/drivers/uart.h | 7 +++++ kernel.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++++ linker.ld | 47 ++++++++++++++++++++++++++++++++ src/boot/entry.S | 28 +++++++++++++++++++ src/drivers/uart.cc | 57 +++++++++++++++++++++++++++++++++++++++ src/kernel/main.cc | 20 ++++++++++++++ 15 files changed, 307 insertions(+) create mode 100644 Makefile create mode 100755 build/kernel.elf create mode 100644 build/src/boot/entry.d create mode 100644 build/src/boot/entry.o create mode 100644 build/src/drivers/uart.d create mode 100644 build/src/drivers/uart.o create mode 100644 build/src/kernel/main.d create mode 100644 build/src/kernel/main.o create mode 100644 include/common/types.h create mode 100644 include/drivers/uart.h create mode 100644 kernel.cc create mode 100644 linker.ld create mode 100644 src/boot/entry.S create mode 100644 src/drivers/uart.cc create mode 100644 src/kernel/main.cc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4d80143 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +TOOLCHAIN := riscv64-linux-gnu +CC := $(TOOLCHAIN)-gcc +CXX := $(TOOLCHAIN)-g++ +LD := $(TOOLCHAIN)-ld +OBJCOPY := $(TOOLCHAIN)-objcopy + +TARGET_ELF := build/kernel.elf +TARGET_BIN := build/kernel.bin + +ARCH_FLAGS := -march=rv64gc -mabi=lp64 -mcmodel=medany +CFLAGS := -Wall -Wextra -O2 -ffreestanding -nostdlib -Iinclude $(ARCH_FLAGS) +CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti -fno-use-cxa-atexit + +SRC_DIRS := src +SRCS_ASM := $(shell find $(SRC_DIRS) -name "*.S") +SRCS_CXX := $(shell find $(SRC_DIRS) -name "*.cc") + +OBJS := $(SRCS_ASM:%.S=build/%.o) $(SRCS_CXX:%.cc=build/%.o) + +DEPS := $(OBJS:.o=.d) + + +LINKER_SCRIPT := linker.ld + +QEMU := qemu-system-riscv64 +QEMU_FLAGS := -machine virt -m 128M -nographic -bios none -kernel $(TARGET_ELF) + + +.PHONY: all clean run debug directories + +all: directories $(TARGET_ELF) + +$(TARGET_ELF): $(OBJS) $(LINKER_SCRIPT) + @echo "Linking $@" + @$(LD) -T $(LINKER_SCRIPT) -o $@ $(OBJS) + +build/%.o: %.S + @mkdir -p $(dir $@) + @echo "Compiling ASM $<" + @$(CC) $(CFLAGS) -MMD -c $< -o $@ + +build/%.o: %.cc + @mkdir -p $(dir $@) + @echo "Compiling C++ $<" + @$(CXX) $(CXXFLAGS) -MMD -c $< -o $@ + +directories: + @mkdir -p build + +run: all + @echo "Starting QEMU..." + $(QEMU) $(QEMU_FLAGS) + +debug: all + @echo "Starting QEMU in debug mode (connect with gdb-multiarch)..." + $(QEMU) $(QEMU_FLAGS) -S -s + +clean: + @rm -rf build + +-include $(DEPS) \ No newline at end of file diff --git a/build/kernel.elf b/build/kernel.elf new file mode 100755 index 0000000..e57b2af Binary files /dev/null and b/build/kernel.elf differ diff --git a/build/src/boot/entry.d b/build/src/boot/entry.d new file mode 100644 index 0000000..db71800 --- /dev/null +++ b/build/src/boot/entry.d @@ -0,0 +1 @@ +build/src/boot/entry.o: src/boot/entry.S diff --git a/build/src/boot/entry.o b/build/src/boot/entry.o new file mode 100644 index 0000000..5244030 Binary files /dev/null and b/build/src/boot/entry.o differ diff --git a/build/src/drivers/uart.d b/build/src/drivers/uart.d new file mode 100644 index 0000000..e6ff9b6 --- /dev/null +++ b/build/src/drivers/uart.d @@ -0,0 +1,2 @@ +build/src/drivers/uart.o: src/drivers/uart.cc include/drivers/uart.h \ + include/common/types.h diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o new file mode 100644 index 0000000..9283f15 Binary files /dev/null and b/build/src/drivers/uart.o differ diff --git a/build/src/kernel/main.d b/build/src/kernel/main.d new file mode 100644 index 0000000..a31a83b --- /dev/null +++ b/build/src/kernel/main.d @@ -0,0 +1 @@ +build/src/kernel/main.o: src/kernel/main.cc include/drivers/uart.h diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o new file mode 100644 index 0000000..bf89688 Binary files /dev/null and b/build/src/kernel/main.o differ diff --git a/include/common/types.h b/include/common/types.h new file mode 100644 index 0000000..56500c5 --- /dev/null +++ b/include/common/types.h @@ -0,0 +1,14 @@ +#pragma once + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +typedef uint64_t size_t; +typedef uint64_t uintptr_t; \ No newline at end of file diff --git a/include/drivers/uart.h b/include/drivers/uart.h new file mode 100644 index 0000000..8bf4560 --- /dev/null +++ b/include/drivers/uart.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Drivers { + void uart_init(); + void uart_putc(char c); + void uart_puts(const char* s); +} \ No newline at end of file diff --git a/kernel.cc b/kernel.cc new file mode 100644 index 0000000..f9cacba --- /dev/null +++ b/kernel.cc @@ -0,0 +1,69 @@ +extern "C" void kernel_main(); + +#define UART_ADDR 0x10000000UL + +#define THR_OFFSET 0x0 +#define LSR_OFFSET 0x5 +#define FCR_OFFSET 0x2 +#define LCR_OFFSET 0x3 +#define DLL_OFFSET 0x0 +#define DLH_OFFSET 0x1 + +static void +write_byte(unsigned long addr, char byte) +{ + *((volatile char *)addr) = byte; +} + +static int +is_tx_empty() +{ + return *((volatile char *)(UART_ADDR + LSR_OFFSET)) & (1 << 5); +} + +void uart_init() +{ + write_byte(UART_ADDR + LCR_OFFSET, 0x80); + + write_byte(UART_ADDR + DLL_OFFSET, 0x01); + write_byte(UART_ADDR + DLH_OFFSET, 0x00); + + write_byte(UART_ADDR + LCR_OFFSET, 0x03); + + write_byte(UART_ADDR + FCR_OFFSET, 0x07); +} + +void put_char(char c) +{ + if (c == '\n') + { + put_char('\r'); + } + + while (!is_tx_empty()) + { + } + write_byte(UART_ADDR + THR_OFFSET, c); +} + +void print_str(const char *s) +{ + while (*s != '\0') + { + put_char(*s++); + } +} + +void kernel_main() +{ + uart_init(); + + print_str("Modern DOS 1.0\n"); + print_str("Hello OS! Running on RISC-V 64.\n"); + print_str("Hello Ziyi Yang! Love from RUC"); + + while (1) + { + + } +} \ No newline at end of file diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..0b01e98 --- /dev/null +++ b/linker.ld @@ -0,0 +1,47 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (wxa) : ORIGIN = 0x80000000, LENGTH = 128M +} + +SECTIONS +{ + . = 0x80000000; + + .text : { + PROVIDE(_text_start = .); + *(.text.entry) + *(.text .text.*) + PROVIDE(_text_end = .); + } > ram + + .rodata : { + . = ALIGN(16); + PROVIDE(_rodata_start = .); + *(.rodata .rodata.*) + PROVIDE(_rodata_end = .); + } > ram + + .data : { + . = ALIGN(16); + PROVIDE(_data_start = .); + *(.data .data.*) + *(.sdata .sdata.*) + PROVIDE(_data_end = .); + } > ram + + .bss : { + . = ALIGN(16); + PROVIDE(_bss_start = .); + *(.bss .bss.*) + *(.sbss .sbss.*) + PROVIDE(_bss_end = .); + } > ram + + . = ALIGN(4096); + PROVIDE(_stack_top = . + 0x8000); + . = . + 0x8000; + PROVIDE(_heap_start = .); +} \ No newline at end of file diff --git a/src/boot/entry.S b/src/boot/entry.S new file mode 100644 index 0000000..1a6f6b8 --- /dev/null +++ b/src/boot/entry.S @@ -0,0 +1,28 @@ +.section .text.entry +.globl _start + +_start: + csrr t0, mhartid + bnez t0, .L_park_harts + + la sp, _stack_top + + la a0, _bss_start + la a1, _bss_end + bge a0, a1, .L_call_main + +.L_clear_bss: + sd zero, (a0) + addi a0, a0, 8 + blt a0, a1, .L_clear_bss + +.L_call_main: + call kernel_main + +.L_infinite_loop: + wfi + j .L_infinite_loop + +.L_park_harts: + wfi + j .L_park_harts \ No newline at end of file diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc new file mode 100644 index 0000000..758abd9 --- /dev/null +++ b/src/drivers/uart.cc @@ -0,0 +1,57 @@ +#include "drivers/uart.h" +#include "common/types.h" + +#define UART0_BASE 0x10000000L + +#define UART_RBR 0x00 // Receiver Buffer Register (Read) +#define UART_THR 0x00 // Transmitter Holding Register (Write) +#define UART_IER 0x01 // Interrupt Enable Register +#define UART_FCR 0x02 // FIFO Control Register +#define UART_LCR 0x03 // Line Control Register +#define UART_LSR 0x05 // Line Status Register + +#define UART_LSR_RX_READY 0x01 +#define UART_LSR_TX_EMPTY 0x20 + +namespace Drivers{ + inline volatile uint8_t ®(uint32_t offset) + { + return *reinterpret_cast(UART0_BASE + offset); + } + + void uart_init() + { + reg(UART_IER) = 0x00; + + reg(UART_LCR) = 0x80; + reg(0x00) = 0x03; + reg(0x01) = 0x00; + + reg(UART_LCR) = 0x03; + + reg(UART_FCR) = 0x07; // Enable FIFO, clear TX/RX queues + } + + void uart_putc(char c) + { + if (c == '\n') + { + uart_putc('\r'); + } + + while ((reg(UART_LSR) & UART_LSR_TX_EMPTY) == 0) + { + + } + + reg(UART_THR) = c; + } + + void uart_puts(const char *s) + { + while (*s) + { + uart_putc(*s++); + } + } +} \ No newline at end of file diff --git a/src/kernel/main.cc b/src/kernel/main.cc new file mode 100644 index 0000000..49adf2b --- /dev/null +++ b/src/kernel/main.cc @@ -0,0 +1,20 @@ +#include "drivers/uart.h" + +extern "C" void kernel_main() +{ + + Drivers::uart_init(); + + Drivers::uart_puts("\n"); + Drivers::uart_puts("Modern DOS v1.0 [RISC-V 64]\n"); + Drivers::uart_puts("2025 Richard Qin\n"); + Drivers::uart_puts("\n"); + + Drivers::uart_puts("A:\\> "); + + + while (1) + { + + } +} \ No newline at end of file -- cgit v1.2.3