diff --git a/.gitignore b/.gitignore index 87f3c62..f165ffe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/ target/ .DS_Store +.vscode diff --git a/Makefile b/Makefile index aacc46a..6409454 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# arch = {riscv32, riscv64, x86_64, aarch64} +# arch = {riscv32, riscv64, x86_64, aarch64, mipsel} # mode = {debug, release} arch ?= riscv32 mode ?= debug @@ -46,7 +46,7 @@ ifneq ($(arch), x86_64) endif biscuit: -ifeq ($(arch), $(filter $(arch), x86_64 aarch64 riscv64)) +ifeq ($(arch), $(filter $(arch), x86_64 aarch64 riscv64 mipsel)) ifneq ($(shell uname)-$(arch), Darwin-riscv64) @echo Building biscuit programs @mkdir -p biscuit/build diff --git a/README.md b/README.md index a1810da..006415a 100644 --- a/README.md +++ b/README.md @@ -42,25 +42,25 @@ $ brew install FileSottile/musl-cross/musl-cross {--with-aarch64} Then, build userspace programs for rCore: ```bash -$ make {ucore,biscuit,rust,nginx,redis,all} arch={x86_64,aarch64,riscv32,riscv64} +$ make {ucore,biscuit,rust,nginx,redis,all} arch={x86_64,aarch64,riscv32,riscv64,mipsel} $ make alpine arch={x86_64,aarch64} # if you want to use alpine rootfs -$ make sfsimg arch={x86_64,aarch64,riscv32,riscv64} +$ make sfsimg arch={x86_64,aarch64,riscv32,riscv64,mipsel} ``` A rootfs is created at `build/$(arch)` and converted to `qcow2`. ## Support matrix -| | x86_64 | aarch64 | riscv32 | riscv64 | -| ------------------ | ------ | ------- | ------- | ------- | -| ucore | ❌ | ✅ | ✅ | ✅ | -| rust | ✅ | ✅ | ✅ | ✅ | -| biscuit | ✅ | ✅ | ❌ | ✅ | -| nginx (linux only) | ✅ | ✅ | ❌ | ✅ | -| redis (linux only) | ✅ | ✅ | ✅ | ❌ | -| busybox | ✅ | ✅ | ❌ | ✅ | -| alpine rootfs | ✅ | ✅ | ❌ | ❌ | -| iperf3 | ✅ | ❌ | ❌ | ❌ | +| | x86_64 | aarch64 | riscv32 | riscv64 | mipsel | +| ------------------ | ------ | ------- | ------- | ------- | ------ | +| ucore | ❌ | ✅ | ✅ | ✅ | ✅ | +| rust | ✅ | ✅ | ✅ | ✅ | ✅ | +| biscuit | ✅ | ✅ | ❌ | ✅ | ✅ | +| nginx (linux only) | ✅ | ✅ | ❌ | ✅ | ❓ | +| redis (linux only) | ✅ | ✅ | ✅ | ❌ | ❓ | +| busybox | ✅ | ✅ | ❌ | ✅ | ❓ | +| alpine rootfs | ✅ | ✅ | ❌ | ❌ | ❌ | +| iperf3 | ✅ | ❌ | ❌ | ❌ | ❓ | ## How to run real world programs diff --git a/biscuit/CMakeLists.txt b/biscuit/CMakeLists.txt index f05f3d2..31df56a 100644 --- a/biscuit/CMakeLists.txt +++ b/biscuit/CMakeLists.txt @@ -23,17 +23,18 @@ find_path(KERNEL_HEADERS_DIR ) # Toolchain + +set(PREFIX ${ARCH}-linux-musl-) + if (${ARCH} STREQUAL x86_64) - set(PREFIX x86_64-linux-musl-) set(CMAKE_C_FLAGS "-m64 -mno-red-zone") elseif (${ARCH} STREQUAL riscv32) set(PREFIX riscv64-unknown-elf-) set(CMAKE_C_FLAGS "-march=rv32imac -mabi=ilp32 -mcmodel=medany") elseif (${ARCH} STREQUAL riscv64) - set(PREFIX riscv64-linux-musl-) set(CMAKE_C_FLAGS "-march=rv64imafdc -mabi=lp64d -mcmodel=medany") elseif (${ARCH} STREQUAL aarch64) - set(PREFIX aarch64-linux-musl-) +elseif (${ARCH} STREQUAL mipsel) else () message("Unsupported arch: ${ARCH}") endif () diff --git a/biscuit/c/usertests.c b/biscuit/c/usertests.c index 851fd20..9faceca 100644 --- a/biscuit/c/usertests.c +++ b/biscuit/c/usertests.c @@ -2803,7 +2803,11 @@ static void *_locker(void *v) asm volatile("pause\n":::"memory"); #elif defined(__aarch64__) asm volatile("yield\n":::"memory"); +#else +#warning Yield instruction is not implemented + {} #endif + pthread_mutex_t *m = (pthread_mutex_t *)v; int i; for (i = 0; i < ltimes; i++) { @@ -2922,6 +2926,9 @@ static void _condtest(const int nt) asm volatile("pause\n":::"memory"); #elif defined(__aarch64__) asm volatile("yield\n":::"memory"); +#else +#warning Yield instruction is not implemented + {} #endif } diff --git a/rust/src/syscall.rs b/rust/src/syscall.rs index 5b36464..a49d09f 100644 --- a/rust/src/syscall.rs +++ b/rust/src/syscall.rs @@ -31,6 +31,12 @@ fn sys_call(syscall_id: SyscallId, arg0: usize, arg1: usize, arg2: usize, arg3: : "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5) : "memory" : "volatile"); + #[cfg(target_arch = "mips")] + asm!("syscall" + : "={v0}" (ret) + : "{t0}" (id), "{a0}" (arg0), "{a1}" (arg1), "{a2}" (arg2), "{a3}" (arg3), "{s0}" (arg4), "{s1}" (arg5) + : "memory" + : "volatile"); } ret } diff --git a/rust/targets/mipsel-rcore.json b/rust/targets/mipsel-rcore.json new file mode 100644 index 0000000..582df4f --- /dev/null +++ b/rust/targets/mipsel-rcore.json @@ -0,0 +1,32 @@ +{ + "arch": "mips", + "cpu": "mips32r2", + "llvm-target": "mipsel-unknown-none", + "data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", + "target-endian": "little", + "target-pointer-width": "32", + "target-c-int-width": "32", + "os": "none", + "features": "+mips32r2,+soft-float", + "max-atomic-width": "32", + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "executables": true, + "panic-strategy": "abort", + "relocation-model": "static", + "abi-blacklist": [ + "cdecl", + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "aapcs", + "win64", + "sysv64", + "ptx-kernel", + "msp430-interrupt", + "x86-interrupt" + ], + "eliminate-frame-pointer": false + } + \ No newline at end of file diff --git a/ucore/CMakeLists.txt b/ucore/CMakeLists.txt index 0f393cc..3cdce4a 100644 --- a/ucore/CMakeLists.txt +++ b/ucore/CMakeLists.txt @@ -35,6 +35,8 @@ elseif (${ARCH} STREQUAL aarch64) set(PREFIX aarch64-elf-) endif () set(CMAKE_C_FLAGS "-mgeneral-regs-only") +elseif (${ARCH} STREQUAL mipsel) + set(PREFIX mipsel-linux-musl-) else() message("Unsupported arch: ${ARCH}") endif () diff --git a/ucore/src/arch/mipsel/arch.h b/ucore/src/arch/mipsel/arch.h new file mode 100644 index 0000000..f7fb742 --- /dev/null +++ b/ucore/src/arch/mipsel/arch.h @@ -0,0 +1,14 @@ +// See LICENSE for license details. + +#ifndef __LIBS_MIPSEL_H__ +#define __LIBS_MIPSEL_H__ + +#define do_div(n, base) \ + ({ \ + int __res; \ + __res = ((unsigned long)n) % (unsigned)base; \ + n = ((unsigned long)n) / (unsigned)base; \ + __res; \ + }) + +#endif diff --git a/ucore/src/arch/mipsel/atomic.h b/ucore/src/arch/mipsel/atomic.h new file mode 100644 index 0000000..bbbb8da --- /dev/null +++ b/ucore/src/arch/mipsel/atomic.h @@ -0,0 +1,75 @@ +#ifndef __LIBS_ATOMIC_H__ +#define __LIBS_ATOMIC_H__ + +// TODO: implement atomic operations for aarch64 + +/* Atomic operations that C can't guarantee us. Useful for resource counting etc.. */ + +static inline void set_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline void clear_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline void change_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline bool test_and_set_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline bool test_and_clear_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline bool test_bit(int nr, volatile void *addr) __attribute__((always_inline)); + +/* * + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + * */ +static inline void set_bit(int nr, volatile void *addr) { + /* unimplemented */ +} + +/* * + * clear_bit - Atomically clears a bit in memory + * @nr: the bit to clear + * @addr: the address to start counting from + * */ +static inline void clear_bit(int nr, volatile void *addr) { + /* unimplemented */ +} + +/* * + * change_bit - Atomically toggle a bit in memory + * @nr: the bit to change + * @addr: the address to start counting from + * */ +static inline void change_bit(int nr, volatile void *addr) { + /* unimplemented */ +} + +/* * + * test_bit - Determine whether a bit is set + * @nr: the bit to test + * @addr: the address to count from + * */ +static inline bool test_bit(int nr, volatile void *addr) { + /* unimplemented */ + return 0; +} + +/* * + * test_and_set_bit - Atomically set a bit and return its old value + * @nr: the bit to set + * @addr: the address to count from + * */ +static inline bool test_and_set_bit(int nr, volatile void *addr) { + /* unimplemented */ + return 0; +} + +/* * + * test_and_clear_bit - Atomically clear a bit and return its old value + * @nr: the bit to clear + * @addr: the address to count from + * */ +static inline bool test_and_clear_bit(int nr, volatile void *addr) { + /* unimplemented */ + return 0; +} + +#endif /* !__LIBS_ATOMIC_H__ */ diff --git a/ucore/src/arch/mipsel/initcode.S b/ucore/src/arch/mipsel/initcode.S new file mode 100644 index 0000000..0c56ff2 --- /dev/null +++ b/ucore/src/arch/mipsel/initcode.S @@ -0,0 +1,10 @@ +#include + +.text +.globl _start +_start: + # call user-program function + lw a0, 0(sp) + addiu a1, sp, 8 + b umain + nop diff --git a/ucore/src/arch/mipsel/regdef.h b/ucore/src/arch/mipsel/regdef.h new file mode 100644 index 0000000..14721cb --- /dev/null +++ b/ucore/src/arch/mipsel/regdef.h @@ -0,0 +1,55 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1985 MIPS Computer Systems, Inc. + * Copyright (C) 1994, 95, 99, 2003 by Ralf Baechle + * Copyright (C) 1990 - 1992, 1999 Silicon Graphics, Inc. + */ +#ifndef _ASM_REGDEF_H +#define _ASM_REGDEF_H + + + +/* + * Symbolic register names for 32 bit ABI + */ +#define zero $0 /* wired zero */ +#define AT $1 /* assembler temp - uppercase because of ".set at" */ +#define v0 $2 /* return value */ +#define v1 $3 +#define a0 $4 /* argument registers */ +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 /* caller saved */ +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 /* callee saved */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* caller saved */ +#define t9 $25 +#define jp $25 /* PIC jump register */ +#define k0 $26 /* kernel scratch */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define fp $30 /* frame pointer */ +#define s8 $30 /* same like fp! */ +#define ra $31 /* return address */ + + + +#endif /* _ASM_REGDEF_H */ diff --git a/ucore/src/libs/defs.h b/ucore/src/libs/defs.h index ad73668..2c66c6f 100644 --- a/ucore/src/libs/defs.h +++ b/ucore/src/libs/defs.h @@ -32,7 +32,7 @@ typedef unsigned long long uint64_t; #if __riscv_xlen == 64 || defined(__x86_64__) || defined(__aarch64__) typedef int64_t intptr_t; typedef uint64_t uintptr_t; -#elif __riscv_xlen == 32 || defined(__i386__) +#elif __riscv_xlen == 32 || defined(__i386__) || defined(__mips__) typedef int32_t intptr_t; typedef uint32_t uintptr_t; #endif diff --git a/ucore/src/libs/elf.h b/ucore/src/libs/elf.h index f8958d3..ed973ea 100644 --- a/ucore/src/libs/elf.h +++ b/ucore/src/libs/elf.h @@ -36,7 +36,7 @@ struct proghdr { uint64_t p_memsz; // size of segment in memory (bigger if contains bss) uint64_t p_align; // required alignment, invariably hardware page size }; -#elif __riscv_xlen == 32 || defined(__i386__) +#elif __riscv_xlen == 32 || defined(__i386__) || defined(__mipsel) struct proghdr { uint32_t p_type; // loadable code or data, dynamic linking info,etc. uint32_t p_offset; // file offset of segment