From: Tulio A M Mendes Date: Sun, 15 Feb 2026 04:33:01 +0000 (-0300) Subject: feat: MIPS32 bring-up + refactor spinlock.h arch separation X-Git-Url: https://projects.tadryanom.me/docs/static/gitweb.css?a=commitdiff_plain;h=8435521f6edff71a98b9323dacab48c98be116cb;p=AdrOS.git feat: MIPS32 bring-up + refactor spinlock.h arch separation MIPS bring-up (T20): - src/arch/mips/boot.S: BSS zeroing, di/ehb interrupt disable, .set mips32r2 - src/arch/mips/stubs.c: UART console, VGA no-ops, kernel subsystem stubs - src/arch/mips/linker.ld: proper sections, BSS markers, discard MIPS ABI sections - src/arch/mips/arch_early_setup.c: boot message for Malta - src/hal/mips/uart.c: fix UART base 0xBFD003F8 → 0xB80003F8 (ISA I/O @ 0x18000000) - src/hal/mips/usermode.c: fix type mismatch (const void*) - Makefile: -mno-abicalls -fno-pic -G0 -march=mips32r2, run-mips target - Boots on QEMU Malta with UART console output spinlock.h refactor (T21): - Extract arch-specific cpu_relax/irq_save/irq_restore into per-arch headers: include/arch/x86/spinlock.h, include/arch/arm/spinlock.h, include/arch/riscv/spinlock.h, include/arch/mips/spinlock.h - spinlock.h now uses dispatcher pattern (#include arch/ARCH/spinlock.h) - No inline asm remains in the agnostic header - spinlock_t, spin_lock/unlock, TTAS logic remain agnostic Verified: x86 35/35 smoke, 47/47 host tests, ARM64/RISC-V/MIPS boot on QEMU --- diff --git a/Makefile b/Makefile index cbf50a9..83a6f1b 100644 --- a/Makefile +++ b/Makefile @@ -117,9 +117,9 @@ ifeq ($(ARCH),mips) CC := mipsel-linux-gnu-gcc AS := mipsel-linux-gnu-as LD := mipsel-linux-gnu-ld - CFLAGS := -ffreestanding -O2 -Wall -Wextra -Werror -Wno-error=cpp -Iinclude -mabi=32 -march=mips32 + CFLAGS := -ffreestanding -O2 -Wall -Wextra -Werror -Wno-error=cpp -Iinclude -mabi=32 -march=mips32r2 -mno-abicalls -fno-pic -G0 LDFLAGS := -T $(SRC_DIR)/arch/mips/linker.ld - ASFLAGS := + ASFLAGS := -march=mips32r2 ASM_SOURCES := $(wildcard $(SRC_DIR)/arch/mips/*.S) C_SOURCES += $(wildcard $(SRC_DIR)/arch/mips/*.c) endif @@ -222,6 +222,11 @@ run-riscv: adros-riscv.bin @qemu-system-riscv64 -M virt -m 128M -nographic -bios none \ -kernel adros-riscv.bin -serial mon:stdio $(QEMU_DFLAGS) +run-mips: adros-mips.bin + @rm -f serial-mips.log + @qemu-system-mipsel -M malta -m 128M -nographic \ + -kernel adros-mips.bin -serial mon:stdio $(QEMU_DFLAGS) + # ---- Static Analysis ---- cppcheck: diff --git a/include/arch/arm/spinlock.h b/include/arch/arm/spinlock.h new file mode 100644 index 0000000..fc4cb5a --- /dev/null +++ b/include/arch/arm/spinlock.h @@ -0,0 +1,40 @@ +#ifndef ARCH_ARM_SPINLOCK_H +#define ARCH_ARM_SPINLOCK_H + +#include + +#if defined(__aarch64__) + +static inline void cpu_relax(void) { + __asm__ volatile("yield" ::: "memory"); +} + +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"); +} + +#else /* ARM32 */ + +static inline void cpu_relax(void) { + __asm__ volatile("yield" ::: "memory"); +} + +static inline uintptr_t irq_save(void) { + uintptr_t cpsr; + __asm__ volatile("mrs %0, cpsr\n\tcpsid i" : "=r"(cpsr) :: "memory"); + return cpsr; +} + +static inline void irq_restore(uintptr_t flags) { + __asm__ volatile("msr cpsr_c, %0" :: "r"(flags) : "memory"); +} + +#endif + +#endif /* ARCH_ARM_SPINLOCK_H */ diff --git a/include/arch/mips/spinlock.h b/include/arch/mips/spinlock.h new file mode 100644 index 0000000..d915305 --- /dev/null +++ b/include/arch/mips/spinlock.h @@ -0,0 +1,25 @@ +#ifndef ARCH_MIPS_SPINLOCK_H +#define ARCH_MIPS_SPINLOCK_H + +#include + +static inline void cpu_relax(void) { + __asm__ volatile("pause" ::: "memory"); +} + +static inline uintptr_t irq_save(void) { + uintptr_t status; + __asm__ volatile( + "mfc0 %0, $12\n\t" + "di" + : "=r"(status) :: "memory"); + return status & 1U; +} + +static inline void irq_restore(uintptr_t flags) { + if (flags) { + __asm__ volatile("ei" ::: "memory"); + } +} + +#endif /* ARCH_MIPS_SPINLOCK_H */ diff --git a/include/arch/riscv/spinlock.h b/include/arch/riscv/spinlock.h new file mode 100644 index 0000000..1bcf531 --- /dev/null +++ b/include/arch/riscv/spinlock.h @@ -0,0 +1,22 @@ +#ifndef ARCH_RISCV_SPINLOCK_H +#define ARCH_RISCV_SPINLOCK_H + +#include + +static inline void cpu_relax(void) { + __asm__ volatile("fence" ::: "memory"); +} + +static inline uintptr_t irq_save(void) { + uintptr_t mstatus; + __asm__ volatile("csrrci %0, mstatus, 0x8" : "=r"(mstatus) :: "memory"); + return mstatus & 0x8; +} + +static inline void irq_restore(uintptr_t flags) { + if (flags) { + __asm__ volatile("csrsi mstatus, 0x8" ::: "memory"); + } +} + +#endif /* ARCH_RISCV_SPINLOCK_H */ diff --git a/include/arch/x86/spinlock.h b/include/arch/x86/spinlock.h new file mode 100644 index 0000000..7228560 --- /dev/null +++ b/include/arch/x86/spinlock.h @@ -0,0 +1,28 @@ +#ifndef ARCH_X86_SPINLOCK_H +#define ARCH_X86_SPINLOCK_H + +#include + +static inline void cpu_relax(void) { + __asm__ volatile("pause" ::: "memory"); +} + +static inline uintptr_t irq_save(void) { + uintptr_t flags; +#if defined(__x86_64__) + __asm__ volatile ("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); +#else + __asm__ volatile ("pushf; pop %0; cli" : "=r"(flags) :: "memory"); +#endif + return flags; +} + +static inline void irq_restore(uintptr_t flags) { +#if defined(__x86_64__) + __asm__ volatile ("push %0; popfq" :: "r"(flags) : "memory", "cc"); +#else + __asm__ volatile ("push %0; popf" :: "r"(flags) : "memory", "cc"); +#endif +} + +#endif /* ARCH_X86_SPINLOCK_H */ diff --git a/include/spinlock.h b/include/spinlock.h index f3c7c35..c490d25 100644 --- a/include/spinlock.h +++ b/include/spinlock.h @@ -2,29 +2,32 @@ #define SPINLOCK_H #include - #include /* - * Per-architecture spin-wait hint. - * Reduces power consumption and avoids memory-order pipeline stalls - * while spinning. Essential for SMP correctness and performance. + * Architecture-specific primitives: cpu_relax(), irq_save(), irq_restore(). + * Each arch header provides these as static inline functions with the + * appropriate inline assembly. The agnostic layer below only uses them + * through the function interface — no arch #ifdefs leak here. */ -static inline void cpu_relax(void) { #if defined(__i386__) || defined(__x86_64__) - __asm__ volatile("pause" ::: "memory"); -#elif defined(__arm__) - __asm__ volatile("yield" ::: "memory"); -#elif defined(__aarch64__) - __asm__ volatile("yield" ::: "memory"); +#include "arch/x86/spinlock.h" +#elif defined(__aarch64__) || defined(__arm__) +#include "arch/arm/spinlock.h" #elif defined(__riscv) - __asm__ volatile("fence" ::: "memory"); +#include "arch/riscv/spinlock.h" #elif defined(__mips__) - __asm__ volatile("pause" ::: "memory"); +#include "arch/mips/spinlock.h" #else - __sync_synchronize(); +/* Generic fallback — no interrupt masking, memory barrier as relax hint */ +static inline void cpu_relax(void) { __sync_synchronize(); } +static inline uintptr_t irq_save(void) { return 0; } +static inline void irq_restore(uintptr_t flags) { (void)flags; } #endif -} + +/* ------------------------------------------------------------------ */ +/* Architecture-agnostic spinlock implementation */ +/* ------------------------------------------------------------------ */ typedef struct { volatile uint32_t locked; @@ -90,79 +93,9 @@ static inline void spin_unlock(spinlock_t* l) { } #endif -#if defined(__i386__) || defined(__x86_64__) -static inline uintptr_t irq_save(void) { - uintptr_t flags; -#if defined(__x86_64__) - __asm__ volatile ("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); -#else - __asm__ volatile ("pushf; pop %0; cli" : "=r"(flags) :: "memory"); -#endif - return flags; -} - -static inline void irq_restore(uintptr_t flags) { -#if defined(__x86_64__) - __asm__ volatile ("push %0; popfq" :: "r"(flags) : "memory", "cc"); -#else - __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; - __asm__ volatile("mrs %0, cpsr\n\tcpsid i" : "=r"(cpsr) :: "memory"); - return cpsr; -} - -static inline void irq_restore(uintptr_t flags) { - __asm__ volatile("msr cpsr_c, %0" :: "r"(flags) : "memory"); -} - -#elif defined(__riscv) -static inline uintptr_t irq_save(void) { - uintptr_t mstatus; - __asm__ volatile("csrrci %0, mstatus, 0x8" : "=r"(mstatus) :: "memory"); - return mstatus & 0x8; -} - -static inline void irq_restore(uintptr_t flags) { - if (flags) { - __asm__ volatile("csrsi mstatus, 0x8" ::: "memory"); - } -} - -#elif defined(__mips__) -static inline uintptr_t irq_save(void) { - uintptr_t status; - __asm__ volatile( - "mfc0 %0, $12\n\t" - "di" - : "=r"(status) :: "memory"); - return status & 1U; -} - -static inline void irq_restore(uintptr_t flags) { - if (flags) { - __asm__ volatile("ei" ::: "memory"); - } -} - -#else -static inline uintptr_t irq_save(void) { return 0; } -static inline void irq_restore(uintptr_t flags) { (void)flags; } -#endif +/* ------------------------------------------------------------------ */ +/* Convenience wrappers (fully agnostic) */ +/* ------------------------------------------------------------------ */ static inline uintptr_t spin_lock_irqsave(spinlock_t* l) { uintptr_t flags = irq_save(); diff --git a/src/arch/mips/arch_early_setup.c b/src/arch/mips/arch_early_setup.c index ecab996..d89f615 100644 --- a/src/arch/mips/arch_early_setup.c +++ b/src/arch/mips/arch_early_setup.c @@ -10,7 +10,7 @@ extern void kernel_main(const struct boot_info* bi); (void)args; uart_init(); - kprintf("\n[AdrOS] Booting...\n"); + kprintf("\n[AdrOS/mips32] Booting on QEMU Malta...\n"); struct boot_info bi; bi.arch_magic = 0; diff --git a/src/arch/mips/boot.S b/src/arch/mips/boot.S index 45cbe4c..6054f6e 100644 --- a/src/arch/mips/boot.S +++ b/src/arch/mips/boot.S @@ -1,30 +1,42 @@ /* - * AdrOS - MIPS32 Bootstrap - * Minimal entry point that sets up a stack and calls kernel_main. + * AdrOS - MIPS32r2 Bootstrap + * Target: QEMU Malta board (little-endian, RAM at KSEG0 0x80000000) */ .set noreorder - .set noat + .set mips32r2 .section .text .globl _start .ent _start _start: + /* Disable interrupts: clear IE bit in CP0 Status */ + di + ehb + + /* Set up stack pointer */ la $sp, stack_top - /* Build arch_boot_args (in .bss) and call arch_early_setup(args) */ - la $a0, arch_boot_args - sw $zero, 0($a0) - sw $zero, 4($a0) - sw $zero, 8($a0) - sw $zero, 12($a0) + /* Zero BSS section */ + la $t0, __bss_start + la $t1, __bss_end +1: bge $t0, $t1, 2f + nop + sw $zero, 0($t0) + addiu $t0, $t0, 4 + j 1b + nop +2: + /* Call arch_early_setup(args) */ + la $a0, arch_boot_args jal arch_early_setup nop -1: - j 1b + /* Hang if return */ +3: wait + j 3b nop .end _start diff --git a/src/arch/mips/linker.ld b/src/arch/mips/linker.ld index babb9cc..f5a88cc 100644 --- a/src/arch/mips/linker.ld +++ b/src/arch/mips/linker.ld @@ -1,32 +1,47 @@ /* - * AdrOS - MIPS32 Linker Script - * Target: QEMU malta (RAM typically starts at 0x80000000, KSEG0) + * AdrOS - MIPS32r2 Linker Script + * Target: QEMU Malta board (KSEG0, RAM at 0x80000000) */ ENTRY(_start) SECTIONS { - . = 0x80000000; - - _start = .; + . = 0x80100000; .text : { - *(.text) + *(.text .text.*) } + . = ALIGN(4096); .rodata : { - *(.rodata) + *(.rodata .rodata.*) } + . = ALIGN(4096); .data : { - *(.data) + *(.data .data.*) } + . = ALIGN(4096); + __bss_start = .; .bss : { - *(.bss) + *(.bss .bss.*) *(COMMON) } + __bss_end = .; + . = ALIGN(4096); _end = .; + + /DISCARD/ : { + *(.comment) + *(.note*) + *(.eh_frame*) + *(.gnu.hash) + *(.dynsym) + *(.dynstr) + *(.MIPS.abiflags) + *(.reginfo) + } } diff --git a/src/arch/mips/stubs.c b/src/arch/mips/stubs.c new file mode 100644 index 0000000..0703d49 --- /dev/null +++ b/src/arch/mips/stubs.c @@ -0,0 +1,67 @@ +/* + * MIPS32 stub implementations for kernel subsystems not yet ported. + * Provides weak symbols so main.c and console.c link successfully. + */ +#include +#include +#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 MIPS) ---- */ +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("di" ::: "memory"); +} +uint32_t hal_cpu_read_timestamp(void) { + uint32_t count; + __asm__ volatile("mfc0 %0, $9" : "=r"(count)); + return count; +} +void hal_cpu_set_tls(uintptr_t base) { (void)base; } diff --git a/src/hal/mips/uart.c b/src/hal/mips/uart.c index cfaaf9b..035f5ae 100644 --- a/src/hal/mips/uart.c +++ b/src/hal/mips/uart.c @@ -3,9 +3,11 @@ #include /* - * QEMU MIPS Malta exposes a 16550-compatible UART at 0xBFD003F8. + * QEMU MIPS Malta: ISA I/O base = physical 0x18000000 + * 16550 UART at ISA port 0x3F8 → physical 0x180003F8 + * Accessed via KSEG1 (uncached) at 0xB80003F8. */ -#define UART_BASE 0xBFD003F8 +#define UART_BASE 0xB80003F8 void hal_uart_init(void) { /* Minimal init: assume firmware/QEMU defaults are usable */ diff --git a/src/hal/mips/usermode.c b/src/hal/mips/usermode.c index ef09a7f..f91d185 100644 --- a/src/hal/mips/usermode.c +++ b/src/hal/mips/usermode.c @@ -6,6 +6,6 @@ int hal_usermode_enter(uintptr_t user_eip, uintptr_t user_esp) { return -1; } -void hal_usermode_enter_regs(const struct registers* regs) { +void hal_usermode_enter_regs(const void* regs) { (void)regs; }