diff --git a/Dockerfile b/Dockerfile index 8d6d816..2911cca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage for qemu-system-arm -FROM debian:stable-slim AS qemu-system-arm-builder +FROM debian:stable-slim AS qemu-builder ARG QEMU_VERSION=4.2.0 ENV QEMU_TARBALL="qemu-${QEMU_VERSION}.tar.xz" WORKDIR /qemu @@ -28,11 +28,35 @@ RUN apt-get -y install python build-essential libglib2.0-dev libpixman-1-dev RUN apt-get -y install libfdt-dev zlib1g-dev # Not required or specified anywhere but supress build warnings RUN apt-get -y install flex bison -RUN "qemu-${QEMU_VERSION}/configure" --static --target-list=arm-softmmu +RUN "qemu-${QEMU_VERSION}/configure" --static --target-list=arm-softmmu,aarch64-softmmu RUN make -j$(nproc) RUN # Strip the binary, this gives a substantial size reduction! -RUN strip "arm-softmmu/qemu-system-arm" +RUN strip "arm-softmmu/qemu-system-arm" "aarch64-softmmu/qemu-system-aarch64" + + +# Build stage for fatcat +FROM debian:stable-slim AS fatcat-builder +ARG FATCAT_VERSION=v1.1.0 +ARG FATCAT_CHECKSUM="303efe2aa73cbfe6fbc5d8af346d0f2c70b3f996fc891e8859213a58b95ad88c" +ENV FATCAT_TARBALL="${FATCAT_VERSION}.tar.gz" +WORKDIR /fatcat + +RUN # Update package lists +RUN apt-get update + +RUN # Pull source +RUN apt-get -y install wget +RUN wget "https://github.com/Gregwar/fatcat/archive/${FATCAT_TARBALL}" +RUN echo "${FATCAT_CHECKSUM} ${FATCAT_TARBALL}" | sha256sum --check + +RUN # Extract source tarball +RUN tar xvf "${FATCAT_TARBALL}" + +RUN # Build source +RUN apt-get -y install build-essential cmake +RUN cmake fatcat-* -DCMAKE_CXX_FLAGS='-static' +RUN make -j$(nproc) # Build the dockerpi VM image @@ -41,7 +65,9 @@ LABEL maintainer="Luke Childs " ARG RPI_KERNEL_URL="https://github.com/dhruvvyas90/qemu-rpi-kernel/archive/afe411f2c9b04730bcc6b2168cdc9adca224227c.zip" ARG RPI_KERNEL_CHECKSUM="295a22f1cd49ab51b9e7192103ee7c917624b063cc5ca2e11434164638aad5f4" -COPY --from=qemu-system-arm-builder /qemu/arm-softmmu/qemu-system-arm /usr/local/bin/qemu-system-arm +COPY --from=qemu-builder /qemu/arm-softmmu/qemu-system-arm /usr/local/bin/qemu-system-arm +COPY --from=qemu-builder /qemu/aarch64-softmmu/qemu-system-aarch64 /usr/local/bin/qemu-system-aarch64 +COPY --from=fatcat-builder /fatcat/fatcat /usr/local/bin/fatcat ADD $RPI_KERNEL_URL /tmp/qemu-rpi-kernel.zip diff --git a/README.md b/README.md index 713a4d2..6c35a7b 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,21 @@ If you only want to mount your own image, you can download a much slimmer VM onl docker run -it -v /2019-09-26-raspbian-buster-lite.img:/sdcard/filesystem.img lukechilds/dockerpi:vm ``` +## Which machines are supported? + +By default a Raspberry Pi 1 is virtualised, however experimental support has been added for Pi 2 and Pi 3 machines. + +You can specify a machine by passing the name as a CLI argument: + +``` +docker run -it lukechilds/dockerpi pi1 +docker run -it lukechilds/dockerpi pi2 +docker run -it lukechilds/dockerpi pi3 +``` + +> **Note:** Pi 2 and Pi 3 support is currently experimental. Networking doesn't work and QEMU hangs once the machines are powered down requiring you to `docker kill` the container. See [#4](https://github.com/lukechilds/dockerpi/pull/4) for details. + + ## Wait, what? A full ARM environment is created by using Docker to bootstrap a QEMU virtual machine. The Docker QEMU process virtualises a machine with a single core ARM11 CPU and 256MB RAM, just like the Raspberry Pi. The official Raspbian image is mounted and booted along with a modified QEMU compatible kernel. diff --git a/entrypoint.sh b/entrypoint.sh index a875490..967060a 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,5 +1,6 @@ #!/bin/sh +target="${1:-pi1}" image_path="/sdcard/filesystem.img" zip_path="/filesystem.zip" @@ -8,22 +9,76 @@ if [ ! -e $image_path ]; then if [ -e $zip_path ]; then echo "Extracting fresh filesystem..." unzip $zip_path - mv *.img $image_path + mv -- *.img $image_path else exit 1 fi fi -exec qemu-system-arm \ - --machine versatilepb \ +if [ "${target}" = "pi1" ]; then + emulator=qemu-system-arm + kernel="/root/qemu-rpi-kernel/kernel-qemu-4.19.50-buster" + dtb="/root/qemu-rpi-kernel/versatile-pb.dtb" + machine=versatilepb + memory=256m + root=/dev/sda2 + nic='--net nic --net user,hostfwd=tcp::5022-:22' +elif [ "${target}" = "pi2" ]; then + emulator=qemu-system-arm + machine=raspi2 + memory=1024m + kernel_pattern=kernel7.img + dtb_pattern=bcm2709-rpi-2-b.dtb + nic='' +elif [ "${target}" = "pi3" ]; then + emulator=qemu-system-aarch64 + machine=raspi3 + memory=1024m + kernel_pattern=kernel8.img + dtb_pattern=bcm2710-rpi-3-b-plus.dtb + nic='' +else + echo "Target ${target} not supported" + echo "Supported targets: pi1 pi2 pi3" + exit 2 +fi + +if [ "${kernel_pattern}" ] && [ "${dtb_pattern}" ]; then + fat_path="/fat.img" + echo "Extracting partitions" + fdisk -l ${image_path} \ + | awk "/^[^ ]*1/{print \"dd if=${image_path} of=${fat_path} bs=512 skip=\"\$4\" count=\"\$6}" \ + | sh + + echo "Extracting boot filesystem" + fat_folder="/fat" + mkdir -p "${fat_folder}" + fatcat -x "${fat_folder}" "${fat_path}" + + root=/dev/mmcblk0p2 + + echo "Searching for kernel='${kernel_pattern}'" + kernel=$(find "${fat_folder}" -name "${kernel_pattern}") + + echo "Searching for dtb='${dtb_pattern}'" + dtb=$(find "${fat_folder}" -name "${dtb_pattern}") +fi + +if [ "${kernel}" = "" ] || [ "${dtb}" = "" ]; then + echo "Missing kernel='${kernel}' or dtb='${dtb}'" + exit 2 +fi + +echo "Booting QEMU machine \"${machine}\" with kernel=${kernel} dtb=${dtb}" +exec ${emulator} \ + --machine "${machine}" \ --cpu arm1176 \ - --m 256M \ - --hda /sdcard/filesystem.img \ - --net nic \ - --net user,hostfwd=tcp::5022-:22 \ - --dtb /root/qemu-rpi-kernel/versatile-pb.dtb \ - --kernel /root/qemu-rpi-kernel/kernel-qemu-4.19.50-buster \ - --append "root=/dev/sda2 panic=1" \ + --m "${memory}" \ + --hda "${image_path}" \ + ${nic} \ + --dtb "${dtb}" \ + --kernel "${kernel}" \ + --append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=${root} rootwait panic=1" \ --no-reboot \ --display none \ --serial mon:stdio