summaryrefslogtreecommitdiff
path: root/Makefile
diff options
context:
space:
mode:
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile458
1 files changed, 368 insertions, 90 deletions
diff --git a/Makefile b/Makefile
index 0722f8c..88689f5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,20 +1,81 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2026 Richard Qin
+#
+# LumeOS Kernel Makefile (Non-Recursive)
+#
+# Usage:
+# make - Build kernel ELF
+# make run - Run in QEMU
+# make debug - Run in QEMU with GDB server
+# make clean - Clean build artifacts
+# make fmt - Format all source files
+# make disasm - Generate disassembly listing
+#
+# Reference: docs/specs/00_conventions.md §7
-# Try to find a suitable RISC-V toolchain prefix
+# ============================================================
+# Build Configuration
+# ============================================================
+BUILD := build
+
+# Make sure `make` with no arguments builds the kernel image, not the
+# first rule encountered during makefile parsing. scripts/Kconfig.mk
+# (included next) defines `defconfig:` at the top of its rule list,
+# which would otherwise become the default goal and silently overwrite
+# .config from arch/$(ARCH)/defconfig.
+.DEFAULT_GOAL := all
+
+# Load Kbuild helpers (Q, $(call cmd,...), quiet_cmd_* / cmd_* templates,
+# kbuild-objs translator). Must come before Kconfig.mk so subsequent
+# rules can use $(call cmd,...) immediately.
+include scripts/Kbuild.include
+
+# Load Kconfig infrastructure (reads .config, sets KCPPFLAGS)
+include scripts/Kconfig.mk
+
+ARCH ?= $(CONFIG_ARCH)
+
+# Two boot products — same pair as Linux RISC-V's arch/riscv/boot/Makefile
+# (vmlinux + Image), but named LumeOS-style:
+# VMLUME -> build/vmlume.elf : ELF with .symtab/PT_DYNAMIC/.rela.dyn
+# IMAGE -> build/vmlume.bin : raw binary (objcopy -O binary)
+VMLUME := $(BUILD)/vmlume.elf
+IMAGE := $(BUILD)/vmlume.bin
+
+# Initramfs paths
+INITRAMFS_DIR := $(BUILD)/initramfs
+INITRAMFS_CPIO := $(BUILD)/initramfs.cpio
+INITRAMFS_OBJ := $(BUILD)/initramfs.o
+USR_INIT_ELF := $(BUILD)/usr/init
+# Relocations: linker emits .rela.dyn under -shared -Bsymbolic; boot
+# code in arch/riscv/mm/init.cc::relocate_kernel walks it at startup.
+LDS_SRC := arch/$(ARCH)/kernel/lumeos.lds.S
+LINKER_SCRIPT := $(BUILD)/lumeos.lds
+PYTHON ?= python3
+
+# ============================================================
+# Toolchain Detection
+# ============================================================
ifndef TOOLCHAIN_PREFIX
+ifeq ($(ARCH),riscv)
+ # Prefer the linux-gnu toolchain — it supports -shared / -pie which
+ # are required to emit .rela.dyn (Linux RISC-V kernel uses the same).
+ # The bare-metal `riscv64-unknown-elf-` is kept only as a last-resort
+ # fallback; with that one, `-shared` fails ("not supported") and the
+ # kernel can't relocate at runtime.
TOOLCHAIN_PREFIX := $(shell \
- if command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then \
- echo riscv64-linux-gnu-; \
- elif command -v riscv64-unknown-gnu-gcc >/dev/null 2>&1; then \
- echo riscv64-unknown-gnu-; \
- elif command -v riscv64-unknown-linux-gnu-gcc >/dev/null 2>&1; then \
+ if command -v riscv64-unknown-linux-gnu-g++ >/dev/null 2>&1; then \
echo riscv64-unknown-linux-gnu-; \
- elif command -v riscv64-unknown-elf-gcc >/dev/null 2>&1; then \
- echo riscv64-unknown-elf-; \
- else \
+ elif command -v riscv64-linux-gnu-g++ >/dev/null 2>&1; then \
echo riscv64-linux-gnu-; \
+ else \
+ echo riscv64-unknown-linux-gnu-; \
fi)
+else ifeq ($(ARCH),aarch64)
+ TOOLCHAIN_PREFIX := aarch64-linux-gnu-
+else ifeq ($(ARCH),x86_64)
+ TOOLCHAIN_PREFIX := x86_64-linux-gnu-
+endif
endif
CC := $(TOOLCHAIN_PREFIX)gcc
@@ -22,120 +83,337 @@ CXX := $(TOOLCHAIN_PREFIX)g++
LD := $(TOOLCHAIN_PREFIX)ld
OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy
OBJDUMP := $(TOOLCHAIN_PREFIX)objdump
+# Objcopy output formats for binary-to-ELF relocation blob
+OBJCOPY_ELF_riscv := elf64-littleriscv
+OBJCOPY_ELF_aarch64 := elf64-littleaarch64
+OBJCOPY_ELF_x86_64 := elf64-x86-64
+OBJCOPY_ELF := $(OBJCOPY_ELF_$(ARCH))
-BUILD_DIR := build
-SRC_DIR := src
+OBJCOPY_BINARCH_riscv := riscv
+OBJCOPY_BINARCH_aarch64 := aarch64
+OBJCOPY_BINARCH_x86_64 := i386:x86-64
+OBJCOPY_BINARCH := $(OBJCOPY_BINARCH_$(ARCH))
-CFLAGS := -Wall -Wextra -O2 -g -ffreestanding -nostdlib -mcmodel=medany -Iinclude
-CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti -fno-use-cxa-atexit
-LINKER_SCRIPT := linker.ld
+# Common flags (base, before module includes)
+WARNINGS := -Wall -Wextra -Wno-unused-parameter
+INCLUDES := -Iinclude -I.
-USER_LD := $(SRC_DIR)/user/user.ld
-ULIB_OBJS := $(BUILD_DIR)/user/entry.o \
- $(BUILD_DIR)/user/usys.o \
- $(BUILD_DIR)/ulib/stdio.o \
- $(BUILD_DIR)/ulib/stdlib.o \
- $(BUILD_DIR)/ulib/string.o \
- $(BUILD_DIR)/ulib/cxx.o \
- $(BUILD_DIR)/ulib/iostream.o \
- $(BUILD_DIR)/ulib/syscalls.o
+# ============================================================
+# Source Collection (Non-Recursive Module Fragments)
+# Module .mk files may append to SRCS_CC, SRCS_S, INCLUDES
+# ============================================================
+SRCS_CC :=
+SRCS_C :=
+SRCS_S :=
+SRCS_s :=
-INITCODE_BIN := $(BUILD_DIR)/user/initcode
+-include arch/$(ARCH)/module.mk
+include kernel/module.mk
+include mm/module.mk
+include fs/module.mk
+include drivers/base/module.mk
+include drivers/module.mk
+include drivers/tty/module.mk
+include fdt/module.mk
+include lib/module.mk
+include test/module.mk
+# Compiler flags (defined AFTER includes so INCLUDES is complete)
+CFLAGS := $(WARNINGS) -O2 -g \
+ -ffreestanding -nostdlib \
+ -mcmodel=medany \
+ -fPIE \
+ -MMD -MP \
+ $(KCPPFLAGS) \
+ $(INCLUDES) \
+ -I$(BUILD)/generated
-USER_SRCS := $(wildcard $(SRC_DIR)/user/*.cc)
-UPROGS := $(patsubst $(SRC_DIR)/user/%.cc, $(BUILD_DIR)/user/%, $(USER_SRCS))
+# -fPIE makes the compiler emit position-independent code (PC-relative
+# addressing + GOT for globals), which is what `-shared` linking expects.
+# Mirrors Linux's arch/riscv/Makefile under CONFIG_RELOCATABLE=y:
+# KBUILD_CFLAGS += -fPIE
-SRCS_S := $(shell find $(SRC_DIR) -name "*.S" -not -path "$(SRC_DIR)/user/*" -not -path "$(SRC_DIR)/ulib/*")
-SRCS_CXX := $(shell find $(SRC_DIR) -name "*.cc" -not -path "$(SRC_DIR)/user/*" -not -path "$(SRC_DIR)/ulib/*")
-OBJS := $(SRCS_S:%.S=$(BUILD_DIR)/%.o) $(SRCS_CXX:%.cc=$(BUILD_DIR)/%.o)
+# C flags for musl libc sources: add libc-shim headers first
+CFLAGS_LIBC := $(CFLAGS) -Iinclude/libc-shim \
+ -Wno-parentheses -Wno-sign-compare
-TARGET := $(BUILD_DIR)/kernel.elf
+CXXFLAGS := $(CFLAGS) \
+ -std=c++17 \
+ -fno-exceptions -fno-rtti -fno-use-cxa-atexit \
+ -fno-threadsafe-statics
-QEMUOPTS = -drive file=fs.img,if=none,format=raw,id=x0
-QEMUOPTS += -device virtio-blk-device,drive=x0 -global virtio-mmio.force-legacy=false
+# Assembler flags MUST NOT include -fPIE.
+# Linux's arch/riscv/Makefile adds -fPIE only to KBUILD_CFLAGS, NOT to
+# KBUILD_AFLAGS: with -fPIE the gcc driver puts the assembler in PIC
+# mode, where the `la` macro silently expands to a GOT-indirect load
+# (`auipc + ld` reading a slot that holds the link-time VA). In our
+# pre-MMU boot path that VA is unmapped, so any `la sym, sym` faults
+# and reboots into a `_start` loop. Stripping -fPIE makes `la` emit
+# direct PC-relative addressing (`auipc + addi`) which works at PA.
+ASFLAGS := $(filter-out -fPIE,$(CFLAGS))
-.PHONY: all clean run debug
+# Link as a position-independent shared object so the linker emits
+# `.rela.dyn` with R_RISCV_RELATIVE entries that the boot stub applies
+# at load time. Mirrors Linux's arch/riscv/Makefile §10:
+# LDFLAGS_vmlinux += -shared -Bsymbolic -z notext
+# `-Bsymbolic` resolves all global refs at link time (no dynamic
+# resolution); `-z notext` lets us keep relocations in code pages.
+LDFLAGS := -nostdlib -shared -Bsymbolic -z notext -z norelro --no-dynamic-linker
-all: $(TARGET) $(INITCODE_BIN) $(UPROGS) fs.img
+# ============================================================
+# Object File Computation
+# ============================================================
+OBJS := $(patsubst %.cc,$(BUILD)/%.o,$(SRCS_CC)) \
+ $(patsubst %.c,$(BUILD)/%.o,$(SRCS_C)) \
+ $(patsubst %.S,$(BUILD)/%.o,$(SRCS_S)) \
+ $(patsubst %.s,$(BUILD)/%.o,$(SRCS_s))
+DEPS := $(OBJS:.o=.d)
-$(BUILD_DIR)/ulib/%.o: $(SRC_DIR)/ulib/%.c
- @mkdir -p $(dir $@)
- @echo " ULIB_C $<"
- @$(CC) $(CFLAGS) -c $< -o $@
+# ============================================================
+# Build Rules
+# ============================================================
+.PHONY: all clean run debug fmt disasm defconfig savedefconfig showconfig
-$(BUILD_DIR)/ulib/%.o: $(SRC_DIR)/ulib/%.cc
- @mkdir -p $(dir $@)
- @echo " ULIB_CC $<"
- @$(CXX) $(CXXFLAGS) -c $< -o $@
+all: $(VMLUME) $(IMAGE)
+
+# Generate autoconf.h before any compilation
+$(AUTOCONF_H): scripts/Kconfig.mk $(wildcard .config)
+ $(generate-autoconf)
-$(BUILD_DIR)/ulib/%.o: $(SRC_DIR)/ulib/%.cpp
+# ============================================================
+# Generated header: asm-offsets.h
+#
+# Linux-style trick (mirrors include/linux/kbuild.h + arch/*/kernel/
+# asm-offsets.c + scripts/Makefile.build): compile asm-offsets.c to
+# assembly, scrape the magic `->SYM val` markers produced by the
+# DEFINE/OFFSET inline-asm macros, rewrite them into `#define`
+# directives via sed. head.S and friends then `#include
+# <generated/asm-offsets.h>` to access struct field offsets without
+# having to hand-maintain them — re-order a struct field, the
+# generated constant follows.
+# ============================================================
+ASM_OFFSETS_C := arch/$(ARCH)/kernel/asm-offsets.c
+ASM_OFFSETS_S := $(BUILD)/arch/$(ARCH)/kernel/asm-offsets.s
+ASM_OFFSETS_H := $(BUILD)/generated/asm-offsets.h
+ASM_OFFSETS_SED := scripts/extract-asm-offsets.sed
+
+# Compile asm-offsets.c to *.s only — we never want the .o linked in.
+$(ASM_OFFSETS_S): $(ASM_OFFSETS_C) $(AUTOCONF_H)
+ @echo " CC -S $<"
@mkdir -p $(dir $@)
- @echo " ULIB_CPP $<"
- @$(CXX) $(CXXFLAGS) -c $< -o $@
+ @$(CC) $(CFLAGS_LIBC) -S $< -o $@
-$(BUILD_DIR)/user/%.o: $(SRC_DIR)/user/%.cc
+# Rewrite ->NAME markers into #define lines. Header guard hand-rolled
+# at the top, sed body in the middle, closing #endif at the bottom.
+$(ASM_OFFSETS_H): $(ASM_OFFSETS_S) $(ASM_OFFSETS_SED)
+ @echo " GEN $@"
@mkdir -p $(dir $@)
- @echo " USER_CC $<"
- @$(CXX) $(CXXFLAGS) -c $< -o $@
+ @(echo "/* AUTO-GENERATED — DO NOT EDIT */"; \
+ echo "/* Generated from $(ASM_OFFSETS_C) by scripts/extract-asm-offsets.sed */"; \
+ echo "#ifndef _LUME_GENERATED_ASM_OFFSETS_H"; \
+ echo "#define _LUME_GENERATED_ASM_OFFSETS_H"; \
+ echo ""; \
+ sed -n -f $(ASM_OFFSETS_SED) $<; \
+ echo ""; \
+ echo "#endif /* _LUME_GENERATED_ASM_OFFSETS_H */") > $@
+
+# All objects depend on autoconf.h and asm-offsets.h
+$(OBJS): $(AUTOCONF_H) $(ASM_OFFSETS_H)
-$(BUILD_DIR)/user/%.o: $(SRC_DIR)/user/%.S
+# ============================================================
+# Generic %.pi.o post-processing rule
+#
+# Mirrors arch/riscv/kernel/pi/Makefile §26-30 in Linux:
+#
+# $(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_
+# --remove-section=.note.gnu.property
+# --prefix-alloc-sections=.init.pi
+# $(obj)/%.pi.o: $(obj)/%.o FORCE
+# $(call if_changed,objcopy)
+#
+# Purpose: take a regular .o produced by the normal compile rule and
+# rewrite it so the early position-independent code can coexist with
+# the rest of the kernel without symbol clashes:
+#
+# --prefix-symbols=__pi_ Every global symbol becomes __pi_<name>.
+# head.S calls them as __pi_fdt_path_offset
+# etc., keeping the pre-MMU namespace
+# cleanly isolated.
+#
+# --prefix-alloc-sections=.init.pi
+# All SHF_ALLOC sections get re-prefixed
+# so they land in .init.pi in vmlinux.lds.S,
+# which positions them where the boot
+# loader has already mapped memory.
+#
+# --remove-section=.note.gnu.property
+# Discarded because post-rename it can
+# confuse the linker about ELF features.
+#
+# Generic pattern (`$(BUILD)/%.pi.o`) so any subdir's source can opt in
+# by listing a `.pi.o` target in its SRCS. The companion compile-side
+# CFLAGS overrides (replacing -fPIE with -fpie, adding -Os, etc.) are
+# expected to come from the subdir's own .mk fragment via target-
+# specific CFLAGS_LIBC / CXXFLAGS overrides.
+# ============================================================
+$(BUILD)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \
+ --remove-section=.note.gnu.property \
+ --prefix-alloc-sections=.init.pi
+
+$(BUILD)/%.pi.o: $(BUILD)/%.o
+ $(call cmd,objcopy)
+
+# Preprocess linker script template (.lds.S → .lds)
+$(LINKER_SCRIPT): $(LDS_SRC) include/lume/lumeos.lds.h
+ @echo " LDS $@"
@mkdir -p $(dir $@)
- @echo " USER_AS $<"
- @$(CC) $(CFLAGS) -c $< -o $@
+ @$(CC) -E -P -x c $(INCLUDES) $< -o $@
-$(INITCODE_BIN): $(BUILD_DIR)/user/init.o $(ULIB_OBJS) $(USER_LD)
- @echo " U_LD $@"
- @$(LD) -T $(USER_LD) -o $@.out $(BUILD_DIR)/user/init.o $(ULIB_OBJS)
- @$(OBJCOPY) -S -O binary $@.out $@
- @$(OBJDUMP) -S $@.out > $@.asm
+# ============================================================
+# Initramfs: pack a root filesystem into a newc cpio.
+#
+# Pipeline mirrors Linux's Kbuild:
+# usr/gen_init_cpio — host C tool, produces cpio bytes
+# scripts/gen_initramfs.sh — wrapper that prepares the listing,
+# handles directories vs. listing files,
+# applies uid/gid remap, then invokes the
+# host tool.
+# Sourced from $(CONFIG_INITRAMFS_SOURCE) — see scripts/Kconfig.mk.
+# ============================================================
+# Host compiler — distinct from $(CC), which may be the cross compiler.
+HOSTCC ?= cc
+HOSTCFLAGS ?= -O2 -Wall
-$(BUILD_DIR)/user/%: $(BUILD_DIR)/user/%.o $(ULIB_OBJS) $(USER_LD)
- @echo " USER_LD $@"
- @$(LD) -T $(USER_LD) -o $@ $< $(ULIB_OBJS)
- @$(OBJDUMP) -S $@ > $@.asm
- @$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $@.sym
+# Output path matches Linux convention (usr/gen_init_cpio) so the
+# verbatim copy of scripts/gen_initramfs.sh from Linux finds it via its
+# hardcoded relative path when invoked from the kernel source root.
+GEN_INIT_CPIO := usr/gen_init_cpio
+$(GEN_INIT_CPIO): usr/gen_init_cpio.c
+ @echo " HOSTCC $@"
+ @$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
-$(TARGET): $(OBJS) $(LINKER_SCRIPT)
- @echo " K_LD $@"
- @$(LD) -T $(LINKER_SCRIPT) -o $@ $(OBJS)
- @echo " K_ASM $@.asm"
- @$(OBJDUMP) -S $@ > $@.asm
- @$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $@.sym
+INITRAMFS_SOURCE := $(CONFIG_INITRAMFS_SOURCE)
-$(BUILD_DIR)/src/kernel/initcode.o: $(SRC_DIR)/kernel/initcode.S $(INITCODE_BIN)
- @mkdir -p $(dir $@)
- @echo " AS_INC $<"
- @$(CC) $(CFLAGS) -c $< -o $@
+# Record the chosen source so changing CONFIG_INITRAMFS_SOURCE on the
+# command line forces a rebuild — without this, `make` only compares
+# file mtimes and would happily reuse a cpio packed from a different
+# source as long as that other source isn't newer. Evaluated at
+# Makefile parse time so the dep edge is correct from the first rule
+# check. Mirrors the idea behind Linux's $(call if_changed,...).
+INITRAMFS_SRC_STAMP := $(BUILD)/.initramfs_src.stamp
+$(shell mkdir -p $(BUILD) 2>/dev/null; \
+ prev=$$([ -f "$(INITRAMFS_SRC_STAMP)" ] && cat "$(INITRAMFS_SRC_STAMP)" || echo); \
+ if [ "$$prev" != "$(INITRAMFS_SOURCE)" ]; then \
+ printf '%s\n' "$(INITRAMFS_SOURCE)" > "$(INITRAMFS_SRC_STAMP)"; \
+ fi)
-$(BUILD_DIR)/%.o: %.S
+$(INITRAMFS_CPIO): $(INITRAMFS_SOURCE) $(INITRAMFS_SRC_STAMP) \
+ $(GEN_INIT_CPIO) scripts/gen_initramfs.sh
+ @echo " INITRAMFS $(INITRAMFS_SOURCE)"
@mkdir -p $(dir $@)
- @echo " K_AS $<"
- @$(CC) $(CFLAGS) -c $< -o $@
+ @./scripts/gen_initramfs.sh -o $@ \
+ -u $(CONFIG_INITRAMFS_ROOT_UID) \
+ -g $(CONFIG_INITRAMFS_ROOT_GID) \
+ $(INITRAMFS_SOURCE)
-$(BUILD_DIR)/%.o: %.cc
+$(INITRAMFS_OBJ): $(INITRAMFS_CPIO)
+ @echo " OBJCOPY $@ (initramfs)"
+ @$(OBJCOPY) -I binary -O $(OBJCOPY_ELF) -B $(OBJCOPY_BINARCH) \
+ --rename-section .data=.init.ramfs,alloc,load,readonly,data,contents \
+ $< $@
+
+# Single-pass kernel link. With `-shared -Bsymbolic`, the linker
+# emits `.rela.dyn` containing R_RISCV_RELATIVE entries directly into
+# the output ELF — no separate gen_reloc pass.
+$(VMLUME): $(OBJS) $(INITRAMFS_OBJ) $(LINKER_SCRIPT)
+ @echo " LD $@"
@mkdir -p $(dir $@)
- @echo " K_CXX $<"
- @$(CXX) $(CXXFLAGS) -c $< -o $@
+ @$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(OBJS) $(INITRAMFS_OBJ)
+ @$(TOOLCHAIN_PREFIX)size $@
+
+# Image = raw binary, mirrors Linux's `arch/riscv/boot/Image` (objcopy
+# vmlinux to raw bytes, no ELF header — what U-Boot or QEMU's `-bios`
+# bare-loading would consume). Linux always builds both vmlinux and
+# Image; LumeOS follows the same convention.
+$(IMAGE): $(VMLUME)
+ @echo " OBJCOPY $@"
+ @$(OBJCOPY) -O binary $< $@
+
+# Compile C++ sources. Recipe goes through $(call cmd,...) so that
+# `make V=1` echoes the full command line. $(Q) prefix on mkdir keeps
+# the directory-creation step silent in quiet mode but visible at V=1.
+$(BUILD)/%.o: %.cc
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,cxx_o_cc)
+
+$(BUILD)/%.o: %.c
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,cc_o_c)
-fs.img: $(UPROGS)
- @echo " IMG Generating fs.img (FAT32)"
- @dd if=/dev/zero of=fs.img bs=1M count=32 2>/dev/null
- @mkfs.vfat -F 32 fs.img >/dev/null
- $(foreach prog,$(UPROGS),mcopy -i fs.img $(prog) ::/$(notdir $(prog));)
+$(BUILD)/%.o: %.S
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,as_o_S)
-run: $(TARGET) fs.img
+$(BUILD)/%.o: %.s
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,as_o_S)
+
+# Auto-dependency tracking
+-include $(DEPS)
+
+# ============================================================
+# Run & Debug
+# ============================================================
+ifeq ($(ARCH),riscv)
+QEMU := qemu-system-riscv64
+QEMU_MACHINE := -machine virt -smp 4 -m 128M -nographic
+QEMU_BIOS := -bios default
+else ifeq ($(ARCH),aarch64)
+QEMU := qemu-system-aarch64
+QEMU_MACHINE := -machine virt -cpu cortex-a53 -m 128M -nographic
+QEMU_BIOS :=
+else ifeq ($(ARCH),x86_64)
+QEMU := qemu-system-x86_64
+QEMU_MACHINE := -m 128M -nographic
+QEMU_BIOS :=
+endif
+
+run: $(VMLUME) $(IMAGE)
@echo " QEMU Running..."
- @qemu-system-riscv64 -machine virt -nographic \
- -kernel $(TARGET) -m 128M $(QEMUOPTS)
+ $(QEMU) $(QEMU_MACHINE) $(QEMU_BIOS) -kernel $(VMLUME)
-debug: $(TARGET) fs.img
- @echo " QEMU (DEBUG) Waiting for GDB..."
- @qemu-system-riscv64 -machine virt -nographic \
- -kernel $(TARGET) -m 128M -s -S $(QEMUOPTS)
+debug: $(VMLUME) $(IMAGE)
+ @echo " QEMU Waiting for GDB on :1234..."
+ $(QEMU) $(QEMU_MACHINE) $(QEMU_BIOS) -kernel $(VMLUME) -s -S
+# ============================================================
+# Utilities
+# ============================================================
clean:
- rm -rf $(BUILD_DIR) fs.img \ No newline at end of file
+ rm -rf $(BUILD)
+
+disasm: $(VMLUME)
+ @echo " OBJDUMP $<"
+ @$(OBJDUMP) -d -S $(VMLUME) > $(VMLUME).asm
+ @echo " Written to $(VMLUME).asm"
+
+fmt:
+ @echo " FMT Formatting source files..."
+ @find . -name '*.cc' -o -name '*.h' | xargs clang-format -i 2>/dev/null || true
+
+lint:
+ @echo " LINT Generating compile_commands.json via bear..."
+ @bear -- $(MAKE) all
+ @echo " LINT Running clang-tidy on C++ sources..."
+ @clang-tidy -p . $(SRCS_CC) || true
+
+# Print build info (for debugging Makefile issues)
+info:
+ @echo "TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX)"
+ @echo "SRCS_CC = $(SRCS_CC)"
+ @echo "SRCS_S = $(SRCS_S)"
+ @echo "OBJS = $(OBJS)"
+ @echo "KCPPFLAGS = $(KCPPFLAGS)"