Skip to content

Commit

Permalink
Merge pull request #508 from ChinYikMing/feat/bring-up-linux
Browse files Browse the repository at this point in the history
Bring up Linux kernel
  • Loading branch information
jserv authored Dec 16, 2024
2 parents 451f8c0 + 3ef4675 commit 04e7396
Show file tree
Hide file tree
Showing 35 changed files with 5,018 additions and 341 deletions.
46 changes: 46 additions & 0 deletions .ci/boot-linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bash

function cleanup {
sleep 1
pkill -9 rv32emu
}

function ASSERT {
$*
local RES=$?
if [ $RES -ne 0 ]; then
echo 'Assert failed: "' $* '"'
exit $RES
fi
}

cleanup

TIMEOUT=50
OPTS=" -k build/linux-image/Image "
OPTS+=" -i build/linux-image/rootfs.cpio "
OPTS+=" -b build/minimal.dtb "
RUN_LINUX="build/rv32emu ${OPTS}"

ASSERT expect <<DONE
set timeout ${TIMEOUT}
spawn ${RUN_LINUX}
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "\x01"; send "x" } timeout { exit 3 }
DONE

ret=$?
cleanup

MESSAGES=("OK!" \
"Fail to boot" \
"Fail to login" \
"Fail to run commands" \
)

COLOR_G='\e[32;01m' # Green
COLOR_N='\e[0m' # No color
printf "\n[ ${COLOR_G}${MESSAGES[$ret]}${COLOR_N} ]\n"

exit ${ret}
60 changes: 59 additions & 1 deletion .github/workflows/build-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ jobs:
tests/quake/**
tests/scimark2/**
tests/*.c
- name: Test file change of Linux image
id: test-linux-image-version-change
uses: tj-actions/changed-files@v45
with:
files: |
mk/external.mk
- name: Set alias
id: has_changed_files
run: |
Expand All @@ -35,8 +41,60 @@ jobs:
else
echo "has_changed_files=false" >> $GITHUB_OUTPUT
fi
if [[ ${{ steps.test-linux-image-version-change.outputs.any_modified }} == true ]]; then
# Determine if the changes are from Buildroot or the Linux version (The Linux might have several patches, so also need to check the SHA value)
echo -n $(git --no-pager diff HEAD^ HEAD | grep -e "+BUILDROOT_VERSION" -e "+LINUX_VERSION" -e "+LINUX_DATA_SHA1") >> linux-image-version-change
if [[ -s linux-image-version-change ]]; then
echo "has_changed_linux_image_version=true" >> $GITHUB_OUTPUT
else
echo "has_changed_linux_image_version=false" >> $GITHUB_OUTPUT
fi
else
echo "has_changed_linux_image_version=false" >> $GITHUB_OUTPUT
fi
outputs:
has_changed_files: ${{ steps.has_changed_files.outputs.has_changed_files }}
has_changed_linux_image_version: ${{ steps.has_changed_files.outputs.has_changed_linux_image_version }}

build-linux-image-artifact:
needs: [detect-file-change]
if: ${{ needs.detect-file-change.outputs.has_changed_linux_image_version == 'true' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: 'true'
- name: Install dependencies
run: |
sudo apt-get update -q -y
sudo apt-get upgrade -q -y
sudo apt-get install -q -y build-essential git
- name: Build Linux image
run: |
make build-linux-image
make artifact ENABLE_PREBUILT=0 ENABLE_SYSTEM=1
mkdir -p /tmp/rv32emu-linux-image-prebuilt/linux-image
mv build/linux-image/Image /tmp/rv32emu-linux-image-prebuilt/linux-image
mv build/linux-image/rootfs.cpio /tmp/rv32emu-linux-image-prebuilt/linux-image
mv build/sha1sum-linux-image /tmp
- name: Create tarball
run: |
cd /tmp
tar -zcvf rv32emu-linux-image-prebuilt.tar.gz rv32emu-linux-image-prebuilt
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.RV32EMU_PREBUILT_TOKEN }}
run: |
RELEASE_TAG=$(date +'%Y.%m.%d'-Linux-Image)
cd /tmp
gh release create $RELEASE_TAG \
--repo sysprog21/rv32emu-prebuilt \
--title "$RELEASE_TAG""-nightly"
gh release upload $RELEASE_TAG \
rv32emu-linux-image-prebuilt.tar.gz \
sha1sum-linux-image \
--repo sysprog21/rv32emu-prebuilt
build-artifact:
needs: [detect-file-change]
Expand Down Expand Up @@ -83,7 +141,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.RV32EMU_PREBUILT_TOKEN }}
run: |
RELEASE_TAG=$(date +'%Y.%m.%d')
RELEASE_TAG=$(date +'%Y.%m.%d'-ELF)
cd /tmp
gh release create $RELEASE_TAG \
--repo sysprog21/rv32emu-prebuilt \
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- name: install-dependencies
run: |
sudo apt-get update -q -y
sudo apt-get install -q -y libsdl2-dev libsdl2-mixer-dev
sudo apt-get install -q -y libsdl2-dev libsdl2-mixer-dev device-tree-compiler expect
.ci/riscv-toolchain-install.sh
echo "${{ github.workspace }}/toolchain/bin" >> $GITHUB_PATH
wget https://apt.llvm.org/llvm.sh
Expand All @@ -67,11 +67,11 @@ jobs:
- name: misalignment test in block emulation
run: |
make -C tests/system/alignment/
make distclean && make ENABLE_EXT_C=0 ENABLE_SYSTEM=1 misalign-in-blk-emu -j$(nproc)
make distclean && make ENABLE_ELF_LOADER=1 ENABLE_EXT_C=0 ENABLE_SYSTEM=1 misalign-in-blk-emu -j$(nproc)
- name: MMU test
run: |
make -C tests/system/mmu/
make distclean && make ENABLE_SYSTEM=1 mmu-test -j$(nproc)
make distclean && make ENABLE_ELF_LOADER=1 ENABLE_SYSTEM=1 mmu-test -j$(nproc)
- name: gdbstub test
run: |
make distclean && make ENABLE_GDBSTUB=1 gdbstub-test -j$(nproc)
Expand All @@ -85,6 +85,11 @@ jobs:
run: |
make clean && make ENABLE_UBSAN=1 check -j$(nproc)
make ENABLE_JIT=1 clean && make ENABLE_JIT=1 ENABLE_UBSAN=1 check -j$(nproc)
- name: boot Linux kernel test
run: |
make clean && make ENABLE_SYSTEM=1 && make ENABLE_SYSTEM=1 artifact -j$(nproc)
.ci/boot-linux.sh
make ENABLE_SYSTEM=1 clean
host-arm64:
needs: [detect-code-related-file-changes]
Expand Down
43 changes: 32 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,24 @@ CONFIG_FILE := $(OUT)/.config

CFLAGS = -std=gnu99 -O2 -Wall -Wextra
CFLAGS += -Wno-unused-label
CFLAGS += -include src/common.h
CFLAGS += -include src/common.h -Isrc/

# In the system test suite, the executable is an ELF file (e.g., MMU).
# However, the Linux kernel emulation includes the Image, DT, and
# root filesystem (rootfs). Therefore, the test suite needs this
# flag to load the ELF and differentiate it from the kernel emulation.
ENABLE_ELF_LOADER ?= 0
$(call set-feature, ELF_LOADER)

# Enable MOP fusion, easier for ablation study
ENABLE_MOP_FUSION ?= 1
$(call set-feature, MOP_FUSION)

# Enable block chaining, easier for ablation study
ENABLE_BLOCK_CHAINING ?= 1
$(call set-feature, BLOCK_CHAINING)

# Enable system emulation
ENABLE_SYSTEM ?= 0
$(call set-feature, SYSTEM)

Expand Down Expand Up @@ -45,10 +61,6 @@ CFLAGS += $(CFLAGS_NO_CET)

OBJS_EXT :=

ifeq ($(call has, SYSTEM), 1)
OBJS_EXT += system.o
endif

# Integer Multiplication and Division instructions
ENABLE_EXT_M ?= 1
$(call set-feature, EXT_M)
Expand All @@ -71,7 +83,14 @@ src/softfloat/build/Linux-RISCV-GCC/Makefile:
SOFTFLOAT_LIB := $(SOFTFLOAT_OUT)/softfloat.a
$(SOFTFLOAT_LIB): src/softfloat/build/Linux-RISCV-GCC/Makefile
$(MAKE) -C $(dir $<) BUILD_DIR=$(SOFTFLOAT_OUT) CC=$(CC) AR=$(AR)
$(OUT)/decode.o $(OUT)/riscv.o: $(SOFTFLOAT_LIB)
ifeq ($(call has, SYSTEM), 1)
DEV_OUT := $(OUT)/devices
endif
OBJS_NEED_SOFTFLOAT := $(OUT)/decode.o \
$(OUT)/riscv.o \
$(DEV_OUT)/uart.o \
$(DEV_OUT)/plic.o
$(OBJS_NEED_SOFTFLOAT): $(SOFTFLOAT_LIB)
LDFLAGS += $(SOFTFLOAT_LIB)
LDFLAGS += -lm
endif
Expand Down Expand Up @@ -204,8 +223,9 @@ $(OUT)/emulate.o: CFLAGS += -foptimize-sibling-calls -fomit-frame-pointer -fno-s
include mk/external.mk
include mk/artifact.mk
include mk/wasm.mk
include mk/system.mk

all: config $(BIN)
all: config $(BUILD_DTB) $(BIN)

OBJS := \
map.o \
Expand All @@ -222,7 +242,7 @@ OBJS := \
main.o

OBJS := $(addprefix $(OUT)/, $(OBJS))
deps := $(OBJS:%.o=%.o.d)
deps += $(OBJS:%.o=%.o.d) # mk/system.mk includes prior this line, so declare deps at there

ifeq ($(call has, EXT_F), 1)
$(OBJS): $(SOFTFLOAT_LIB)
Expand All @@ -236,7 +256,7 @@ $(OUT)/%.o: src/%.c $(deps_emcc)
$(VECHO) " CC\t$@\n"
$(Q)$(CC) -o $@ $(CFLAGS) $(CFLAGS_emcc) -c -MMD -MF $@.d $<

$(BIN): $(OBJS)
$(BIN): $(OBJS) $(DEV_OBJS)
$(VECHO) " LD\t$@\n"
$(Q)$(CC) -o $@ $(CFLAGS_emcc) $^ $(LDFLAGS)

Expand Down Expand Up @@ -333,9 +353,10 @@ endif
endif

clean:
$(RM) $(BIN) $(OBJS) $(HIST_BIN) $(HIST_OBJS) $(deps) $(WEB_FILES) $(CACHE_OUT) src/rv32_jit.c
$(RM) $(BIN) $(OBJS) $(DEV_OBJS) $(BUILD_DTB) $(HIST_BIN) $(HIST_OBJS) $(deps) $(WEB_FILES) $(CACHE_OUT) src/rv32_jit.c
distclean: clean
-$(RM) $(DOOM_DATA) $(QUAKE_DATA)
-$(RM) $(DOOM_DATA) $(QUAKE_DATA) $(BUILDROOT_DATA) $(LINUX_DATA)
$(RM) -r $(OUT)/linux-image
$(RM) -r $(TIMIDITY_DATA)
$(RM) -r $(OUT)/id1
$(RM) -r $(DEMO_DIR)
Expand Down
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,34 @@ If you don't want the JIT compilation feature, simply build with the following:
$ make
```

### Experimental system emulation
Device Tree compiler (dtc) is required. To install it on Debian/Ubuntu Linux, enter the following command:
```
$ sudo apt install device-tree-compiler
```
For macOS, use the following command:
```
$ brew install dtc
```

#### Build and run system emulation
Build and run using default images (the default images will be fetched from [rv32emu-prebuilt](https://github.com/sysprog21/rv32emu-prebuilt) before running):
```shell
$ make ENABLE_SYSTEM=1 system
```

Build using run using specified images:
```shell
$ make ENABLE_SYSTEM=1
$ build/rv32emu -k <kernel_img_path> -i <rootfs_img_path> -b <dtb_path>
```

#### Build Linux image
An automated build script is provided to compile the RISC-V cross-compiler, Busybox, and Linux kernel from source. Please note that it only supports the Linux host environment. It can be found at tools/build-linux-image.sh.
```
$ make build-linux-img
```

### Verify with prebuilt RISC-V ELF files

Run sample RV32I[M] programs:
Expand Down Expand Up @@ -98,7 +126,9 @@ The image containing all the necessary tools for development and testing can be
* `ENABLE_FULL4G` : Full access to 4 GiB address space
* `ENABLE_SDL` : Experimental Display and Event System Calls
* `ENABLE_JIT` : Experimental JIT compiler
* `ENABLE_SYSTEM` : Experimental system emulation, allowing booting Linux kernel
* `ENABLE_SYSTEM`: Experimental system emulation, allowing booting Linux kernel. To enable this feature, additional features must also be enabled. However, by default, when `ENABLE_SYSTEM` is enabled, CSR, fence, integer multiplication/division, and atomic Instructions are automatically enabled
* `ENABLE_MOP_FUSION` : Macro-operation fusion
* `ENABLE_BLOCK_CHAINING` : Block chaining of translated blocks

e.g., run `make ENABLE_EXT_F=0` for the build without floating-point support.

Expand Down Expand Up @@ -145,7 +175,7 @@ For macOS users, installing `sdiff` might be required:
$ brew install diffutils
```

To run the tests for specific extension, set the environmental variable `RISCV_DEVICE` to one of `I`, `M`, `A`, `F`, `C`, `Zifencei`, `privilege`.
To run the tests for specific extension, set the environmental variable `RISCV_DEVICE` to one of `I`, `M`, `A`, `F`, `C`, `Zifencei`, `privilege`, `SYSTEM`.
```shell
$ make arch-test RISCV_DEVICE=I
```
Expand Down
47 changes: 47 additions & 0 deletions assets/system/configs/buildroot.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
BR2_riscv=y
BR2_ARCH="riscv32"
BR2_NORMALIZED_ARCH="riscv"
BR2_ENDIAN="LITTLE"
BR2_GCC_TARGET_ABI="ilp32"
BR2_READELF_ARCH_NAME="RISC-V"
BR2_RISCV_ISA_RVI=y
BR2_RISCV_ISA_RVM=y
BR2_RISCV_ISA_RVA=y
# BR2_riscv_g is not set
BR2_riscv_custom=y
BR2_RISCV_ISA_CUSTOM_RVM=y
BR2_RISCV_ISA_CUSTOM_RVA=y
# BR2_RISCV_ISA_CUSTOM_RVF is not set
# BR2_RISCV_ISA_CUSTOM_RVC is not set
BR2_RISCV_32=y
# BR2_RISCV_64 is not set
BR2_RISCV_ABI_ILP32=y
BR2_BINFMT_ELF=y
BR2_TOOLCHAIN_BUILDROOT_VENDOR="buildroot"
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
BR2_TOOLCHAIN_BUILDROOT_LIBC="glibc"
# BR2_TOOLCHAIN_BUILDROOT_CXX is not set
BR2_KERNEL_HEADERS_6_1=y
BR2_BINUTILS_VERSION_2_42_X=y
# BR2_BINUTILS_GPROFNG is not set
BR2_GCC_VERSION_14_X=y
BR2_EXTRA_GCC_CONFIG_OPTIONS="--enable-softfloat"
BR2_TOOLCHAIN_HEADERS_AT_LEAST="6.1"
BR2_TOOLCHAIN_GCC_AT_LEAST_14=y
BR2_TOOLCHAIN_GCC_AT_LEAST="14"
BR2_SSP_NONE=y
# BR2_SSP_REGULAR is not set
# BR2_SSP_STRONG is not set
BR2_RELRO_NONE=y
# BR2_RELRO_PARTIAL is not set
# BR2_RELRO_FULL is not set
BR2_FORTIFY_SOURCE_1=y
# BR2_PACKAGE_URANDOM_SCRIPTS is not set
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_CPIO_FULL=y
# BR2_TARGET_ROOTFS_CPIO_DRACUT is not set
BR2_TARGET_ROOTFS_CPIO_NONE=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_BUSYBOX_CONFIG="busybox.config"
BR2_PACKAGE_COREMARK=y
BR2_PACKAGE_DHRYSTONE=y
Loading

0 comments on commit 04e7396

Please sign in to comment.