]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: MIPS32 bring-up + refactor spinlock.h arch separation
authorTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 04:33:01 +0000 (01:33 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 04:33:01 +0000 (01:33 -0300)
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

12 files changed:
Makefile
include/arch/arm/spinlock.h [new file with mode: 0644]
include/arch/mips/spinlock.h [new file with mode: 0644]
include/arch/riscv/spinlock.h [new file with mode: 0644]
include/arch/x86/spinlock.h [new file with mode: 0644]
include/spinlock.h
src/arch/mips/arch_early_setup.c
src/arch/mips/boot.S
src/arch/mips/linker.ld
src/arch/mips/stubs.c [new file with mode: 0644]
src/hal/mips/uart.c
src/hal/mips/usermode.c

index cbf50a94468ab13cad01583b53c16cf040c29aa9..83a6f1b7a4b379e0718f0015886e57f105048c0c 100644 (file)
--- 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 (file)
index 0000000..fc4cb5a
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef ARCH_ARM_SPINLOCK_H
+#define ARCH_ARM_SPINLOCK_H
+
+#include <stdint.h>
+
+#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 (file)
index 0000000..d915305
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef ARCH_MIPS_SPINLOCK_H
+#define ARCH_MIPS_SPINLOCK_H
+
+#include <stdint.h>
+
+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 (file)
index 0000000..1bcf531
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef ARCH_RISCV_SPINLOCK_H
+#define ARCH_RISCV_SPINLOCK_H
+
+#include <stdint.h>
+
+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 (file)
index 0000000..7228560
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef ARCH_X86_SPINLOCK_H
+#define ARCH_X86_SPINLOCK_H
+
+#include <stdint.h>
+
+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 */
index f3c7c35a5093a7aceafa08980b69c50684f65ae2..c490d25fd20fcb0441e9a35539659dd79fa850fe 100644 (file)
@@ -2,29 +2,32 @@
 #define SPINLOCK_H
 
 #include <stdint.h>
-
 #include <stddef.h>
 
 /*
- * 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();
index ecab9963b0f95eaba3ed14f7797931238a421a05..d89f615d6d606bb4b507e98cdf5569c160cab2b4 100644 (file)
@@ -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;
index 45cbe4cfdd04efc8492a654042ec5a29ad7f4290..6054f6e02c7ddd65d10fadcc09e3865cac332d4c 100644 (file)
@@ -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
index babb9cc031ee1dc795cb8639de8ad94aa11fe49d..f5a88cc67fbda310a027771a3eea44d27c72981c 100644 (file)
@@ -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 (file)
index 0000000..0703d49
--- /dev/null
@@ -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 <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 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; }
index cfaaf9ba851426618f9b2f2d4a80fdd9bc6cfc42..035f5ae4a72679b31b8b780a59e9eaee9bb77fcd 100644 (file)
@@ -3,9 +3,11 @@
 #include <stdint.h>
 
 /*
- * 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 */
index ef09a7f56c67548ba492c598c7ad9e9e87db4882..f91d18571dfeb3620dbd564076cf3a4804818352 100644 (file)
@@ -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;
 }