This repository provides scripts and configuration files for building a Caplifive system that can run on Caplifive-QEMU.
It also includes a Linux kernel module for Caplifive, along with corresponding test programs and case studies.
Note: The full system can be built using the build script provided in caplifive-qemu.
Before building, ensure you have the following repositories built (Alternatively, use the build.sh script in Caplifive-QEMU to build the full system):
To build on a local Debian-based machine, make sure you have locally built Capstone-C and Caplifive-QEMU using their respective local build scripts. Then, run the following command:
./local_build.shTo build the Docker image, follow these steps:
-
First, build the Capstone-C and Caplifive-QEMU images (they are tagged as
capstone-candqemu-buildif built using the default instructions). -
If you've customized the names, make sure to change them in the
Dockerfile. -
Run the following command to build the full-system Docker image:
docker build -t <tag> .You will be able to find the built images in
./build/images, ready to be fed to Caplifive-QEMU.
If you have made changes to OpenSBI, sync and rebuild with
Please manually delete sbi_capstone_dom.c.S and capstone_int_handler.c.S in components/opensbi/lib/sbi before rebuild.
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=opensbi-rebuildSimilarly, to sync changes to the Linux kernel and rebuild, use
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=linux-rebuildFor the kernel module or the test program,
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=modcapstone-rebuildYou can place the files you want to include in the rootfs in ./overlay.
- You can run the
start.shscript in the Caplifive-QEMU repository, or you can pass the following arguments to the qemu image:
-M virt-capstone -m 8G -nographic
-bios <path>/build/images/fw_jump.elf
-kernel <path>/build/images/Image
-append 'root=/dev/vda ro'
-drive file=<path>/build/images/rootfs.ext2,format=raw,id=hd0
-netdev user,id=net0,hostfwd=tcp::60022-:22
-device virtio-blk-device,drive=hd0
-chardev stdio,mux=on,id=ch0,signal=on
-mon chardev=ch0,mode=readline
-serial chardev:ch0
-device e1000,netdev=net0
-cpu rv64,sstc=false,h=false
# Where `<path>` is the local working directory of this repo.- Log in using the
rootaccount. Both the kernel module and test program can be found at/.
- To install or uninstall the kernel module, run:
# Install the kernel module
insmod /capstone.ko# Uninstall the kernel module
rmmod capstone- After installing the kernel module, run the test program with:
/capstone-test.user <test domain ELF file> [<number of times to call the domain (default: 1)>]Alternatively, use the
run-testscript to automate the entire process:
/run-test <test domain name> [<number of times to call the domain (default: 1)>]Build the null block device driver:
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=capstone-null-blk-buildBuild the user space setup program:
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=modcapstone-rebuildInside the qemu image after logging in:
- Install the
capstoneandconfigfskernel modules:
modprobe configfs
insmod /capstone.ko- Run the user space setup program:
/null_blk.user- Install the null block device driver:
insmod /nullb/capstone_split/null_blk.ko- Then the null block device
/dev/nullb0is ready to be used. You can write to the driver:
echo "hello world" | dd of=/dev/nullb0 bs=1024 count=10Or read from the driver:
dd if=/dev/nullb0 bs=1024 count=10 | hexdump -CIf you want to remove the device, simple run:
rmmod null_blkBuild the web server frontend:
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=modcapstone-rebuildBuild the web server middle end and external scripts:
make build CAPSTONE_CC_PATH=<path-to-capstone-c-compiler-directory> A=capstone-nested-enclave-buildInside the qemu image after logging in:
- Install the
capstonekernel module:
insmod /capstone.ko- Start the web server at the background:
/miniweb_frontend.user &- Now the web server is ready to be used. You can now use
wgetto send a GET request to the web server, e.g.,
busybox wget -O - http://localhost:8888/index.html
busybox wget -O - http://localhost:8888/null.html # 404 response
busybox wget -O - http://localhost:8888/register.htmlYou can also send a POST request and specify an external script to handle such request, e.g.,
busybox wget --post-data "name=Alex&[email protected]" -O - http://localhost:8888/cgi/cgi_register_success.dombusybox wget --post-data "name=Bob&[email protected]" -O - http://localhost:8888/cgi/cgi_register_success.dombusybox wget --post-data "name=Alex&[email protected]" -O - http://localhost:8888/cgi/cgi_register_fail.domNote: Expected benchmarks in
overlay/benchmark.
Simply run the scripts in overlay-sources to randomly generate the benchmarks for each case study:
cd overlay-sources
./benchmark-nullb-gen.sh > ../overlay/benchmark/null-blk # for block device driver
./benchmark-nested-gen.sh > ../overlay/benchmark/nested-enclave # for web server in nested domainsSimply run the scripts in scripts directory (present in docker container as well as local machine) as below to run the benchmarks automatically:
cd scripts
# replace <<path-to-caplifive-qemu> to the real path on your machine
CAPSTONE_QEMU_PATH=<path-to-caplifive-qemu> expect benchmark_nullb.tcl
CAPSTONE_QEMU_PATH=<path-to-caplifive-qemu> expect benchmark_nested.tclAt the end of benchmarking, the results will be shown in the following format:
[CAPSTONE] CAPSTONE DEBUG COUNTERS
[CAPSTONE] counter[<index>] = <value>
[CAPSTONE] counter[<index>] = <value>
...
Each index corresponds to a profiling result in our benchmark, the correspondence relationship is shown in the table below:
| Index | Profiling Subject |
|---|---|
| 0 | Context switching (U-mode) |
| 1 | Context switching (S-mode) |
| 2 | Context switching (C/M-mode) |
| 3 | Interrupt handling |
| 4 | Memory access fault handling |
| 5 - 9 | Not used yet |
| 10 | Asynchronous sharing (bytes) |
| 11 | Asynchronous sharing (times) |
| 12 | Synchronous immutable borrowing (bytes) |
| 13 | Synchronous immutable borrowing (times) |
| 14 | Synchronous double transfer (bytes) |
| 15 | Synchronous double transfer (times) |
| 16 | Synchronous immutable transferred borrowing (bytes) |
| 17 | Synchronous immutable transferred borrowing (times) |
| 18 | Synchronous mutable transferred borrowing (bytes) |
| 19 | Synchronous mutable transferred borrowing (times) |
| 20 - 31 | Not used yet |