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
@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:
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
#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;
}
#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();
(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;
/*
- * 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
/*
- * 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)
+ }
}
--- /dev/null
+/*
+ * 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; }
#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 */
return -1;
}
-void hal_usermode_enter_regs(const struct registers* regs) {
+void hal_usermode_enter_regs(const void* regs) {
(void)regs;
}