SRC_DIR := src
BUILD_DIR := build/$(ARCH)
-# Common sources
-C_SOURCES := $(wildcard $(SRC_DIR)/kernel/*.c)
-C_SOURCES += $(wildcard $(SRC_DIR)/drivers/*.c)
-C_SOURCES += $(wildcard $(SRC_DIR)/mm/*.c)
-
- # HAL sources (architecture-specific)
- C_SOURCES += $(wildcard $(SRC_DIR)/hal/$(ARCH)/*.c)
+# Minimal kernel sources shared across all architectures
+KERNEL_COMMON := main.c console.c utils.c cmdline.c driver.c cpu_features.c
+C_SOURCES := $(addprefix $(SRC_DIR)/kernel/,$(KERNEL_COMMON))
+
+# HAL sources (architecture-specific)
+C_SOURCES += $(wildcard $(SRC_DIR)/hal/$(ARCH)/*.c)
# --- x86 Configuration ---
ifeq ($(ARCH),x86)
+ # x86 gets ALL kernel sources, drivers, and mm
+ C_SOURCES := $(wildcard $(SRC_DIR)/kernel/*.c)
+ C_SOURCES += $(wildcard $(SRC_DIR)/drivers/*.c)
+ C_SOURCES += $(wildcard $(SRC_DIR)/mm/*.c)
+ C_SOURCES += $(wildcard $(SRC_DIR)/hal/$(ARCH)/*.c)
+
# Default Toolchain Prefix (can be overridden)
ifdef CROSS
TOOLPREFIX ?= i686-elf-
CC := aarch64-linux-gnu-gcc
AS := aarch64-linux-gnu-as
LD := aarch64-linux-gnu-ld
- CFLAGS := -ffreestanding -O2 -Wall -Wextra -Werror -Wno-error=cpp -Iinclude
+ OBJCOPY := aarch64-linux-gnu-objcopy
+ CFLAGS := -ffreestanding -O2 -Wall -Wextra -Werror -Wno-error=cpp -mno-outline-atomics -Iinclude
LDFLAGS := -T $(SRC_DIR)/arch/arm/linker.ld
- ASFLAGS :=
+ ASFLAGS :=
ASM_SOURCES := $(wildcard $(SRC_DIR)/arch/arm/*.S)
C_SOURCES += $(wildcard $(SRC_DIR)/arch/arm/*.c)
endif
CC := riscv64-linux-gnu-gcc
AS := riscv64-linux-gnu-as
LD := riscv64-linux-gnu-ld
+ OBJCOPY := riscv64-linux-gnu-objcopy
CFLAGS := -ffreestanding -O2 -Wall -Wextra -Werror -Wno-error=cpp -Iinclude -mcmodel=medany
LDFLAGS := -T $(SRC_DIR)/arch/riscv/linker.ld
- ASFLAGS :=
+ ASFLAGS :=
ASM_SOURCES := $(wildcard $(SRC_DIR)/arch/riscv/*.S)
C_SOURCES += $(wildcard $(SRC_DIR)/arch/riscv/*.c)
endif
QEMU_DFLAGS := $(QEMU_DFLAGS) -d int
endif
-BOOT_OBJ := $(BUILD_DIR)/arch/x86/boot.o
+BOOT_OBJ := $(BUILD_DIR)/arch/$(ARCH)/boot.o
KERNEL_OBJ := $(filter-out $(BOOT_OBJ), $(OBJ))
all: $(KERNEL_NAME)
-serial file:serial.log -monitor none -no-reboot -no-shutdown \
$(QEMU_DFLAGS)
+run-arm: adros-arm.bin
+ @rm -f serial-arm.log
+ @qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -nographic \
+ -kernel adros-arm.bin -serial mon:stdio $(QEMU_DFLAGS)
+
+run-riscv: adros-riscv.bin
+ @rm -f serial-riscv.log
+ @qemu-system-riscv64 -M virt -m 128M -nographic -bios none \
+ -kernel adros-riscv.bin -serial mon:stdio $(QEMU_DFLAGS)
+
# ---- Static Analysis ----
cppcheck:
* ARM: LDREX/STREX
* RISC-V: AMOSWAP.W.AQ
* MIPS: LL/SC
+ *
+ * Note: AArch64/RISC-V without MMU may need simpler locking since
+ * exclusive monitors (LDAXR/STXR) require cacheable memory.
*/
+#if defined(__aarch64__) || defined(__riscv)
+/* Simple volatile flag lock — safe for single-core bring-up without MMU.
+ * Will be replaced with proper atomics once MMU is enabled. */
+static inline void spin_lock(spinlock_t* l) {
+ while (l->locked) {
+ cpu_relax();
+ }
+ l->locked = 1;
+ __sync_synchronize();
+}
+
+static inline int spin_trylock(spinlock_t* l) {
+ if (l->locked) return 0;
+ l->locked = 1;
+ __sync_synchronize();
+ return 1;
+}
+
+static inline void spin_unlock(spinlock_t* l) {
+ __sync_synchronize();
+ l->locked = 0;
+}
+#else
static inline void spin_lock(spinlock_t* l) {
while (__sync_lock_test_and_set(&l->locked, 1)) {
while (l->locked) {
__sync_synchronize();
__sync_lock_release(&l->locked);
}
+#endif
#if defined(__i386__) || defined(__x86_64__)
static inline uintptr_t irq_save(void) {
__asm__ volatile ("push %0; popf" :: "r"(flags) : "memory", "cc");
#endif
}
+#elif defined(__aarch64__)
+static inline uintptr_t irq_save(void) {
+ uintptr_t daif;
+ __asm__ volatile("mrs %0, daif\n\tmsr daifset, #2" : "=r"(daif) :: "memory");
+ return daif;
+}
+
+static inline void irq_restore(uintptr_t flags) {
+ __asm__ volatile("msr daif, %0" :: "r"(flags) : "memory");
+}
+
#elif defined(__arm__)
static inline uintptr_t irq_save(void) {
uintptr_t cpsr;
(void)args;
uart_init();
- kprintf("\n[AdrOS] Booting...\n");
+ kprintf("\n[AdrOS/arm64] Booting on QEMU virt...\n");
struct boot_info bi;
bi.arch_magic = 0;
/*
* AdrOS - ARM64 (AArch64) Bootstrap
- * Target: QEMU 'virt' machine
+ * Target: QEMU 'virt' machine (-cpu cortex-a57)
*/
.section .text
.global _start
_start:
- /*
- * CPU usually starts in EL2 or EL3 on QEMU.
- * Ideally we should switch to EL1, but for a "hello world"
- * we will just set up the stack and run.
- */
+ /* Disable all interrupts */
+ msr daifset, #0xf
- /* Set up stack pointer (x30 is link register, don't clobber it yet) */
+ /* Check current exception level */
+ mrs x0, CurrentEL
+ lsr x0, x0, #2
+ cmp x0, #2
+ b.ne 1f
+
+ /* EL2 -> EL1 transition */
+ mov x0, #(1 << 31) /* EL1 is AArch64 */
+ msr hcr_el2, x0
+ mov x0, #0x3c5 /* EL1h, all DAIF masked */
+ msr spsr_el2, x0
+ adr x0, 1f
+ msr elr_el2, x0
+ eret
+
+1:
+ /* Now in EL1 (or started in EL1) */
+
+ /* Enable FP/SIMD — required for variadic function prologues
+ * which save q0-q7 as part of the va_list register save area.
+ * Without this, any variadic call (kprintf etc.) traps. */
+ mrs x0, cpacr_el1
+ orr x0, x0, #(3 << 20) /* FPEN = 0b11 (no trapping) */
+ msr cpacr_el1, x0
+ isb
+
+ /* Set up stack pointer */
ldr x0, =stack_top
mov sp, x0
+ /* Zero BSS section */
+ ldr x0, =__bss_start
+ ldr x1, =__bss_end
+3: cmp x0, x1
+ b.ge 4f
+ str xzr, [x0], #8
+ b 3b
+4:
/* Build arch_boot_args (in .bss) and call arch_early_setup(args) */
ldr x0, =arch_boot_args
bl arch_early_setup
/* Hang */
-1: wfi
- b 1b
+2: wfi
+ b 2b
.section .bss
.align 16
/*
* AdrOS - ARM64 Linker Script
- * Target: QEMU virt (RAM starts at 0x40000000 usually)
+ * Target: QEMU virt (RAM starts at 0x40000000)
*/
ENTRY(_start)
SECTIONS
{
. = 0x40000000;
-
- _start = .;
.text : {
- *(.text)
+ *(.text .text.*)
}
+ . = ALIGN(4096);
.rodata : {
- *(.rodata)
+ *(.rodata .rodata.*)
}
+ . = ALIGN(4096);
.data : {
- *(.data)
+ *(.data .data.*)
}
+ . = ALIGN(4096);
.bss : {
- *(.bss)
+ __bss_start = .;
+ *(.bss .bss.*)
*(COMMON)
+ __bss_end = .;
}
-
+
_end = .;
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note*)
+ }
}
--- /dev/null
+/*
+ * ARM64 stub implementations for kernel subsystems not yet ported.
+ * Provides weak symbols so main.c and console.c link successfully.
+ */
+#include <stdint.h>
+#include <stddef.h>
+#include "hal/uart.h"
+#include "spinlock.h"
+
+/* ---- UART console (wraps HAL UART) ---- */
+static spinlock_t uart_lock = {0};
+
+void uart_init(void) {
+ hal_uart_init();
+}
+
+void uart_put_char(char c) {
+ uintptr_t flags = spin_lock_irqsave(&uart_lock);
+ hal_uart_putc(c);
+ spin_unlock_irqrestore(&uart_lock, flags);
+}
+
+void uart_print(const char* str) {
+ uintptr_t flags = spin_lock_irqsave(&uart_lock);
+ for (int i = 0; str[i] != '\0'; i++)
+ hal_uart_putc(str[i]);
+ spin_unlock_irqrestore(&uart_lock, flags);
+}
+
+/* ---- VGA console (no-op on ARM) ---- */
+void vga_init(void) { }
+void vga_put_char(char c) { (void)c; }
+void vga_write_buf(const char* buf, uint32_t len) { (void)buf; (void)len; }
+void vga_print(const char* str) { (void)str; }
+void vga_set_color(uint8_t fg, uint8_t bg) { (void)fg; (void)bg; }
+void vga_flush(void) { }
+void vga_clear(void) { }
+void vga_scroll_back(void) { }
+void vga_scroll_fwd(void) { }
+
+/* ---- Kernel subsystem stubs (not yet ported) ---- */
+void pmm_init(void* mboot_info) { (void)mboot_info; }
+void kheap_init(void) { }
+void shm_init(void) { }
+void kaslr_init(void) { }
+void process_init(void) { }
+void vdso_init(void) { }
+void timer_init(uint32_t hz) { (void)hz; }
+int init_start(const void* bi) { (void)bi; return -1; }
+void kconsole_enter(void) { }
+
+/* ---- Keyboard (no-op) ---- */
+void keyboard_init(void) { }
+int keyboard_getchar(void) { return -1; }
+int keyboard_read_nonblock(void) { return -1; }
+
+/* ---- HAL CPU extras ---- */
+void hal_cpu_set_address_space(uintptr_t as) { (void)as; }
+void hal_cpu_disable_interrupts(void) {
+ __asm__ volatile("msr daifset, #2" ::: "memory");
+}
+uint64_t hal_cpu_read_timestamp(void) { return 0; }
+void hal_cpu_set_tls(uintptr_t base) { (void)base; }
(void)args;
uart_init();
- kprintf("\n[AdrOS] Booting...\n");
+ kprintf("\n[AdrOS/riscv64] Booting on QEMU virt...\n");
struct boot_info bi;
bi.arch_magic = 0;
/*
* AdrOS - RISC-V 64-bit Bootstrap
- * Target: QEMU 'virt' machine (starts at 0x80000000)
+ * Target: QEMU 'virt' machine (-bios none, starts at 0x80000000)
*/
.section .text
.global _start
_start:
- /* Disable interrupts (sie = Supervisor Interrupt Enable) */
- csrw sie, zero
+ /* Disable interrupts */
+ csrw mie, zero
- /* Set up stack pointer.
- * In linker.ld we will define a symbol for the stack top.
- */
+ /* Set up stack pointer */
la sp, stack_top
- /* Build arch_boot_args (in .bss) and call arch_early_setup(args) */
+ /* Zero BSS section */
+ la t0, __bss_start
+ la t1, __bss_end
+1: bge t0, t1, 2f
+ sd zero, 0(t0)
+ addi t0, t0, 8
+ j 1b
+2:
+ /* Call arch_early_setup(args) */
la a0, arch_boot_args
call arch_early_setup
/* Hang if return */
-1: wfi
- j 1b
+3: wfi
+ j 3b
.section .bss
.align 16
/*
- * AdrOS - RISC-V Linker Script
+ * AdrOS - RISC-V 64-bit Linker Script
* Target: QEMU virt (RAM starts at 0x80000000)
*/
SECTIONS
{
. = 0x80000000;
-
- _start = .;
.text : {
- *(.text)
+ *(.text .text.*)
}
+ . = ALIGN(4096);
.rodata : {
- *(.rodata)
+ *(.rodata .rodata.*)
}
+ . = ALIGN(4096);
.data : {
- *(.data)
+ *(.data .data.*)
}
+ . = ALIGN(4096);
.bss : {
- *(.bss)
+ __bss_start = .;
+ *(.bss .bss.*)
*(COMMON)
+ __bss_end = .;
}
-
+
_end = .;
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note*)
+ }
}
--- /dev/null
+/*
+ * RISC-V 64 stub implementations for kernel subsystems not yet ported.
+ * Provides weak symbols so main.c and console.c link successfully.
+ */
+#include <stdint.h>
+#include <stddef.h>
+#include "hal/uart.h"
+#include "spinlock.h"
+
+/* ---- UART console (wraps HAL UART) ---- */
+static spinlock_t uart_lock = {0};
+
+void uart_init(void) {
+ hal_uart_init();
+}
+
+void uart_put_char(char c) {
+ uintptr_t flags = spin_lock_irqsave(&uart_lock);
+ hal_uart_putc(c);
+ spin_unlock_irqrestore(&uart_lock, flags);
+}
+
+void uart_print(const char* str) {
+ uintptr_t flags = spin_lock_irqsave(&uart_lock);
+ for (int i = 0; str[i] != '\0'; i++)
+ hal_uart_putc(str[i]);
+ spin_unlock_irqrestore(&uart_lock, flags);
+}
+
+/* ---- VGA console (no-op on RISC-V) ---- */
+void vga_init(void) { }
+void vga_put_char(char c) { (void)c; }
+void vga_write_buf(const char* buf, uint32_t len) { (void)buf; (void)len; }
+void vga_print(const char* str) { (void)str; }
+void vga_set_color(uint8_t fg, uint8_t bg) { (void)fg; (void)bg; }
+void vga_flush(void) { }
+void vga_clear(void) { }
+void vga_scroll_back(void) { }
+void vga_scroll_fwd(void) { }
+
+/* ---- Kernel subsystem stubs (not yet ported) ---- */
+void pmm_init(void* mboot_info) { (void)mboot_info; }
+void kheap_init(void) { }
+void shm_init(void) { }
+void kaslr_init(void) { }
+void process_init(void) { }
+void vdso_init(void) { }
+void timer_init(uint32_t hz) { (void)hz; }
+int init_start(const void* bi) { (void)bi; return -1; }
+void kconsole_enter(void) { }
+
+/* ---- Keyboard (no-op) ---- */
+void keyboard_init(void) { }
+int keyboard_getchar(void) { return -1; }
+int keyboard_read_nonblock(void) { return -1; }
+
+/* ---- HAL CPU extras ---- */
+void hal_cpu_set_address_space(uintptr_t as) { (void)as; }
+void hal_cpu_disable_interrupts(void) {
+ __asm__ volatile("csrci mstatus, 0x8" ::: "memory");
+}
+uint64_t hal_cpu_read_timestamp(void) {
+ uint64_t val;
+ __asm__ volatile("rdcycle %0" : "=r"(val));
+ return val;
+}
+void hal_cpu_set_tls(uintptr_t base) { (void)base; }
return -1;
}
-void hal_usermode_enter_regs(const struct registers* regs) {
+void hal_usermode_enter_regs(const void* regs) {
(void)regs;
}
return -1;
}
-void hal_usermode_enter_regs(const struct registers* regs) {
+void hal_usermode_enter_regs(const void* regs) {
(void)regs;
}