diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile new file mode 100644 index 00000000000000..a85591ca6551dc --- /dev/null +++ b/.github/workflows/Dockerfile @@ -0,0 +1,34 @@ +FROM alpine:3.20.3 + +ADD vmlinux /root/. +ADD inittab /etc/inittab +RUN mkdir /etc/init.d +ADD rcS /etc/init.d/. +RUN sed "s/\'/\"/g" /etc/profile > /.profile + +ADD bench.sh / +ADD do_getpid /root/. +ADD clone /root/. +ADD futex /root/. +ADD nullptr /root/. +ADD ctest /root/. +ADD stackp /root/. +ADD init_array /root/. +ADD entropy /root/. +ADD locale /root/. +ADD vdso_test /root/. +ADD Makefile /root/. +ADD lmbench2/ /lmbench2 +ADD lmbench_run.sh /lmbench2/bin/x86_64-linux-gnulibc1/ + + +RUN apk update && apk add utmps-libs libtirpc curl make +RUN mkdir -p setup && cd setup && curl -L -o output.zip \ + 'https://gitlab.alpinelinux.org/thehajime/aports/-/jobs/1619053/artifacts/download?file_type=archive' \ + && unzip output.zip +RUN apk add --allow-untrusted \ + setup/packages/main/x86_64/busybox-nommu-1.36.1-r29.apk \ + setup/packages/main/x86_64/musl-nommu-1.2.5-r0.apk +RUN rm -rf setup + +ENTRYPOINT ["/root/vmlinux", "eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1", "root=/dev/root", "rootflags=/", "rootfstype=hostfs", "rw", "mem=1024m", "loglevel=8", "init=/sbin/init"] diff --git a/.github/workflows/Makefile b/.github/workflows/Makefile new file mode 100644 index 00000000000000..9459fde01e0723 --- /dev/null +++ b/.github/workflows/Makefile @@ -0,0 +1,25 @@ +SRCS := clone.c futex.c nullptr.c ctest.c stackp.c do_getpid.c init_array.c entropy.c locale.c vdso_test.c +BKUP := exit.c noop.c +TARGETS := $(SRCS:.c=) + +CFLAGS_exit = -nostdlib -pie -fPIE -fomit-frame-pointer +all: ${TARGETS} + +tests: ${TARGETS} + set +x + ./clone host + ./futex + ./nullptr 1 0 || RET=$$? ; echo "code="$$RET && if [ "$$RET" -ne "139" ] ; then false ; fi + ./nullptr 1 1 || RET=$$? ; echo "code="$$RET && if [ "$$RET" -ne "11" ] ; then false ; fi + ./nullptr 0 0 || RET=$$? ; echo "code="$$RET && if [ "$$RET" -ne "139" ] ; then false ; fi + ./nullptr 0 1 || RET=$$? ; echo "code="$$RET && if [ "$$RET" -ne "11" ] ; then false ; fi + ./nullptr + echo "test" | ./ctest + ./stackp + ./entropy 10000 + ./locale + ./vdso_test -c 10000 + set -x + +clean: + rm -f ${TARGETS} diff --git a/.github/workflows/bench.sh b/.github/workflows/bench.sh new file mode 100755 index 00000000000000..015d3f1d9d2d73 --- /dev/null +++ b/.github/workflows/bench.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +mount proc /proc -t proc +export PATH=/home:/sbin:/usr/sbin:/bin:/usr/bin + + +cd /lmbench2/bin/x86_64-linux-gnulibc1 +sh lmbench_run.sh + +/root/do_getpid -c 10000 + +make -C /root tests +halt -f diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000000..89252d1102e39b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,306 @@ +on: + push: + branches: + - '**' + #pull_request: + # branches: + # - master + workflow_dispatch: + inputs: + debug_enabled: + description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + required: false + default: false + +jobs: + tests: + runs-on: ${{ matrix.runs_on }} + strategy: + fail-fast: false + matrix: + include: + - displayTargetName: ubuntu-22.04 + os: unix + runs_on: ubuntu-22.04 + shell: bash + defconfig: defconfig + testname: um-mmu + - displayTargetName: ubuntu-22.04 (nommu) + os: unix + runs_on: ubuntu-22.04 + shell: bash + defconfig: x86_64_nommu_defconfig + kunit_opts: --kconfig_add CONFIG_MMU=n + testname: um-nommu + timeout-minutes: 100 + env: + CCACHE_DIR: ${{ github.workspace }}/.ccache + USE_CCACHE: 1 + + defaults: + run: + shell: ${{ matrix.shell }} + + steps: + - name: Set env + shell: bash + run: | + echo "/usr/lib/ccache/bin:/usr/lib/ccache:${{ github.workspace }}/bin" >> $GITHUB_PATH + echo "export PATH=/usr/lib/ccache/bin:/usr/lib/ccache:${{ github.workspace }}/bin:$PATH" >> $HOME/.bashrc + + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ runner.os }}-${{ matrix.defconfig }}-ccache-build-${{ github.sha }} + restore-keys: ${{ runner.os }}-${{ matrix.defconfig }}-ccache-build- + - name: Install packages + run: | + sudo apt update -y + sudo apt install -y ccache sparse + - name: Setup latest Alpine Linux + uses: jirutka/setup-alpine@v1 + with: + branch: v3.20 + packages: > + alpine-sdk + doas + libtirpc-dev + linux-headers + - name: build bench tools + run: | + git clone https://github.com/ricarkol/lmbench2.git + cd lmbench2 + touch src/Makefile + touch Makefile + make + cd .. + make -C .github/workflows/ + shell: alpine.sh {0} + # --root {0} + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + with: + detached: true + - name: Setup faketty + uses: Yuri6037/Action-FakeTTY@v1.1 + - name: build-0 (static) + run: | + make ARCH=um ${{ matrix.defconfig }} O=build + cat build/.config | sed "s/.*CONFIG_STATIC_LINK.*/CONFIG_STATIC_LINK=y/" > /tmp/a; mv /tmp/a build/.config + make -j8 ARCH=um O=build + - name: prep for docker build + run: | + cp build/vmlinux .github/workflows/ + cp -rpf lmbench2 .github/workflows/ + - name: Build and push Docker image (no push) + uses: docker/build-push-action@v6 + with: + context: .github/workflows + push: false + tags: | + ghcr.io/thehajime/alpine:3.20.3-${{ matrix.testname }} + - name: image for test + run: | + container_id=$(docker create ghcr.io/thehajime/alpine:3.20.3-${{ matrix.testname }}) + docker start $container_id + docker wait $container_id + docker logs $container_id + docker export $container_id > alpine.tar + docker rm $container_id + mnt=$(mktemp -d) + dd if=/dev/zero of=alpine.ext4 bs=1 count=0 seek=1G + sudo chmod og+wr "alpine.ext4" + yes 2>/dev/null | mkfs.ext4 "alpine.ext4" || true + sudo mount "alpine.ext4" $mnt + sudo tar -xf alpine.tar -C $mnt + sudo umount $mnt + - name: test-0 (static) + run: | + sudo sh -c "echo 0 > /proc/sys/vm/mmap_min_addr" + sudo ip tuntap add dev tap100 mode tap user ${USER} + faketty ./build/vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine.ext4 rw mem=1024m loglevel=8 console=tty init=/sbin/init 2>&1 | tee /tmp/log.txt & + sleep 10 && pkill vmlinux + echo "=========" + cat /tmp/log.txt + - name: kunit test + run: | + for config in `find ./ -name .kunitconfig | grep -v -E "kfence|sunrpc|handshake|kcsan|gpu|damon" `; do \ + echo "==" $config "==" ; \ + ./tools/testing/kunit/kunit.py run --kunitconfig=$config ${{ matrix.kunit_opts }} + done + - name: build-1 + run: | + make ARCH=um ${{ matrix.defconfig }} + make -j8 ARCH=um + - name: test-1 + run: | + faketty ./vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine.ext4 rw mem=1024m loglevel=8 init=/sbin/init 2>&1 | tee /tmp/log.txt & + sleep 10 && pkill vmlinux + echo "=========" + cat /tmp/log.txt + - name: benchmark-0 + if: matrix.testname == 'um-nommu' + run: | + mkdir -p output + faketty ./vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine.ext4 rw mem=1024m \ + loglevel=8 console=tty zpoline=1 init=/bench.sh \ + | tee output/${{ matrix.testname }}-zpoline.dat || true # XXX: until 6.12 pulled + faketty ./vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine.ext4 rw mem=1024m \ + loglevel=8 console=tty zpoline=0 init=/bench.sh \ + | tee output/${{ matrix.testname }}-seccomp.dat || true # XXX: until 6.12 pulled + - name: benchmark-1 + if: matrix.testname == 'um-mmu' + run: | + mkdir -p output + faketty ./vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine.ext4 rw mem=1024m \ + loglevel=0 console=tty init=/bench.sh \ + | tee output/${{ matrix.testname }}.dat + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver-opts: network=host + - name: Log in to the ghcr.io + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: .github/workflows + push: true + tags: | + ghcr.io/thehajime/alpine:3.20.3-${{ matrix.testname }} + - uses: actions/upload-artifact@v4 + with: + name: bench-result-${{ matrix.testname }} + path: output/${{ matrix.testname }}*.dat + + checkpatch: + runs-on: ubuntu-22.04 + name: checkpatch and co + env: + CCACHE_DIR: ${{ github.workspace }}/.ccache + USE_CCACHE: 1 + steps: + - name: Set env + shell: bash + run: | + echo "/usr/lib/ccache/bin:/usr/lib/ccache:${{ github.workspace }}/bin" >> $GITHUB_PATH + echo "export PATH=/usr/lib/ccache/bin:/usr/lib/ccache:${{ github.workspace }}/bin:$PATH" >> $HOME/.bashrc + - name: Checkout + with: + fetch-depth: 0 + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ runner.os }}-checkpatch-ccache-build-${{ github.sha }} + restore-keys: ${{ runner.os }}-checkpatch-ccache-build- + - name: Install packages + run: | + sudo pip install ply GitPython mypy + sudo apt update -y + sudo apt install -y aspell ccache sparse + git clone https://github.com/daxtens/smart-sparse-diff + #- name: Setup tmate session + # uses: mxschmitt/action-tmate@v3 + # with: + # detached: true + - name: checkout trees + run: | + #git remote add linus git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + #git fetch linus + #git format-patch -o p1 linus/master..HEAD~1 + git remote add uml git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git + git fetch uml + git checkout uml/next + git checkout zpoline-nommu-v6.10 + #- name: build (sparse) + # run: | + # make ARCH=um W=1 C=2 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__ -fmax-errors=unlimited -fmax-warnings=unlimited' defconfig O=build-sparse + # make ARCH=um W=1 C=2 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__ -fmax-errors=unlimited -fmax-warnings=unlimited' O=build-sparse clean + # make ARCH=um W=1 C=2 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__ -fmax-errors=unlimited -fmax-warnings=unlimited' O=build-sparse -j8 2> old-sparse.log 1> /dev/null + # git checkout zpoline-nommu-v6.10 + # git checkout HEAD~1 + # make ARCH=um W=1 C=2 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__ -fmax-errors=unlimited -fmax-warnings=unlimited' O=build-sparse -j8 2> new-sparse.log 1> /dev/null + # ./smart-sparse-diff/smart-sparse-diff.py old-sparse.log new-sparse.log + - name: check coding style + run: | + git format-patch -o p1 uml/next..HEAD~1 + ./scripts/checkpatch.pl --summary-file --ignore FILE_PATH_CHANGES \ + --ignore AVOID_EXTERNS p1/*.patch + - name: check spells on commit message + continue-on-error: true + run: | + git log uml/next..HEAD |grep -v -E "^commit" > /tmp/a + aspell list /tmp/a + exit 1 + + bench-result: + runs-on: ubuntu-22.04 + name: bench-result + needs: tests + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + path: output + pattern: bench-result-* + merge-multiple: true + - name: Display structure of downloaded files + run: ls -R output + - name: Install packages + run: | + sudo apt update -y + sudo apt install -y gnuplot lmbench + - name: benchmark-host + run: | + mkdir -p output + sudo ln -s /usr/include/x86_64-linux-gnu/sys /usr/include/sys + sudo mkdir -p /var/tmp/lmbench/ + sudo chown ${USER} /var/tmp/lmbench/ + sh .github/workflows/lmbench_run.sh |& tee output/native.dat + gcc -o do_getpid .github/workflows/do_getpid.c + ./do_getpid -c 100 | tee -a output/native.dat + - name: bench data parse/out + run: | + export TMP_OUTPUT=$(bash .github/workflows/um-nommu-plot.sh output) + echo "TMP_OUTPUT<> $GITHUB_ENV + echo "$TMP_OUTPUT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo ${{env.TMP_OUTPUT}} + - uses: actions/upload-artifact@v4 + with: + name: bench-result-all + path: output/out/lmbench.* + - name: publish to imgur + uses: devicons/public-upload-to-imgur@v2.2.2 + id: publish-to-imgur + with: + path: "output/out/*.png" + client_id: ${{secrets.IMGUR_CLIENT_ID}} + - name: bench data parse/out + run: | + export SCRIPT_OUTPUT="${{ join(fromJSON(steps.publish-to-imgur.outputs.markdown_urls)) }}" + echo "SCRIPT_OUTPUT<> $GITHUB_ENV + echo "$TMP_OUTPUT" >> $GITHUB_ENV + echo "" >> $GITHUB_ENV + echo "$SCRIPT_OUTPUT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo ${{env.SCRIPT_OUTPUT}} + - uses: actions/github-script@v7 + env: + COMMENT_BODY: ${{env.SCRIPT_OUTPUT}} + with: + script: | + github.rest.issues.createComment({ + issue_number: 1, + owner: context.repo.owner, + repo: context.repo.repo, + body: process.env.COMMENT_BODY + }) diff --git a/.github/workflows/clone.c b/.github/workflows/clone.c new file mode 100644 index 00000000000000..811b61f6b105f6 --- /dev/null +++ b/.github/workflows/clone.c @@ -0,0 +1,85 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ +} while (0) + + static int /* Start function for cloned child */ +childFunc(void *arg) +{ + struct utsname uts; + + printf("arg=%lx\n", (unsigned long)arg); + + /* Change hostname in UTS namespace of child */ + + if (sethostname(arg, strlen(arg)) == -1) + errExit("sethostname"); + + /* Retrieve and display hostname */ + + if (uname(&uts) == -1) + errExit("uname"); + printf("uts.nodename in child: %s\n", uts.nodename); + + /* Keep the namespace open for a while, by sleeping. + This allows some experimentation--for example, another + process might join the namespace. */ + + return 0; /* Child terminates now */ +} + +#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */ + + int +main(int argc, char *argv[]) +{ + char *stack; /* Start of stack buffer */ + char *stackTop; /* End of stack buffer */ + pid_t pid; + struct utsname uts; + + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_SUCCESS); + } + + /* Allocate stack for child */ + + stack = malloc(STACK_SIZE); + if (stack == NULL) + errExit("malloc"); + stackTop = stack + STACK_SIZE; /* Assume stack grows downward */ + + /* Create child that has its own UTS namespace; + child commences execution in childFunc() */ + + printf("arg=%lx\n", (unsigned long)argv[1]); + pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]); + if (pid == -1) + errExit("clone"); + sleep(1); + printf("clone() returned %ld\n", (long) pid); + + /* Parent falls through to here */ + + /* Display hostname in parent's UTS namespace. This will be + different from hostname in child's UTS namespace. */ + + if (uname(&uts) == -1) + errExit("uname"); + printf("uts.nodename in parent: %s\n", uts.nodename); + + if (waitpid(pid, NULL, 0) == -1) /* Wait for child */ + errExit("waitpid"); + printf("child has terminated\n"); + + exit(EXIT_SUCCESS); +} + diff --git a/.github/workflows/ctest.c b/.github/workflows/ctest.c new file mode 100644 index 00000000000000..791c27a6869938 --- /dev/null +++ b/.github/workflows/ctest.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +static void __kill(int pid, int sig) { + register int syscall_no asm("rax") = 62; + register int arg1 asm("rdi") = pid; + register int arg2 asm("rsi") = sig; + asm("syscall"); +} + +static void exit_host(int r){ + __kill(0, 9); + return; +} + +int vfork1() +{ + int a = 0; + int ret = 0xfafafafa; + ret = vfork(); + return ret; +} + +int vfork2() +{ + return vfork(); +} + +void test_files(); + +char *argv[3] = {"/ctest", "noop", NULL}; +char *env[2] = {"PATH=/", NULL}; + +int test_vfork() +{ + int i, ret; + int status; + + ret = vfork(); + if (ret == 0) { + printf("child: ret=%d\r\n", ret); + //printf("got %c\n", getchar()); + ret = execve("./ctest", argv, env); + if (ret != 0) { + printf("child: exec ret=%d\r\n", ret); + while(1); + _exit(0); + } + + // should not be here + test_files(); + _exit(0); + } else if (ret < 0) { + printf("error %d\r\n", ret); + while(1); + _exit(0); + } else { + wait(&status); + //while(1); + printf("parent (%s): fork status=%d child_pid=%d\r\n", __FUNCTION__, status, ret); + } + return ret; +} + +void test_files() +{ + printf("opening\r\n"); + char *tmpname = "/files/mifile"; + char buf[128]; + int fd = open("/files/mifile2", O_RDONLY, 0); + if (fd < 1) { + printf("could not open %d\n", fd); + return; + } + //write(fd, "_*_", 3); + fsync(fd); + close(fd); + printf("opening\r\n"); + fd = open("/files/mifile2", O_RDONLY, 0); + if (fd < 1) { + printf("could not open %d\n", fd); + return; + } + + memset(buf, 0, 128); + read(fd, buf, 64); + printf("%s\r\n", buf); +} + +int test_vfork_only() +{ + int i, ret; + int status; + + ret = vfork1(); + if (ret == 0) { + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + printf("child %s\n", __FUNCTION__); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + sleep(1); + _exit(0); + } else if (ret < 0) { + printf("error %d\r\n", ret); + while(1); + _exit(0); + } else { + sleep(1); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + printf("parent (%s): fork status=%d child_pid=%d\r\n", __FUNCTION__, status, ret); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + } + return ret; +} + + + +int test_vfork_sleeping() +{ + int i, ret; + int status; + + ret = vfork(); + if (ret == 0) { + ret = execve("./ctest", argv, env); + _exit(0); + } else if (ret < 0) { + printf("error %d\r\n", ret); + while(1); + _exit(0); + } else { + printf("parent (%s): fork status=%d child_pid=%d\r\n", __FUNCTION__, status, ret); + } + return ret; +} + + +int test_vfork_in_vfork() +{ + int i, ret; + int status; + + ret = vfork(); + if (ret == 0) { + printf("child 1\n"); + ret = vfork(); + if (ret == 0) { + printf("child 2\n"); + _exit(0); + } else if (ret < 0) { + printf("error %d\r\n", ret); + while(1); + _exit(0); + } else { + printf("parent: fork status=%d child_pid=%d\r\n", status, ret); + } + _exit(0); + } else if (ret < 0) { + printf("error %d\r\n", ret); + while(1); + _exit(0); + } else { + printf("parent (%s): fork status=%d child_pid=%d\r\n", __FUNCTION__, status, ret); + } + return ret; +} + +int test_exec_with_vfork_in_vfork() +{ + int i, ret; + int status; + + char *argv[3] = {"/ctest", "fork", NULL}; + char *env[2] = {"PATH=/", NULL}; + + ret = vfork(); + if (ret == 0) { + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + printf("child %s\n", __FUNCTION__); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + ret = execve("./ctest", argv, env); + while(1); // should not be reached + } else if (ret < 0) { + printf("error %d\r\n", ret); + while(1); + _exit(0); + } else { + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + printf("parent (%s): fork status=%d child_pid=%d\r\n", __FUNCTION__, status, ret); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + } + return ret; +} + + +int main(int argc, char **argv) +{ + int i, ret; + int iterations; + + if (argc < 2) { + iterations = 10; + } else if (strcmp(argv[1], "files") == 0) { + test_files(); + exit(0); + } else if (strcmp(argv[1], "loop") == 0) { + printf("looping forever\n"); + //printf("got %c\n", getchar()); + while(1); + exit(0); + } else if (strcmp(argv[1], "fork") == 0) { + //test_vfork_only(); + test_vfork(); + exit(0); + } else if (strcmp(argv[1], "exec") == 0) { + test_exec_with_vfork_in_vfork(); + test_files(); + exit(0); + } else if (strcmp(argv[1], "noop") == 0) { + printf("noop\n"); + exit(0); + } else if (strcmp(argv[1], "exit") == 0) { + printf("exit"); + exit_host(0); + } else if (strcmp(argv[1], "time") == 0) { + struct timeval current_time; + gettimeofday(¤t_time, NULL); + printf("seconds : %ld\nmicro seconds : %ld\n", + current_time.tv_sec, current_time.tv_usec); + exit(0); + } else { + printf("default arg\n"); + } + + test_exec_with_vfork_in_vfork(); + + test_vfork(); + test_vfork(); + test_vfork(); + test_vfork(); + test_vfork_sleeping(); + + test_files(); + + printf("got %c\n", getchar()); + + //while(1); + exit(0); +} diff --git a/.github/workflows/do_getpid.c b/.github/workflows/do_getpid.c new file mode 100644 index 00000000000000..9a1171ded536ed --- /dev/null +++ b/.github/workflows/do_getpid.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include + + +#ifndef BENCH_LDPRELOAD +extern pid_t do_getpid(void); + +void __do_getpid(void) +{ + asm volatile (".globl do_getpid"); + asm volatile ("do_getpid:"); + asm volatile ("movq $39, %rax"); + asm volatile ("syscall"); + asm volatile ("ret"); +} +#else +pid_t do_getpid(void) +{ + return getpid(); +} +#endif + +int main(int argc, char* const* argv) +{ + int ch; + unsigned long loopcnt = 0; + + while ((ch = getopt(argc, argv, "c:")) != -1) { + switch (ch) { + case 'c': + loopcnt = atol(optarg); + break; + + default: + printf("unknown option\n"); + exit(1); + } + } + + if (!loopcnt) { + printf("please specify loop count by -c\n"); + exit(0); + } + + { + pid_t my_pid = getpid(); + { + unsigned long t; + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + t = ts.tv_sec * 1000000000UL + ts.tv_nsec; + } + { + unsigned long i; + for (i = 0; i < loopcnt; i++) + assert(my_pid == do_getpid()); + } + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + t = ts.tv_sec * 1000000000UL + ts.tv_nsec - t; + } + printf("average %5lu nsec\n", t / loopcnt); + } + } + + return 0; +} diff --git a/.github/workflows/entropy.c b/.github/workflows/entropy.c new file mode 100644 index 00000000000000..59ae1da93239c9 --- /dev/null +++ b/.github/workflows/entropy.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 256 + +struct rand_pool_info { + int entropy_count; + int buf_size; + unsigned int buf[256]; +}; + +uint8_t prng(void) { + static uint8_t seed=19; + seed = 311 * seed + 17; + return seed; +} + +#define BUF_SIZE 256 +#define MAX_ITERS 10000 + +#define RNDADDENTROPY 0x40085203 + +int main(int argc, char **argv) +{ + struct rand_pool_info *output; + int max_iters = MAX_ITERS; + int iters = 0, ret; + int fd = open("/dev/random", O_WRONLY); + + if (argc == 2) + max_iters = atoi(argv[1]); + + printf("generating \"entropy\"..."); + output = (struct rand_pool_info *)malloc(sizeof(struct rand_pool_info) + + BUF_SIZE); + do { + int i; + output->entropy_count = BUF_SIZE * 8; + output->buf_size = BUF_SIZE; + for (i=0; i< BUF_SIZE; i++) + output->buf[i] = prng(); + ret = ioctl(fd, RNDADDENTROPY, &output); + iters++; + } while((ret >= 0) && (iters < max_iters)); + + printf("for %d iters\n", iters); +} + diff --git a/.github/workflows/exit.c b/.github/workflows/exit.c new file mode 100644 index 00000000000000..b60675e1e7d381 --- /dev/null +++ b/.github/workflows/exit.c @@ -0,0 +1,13 @@ + +static void kill(int pid, int sig) { + register int syscall_no asm("rax") = 62; + register int arg1 asm("rdi") = pid; + register int arg2 asm("rsi") = sig; + asm("syscall"); +} + +void _start() +{ + kill(0, 9); + return; +} diff --git a/.github/workflows/futex.c b/.github/workflows/futex.c new file mode 100644 index 00000000000000..566e61c8773bee --- /dev/null +++ b/.github/workflows/futex.c @@ -0,0 +1,55 @@ +#include +#include + +/* this function is run by the second thread */ +void *inc_x(void *x_void_ptr) +{ + + /* increment x to 100 */ + int *x_ptr = (int *)x_void_ptr; + while(++(*x_ptr) < 100); + + printf("x increment finished\n"); + + /* the function must return something - NULL will do */ + return NULL; + +} + +int main() +{ + + int x = 0, y = 0; + + /* show the initial values of x and y */ + printf("x: %d, y: %d\n", x, y); + + /* this variable is our reference to the second thread */ + pthread_t inc_x_thread; + + /* create a second thread which executes inc_x(&x) */ + if(pthread_create(&inc_x_thread, NULL, inc_x, &x)) { + + fprintf(stderr, "Error creating thread\n"); + return 1; + + } + /* increment y to 100 in the first thread */ + while(++y < 100); + + printf("y increment finished\n"); + + /* wait for the second thread to finish */ + if(pthread_join(inc_x_thread, NULL)) { + + fprintf(stderr, "Error joining thread\n"); + return 2; + + } + + /* show the results - x is now 100 thanks to the second thread */ + printf("x: %d, y: %d\n", x, y); + + return 0; + +} diff --git a/.github/workflows/init_array.c b/.github/workflows/init_array.c new file mode 100644 index 00000000000000..8faf546c978cb6 --- /dev/null +++ b/.github/workflows/init_array.c @@ -0,0 +1,19 @@ +#include + +static void init(int argc, char **argv, char **envp) { + printf("> l:%s\n", __FUNCTION__); +} + +static void fini(void) { + printf("< l:%s\n", __FUNCTION__); +} + + +__attribute__((section(".init_array"), used)) static typeof(init) *init_p = init; +__attribute__((section(".fini_array"), used)) static typeof(fini) *fini_p = fini; + +int main (int argc, char *argv[]) +{ + return 0; +} + diff --git a/.github/workflows/inittab b/.github/workflows/inittab new file mode 100644 index 00000000000000..81eef106465f99 --- /dev/null +++ b/.github/workflows/inittab @@ -0,0 +1,13 @@ +# /etc/inittab + +::sysinit:/etc/init.d/rcS + +::respawn:-/bin/sh + +# Stuff to do when restarting the init process +::restart:/sbin/init + +# Stuff to do before rebooting +::ctrlaltdel:/sbin/reboot +::shutdown:/bin/umount -a -r +::shutdown:/sbin/swapoff -a diff --git a/.github/workflows/lmbench_run.sh b/.github/workflows/lmbench_run.sh new file mode 100644 index 00000000000000..26596236ed4bf6 --- /dev/null +++ b/.github/workflows/lmbench_run.sh @@ -0,0 +1,26 @@ + +PATH=/usr/lib/lmbench/bin/x86_64-linux-gnu/:/lmbench2/bin/x86_64-linux-gnulibc1:$PATH +mkdir -p /var/tmp/lmbench +cp `which hello` /var/tmp/lmbench/hello +cp `which hello` /tmp/hello + +mkdir -p /usr/include/sys/ || true +touch /usr/include/sys/types.h || true + +if [ -d "/usr/lib/lmbench/bin/x86_64-linux-gnu/" ] ; then +ENOUGH=10000 lat_select -n 10 file +ENOUGH=10000 lat_select -n 100 file +ENOUGH=10000 lat_select -n 1000 file +else +ENOUGH=10000 lat_select file 10 +ENOUGH=10000 lat_select file 100 +ENOUGH=10000 lat_select file 1000 +fi + +ENOUGH=100000 lat_syscall null +ENOUGH=100000 lat_syscall read +ENOUGH=100000 lat_syscall write +ENOUGH=100000 lat_syscall stat +ENOUGH=100000 lat_syscall open +ENOUGH=10000 lat_proc shell +ENOUGH=10000 lat_proc exec diff --git a/.github/workflows/locale.c b/.github/workflows/locale.c new file mode 100644 index 00000000000000..1d4d83c71ff4fa --- /dev/null +++ b/.github/workflows/locale.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int ret = getpid(); + printf("strerr = %s\n", strerror(errno)); + return 0; +} diff --git a/.github/workflows/noop.c b/.github/workflows/noop.c new file mode 100644 index 00000000000000..23d5b86bec1197 --- /dev/null +++ b/.github/workflows/noop.c @@ -0,0 +1,38 @@ +#include "syscall_nr.h" + +static unsigned long __sysinfo = 0; +#include "syscall-x86_64.h" + +typedef unsigned long size_t; + +#define AUX_CNT 64 +#define DYN_CNT 32 + +#define AT_NULL 0 +#define AT_SYSINFO 32 + +void _start_c(size_t *sp) +{ + size_t i, aux[AUX_CNT], dyn[DYN_CNT]; + size_t *rel, rel_size, base; + + int argc = *sp; + char **argv = (void *)(sp+1); + + for (i=argc+1; argv[i]; i++); + size_t *auxv = (void *)(argv+i+1); + + for (i=0; i +#include +#include +#include +#include + +static void segv_handler (int cause, siginfo_t * info, void *uap) +{ + //For test. Never ever call stdio functions in a signal handler otherwise*/ + printf ("SIGSEGV handled\n"); + printf ("SIGSEGV raised at address 0x%lx\n", (unsigned long)info->si_addr); + ucontext_t *context = uap; + /*On my particular system, compiled with gcc -O2, the offending instruction + generated for "*f = 16;" is 6 bytes. Lets try to set the instruction + pointer to the next instruction (general register 14 is EIP, on linux x86) */ + context->uc_mcontext.gregs[16] += 14; + //alternativly, try to jump to a "safe place" + //context->uc_mcontext.gregs[14] = (unsigned int)safe_func; + exit(cause); +} + +/* XXX: this code doesn't work as 2nd fprintf() causes SEGV + * (probably) due to alignment issue of xmm0/rsp register + * + * https://stackoverflow.com/questions/5397041/getting-the-saved-instruction-pointer-address-from-a-signal-handler + */ +static void signal_segv(int signum, siginfo_t *info, void *ptr) +{ + static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"}; + int i, f = 0; + ucontext_t *ucontext = (ucontext_t*)ptr; + void **bp = 0; + void *ip = 0; + + fprintf(stderr, "Segmentation Fault!\n"); + fprintf(stderr, "info.si_signo = %d\n", signum); + fprintf(stderr, "info.si_errno = %d\n", info->si_errno); + fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]); + fprintf(stderr, "info.si_addr = %p\n", info->si_addr); + for(i = 0; i < NGREG; i++) + fprintf(stderr, "reg[%02d] = 0x%016llx\n", i, ucontext->uc_mcontext.gregs[i]); + + ucontext->uc_mcontext.gregs[16] += 14; + exit(signum); +} + +int main (int argc, char *argv[]) +{ + char *ptr = NULL; + struct sigaction sa; + int *f = NULL; + + if (argc != 3) { + printf("%s [nullptr or raise] [handler or not]\n", argv[0]); + return 0; + } + + if (atoi(argv[2]) >= 1) { + printf("register handler\n"); + if (atoi(argv[2]) == 1) + sa.sa_sigaction = segv_handler; + else + sa.sa_sigaction = signal_segv; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + if (sigaction (SIGSEGV, &sa, 0)) { + perror ("sigaction"); + return -1; + } + } + + if (atoi(argv[1]) == 0) + memcpy(ptr, 0, 8); + else { + printf("raising signal\n"); + raise(SIGSEGV); + } + return 0; +} diff --git a/.github/workflows/rcS b/.github/workflows/rcS new file mode 100755 index 00000000000000..3d918872f3c8d4 --- /dev/null +++ b/.github/workflows/rcS @@ -0,0 +1,15 @@ +#!/bin/sh + +mount proc /proc -t proc +echo "nameserver 8.8.8.8" > /etc/resolv.conf +/sbin/ifconfig lo 127.0.0.1 up +/sbin/ifconfig eth0 192.168.122.2 up +/sbin/ip route add default via 192.168.122.1 dev eth0 + +export PATH=/home:/sbin:/usr/sbin:/bin:/usr/bin +export TERM=linux + +# hanging +#export PS1="\[$(tput bold)\]\[$(tput setaf 4)\][\[$(tput setaf 5)\]\u\[$(tput setaf 4)\]@\[$(tput setaf 5)\]\h \[$(tput setaf 2)\]\W\[$(tput setaf 4)\]]\\$ \[$(tput sgr0)\]" + +exec "$@" diff --git a/.github/workflows/stackp.c b/.github/workflows/stackp.c new file mode 100644 index 00000000000000..df058766eecf69 --- /dev/null +++ b/.github/workflows/stackp.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + char str[64]; + + write(2, "Done\nChild\n", 11); +} diff --git a/.github/workflows/um-nommu-bench.sh b/.github/workflows/um-nommu-bench.sh new file mode 100755 index 00000000000000..84c4540ca873ba --- /dev/null +++ b/.github/workflows/um-nommu-bench.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}"); pwd)" + +# macos has different syntax +OUTPUT=$SCRIPT_DIR/$(date "+%Y-%m-%d") +mkdir -p $OUTPUT + +TRIALS="1" +ENTRIES="1000000" +VSIZES="1 8 256 1024 8192" +RUNTIMES="build/mmu build" + + +echo "$(tput bold)== um (mmu) ($test-$num-$vsize) ==$(tput sgr0)" +../linux-um-nommu/build-mmu/vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine-test.ext3 rw mem=1024m loglevel=0 init=/bench.sh \ + | tee "$OUTPUT/um-mmu.dat" + +echo "$(tput bold)== um (nommu) ($test-$num-$vsize) ==$(tput sgr0)" +../linux-um-nommu/build/vmlinux eth0=tuntap,tap100,0e:fd:0:0:0:1,172.17.0.1 ubd0=./alpine-test.ext3 rw mem=1024m loglevel=0 init=/bench.sh \ + | tee "$OUTPUT/um-nommu.dat" + +echo "$(tput bold)== host (mmu) ($test-$num-$vsize) ==$(tput sgr0)" +sh docker/alpine/lmbench_run.sh \ + |& tee "$OUTPUT/native.dat" +./zpoline-bench/do_getpid -c 100 | tee -a "$OUTPUT/native.dat" + +bash ${SCRIPT_DIR}/um-nommu-plot.sh ${OUTPUT} diff --git a/.github/workflows/um-nommu-plot.sh b/.github/workflows/um-nommu-plot.sh new file mode 100755 index 00000000000000..9175ce80b76567 --- /dev/null +++ b/.github/workflows/um-nommu-plot.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" + +OUTPUT="$1" +DIRS="read fill" + +mkdir -p "$OUTPUT/out/" + +# parse outputs + +for f in `ls $OUTPUT/*.dat` +do + cat $f | grep microsec | sed "s/.*:\(.*\)/\1/" | awk '{print $1}' \ + > $OUTPUT/out/`basename $f .dat`-out.dat + + cat $f | grep average |grep -v time | awk '{print $2 $3}' \ + > $OUTPUT/out/`basename $f .dat`-getpid-out.dat +done + +gnuplot << EndGNUPLOT +set terminal postscript eps lw 3 "Helvetica" 24 +set output "${OUTPUT}/out/lmbench.eps" +#set xtics font "Helvetica,14" +set pointsize 2 +set xzeroaxis +set grid ytics + +set boxwidth 0.2 +set style fill pattern + +set size 1.0,0.8 +set key top left + +set xrange [-0.5:10] +set xtics ('select-10' 0, 'select-100' 1, 'select-1000' 2, 'syscall' 3, 'read' 4, 'write' 5, 'stat' 6, 'open/close' 7, 'fork+sh' 8, 'fork+execve' 9) +set xtics rotate by 45 right +set yrange [0.01:100000] +set ylabel "Latency (usec)" +set logscale y + +plot \ + '${OUTPUT}/out/um-mmu-out.dat' usin (\$0-0.3):(\$1) w boxes fill patter 2 lt 1 lc rgb "green" title "um(mmu)" ,\ + '${OUTPUT}/out/um-nommu-zpoline-out.dat' usin (\$0-0.1):(\$1) w boxes fill patter 2 lt 1 lc rgb "blue" title "um(nommu(z))" ,\ + '${OUTPUT}/out/um-nommu-seccomp-out.dat' usin (\$0+0.1):(\$1) w boxes fill patter 2 lt 1 lc rgb "royalblue" title "um(nommu(s))" ,\ + '${OUTPUT}/out/native-out.dat' usin (\$0+0.3):(\$1) w boxes fill patter 2 lt 1 lc rgb "red" title "native" + +set terminal png lw 3 14 crop +set output "${OUTPUT}/out/lmbench.png" +replot + +EndGNUPLOT + +echo -e "### lmbench (usec)\n" +echo -e "|select-10\n|select-100\n|select-1000\n|syscall\n|read\n|write\n|stat\n|open/close\n|fork+sh\n|fork+execve" > /tmp/a + +echo -e "||native|um|um-nommu(s)|um-nommu(z)|\n|--|--|--|--|--|"; paste -d "|" `ls ${OUTPUT}/out/*.dat |grep -v getpid` | sed "s/\(.*\)/\|\1\|/" | paste /tmp/a - | column -t + +rm -f /tmp/a + +echo "" +echo -e "### do_getpid bench (nsec)\n" +for f in `ls $OUTPUT/*.dat` +do + export $(basename $f .dat|sed "s/-/_/g")=`grep aver $f | grep -v time | awk '{print $2}'` +done +echo -e "||native|um|um-nommu(s)|um-nommu(z)|\n|--|--|--|--|--|" +echo "|getpid | ${native} | ${um_mmu} | ${um_nommu_seccomp}| ${um_nommu_zpoline}|" diff --git a/.github/workflows/vdso_test.c b/.github/workflows/vdso_test.c new file mode 100644 index 00000000000000..f5891cfe5445e2 --- /dev/null +++ b/.github/workflows/vdso_test.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + + +int main(int argc, char* const* argv) +{ + int ch; + unsigned long loopcnt = 0; + + while ((ch = getopt(argc, argv, "c:")) != -1) { + switch (ch) { + case 'c': + loopcnt = atol(optarg); + break; + + default: + printf("unknown option\n"); + exit(1); + } + } + + if (!loopcnt) { + printf("please specify loop count by -c\n"); + exit(0); + } + + unsigned long t; + struct timespec ts; + struct timeval tv; + + unsigned long i, j; + for (j = 0; j < 2; j++) { + clock_gettime(CLOCK_REALTIME, &ts); + t = ts.tv_sec * 1000000000UL + ts.tv_nsec; + + for (i = 0; i < loopcnt; i++) { + if (j == 0) + clock_gettime(CLOCK_REALTIME, &ts); + else + gettimeofday(&tv, NULL); + } + + clock_gettime(CLOCK_REALTIME, &ts); + t = ts.tv_sec * 1000000000UL + ts.tv_nsec - t; + printf("average[%s] %5lu nsec\n", j == 0 ? "clock_gettime" + : "gettimeofday", t / loopcnt); + } + + + return 0; +}