diff --git a/.gitignore b/.gitignore index fe8b1fd..975d0c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ build target /kernel/src/arch/x86_64/interrupt/vector.asm -/crate/bit-allocator/Cargo.lock -/crate/memory/Cargo.lock -/crate/bbl/Cargo.lock -/crate/sync/Cargo.lock -/crate/process/Cargo.lock + +Cargo.lock +!kernel/Cargo.lock +!user/Cargo.lock .DS_Store diff --git a/crate/atags/Cargo.lock b/crate/atags/Cargo.lock deleted file mode 100644 index 42d11eb..0000000 --- a/crate/atags/Cargo.lock +++ /dev/null @@ -1,14 +0,0 @@ -[[package]] -name = "atags" -version = "0.1.0" -dependencies = [ - "volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "volatile" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ca391c55768e479d5c2f8beb40c136df09257292a809ea514e82cfdfc15d00" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index e8ba981..aa429ce 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -63,6 +63,7 @@ minimum-image-size = 0 # The minimum output file size (in MiB) # (the "{}" will be replaced with the path to the bootable disk image) run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}", + # TODO: use SFSIMG environment variable "-drive", "format=raw,file=../user/img/ucore-i386-pic.img,media=disk,cache=writeback", "-serial", "mon:stdio", "-device", "isa-debug-exit", diff --git a/kernel/Makefile b/kernel/Makefile index 5ab7d19..87668a4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,6 +12,7 @@ # d = int | in_asm | ... QEMU debug info # mode = debug | release # LOG = off | error | warn | info | debug | trace +# SFSIMG = SFS image path of user programs # smp = 1 | 2 | ... SMP core number # board = fpga Only available on riscv32, build without bbl, run on board # | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ @@ -31,6 +32,14 @@ kernel := target/$(target)/$(mode)/ucore bin := target/$(target)/$(mode)/kernel.bin bootimage := target/$(target)/bootimage.bin +user_dir := ../user +user_bin_path := $(user_dir)/target/$(arch)-ucore/debug +user_bins := $(patsubst $(user_bin_path)/%.d, $(user_bin_path)/%, $(wildcard $(user_bin_path)/*.d)) +user_obj := build/$(arch)/user.o + +export ARCH = $(arch) +export SFSIMG = $(user_dir)/build/user-$(arch).img + ### qemu options ### qemu_opts := \ -smp cores=$(smp) \ @@ -39,7 +48,7 @@ qemu_opts := \ ifeq ($(arch), x86_64) qemu_opts += \ -drive format=raw,file=$(bootimage) \ - -drive format=raw,file="../user/img/ucore-i386-pic.img",media=disk,cache=writeback \ + -drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \ -serial mon:stdio \ -device isa-debug-exit @@ -101,18 +110,19 @@ cc := $(prefix)gcc as := $(prefix)as gdb := $(prefix)gdb -.PHONY: all clean run build asm doc justrun kernel +.PHONY: all clean run build asm doc justrun debug kernel sfsimg install all: kernel clean: @cargo clean + @cd $(user_dir) && make clean @rm -rf ../riscv-pk/build doc: @cargo rustdoc -- --document-private-items -run: build justrun +run: build sfsimg justrun justrun: @qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11 @@ -158,17 +168,30 @@ else ifeq ($(arch), aarch64) @$(objcopy) $(kernel) --strip-all -O binary $@ endif -kernel: ifeq ($(arch), x86_64) +kernel: @bootimage build $(build_args) else +kernel: sfsimg +ifeq ($(arch), riscv32) @-patch -p0 -N -b \ $(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ src/arch/riscv32/atomic.patch +endif @CC=$(cc) cargo xbuild $(build_args) endif +### user programs ### +sfsimg: + @cd $(user_dir) && make sfsimg + +# make user.o from binary files +$(user_obj): $(user_bins) + @cd $(user_bin_path) && \ + $(ld) -o $(abspath $@) $(patsubst %, -b binary %, $(notdir $(user_bins))) + + ### install ### ifeq ($(board), raspi3) sd_card ?= diff --git a/kernel/build.rs b/kernel/build.rs index ec94d4e..73117d7 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,23 +1,42 @@ extern crate cc; use std::fs::File; -use std::io::{Write, Result}; +use std::path::Path; +use std::io::{Result, Write}; fn main() { - if std::env::var("TARGET").unwrap().find("x86_64").is_some() { -// cc::Build::new() -// .file("src/arch/x86_64/driver/apic/lapic.c") -// .file("src/arch/x86_64/driver/keyboard/keyboard.c") -// .flag("-mcmodel=large") -// .compile("cobj"); - gen_vector_asm().unwrap(); - } - if std::env::var("TARGET").unwrap().find("riscv32").is_some() { - cc::Build::new() - .file("src/arch/riscv32/compiler_rt.c") - .flag("-march=rv32ia") - .flag("-mabi=ilp32") - .compile("atomic_rt"); + println!("cargo:rerun-if-env-changed=LOG"); + + let arch: String = std::env::var("ARCH").unwrap(); + match arch.as_str() { + "x86_64" => { + // cc::Build::new() + // .file("src/arch/x86_64/driver/apic/lapic.c") + // .file("src/arch/x86_64/driver/keyboard/keyboard.c") + // .flag("-mcmodel=large") + // .compile("cobj"); + gen_vector_asm().unwrap(); + } + "riscv32" => { + cc::Build::new() + .file("src/arch/riscv32/compiler_rt.c") + .flag("-march=rv32ia") + .flag("-mabi=ilp32") + .compile("atomic_rt"); + if let Ok(file_path) = gen_sfsimg_asm() { + cc::Build::new() + .file(&file_path) + .flag("-march=rv32ia") + .flag("-mabi=ilp32") + .compile("sfsimg"); + } + } + "aarch64" => { + if let Ok(file_path) = gen_sfsimg_asm() { + cc::Build::new().file(&file_path).compile("sfsimg"); + } + } + _ => panic!("Unknown arch {}", arch), } } @@ -43,4 +62,28 @@ fn gen_vector_asm() -> Result<()> { writeln!(f, "\t.quad vector{}", i)?; } Ok(()) -} \ No newline at end of file +} + +fn gen_sfsimg_asm() -> Result { + let out_dir = std::env::var("OUT_DIR").unwrap(); + let sfsimg = std::env::var("SFSIMG").unwrap(); + + let file_path = Path::new(&out_dir).join("sfsimg.S"); + let mut f = File::create(&file_path).unwrap(); + + write!(f, "# generated by build.rs - do not edit")?; + write!(f, r#" + .section .rodata + .align 12 + .global _user_img_start + .global _user_img_end +_user_img_start: + .incbin "{}" +_user_img_end: +"#, sfsimg)?; + + println!("cargo:rerun-if-changed={}", sfsimg); + println!("cargo:rerun-if-env-changed=SFSIMG"); + + Ok(file_path) +} diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index f4f44fa..9b9d04b 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -8,30 +8,6 @@ use crate::arch::driver::ide; use crate::sync::Condvar; use crate::sync::SpinNoIrqLock as Mutex; -// Hard link user program -#[cfg(target_arch = "riscv32")] -global_asm!(r#" - .section .rodata - .align 12 - .global _user_img_start - .global _user_img_end -_user_img_start: - .incbin "../user/img/ucore-rv32.img" -_user_img_end: -"#); - -// Hard link user program -#[cfg(target_arch = "aarch64")] -global_asm!(r#" - .section .rodata - .align 12 - .global _user_img_start - .global _user_img_end -_user_img_start: - .incbin "../user/img/ucore-aarch64.img" -_user_img_end: -"#); - lazy_static! { pub static ref ROOT_INODE: Arc = { #[cfg(any(target_arch = "riscv32", target_arch = "aarch64"))] @@ -40,6 +16,7 @@ lazy_static! { fn _user_img_start(); fn _user_img_end(); } + // Hard link user program Box::new(unsafe { MemBuf::new(_user_img_start, _user_img_end) }) }; #[cfg(target_arch = "x86_64")] diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 1dcd521..b8443f3 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -6,12 +6,15 @@ use crate::fs::{ROOT_INODE, INodeExt}; use crate::process::*; pub fn run_user_shell() { - let inode = ROOT_INODE.lookup("sh").unwrap(); - let data = inode.read_as_vec().unwrap(); - processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' ')), 0); + if let Ok(inode) = ROOT_INODE.lookup("sh") { + let data = inode.read_as_vec().unwrap(); + processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' ')), 0); + } else { + processor().manager().add(ContextImpl::new_kernel(shell, 0), 0); + } } -pub fn shell() { +pub extern fn shell(_arg: usize) -> ! { let files = ROOT_INODE.list().unwrap(); println!("Available programs: {:?}", files); diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 98a0f9e..4935c29 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -284,6 +284,7 @@ fn get_file(fd: usize) -> Result<&'static Arc>, SysError> { pub type SysResult = Result; #[repr(i32)] +#[derive(Debug)] pub enum SysError { VfsError, InvalidFile, diff --git a/user/Makefile b/user/Makefile index fccacbb..6c5f860 100644 --- a/user/Makefile +++ b/user/Makefile @@ -1,5 +1,59 @@ # arch = {riscv32, x86_64, aarch64} -arch := riscv32 +# mode = {debug, release} +arch ?= riscv32 +mode ?= debug -all: - cargo xbuild --target $(arch)-ucore.json \ No newline at end of file +rust_src_dir := src/bin +rust_bin_path := target/$(arch)-ucore/$(mode) +user_rust_bins := $(patsubst $(rust_src_dir)/%.rs, $(rust_bin_path)/%, $(wildcard $(rust_src_dir)/*.rs)) +c_src_dir := +c_bin_path := +user_c_bins := +user_bins := $(user_rust_bins) $(user_c_bins) + +build_path := build +sfsroot := $(build_path)/sfsroot-$(arch) +sfsimg := $(build_path)/user-$(arch).img + +mksfs := mksfs + +build_args := --target $(arch)-ucore.json +ifeq ($(mode), release) +build_args := $(build_args) --release +endif + +.PHONY: all clean build-rust build-c build mksfs sfsimg + +all: $(sfsimg) + +build-rust: + @echo Building user rust programs + @cargo xbuild $(build_args) + +build-c: + @echo Building user C programs + +build: build-rust build-c + +$(user_rust_bins): build-rust + +$(user_c_bins): build-c + +mksfs: +ifeq ($(shell which $(mksfs)),) + @cargo install --git https://github.com/wangrunji0408/SimpleFileSystem-Rust --features="std" +endif + +$(sfsroot): $(user_bins) + @mkdir -p $@ + @cp $^ $@/ + +$(sfsimg): $(user_bins) $(sfsroot) | mksfs + @echo Creating SFS image at $@ + @$(mksfs) zip $(sfsroot) $@ + +sfsimg: $(sfsimg) + +clean: + @cargo clean + @rm -rf $(build_path) diff --git a/user/aarch64-ucore.json b/user/aarch64-ucore.json index 357c2e3..7d9e167 100644 --- a/user/aarch64-ucore.json +++ b/user/aarch64-ucore.json @@ -13,6 +13,11 @@ "linker": "rust-lld", "linker-flavor": "ld.lld", "linker-is-gnu": true, + "pre-link-args": { + "ld.lld": [ + "-Tsrc/arch/aarch64/user.ld" + ] + }, "llvm-target": "aarch64-unknown-none", "no-compiler-rt": true, "features": "+a53,+strict-align,-neon", diff --git a/user/riscv32-ucore.json b/user/riscv32-ucore.json index 37dac6f..354279e 100644 --- a/user/riscv32-ucore.json +++ b/user/riscv32-ucore.json @@ -11,6 +11,11 @@ "max-atomic-width": "32", "linker": "rust-lld", "linker-flavor": "ld.lld", + "pre-link-args": { + "ld.lld": [ + "-Tsrc/arch/riscv32/user.ld" + ] + }, "executables": true, "panic-strategy": "abort", "relocation-model": "static", @@ -27,4 +32,4 @@ "msp430-interrupt", "x86-interrupt" ] -} \ No newline at end of file +} diff --git a/user/src/arch/aarch64/user.ld b/user/src/arch/aarch64/user.ld new file mode 100644 index 0000000..b989922 --- /dev/null +++ b/user/src/arch/aarch64/user.ld @@ -0,0 +1,46 @@ +/* Simple linker script for ucore user-level programs. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(aarch64) +ENTRY(_start) + +SECTIONS { + /* Load programs at this address: "." means the current address */ + . = 0xffff000000000000; + + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + *(.data.*) + } + + .sdata : { + *(.sdata) + *(.sdata.*) + } + + PROVIDE(edata = .); + + .bss : { + *(.bss) + } + + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack .comment) + } +} diff --git a/user/src/arch/riscv32/user.ld b/user/src/arch/riscv32/user.ld new file mode 100644 index 0000000..80ac4e5 --- /dev/null +++ b/user/src/arch/riscv32/user.ld @@ -0,0 +1,46 @@ +/* Simple linker script for ucore user-level programs. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +SECTIONS { + /* Load programs at this address: "." means the current address */ + . = 0x800020; + + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + *(.data.*) + } + + .sdata : { + *(.sdata) + *(.sdata.*) + } + + PROVIDE(edata = .); + + .bss : { + *(.bss) + } + + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack .comment) + } +} diff --git a/user/src/arch/x86_64/user.ld b/user/src/arch/x86_64/user.ld new file mode 100644 index 0000000..b135c9f --- /dev/null +++ b/user/src/arch/x86_64/user.ld @@ -0,0 +1,46 @@ +/* Simple linker script for ucore user-level programs. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(x86_64) +ENTRY(_start) + +SECTIONS { + /* Load programs at this address: "." means the current address */ + . = 0x800020; + + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + *(.data.*) + } + + .sdata : { + *(.sdata) + *(.sdata.*) + } + + PROVIDE(edata = .); + + .bss : { + *(.bss) + } + + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack .comment) + } +} diff --git a/user/src/bin/hello.rs b/user/src/bin/hello_rust.rs similarity index 50% rename from user/src/bin/hello.rs rename to user/src/bin/hello_rust.rs index 5a29680..72e3040 100644 --- a/user/src/bin/hello.rs +++ b/user/src/bin/hello_rust.rs @@ -7,5 +7,7 @@ extern crate ucore_ulib; // IMPORTANT: Must define main() like this #[no_mangle] pub fn main() { - println!("Hello uCore!"); + println!("Hello Rust uCore!"); + println!("I am process {}.", ucore_ulib::syscall::sys_getpid()); + println!("hello pass."); } diff --git a/user/ucore-ulib/src/lang_items.rs b/user/ucore-ulib/src/lang_items.rs index 06b4511..e1e58d8 100644 --- a/user/ucore-ulib/src/lang_items.rs +++ b/user/ucore-ulib/src/lang_items.rs @@ -1,15 +1,47 @@ -use crate::syscall::sys_exit; +use crate::syscall::{sys_close, sys_dup, sys_exit, sys_open}; +use crate::syscall::{O_RDONLY, O_WRONLY}; use core::alloc::Layout; use core::panic::PanicInfo; +// used for panic +macro_rules! print { + ($($arg:tt)*) => ({ + $crate::syscall::print_putc(format_args!($($arg)*)); + }); +} + #[linkage = "weak"] #[no_mangle] fn main() { panic!("No main() linked"); } +fn initfd(fd2: usize, path: &str, open_flags: usize) -> i32 { + let fd1 = sys_open(path, open_flags); + if fd1 < 0 { + return fd1; + } + let mut ret = fd1; + let fd1 = fd1 as usize; + if fd1 != fd2 { + sys_close(fd2); + ret = sys_dup(fd1, fd2); + sys_close(fd1); + } + return ret; +} + #[no_mangle] -pub extern fn _start(_argc: isize, _argv: *const *const u8) -> ! { +pub extern "C" fn _start(_argc: isize, _argv: *const *const u8) -> ! { + let fd = initfd(0, "stdin:", O_RDONLY); + if fd < 0 { + panic!("open failed: {}.", fd); + } + let fd = initfd(1, "stdout:", O_WRONLY); + if fd < 0 { + panic!("open failed: {}.", fd); + } + main(); sys_exit(0) } @@ -31,12 +63,12 @@ fn oom(_: Layout) -> ! { } #[no_mangle] -pub extern fn abort() -> ! { +pub extern "C" fn abort() -> ! { sys_exit(2) } #[no_mangle] -pub extern fn __mulsi3(mut a: u32, mut b: u32) -> u32 { +pub extern "C" fn __mulsi3(mut a: u32, mut b: u32) -> u32 { let mut r: u32 = 0; while a > 0 { @@ -48,4 +80,4 @@ pub extern fn __mulsi3(mut a: u32, mut b: u32) -> u32 { } r -} \ No newline at end of file +} diff --git a/user/ucore-ulib/src/syscall.rs b/user/ucore-ulib/src/syscall.rs index f707142..1a75785 100644 --- a/user/ucore-ulib/src/syscall.rs +++ b/user/ucore-ulib/src/syscall.rs @@ -17,14 +17,29 @@ pub fn print(args: fmt::Arguments) { StdOut.write_fmt(args).unwrap(); } +pub fn print_putc(args: fmt::Arguments) { + SysPutc.write_fmt(args).unwrap(); +} + struct StdOut; +struct SysPutc; impl fmt::Write for StdOut { fn write_str(&mut self, s: &str) -> fmt::Result { - match sys_write(0, s.as_ptr(), s.len()) { - 0 => Ok(()), - _ => Err(fmt::Error::default()), + if sys_write(1, s.as_ptr(), s.len()) >= 0 { + Ok(()) + } else { + Err(fmt::Error::default()) + } + } +} + +impl fmt::Write for SysPutc { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.bytes() { + sys_putc(c as char); } + Ok(()) } } @@ -77,6 +92,10 @@ pub fn sys_close(fd: usize) -> i32 { sys_call(SYS_CLOSE, fd, 0, 0, 0, 0, 0) } +pub fn sys_dup(fd1: usize, fd2: usize) -> i32 { + sys_call(SYS_DUP, fd1, fd2, 0, 0, 0, 0) +} + /// Fork the current process. Return the child's PID. pub fn sys_fork() -> i32 { sys_call(SYS_FORK, 0, 0, 0, 0, 0, 0) @@ -144,3 +163,15 @@ const SYS_GETCWD: usize = 121; const SYS_GETDIRENTRY: usize = 128; const SYS_DUP: usize = 130; const SYS_LAB6_SET_PRIORITY: usize = 255; + +/* VFS flags */ +// TODO: use bitflags +// flags for open: choose one of these +pub const O_RDONLY: usize = 0; // open for reading only +pub const O_WRONLY: usize = 1; // open for writing only +pub const O_RDWR: usize = 2; // open for reading and writing +// then or in any of these: +pub const O_CREAT: usize = 0x00000004; // create file if it does not exist +pub const O_EXCL: usize = 0x00000008; // error if O_CREAT and the file exists +pub const O_TRUNC: usize = 0x00000010; // truncate file upon open +pub const O_APPEND: usize = 0x00000020; // append on each write diff --git a/user/x86_64-ucore.json b/user/x86_64-ucore.json index a2691a5..a8ace2c 100644 --- a/user/x86_64-ucore.json +++ b/user/x86_64-ucore.json @@ -9,7 +9,12 @@ "executables": true, "linker": "rust-lld", "linker-flavor": "ld.lld", + "pre-link-args": { + "ld.lld": [ + "-Tsrc/arch/x86_64/user.ld" + ] + }, "panic-strategy": "abort", "disable-redzone": true, "features": "-mmx,-sse,+soft-float" -} \ No newline at end of file +}