diff --git a/lua/.gitignore b/lua/.gitignore new file mode 100644 index 00000000..e6d8f4b7 --- /dev/null +++ b/lua/.gitignore @@ -0,0 +1,2 @@ +/rootfs/ +/workdir/ diff --git a/lua/Config.uk b/lua/Config.uk new file mode 100644 index 00000000..6ce130b3 --- /dev/null +++ b/lua/Config.uk @@ -0,0 +1,30 @@ +# Configure Lua Hello example +# A minimal Unikraft unikernel that runs a Lua script. +# Enable core Lua runtime, filesystem and POSIX environment support. + +config APPLUA +bool "Lua Hello example" +default y + + # Select the core Lua runtime library. + select LIBLUA + + # Select the application’s main function entrypoint (Lua interpreter) + select LIBLUA_MAIN_FUNCTION + + # Select filesystem core components: + # vfscore + automount, CPIO support, ramfs, devfs. + # These provide an in-memory filesystem and device nodes. + select LIBVFSCORE + select LIBVFSCORE_AUTOMOUNT_UP + select LIBUKCPIO + select LIBRAMFS + select LIBDEVFS + select LIBDEVFS_AUTOMOUNT + select LIBDEVFS_DEVSTDOUT + + # Select POSIX environment support for getenv/putenv. + select LIBPOSIX_ENVIRON + + # Use library-parameter parsing for environment variables. + select LIBPOSIX_ENVIRON_LIBPARAM diff --git a/lua/Makefile b/lua/Makefile new file mode 100644 index 00000000..0beb3f61 --- /dev/null +++ b/lua/Makefile @@ -0,0 +1,18 @@ +UK_ROOT ?= $(PWD)/../repos/unikraft +UK_BUILD ?= $(PWD)/workdir/build +UK_APP ?= $(PWD) +LIBS_BASE := $(PWD)/../repos/libs + +UK_LIBS ?= $(LIBS_BASE)/musl:$(LIBS_BASE)/lua + +.PHONY: all clean run + +all: + @$(MAKE) -C $(UK_ROOT) L=$(UK_LIBS) A=$(UK_APP) O=$(UK_BUILD) + +clean: + @$(MAKE) -C $(UK_ROOT) L=$(UK_LIBS) A=$(UK_APP) O=$(UK_BUILD) properclean + @rm -rf $(UK_BUILD) + +%: + @$(MAKE) -C $(UK_ROOT) L=$(UK_LIBS) A=$(UK_APP) O=$(UK_BUILD) $@ diff --git a/lua/Makefile.uk b/lua/Makefile.uk new file mode 100644 index 00000000..f0faba4a --- /dev/null +++ b/lua/Makefile.uk @@ -0,0 +1 @@ +$(eval $(call addlib,applua)) diff --git a/lua/README.md b/lua/README.md new file mode 100644 index 00000000..cb6e1780 --- /dev/null +++ b/lua/README.md @@ -0,0 +1,276 @@ +# Lua 5.4 on Unikraft + +Build and run a Lua 5.4 program on Unikraft. +Follow the instructions below to set up, configure, build and run Lua. +Make sure you installed the [requirements](../README.md#requirements). + +## Quick Setup (aka TLDR) + +For a quick setup, run the commands below. +Note that you still need to install the [requirements](../README.md#requirements). +Before everything, make sure you run the top-level `setup.sh` script: + +```console +./setup.sh +``` + +To build and run the application for `x86_64`, use the commands below: + +```console +./setup.sh +make distclean +wget -O /tmp/defconfig \ + https://raw.githubusercontent.com/unikraft/catalog-core/refs/heads/scripts/lua/scripts/defconfig/qemu.x86_64 +UK_DEFCONFIG=/tmp/defconfig make defconfig +make -j $(nproc) +test -d ./rootfs/ || docker build -o ./rootfs -f Dockerfile . +test -f initrd.cpio || ./workdir/unikraft/support/scripts/mkcpio initrd.cpio ./rootfs/ +./workdir/unikraft/support/scripts/mkcpio initrd.cpio ./rootfs/ +qemu-system-x86_64 \ + -nographic \ + -m 32 \ + -cpu max \ + -kernel workdir/build/lua_qemu-x86_64 \ + -append "lua_qemu-x86_64 vfs.fstab=[\"initrd0:/:extract::ramfs=1:\"] -- /helloworld.lua" \ + -initrd ./initrd.cpio +``` + +This will configure, build and run the Helloworld Lua app, printing "Hello, World!". + +To do the same for AArch64, run: + +```console +make distclean +wget -O /tmp/defconfig \ + https://raw.githubusercontent.com/unikraft/catalog-core/refs/heads/scripts/lua/scripts/defconfig/qemu.arm64 +UK_DEFCONFIG=/tmp/defconfig make defconfig +make -j $(nproc) +test -d ./rootfs/ || docker build -o ./rootfs -f Dockerfile . +test -f initrd.cpio || ./workdir/unikraft/support/scripts/mkcpio initrd.cpio ./rootfs/ +qemu-system-aarch64 \ + -machine virt \ + -nographic \ + -m 128 \ + -cpu max \ + -kernel workdir/build/lua_qemu-arm64 \ + -append "lua_qemu-arm64 vfs.fstab=[\"initrd0:/:extract::ramfs=1:\\"] -- /helloworld.lua" \ + -initrd ./initrd.cpio +``` + +Similar to the x86_64 build, this will print "Hello, World!" on ARM64. + +Information about every step and other build types is detailed below. + +## Set Up + +Set up the required repositories. +You have two options: + +Use the setup.sh script: + +```console +./setup.sh +``` + +It will clone/link `lib-lua` and any other needed libs under `repos/libs/.` + +Manual setup: + +```console +test -d repos/libs/lua || \ + git clone https://github.com/unikraft/lib-lua repos/libs/lua +``` + +## Clean + +While not strictly required, it is safest to clean previous build artifacts: + +```console +make distclean +``` + +## Configure + +To configure the kernel, use: + +```console +make menuconfig +``` + +Select the Architecture (`x86_64` or `ARM64`), then platform (`QEMU`, `Firecracker`, `Xen`), and save to produce the `.config` file. + +## Build + +Build the application for the current configuration: + +```console +make -j $(nproc) +``` + +This results in the creation of the `workdir/build/` directory storing the build artifacts. + +This produces the unikernel at `workdir/build/lua_-`, where `` is the platform name (`qemu`, `fc`, `xen`), and `` is the architecture (`x86_64` or `arm64`). + +### Use a Different Compiler + +If you want to use a different compiler, such as a Clang or a different GCC version, pass the `CC` variable to `make`. + +To build with Clang, use the commands below: + +```console +make properclean +make CC=clang -j $(nproc) +``` + +Note that Clang >= 14 is required to build Unikraft. + +To build with another GCC version, use the commands below: + +```console +make properclean +make CC=gcc- -j $(nproc) +``` + +where `` is the GCC version, such as `11`, `12`. + +Note that GCC >= 8 is required to build Unikraft. + +### Build the Filesystem + +The filesystem is to be packed into `initrd.cpio`, an initial ramdisk CPIO file. +Use the command below for that: + +```console +rm -f initrd.cpio +./workdir/unikraft/support/scripts/mkcpio initrd.cpio ./rootfs/ +``` + +## Run + +Run the resulting image using the corresponding platform tool. +Firecracker requires KVM support. +Xen requires a system with Xen installed. + +A successful run will show a message such as the one below: + +```text +en1: Added +en1: Interface is up +Powered by +o. .o _ _ __ _ +Oo Oo ___ (_) | __ __ __ _ ' _) :_ +oO oO ' _ `| | |/ / _)' _` | |_| _) +oOo oOO| | | | | (| | | (_) | _) :_ + OoOoO ._, ._:_:_,\_._, .__,_:_, \___) + Calypso 0.17.0~5d38d108 +``` + +This means that Lua runs on Unikraft and waiting for connections. + +### Run on QEMU/x86_64 + +To set up networking, use the command below: + +```console +qemu-system-x86_64 \ + -nographic \ + -m 32 \ + -cpu max \ + -kernel workdir/build/lua_qemu-x86_64 \ + -append "lua_qemu-x86_64 vfs.fstab=[\"initrd0:/:extract::ramfs=1:\"] -- /helloworld.lua" \ + -initrd ./initrd.cpio +``` + +### Run on QEMU/ARM64 + +To set up networking, use the command below: + +```console +qemu-system-aarch64 \ + -machine virt \ + -nographic \ + -m 128 \ + -cpu max \ + -kernel workdir/build/lua_qemu-arm64 \ + -append "lua_qemu-arm64 vfs.fstab=[\"initrd0:/:extract::ramfs=1:\\"] -- /helloworld.lua" \ + -initrd ./initrd.cpio +``` + +### Run on Firecracker/x86_64 + +To set up networking, use the command below: + +```console +rm -f firecracker.socket +firecracker-x86_64 --config-file fc.x86_64.json --api-sock firecracker.socket +``` + +### Run on Firecracker/ARM64 + +To set up networking, use the command below: + +```console +rm -f firecracker.socket +firecracker-aarch64 --config-file fc.arm64.json --api-sock firecracker.socket +``` + +### Run on Xen/x86_64 + +To set up networking, use the command below: + +```console +sudo xl create -c xen.x86_64.cfg +``` + +You need use `sudo` or the `root` account to run Xen. + +### Run on Xen/ARM64 + +To set up networking, use the commands below: + +```console +sudo xl create -c xen.arm64.cfg +``` + +You need use `sudo` or the `root` account to run Xen. + +## Clean Up + +To remove build artifacts only: + +```console +make clean +``` + +To remove fetched files and the entire `workdir/build/` directory: + +```console +make properclean +``` + +To remove the generated `.config` file as well: + +```console +make distclean +``` + +## Customize + +### Customize the Filesystem Contents + +The Lua example’s filesystem is under `rootfs/`. +You can update scripts or add files here: + +```text +rootfs/ +`-- helloworld.lua +``` + +After modifying `rootfs/`, rebuild just the filesystem: + +```console +rm -f initrd.cpio +./workdir/unikraft/support/scripts/mkcpio initrd.cpio ./rootfs/ +``` + +No unikernel rebuild is needed. \ No newline at end of file diff --git a/lua/fc.arm64.json b/lua/fc.arm64.json new file mode 100644 index 00000000..d7b6c40a --- /dev/null +++ b/lua/fc.arm64.json @@ -0,0 +1,14 @@ +{ + "boot-source": { + "kernel_image_path": "workdir/build/lua_fc-arm64", + "boot_args": "lua_fc-arm64 vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] -- /helloworld.lua", + "initrd_path": "initrd.cpio" + }, + "drives": [], + "machine-config": { + "vcpu_count": 1, + "mem_size_mib": 8, + "smt": false, + "track_dirty_pages": false + } +} diff --git a/lua/fc.x86_64.json b/lua/fc.x86_64.json new file mode 100644 index 00000000..9fdc52b0 --- /dev/null +++ b/lua/fc.x86_64.json @@ -0,0 +1,14 @@ +{ + "boot-source": { + "kernel_image_path": "workdir/build/lua_fc-x86_64", + "boot_args": "lua_fc-x86_64 vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] -- /helloworld.lua", + "initrd_path": "initrd.cpio" + }, + "drives": [], + "machine-config": { + "vcpu_count": 1, + "mem_size_mib": 8, + "smt": false, + "track_dirty_pages": false + } +} diff --git a/lua/rootfs/helloworld.lua b/lua/rootfs/helloworld.lua new file mode 100644 index 00000000..7df869a1 --- /dev/null +++ b/lua/rootfs/helloworld.lua @@ -0,0 +1 @@ +print("Hello, World!") diff --git a/lua/setup.sh b/lua/setup.sh new file mode 100755 index 00000000..bcc55b2f --- /dev/null +++ b/lua/setup.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +check_exists_and_create_symlink() +{ + path="$1" + + if [ ! -d workdir/"$path" ]; then + if [ ! -d ../repos/"$path" ]; then + echo "No directory ../repos/$path. Run the top-level setup.sh script first." >&2 + exit 1 + fi + + depth=$(echo "$path" | awk -F/ '{ print NF }') + if [ "$depth" -eq 1 ]; then + ln -sfn ../../repos/"$path" workdir/"$path" + elif [ "$depth" -eq 2 ]; then + ln -sfn ../../../repos/"$path" workdir/"$path" + else + echo "Unknown depth of path $path." >&2 + exit 1 + fi + fi +} + +test -d workdir || mkdir workdir +test -d workdir/libs || mkdir workdir/libs + +check_exists_and_create_symlink "unikraft" +check_exists_and_create_symlink "libs/lua" diff --git a/lua/xen.arm64.cfg b/lua/xen.arm64.cfg new file mode 100644 index 00000000..92353660 --- /dev/null +++ b/lua/xen.arm64.cfg @@ -0,0 +1,7 @@ +name = "lua" +vcpus = "1" +kernel = "./workdir/build/lua_xen-arm64" +ramdisk = "./initrd.cpio" +cmdline = "lua_xen-arm64 vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] -- /helloworld.lua" +memory = "8" +type = "pv" diff --git a/lua/xen.x86_64.cfg b/lua/xen.x86_64.cfg new file mode 100644 index 00000000..8ce779be --- /dev/null +++ b/lua/xen.x86_64.cfg @@ -0,0 +1,7 @@ +name = "lua" +vcpus = "1" +kernel = "./workdir/build/lua_xen-x86_64" +ramdisk = "./initrd.cpio" +cmdline = "lua_xen-x86_64 vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] -- /helloworld.lua" +memory = "8" +type = "pv" diff --git a/setup.sh b/setup.sh index e02334c3..d481d3ad 100755 --- a/setup.sh +++ b/setup.sh @@ -12,3 +12,4 @@ test -d repos/libs/python3 || git clone https://github.com/unikraft/lib-python3 test -d repos/libs/libelf || git clone https://github.com/unikraft/lib-libelf repos/libs/libelf test -d repos/apps/elfloader || git clone https://github.com/unikraft/app-elfloader repos/apps/elfloader test -d repos/apps/redis || git clone https://github.com/unikraft/lib-redis repos/libs/redis +test -d repos/libs/lua || git clone https://github.com/unikraft/lib-lua repos/libs/lua