diff --git a/.cargo/config.toml b/.cargo/config.toml index ada23b809..b5e787d0e 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,8 +5,7 @@ runner = "cargo run --package jinux-build --" [alias] kcheck = "check --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" kbuild = "build --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" -krun = "run --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem --" -ksctest = "run --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -- --syscall-test" +krun = "run --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" ktest = "test --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" kclippy = "clippy --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" component-check = "component check --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" diff --git a/Makefile b/Makefile index caae8f95a..974879bbb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,33 @@ -.PHONY: all build clean docs fmt run setup test tools syscall_test syscall_bin +# Make arguments and their defaults +AUTO_SYSCALL_TEST ?= 0 +BUILD_SYSCALL_TEST ?= 0 +EMULATE_IOMMU ?= 0 +ENABLE_KVM ?= 1 +# End of Make arguments + +KERNEL_CMDLINE := SHELL="/bin/sh" LOGNAME="root" HOME="/" USER="root" PATH="/bin" init=/usr/bin/busybox -- sh -l +ifeq ($(AUTO_SYSCALL_TEST), 1) +KERNEL_CMDLINE += /opt/syscall_test/run_syscall_test.sh +endif + +CARGO_KRUN_ARGS := -- '$(KERNEL_CMDLINE)' + +ifeq ($(ENABLE_KVM), 1) +CARGO_KRUN_ARGS += --enable-kvm +endif + +ifeq ($(EMULATE_IOMMU), 1) +CARGO_KRUN_ARGS += --emulate-iommu +endif + +ifeq ($(AUTO_SYSCALL_TEST), 1) +BUILD_SYSCALL_TEST := 1 +endif + +# Pass make variables to all subdirectory makes +export + +.PHONY: all setup build tools run test docs check clean all: build @@ -15,26 +44,9 @@ build: tools: @cd services/libs/comp-sys && cargo install --path cargo-component -# FIXME: Exit code manipulation is not needed using non-x86 QEMU run: build -ifneq ($(ENABLE_KVM), false) - cargo krun --enable-kvm || exit $$(($$? >> 1)) -else - cargo krun || exit $$(($$? >> 1)) -endif + @cargo krun $(CARGO_KRUN_ARGS) -syscall_bin: - @make --no-print-directory -C regression/syscall_test - -# Test Jinux in a QEMU guest VM and run a series of evaluations. -syscall_test: syscall_bin build -ifneq ($(ENABLE_KVM), false) - @cargo ksctest --enable-kvm || exit $$(($$? >> 1)) -else - @cargo ksctest || exit $$(($$? >> 1)) -endif - -# The usermode cargo test of Jinux frame and Jinux standard library. test: build @cargo ktest diff --git a/README.md b/README.md index 94f3a5c54..73f32d674 100644 --- a/README.md +++ b/README.md @@ -75,18 +75,17 @@ cargo component-check ### Syscall Test -This command will build the syscall test binary and run Jinux with it in QEMU. +This command will build the syscall test binary and automatically run Jinux with the tests using QEMU. ```bash -make syscall_test +make run AUTO_SYSCALL_TEST=1 ``` -If you wish to test it interactively inside a shell in Jinux. -``` -make syscall_bin -make run +Alternatively, if you wish to test it interactively inside a shell in Jinux. +```bash +make run BUILD_SYSCALL_TEST=1 ``` -Then, we can run the following script inside the OS to run all syscall test cases. +Then, we can run the following script using the Jinux shell to run all syscall test cases. ```bash /opt/syscall_test/run_syscall_test.sh ``` diff --git a/build/src/main.rs b/build/src/main.rs index a65126732..1380ca374 100644 --- a/build/src/main.rs +++ b/build/src/main.rs @@ -1,5 +1,10 @@ -//! This is the Jinux runner script (I repeat: script) to ease the pain of -//! running and testing Jinux inside a QEMU VM. +//! jinux-build is the Jinux runner script to ease the pain of running +//! and testing Jinux inside a QEMU VM, which should be called as the +//! cargo runner: https://doc.rust-lang.org/cargo/reference/config.html +//! +//! The runner generates the the filesystem image and the containing +//! boot device image. Then it invokes QEMU to boot Jinux. +//! use std::{ fs::{self, OpenOptions}, @@ -8,28 +13,30 @@ use std::{ process::Command, }; -use clap::Parser; +use clap::{Parser, builder::Str}; /// The CLI of this runner. #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { // Positional arguments. + /// The Jinux binary path. path: PathBuf, - // Options. - /// Automatically run integration tests and exit. - #[arg(short, long, default_value_t = false)] - syscall_test: bool, + /// Provide the kernel commandline, which specifies + /// the init process. + kcmdline: String, + + // Optional arguments. /// Enable KVM when running QEMU. - #[arg(short, long, default_value_t = false)] + #[arg(long, default_value_t = false)] enable_kvm: bool, /// Emulate Intel IOMMU by QEMU. - #[arg(short, long, default_value_t = false)] - iommu: bool, + #[arg(long, default_value_t = false)] + emulate_iommu: bool, } const COMMON_ARGS: &[&str] = &[ @@ -86,7 +93,7 @@ fn main() { if args.enable_kvm { qemu_args.push("-enable-kvm"); } - if args.iommu { + if args.emulate_iommu { qemu_args.extend(IOMMU_DEVICE_ARGS.clone().to_vec().iter()); } else { qemu_args.extend(COMMON_DEVICE_ARGS.clone().to_vec().iter()); @@ -96,7 +103,7 @@ fn main() { qemu_args.push("-drive"); qemu_args.push(fs_image.as_str()); - let bootdev_image = create_bootdev_image(args.path, args.syscall_test); + let bootdev_image = create_bootdev_image(args.path, &args.kcmdline); qemu_cmd.arg("-cdrom"); qemu_cmd.arg(bootdev_image.as_str()); @@ -106,16 +113,13 @@ fn main() { let exit_status = qemu_cmd.status().unwrap(); if !exit_status.success() { - std::process::exit(exit_status.code().unwrap_or(1)); + // FIXME: Exit code manipulation is not needed when using non-x86 QEMU + let exit_code = exit_status.code().unwrap_or(0b10) >> 1; + std::process::exit(exit_code); } } -const KERNEL_CMDLINE: &str = - r#"SHELL="/bin/sh" LOGNAME="root" HOME="/" USER="root" PATH="/bin" init=/usr/bin/busybox"#; -const EVAL_INIT_CMDLINE: &str = r#"sh -l /opt/syscall_test/run_syscall_test.sh"#; -const COMMON_INIT_CMDLINE: &str = r#"sh -l"#; - -fn generate_grub_cfg(template_filename: &str, target_filename: &str, is_eval: bool) { +fn generate_grub_cfg(template_filename: &str, target_filename: &str, kcmdline: &str) { let mut buffer = String::new(); // Read the contents of the file @@ -125,12 +129,7 @@ fn generate_grub_cfg(template_filename: &str, target_filename: &str, is_eval: bo .unwrap(); // Replace all occurrences of "#KERNEL_COMMAND_LINE#" with the desired value - let cmdline = if is_eval { - KERNEL_CMDLINE.to_string() + " -- " + EVAL_INIT_CMDLINE - } else { - KERNEL_CMDLINE.to_string() + " -- " + COMMON_INIT_CMDLINE - }; - let replaced_content = buffer.replace("#KERNEL_COMMAND_LINE#", &cmdline); + let replaced_content = buffer.replace("#KERNEL_COMMAND_LINE#", kcmdline); // Write the modified content back to the file fs::File::create(target_filename) @@ -139,7 +138,7 @@ fn generate_grub_cfg(template_filename: &str, target_filename: &str, is_eval: bo .unwrap(); } -fn create_bootdev_image(path: PathBuf, is_eval: bool) -> String { +fn create_bootdev_image(path: PathBuf, kcmdline: &str) -> String { let dir = path.parent().unwrap(); let name = path.file_name().unwrap().to_str().unwrap().to_string(); let iso_path = dir.join(name + ".iso").to_str().unwrap().to_string(); @@ -156,7 +155,7 @@ fn create_bootdev_image(path: PathBuf, is_eval: bool) -> String { generate_grub_cfg( "build/grub/grub.cfg.template", "target/iso_root/boot/grub/grub.cfg", - is_eval, + kcmdline, ); fs::copy( "regression/build/ramdisk.cpio.gz", diff --git a/regression/Makefile b/regression/Makefile index 966f690e0..624950b70 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -4,17 +4,7 @@ BUILD_DIR := $(CUR_DIR)/build INITRAMFS := $(BUILD_DIR)/initramfs RAMDISK := $(BUILD_DIR)/ramdisk.cpio.gz SHELL := /bin/bash - -.PHONY: all clean - -all: build - -TARGETS=\ - $(INITRAMFS)/lib/x86_64-linux-gnu \ - $(INITRAMFS)/lib64 \ - $(INITRAMFS)/bin \ - $(INITRAMFS)/usr/bin \ - $(INITRAMFS)/regression \ +INITRAMFS_EMPTY_DIRS := \ $(INITRAMFS)/etc \ $(INITRAMFS)/sbin \ $(INITRAMFS)/root \ @@ -22,8 +12,18 @@ TARGETS=\ $(INITRAMFS)/opt \ $(INITRAMFS)/proc \ $(INITRAMFS)/dev +INITRAMFS_ALL_DIRS := \ + $(INITRAMFS)/lib/x86_64-linux-gnu \ + $(INITRAMFS)/lib64 \ + $(INITRAMFS)/bin \ + $(INITRAMFS)/usr/bin \ + $(INITRAMFS)/regression \ + $(INITRAMFS_EMPTY_DIRS) + +.PHONY: all clean + +all: build -# Copy necessary libs $(INITRAMFS)/lib/x86_64-linux-gnu: @mkdir -p $@ @cp -L /lib/x86_64-linux-gnu/libc.so.6 $@ @@ -36,7 +36,7 @@ $(INITRAMFS)/lib64: @mkdir -p $@ @cp -L /lib64/ld-linux-x86-64.so.2 $@ -# Install busybox +# Install busybox into /bin and /usr/bin. $(INITRAMFS)/bin: @mkdir -p $@ @/bin/busybox --install -s $@ @@ -45,33 +45,24 @@ $(INITRAMFS)/usr/bin: $(INITRAMFS)/bin @mkdir -p $@ @cp /usr/bin/busybox $@ -# Copy from apps +# Copy from apps. $(INITRAMFS)/regression: @make --no-print-directory -C apps -# Make necessary directories -$(INITRAMFS)/etc: +# Make necessary directories. +$(INITRAMFS_EMPTY_DIRS): @mkdir -p $@ -$(INITRAMFS)/sbin: - @mkdir -p $@ +$(INITRAMFS)/opt/syscall_test: + @make --no-print-directory -C syscall_test -$(INITRAMFS)/root: - @mkdir -p $@ - -$(INITRAMFS)/tmp: - @mkdir -p $@ - -$(INITRAMFS)/opt: - @mkdir -p $@ - -$(INITRAMFS)/proc: - @mkdir -p $@ - -$(INITRAMFS)/dev: - @mkdir -p $@ - -$(RAMDISK): $(TARGETS) +# If the BUILD_SYSCALL_TEST variable is set, we should depend on the +# sub make output to do incremental building. +ifeq ($(BUILD_SYSCALL_TEST), 1) +$(RAMDISK): $(INITRAMFS_ALL_DIRS) $(INITRAMFS)/opt/syscall_test +else +$(RAMDISK): $(INITRAMFS_ALL_DIRS) +endif @echo "Generating the ramdisk image..." @(cd $(INITRAMFS); find . | cpio -o -H newc | gzip) > $@