├── .github └── workflows │ ├── deploy-test.yml │ └── release.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── benchmark-vm.py ├── dev-docs.md └── vm ├── Dockerfile ├── LICENSE ├── README.md └── entrypoint.sh /.github/workflows/deploy-test.yml: -------------------------------------------------------------------------------- 1 | name: Deploy main branch & test builds 2 | 3 | on: 4 | push: 5 | branches: [main, ci] 6 | 7 | jobs: 8 | deploy: 9 | name: Deploy master tag images 10 | runs-on: ubuntu-latest 11 | if: "!contains(github.event.head_commit.message, 'ci-skip') && !contains(github.event.head_commit.message, 'skip-ci')" 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Login to GitHub Container Registry 15 | uses: docker/login-action@v3 16 | with: 17 | registry: ghcr.io 18 | username: ${{ github.repository_owner }} 19 | password: ${{ secrets.CR_PAT }} 20 | - name: Set current date to env variable $DATE_YYYY_MM_DD 21 | id: date 22 | run: echo "DATE_YYYY_MM_DD=$(date +'%Y-%m-%d')" >> $GITHUB_ENV 23 | - name: Build base image (with expanded fs, otherwise is too small) 24 | run: docker build -t ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master --build-arg FILE_SUFFIX=autologin-ssh-expanded . 25 | - name: Tag same base image with date 26 | run: docker tag ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master-${{ env.DATE_YYYY_MM_DD }} 27 | - name: Build Mu image 28 | run: docker build -t ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master-mu --build-arg FILE_SUFFIX=mu . 29 | - name: Push all tags to ghcr.io 30 | run: | 31 | docker push ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master-${{ env.DATE_YYYY_MM_DD }} 32 | docker push ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master-mu 33 | docker push ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master 34 | 35 | # This check is not valid, will probably delete soon 36 | check-action-container: 37 | name: Attempt to bash into container master tag 38 | needs: deploy 39 | runs-on: ubuntu-latest 40 | container: 41 | image: ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master 42 | options: "--entrypoint /entrypoint.sh" 43 | steps: 44 | - run: uname -a 45 | 46 | check-ssh: 47 | name: SSH sample master tag 48 | needs: deploy 49 | runs-on: ubuntu-latest 50 | services: 51 | rpios: 52 | image: ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master 53 | ports: 54 | - 5022:5022 55 | steps: 56 | - name: Give 2m30s for the docker image to start up QEMU and Raspberry Pi OS 57 | run: sleep 150 58 | - name: Executing remote ssh command 1 59 | uses: appleboy/ssh-action@v1.0.0 60 | with: 61 | host: rpios 62 | username: pi 63 | password: raspberry 64 | port: ${{ job.services.rpios.ports[5022] }} 65 | # QEMU might still take some extra time to start up Raspberry Pi OS 66 | timeout: 5m 67 | script: | 68 | uname -a 69 | cat /etc/os-release 70 | touch my_file.txt 71 | df -h 72 | - name: Executing remote ssh command 2 (check state permanence) 73 | uses: appleboy/ssh-action@v1.0.0 74 | with: 75 | host: rpios 76 | username: pi 77 | password: raspberry 78 | port: ${{ job.services.rpios.ports[5022] }} 79 | script: | 80 | uname -a 81 | cat /etc/os-release 82 | ls 83 | test -f my_file.txt && echo "Previously created file exists." 84 | 85 | check-ssh-mu: 86 | name: SSH sample master-mu tag 87 | needs: deploy 88 | runs-on: ubuntu-latest 89 | services: 90 | rpios: 91 | image: ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:master-mu 92 | ports: 93 | - 5022:5022 94 | steps: 95 | - name: Give 2m30s for the docker image to start up QEMU and Raspberry Pi OS 96 | run: sleep 150 97 | - name: Executing remote ssh command 1 98 | uses: appleboy/ssh-action@v1.0.0 99 | with: 100 | host: rpios 101 | username: pi 102 | password: raspberry 103 | port: ${{ job.services.rpios.ports[5022] }} 104 | # QEMU might still take some extra time to start up Raspberry Pi OS 105 | timeout: 5m 106 | script: | 107 | uname -a 108 | cat /etc/os-release 109 | touch my_file.txt 110 | df -h 111 | - name: Executing remote ssh command 2 (check state permanence) 112 | uses: appleboy/ssh-action@v1.0.0 113 | with: 114 | host: rpios 115 | username: pi 116 | password: raspberry 117 | port: ${{ job.services.rpios.ports[5022] }} 118 | script: | 119 | uname -a 120 | cat /etc/os-release 121 | ls 122 | test -f my_file.txt && echo "Previously created file exists." 123 | - name: Check the Mu packages are present 124 | uses: appleboy/ssh-action@v1.0.0 125 | with: 126 | host: rpios 127 | username: pi 128 | password: raspberry 129 | port: ${{ job.services.rpios.ports[5022] }} 130 | script: | 131 | dpkg -s python3-pyqt5 python3-pyqt5.qsci python3-pyqt5.qtserialport python3-pyqt5.qtsvg 132 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Deploy versioned & latest 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | deploy-release: 9 | name: Deploy versioned images 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Set release tag to env variables $TAG 14 | run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 15 | - name: Set 'latest tag' (e.g. buster-legacy-2022-04-19 -> buster-latest) to env variable $TAG_LATEST 16 | run: python -c "t='$TAG'.split('-')[0]; print(f'TAG_LATEST={t}-latest')" >> $GITHUB_ENV 17 | - run: echo "Release tag is '$TAG' and latest tag is '${{ env.TAG_LATEST }}'" 18 | - name: Login to GitHub Container Registry 19 | uses: docker/login-action@v3 20 | with: 21 | registry: ghcr.io 22 | username: ${{ github.repository_owner }} 23 | password: ${{ secrets.CR_PAT }} 24 | - name: Build base image (expanded disk) with latest tag 25 | run: docker build -t ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG_LATEST }} --build-arg FILE_SUFFIX=autologin-ssh-expanded . 26 | - name: Then tag it with the full version as well 27 | run: docker tag ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG_LATEST }} ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG }} 28 | - name: Build Mu image 29 | run: docker build -t ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG }}-mu --build-arg FILE_SUFFIX=mu . 30 | - name: Push images to ghcr.io 31 | run: | 32 | docker push ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG }}-mu 33 | docker push ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG }} 34 | docker push ghcr.io/${{ github.repository_owner }}/qemu-rpi-os-lite:${{ env.TAG_LATEST }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ########### 2 | # Project # 3 | ########### 4 | .venv/* 5 | 6 | ########### 7 | # Editors # 8 | ########### 9 | # VSCode 10 | .vscode/* 11 | #!.vscode/settings.json 12 | !.vscode/tasks.json 13 | !.vscode/launch.json 14 | !.vscode/extensions.json 15 | *.code-workspace 16 | 17 | 18 | ###################### 19 | # OS generated files # 20 | ###################### 21 | # macoOS 22 | .DS_Store 23 | .DS_Store? 24 | .AppleDouble 25 | .LSOverride 26 | ._* 27 | .Spotlight-V100 28 | .Trashes 29 | Icon? 30 | 31 | # Windows 32 | Thumbs.db 33 | ehthumbs.db 34 | ehthumbs_vista.db 35 | *.stackdump 36 | [Dd]esktop.ini 37 | $RECYCLE.BIN/ 38 | *.lnk 39 | 40 | # Linux 41 | *~ 42 | .fuse_hidden* 43 | .directory 44 | .Trash-* 45 | .nfs* 46 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Using a fork of the https://github.com/lukechilds/dockerpi vm with multiple 2 | # improvements and fixes. 3 | FROM ghcr.io/carlosperate/qemu-rpi-vm:2024-01-03 4 | 5 | LABEL org.opencontainers.image.authors="Carlos Pereira Atencio " 6 | LABEL org.opencontainers.image.description="Docker image with Raspberry Pi OS running on QEMU." 7 | LABEL org.opencontainers.image.source="https://github.com/carlosperate/docker-qemu-rpi-os" 8 | 9 | # Select the GitHub tag from the release that hosts the OS files 10 | # https://github.com/carlosperate/rpi-os-custom-image/releases/ 11 | ARG GH_TAG="bullseye-legacy-2023-10-10" 12 | 13 | # To build a different image type from the release the FILE_SUFFIX variable 14 | # can be overwritten with the `docker build --build-arg` flag 15 | ARG FILE_SUFFIX="autologin-ssh-expanded" 16 | 17 | # This only needs to be changed if the releases filename format changes 18 | ARG FILE_PREXIF="raspberry-pi-os-lite-"${GH_TAG}"-" 19 | 20 | ARG FILESYSTEM_IMAGE_URL="https://github.com/carlosperate/rpi-os-custom-image/releases/download/"${GH_TAG}"/"${FILE_PREXIF}${FILE_SUFFIX}".zip" 21 | ADD $FILESYSTEM_IMAGE_URL /filesystem.zip 22 | 23 | # entrypoint.sh has been added in the parent lukechilds/dockerpi:vm 24 | ENTRYPOINT ["/entrypoint.sh"] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Carlos Pereira Atencio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Raspberry Pi OS for Arm Virtualised with QEMU 2 | 3 | Docker images with a QEMU virtual machine emulating ARMv6 and running 4 | Raspberry Pi OS (formerly Raspbian) for the armhf architecture. 5 | 6 | Oversimplified diagram: 7 | 8 | ``` 9 | +-------------------------------+ 10 | | | 11 | | Docker Container | 12 | | | 13 | | +-------------------------+ | 14 | | | | | 15 | | | Raspberry Pi OS | | 16 | | | | | 17 | | +-------------------------+ | 18 | | | | | 19 | | | QEMU Emulating ARMv6 | | 20 | | | | | 21 | | +-------------------------+ | 22 | | | 23 | +-------------------------------+ 24 | | | 25 | | PC Host OS | 26 | | | 27 | +-------------------------------+ 28 | ``` 29 | 30 | These Docker images are built on top of the fantastic 31 | [dockerpi](https://github.com/lukechilds/dockerpi) project, all credit for 32 | the hard work goes to them. The main difference in this version is that the 33 | [Raspberry Pi OS Lite image used](https://github.com/carlosperate/rpi-os-custom-image) 34 | has been updated to enable auto-login, SSH, and expand their filesystem size. 35 | 36 | These changes make these images useful for things like running automated 37 | tests on CI, e.g. GitHub Actions. 38 | 39 | ## How to use these images 40 | 41 | The main image produced in this repository can be run with this command: 42 | 43 | ```bash 44 | docker run -it ghcr.io/carlosperate/qemu-rpi-os-lite:bullseye-latest 45 | ``` 46 | 47 | This will drop you into a bash session inside Raspberry Pi OS. 48 | 49 | ### SSH 50 | 51 | You can also launch an image with port forwarding and access it via SSH: 52 | 53 | ```bash 54 | docker run -it -p 5022:5022 ghcr.io/carlosperate/qemu-rpi-os-lite:bullseye-latest 55 | ``` 56 | 57 | - SSH port: `5022` 58 | - SSH username: `pi` 59 | - SSH password: `raspberry` 60 | 61 | ## Available Images 62 | 63 | There are two main releases right now `buster-latest` and 64 | `bullseye-latest`: 65 | 66 | ``` 67 | ghcr.io/carlosperate/qemu-rpi-os-lite:bullseye-latest 68 | ``` 69 | 70 | ``` 71 | ghcr.io/carlosperate/qemu-rpi-os-lite:buster-latest 72 | ``` 73 | 74 | Each Pi OS release has its own tag, including the OS release date in this 75 | format: 76 | 77 | ``` 78 | ghcr.io/carlosperate/qemu-rpi-os-lite:buster-yyyy-mm-dd 79 | ``` 80 | 81 | There also is an additional tag on each release with the postfix `mu` in the 82 | tag name, which is an specialised image created specifically to include the 83 | [Mu Editor](https://github.com/mu-editor/mu) dependencies pre-installed, 84 | which is used for CI tests on that project: 85 | 86 | ``` 87 | ghcr.io/carlosperate/qemu-rpi-os-lite:buster-yyyy-mm-dd-mu 88 | ``` 89 | 90 | All images can be found here: 91 | https://github.com/carlosperate/docker-qemu-rpi-os/pkgs/container/qemu-rpi-os-lite 92 | 93 | ### Releases 94 | 95 | Each OS release is tracked and customised via the 96 | [Raspberry Pi OS Custom Image](https://github.com/carlosperate/rpi-os-custom-image) 97 | repository, which then hosts the custom images in its 98 | [releases page](https://github.com/carlosperate/rpi-os-custom-image/releases). 99 | 100 | ### Older OS versions 101 | 102 | Older versions of Raspbian/Raspberry Pi OS have been tagged and published: 103 | 104 | ```bash 105 | docker run -it ghcr.io/carlosperate/qemu-rpi-os-lite:jessie-latest 106 | ``` 107 | 108 | ```bash 109 | docker run -it ghcr.io/carlosperate/qemu-rpi-os-lite:stretch-latest 110 | ``` 111 | 112 | ## Build and run this docker image from the repository 113 | 114 | This information can be found in the [dev-docs.md](dev-docs.md) file. 115 | -------------------------------------------------------------------------------- /benchmark-vm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Launch a Raspberry PI OS image with Docker and QEMU, run a couple of 5 | benchmarks, and close it. 6 | 7 | This script requires a Pi OS image with autologin enabled. 8 | """ 9 | import os 10 | import sys 11 | import uuid 12 | import argparse 13 | 14 | import pexpect 15 | 16 | 17 | DOCKER_IMAGE = "ghcr.io/carlosperate/dockerpi-vm:local" 18 | PI_VERSION = "pi1" 19 | 20 | RPI_OS_USERNAME = "pi" 21 | RPI_OS_PASSWORD = "raspberry" 22 | 23 | BASH_PROMPT = "{}@raspberrypi:~$ ".format(RPI_OS_USERNAME) 24 | 25 | 26 | def launch_docker_spawn(docker_img, img_path, pi_version): 27 | """Runs the provided Raspberry Pi OS Lite image in QEMU inside a Docker 28 | container and returns a child process to run commands inside it. 29 | 30 | :param img_path: Path to the Raspberry Pi OS Lite image to update. 31 | """ 32 | img_path = os.path.abspath(img_path) 33 | if not os.path.isfile(img_path): 34 | raise Exception("Provided OS file cannot be found: {}".format(img_path)) 35 | if not img_path.endswith(".img"): 36 | raise Exception("Provided OS .img file does not have the right extension: {}".format(img_path)) 37 | 38 | docker_container_name = "rpi-os-{}".format(str(uuid.uuid4())[:8]) 39 | docker_cmd = " ".join([ 40 | "docker", 41 | "run", 42 | "-it", 43 | "--rm", 44 | "--name {}".format(docker_container_name), 45 | # "-p 5022:5022", 46 | "-v {}:/sdcard/filesystem.img".format(img_path), 47 | docker_img, 48 | pi_version, 49 | ]) 50 | print("Docker cmd: {}".format(docker_cmd)) 51 | 52 | child = pexpect.spawn(docker_cmd, timeout=600, encoding='utf-8') 53 | child.logfile = sys.stdout 54 | 55 | return child, docker_container_name 56 | 57 | 58 | def close_container(child, docker_container_name): 59 | try: 60 | print('! Attempting to close process.') 61 | child.close() 62 | print("! Exit status: {}".format(child.exitstatus)) 63 | print("! Signal status: {}".format(child.signalstatus)) 64 | finally: 65 | print('! Check if {} container is still running'.format(docker_container_name)) 66 | container_id = pexpect.run( 67 | 'docker ps --filter "name={}" -q'.format(docker_container_name), 68 | ) 69 | print(container_id) 70 | if container_id: 71 | print('! Stopping {} container'.format(docker_container_name)) 72 | cmd_op, exit_status = pexpect.run( 73 | 'docker stop {}'.format(docker_container_name), withexitstatus=True, 74 | ) 75 | print("{}\n! Exit status: {}".format(cmd_op, exit_status)) 76 | else: 77 | print('! Docker container was already stopped ✅') 78 | 79 | 80 | def run(docker_img, img_path, pi_version): 81 | print("Staring Raspberry Pi OS container with img: {}".format(img_path)) 82 | 83 | child, docker_container_name = None, None 84 | try: 85 | child, docker_container_name = launch_docker_spawn(docker_img, img_path, pi_version) 86 | child.expect_exact(BASH_PROMPT) 87 | 88 | # System info 89 | child.sendline("uname -a") 90 | child.expect_exact(BASH_PROMPT) 91 | child.sendline("cat /etc/os-release | head -n 1") 92 | child.expect_exact(BASH_PROMPT) 93 | child.sendline("cat /proc/cpuinfo") 94 | child.expect_exact(BASH_PROMPT) 95 | 96 | # Benchmarks 97 | child.sendline("sudo apt update -qq") 98 | child.expect_exact(BASH_PROMPT) 99 | child.sendline("sudo apt install -y speedtest-cli sysbench") 100 | child.expect_exact(BASH_PROMPT) 101 | child.sendline("speedtest-cli --secure") 102 | child.expect_exact(BASH_PROMPT) 103 | child.sendline("# CPU test - 1 thread") 104 | child.expect_exact(BASH_PROMPT) 105 | child.sendline("sysbench --num-threads=1 --validate=on --test=cpu --cpu-max-prime=1000 run") 106 | child.expect_exact(BASH_PROMPT) 107 | child.sendline("# CPU test - 4 thread") 108 | child.expect_exact(BASH_PROMPT) 109 | child.sendline("sysbench --num-threads=4 --validate=on --test=cpu --cpu-max-prime=1000 run") 110 | child.expect_exact(BASH_PROMPT) 111 | child.sendline("# Disk test - Write") 112 | child.expect_exact(BASH_PROMPT) 113 | child.sendline("rm -f ~/test.tmp && sync && dd if=/dev/zero of=~/test.tmp bs=1M count=256 conv=fsync") 114 | child.expect_exact(BASH_PROMPT) 115 | child.sendline("# Disk test - Read") 116 | child.expect_exact(BASH_PROMPT) 117 | child.sendline("sync && dd if=~/test.tmp of=/dev/null bs=1M && rm -f ~/test.tmp") 118 | child.expect_exact(BASH_PROMPT) 119 | 120 | # We are done, let's exit 121 | child.sendline("sudo shutdown now") 122 | child.expect(pexpect.EOF) 123 | child.wait() 124 | # Let ay exceptions bubble up, but ensure clean-up is run 125 | finally: 126 | if child: 127 | close_container(child, docker_container_name) 128 | 129 | 130 | def main(): 131 | parser = argparse.ArgumentParser(description="Launch and shutdown a Raspberry Pi OS image with Docker and QEMU.") 132 | parser.add_argument("os_img", type=str, help="Path to the Raspberry Pi OS Lite image .img file") 133 | parser.add_argument("-d", "--docker-img", type=str, default=DOCKER_IMAGE, help="(Optional) Docker image to use") 134 | parser.add_argument("-p", "--pi-version", type=str, default=PI_VERSION, help="(Optional) Raspberry Pi version (pi1, pi2, pi3)") 135 | args = parser.parse_args() 136 | 137 | if args.pi_version not in ("pi1", "pi2", "pi3", "pivirt"): 138 | raise Exception("Invalid Raspberry Pi version provided: {}".format(args.pi_version)) 139 | 140 | run(args.docker_img, args.os_img, args.pi_version) 141 | 142 | return 0 143 | 144 | 145 | if __name__ == "__main__": 146 | exit(main()) 147 | -------------------------------------------------------------------------------- /dev-docs.md: -------------------------------------------------------------------------------- 1 | # Development Documentation 2 | 3 | ## `qemu-rpi-os-lite` 4 | 5 | ### Build docker image 6 | 7 | ```bash 8 | git clone https://github.com/carlosperate/docker-qemu-rpi-os.git 9 | ``` 10 | ```bash 11 | cd docker-qemu-rpi-os 12 | ``` 13 | ```bash 14 | docker build -t carlosperate/qemu-rpi-os-lite . 15 | ``` 16 | 17 | ### Run docker image 18 | 19 | ```bash 20 | docker run -it carlosperate/qemu-rpi-os-lite 21 | ``` 22 | 23 | ### Publish docker image 24 | 25 | GitHub needs authentication with a personal token: 26 | 27 | ```bash 28 | echo $CR_PAT | docker login ghcr.io -u --password-stdin 29 | ``` 30 | ```bash 31 | docker tag IMAGE_ID carlosperate/qemu-rpi-os-lite:VERSION 32 | ``` 33 | ```bash 34 | docker push ghcr.io/carlosperate/qemu-rpi-os-lite:VERSION 35 | ``` 36 | 37 | 38 | ## `dockerpi` Fork 39 | 40 | The [vm](vm) folder contains a fork of the 41 | [dockerpi](https://github.com/lukechilds/dockerpi/) project, with modifications 42 | as listed in its [vm/README.md](vm/README.md) file. 43 | 44 | ### Build image 45 | 46 | ```bash 47 | cd vm 48 | ``` 49 | ```bash 50 | docker build -t ghcr.io/carlosperate/qemu-rpi-vm:local . 51 | ``` 52 | 53 | ### Run container pointing to Pi OS image file 54 | 55 | ```bash 56 | docker run -it --rm -v full_path_to.img:/sdcard/filesystem.img -p 5022:5022 ghcr.io/carlosperate/dockerpi-vm:local 57 | ``` 58 | 59 | ### Push image to GH Container Registry 60 | 61 | GitHub needs authentication with a personal token: 62 | 63 | ```bash 64 | echo $CR_PAT | docker login ghcr.io -u --password-stdin 65 | ``` 66 | ```bash 67 | docker tag IMAGE_ID ghcr.io/carlosperate/qemu-rpi-vm:VERSION 68 | ``` 69 | ```bash 70 | docker push ghcr.io/carlosperate/qemu-rpi-vm:VERSION 71 | ``` 72 | 73 | ### `benchmark_vm.py` script 74 | 75 | This is a very simple script that launches the dockerpi vm fork image 76 | pointing to a .img file (with autologin enabled), runs a couple of benchmarks, 77 | and closes it. 78 | 79 | It can be used to compare performance of different vm configurations. 80 | 81 | Dependencies: 82 | - Docker 83 | - Python 3 84 | - `pip install pexpect` 85 | 86 | To run the script: 87 | 88 | ```bash 89 | python benchmark_vm.py path_to_my.img -p=pi1 90 | ``` 91 | ```bash 92 | python benchmark_vm.py path_to_my.img -p=pi1 -d=ghcr.io/carlosperate/dockerpi-vm:local 93 | ``` 94 | -------------------------------------------------------------------------------- /vm/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage for qemu-system-arm 2 | FROM ubuntu:23.10 AS qemu-builder 3 | ARG QEMU_VERSION=8.2.0 4 | ENV QEMU_TARBALL="qemu-${QEMU_VERSION}.tar.xz" 5 | WORKDIR /qemu 6 | 7 | RUN # Update package lists 8 | RUN apt-get update 9 | 10 | RUN # Pull source 11 | RUN apt-get -y install wget 12 | RUN wget "https://download.qemu.org/${QEMU_TARBALL}" 13 | 14 | RUN # Verify signatures 15 | RUN apt-get -y install gpg 16 | RUN wget "https://download.qemu.org/${QEMU_TARBALL}.sig" 17 | RUN gpg --keyserver keyserver.ubuntu.com --recv-keys CEACC9E15534EBABB82D3FA03353C9CEF108B584 18 | RUN gpg --verify "${QEMU_TARBALL}.sig" "${QEMU_TARBALL}" 19 | 20 | RUN # Extract source tarball 21 | RUN apt-get -y install pkg-config xz-utils 22 | RUN tar xvf "${QEMU_TARBALL}" 23 | 24 | RUN # Build source 25 | # These seem to be the only deps actually required for a successful build 26 | RUN apt-get -y install python3 python3-venv build-essential libslirp-dev libglib2.0-dev libpixman-1-dev ninja-build 27 | # These don't seem to be required but are specified here: https://wiki.qemu.org/Hosts/Linux 28 | RUN apt-get -y install libfdt-dev zlib1g-dev 29 | # Not required or specified anywhere but supress build warnings 30 | RUN apt-get -y install flex bison 31 | WORKDIR /qemu/qemu-${QEMU_VERSION} 32 | RUN ./configure --static --target-list=arm-softmmu,aarch64-softmmu --enable-slirp --disable-gio --disable-docs 33 | RUN make -j$(nproc) 34 | 35 | RUN # Strip the binary, this gives a substantial size reduction! 36 | RUN cp -r /qemu/qemu-${QEMU_VERSION}/build /qemu/build 37 | WORKDIR /qemu/build 38 | RUN strip "arm-softmmu/qemu-system-arm" "aarch64-softmmu/qemu-system-aarch64" "qemu-img" 39 | 40 | 41 | # Build stage for fatcat 42 | FROM debian:stable-slim AS fatcat-builder 43 | ARG FATCAT_VERSION=v1.1.0 44 | ARG FATCAT_CHECKSUM="303efe2aa73cbfe6fbc5d8af346d0f2c70b3f996fc891e8859213a58b95ad88c" 45 | ENV FATCAT_TARBALL="${FATCAT_VERSION}.tar.gz" 46 | WORKDIR /fatcat 47 | 48 | RUN # Update package lists 49 | RUN apt-get update 50 | 51 | RUN # Pull source 52 | RUN apt-get -y install wget 53 | RUN wget "https://github.com/Gregwar/fatcat/archive/${FATCAT_TARBALL}" 54 | RUN echo "${FATCAT_CHECKSUM} ${FATCAT_TARBALL}" | sha256sum --check 55 | 56 | RUN # Extract source tarball 57 | RUN tar xvf "${FATCAT_TARBALL}" 58 | 59 | RUN # Build source 60 | RUN apt-get -y install build-essential cmake 61 | RUN cmake fatcat-* -DCMAKE_CXX_FLAGS='-static' 62 | RUN make -j$(nproc) 63 | 64 | 65 | # Building the kernell for virt Qemu machine type 66 | FROM ubuntu:23.10 AS kernel-builder 67 | 68 | ARG KERNEL_VERSION=5.10.205 69 | ARG KERNEL_URL="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${KERNEL_VERSION}.tar.xz" 70 | ARG KERNEL_SIG="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${KERNEL_VERSION}.tar.sign" 71 | 72 | RUN # Install cross compiler, build tools, and other dependencies 73 | RUN apt-get update -qq && \ 74 | apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi && \ 75 | apt-get install -y build-essential flex bison libssl-dev libelf-dev bc && \ 76 | apt-get install -y wget xz-utils 77 | 78 | RUN # Pull source 79 | WORKDIR /kernel 80 | RUN wget "${KERNEL_URL}" && \ 81 | tar xvJf linux-${KERNEL_VERSION}.tar.xz 82 | WORKDIR /kernel/linux-${KERNEL_VERSION} 83 | 84 | RUN # Build kernel 85 | RUN export ARCH=arm && \ 86 | export CROSS_COMPILE=arm-linux-gnueabi- && \ 87 | export CONFIG_PCI=y && \ 88 | export CONFIG_VIRTIO_PCI=y && \ 89 | export CONFIG_PCI_HOST_GENERIC=y && \ 90 | export CONFIG_DRM=y && \ 91 | export CONFIG_DRM_VIRTIO_GPU=y && \ 92 | make defconfig && \ 93 | make kvm_guest.config && \ 94 | make -j$(nproc) 95 | RUN mv arch/arm/boot/ ../boot 96 | 97 | 98 | # Build the dockerpi VM image 99 | FROM busybox:1.36 AS dockerpi-vm 100 | LABEL maintainer="Luke Childs " 101 | ARG RPI_KERNEL_URL="https://github.com/dhruvvyas90/qemu-rpi-kernel/archive/afe411f2c9b04730bcc6b2168cdc9adca224227c.zip" 102 | ARG RPI_KERNEL_CHECKSUM="295a22f1cd49ab51b9e7192103ee7c917624b063cc5ca2e11434164638aad5f4" 103 | 104 | COPY --from=qemu-builder /qemu/build/arm-softmmu/qemu-system-arm /usr/local/bin/qemu-system-arm 105 | COPY --from=qemu-builder /qemu/build/aarch64-softmmu/qemu-system-aarch64 /usr/local/bin/qemu-system-aarch64 106 | COPY --from=qemu-builder /qemu/build/qemu-img /usr/local/bin/qemu-img 107 | COPY --from=fatcat-builder /fatcat/fatcat /usr/local/bin/fatcat 108 | COPY --from=kernel-builder /kernel/boot/zImage /root/zImage 109 | 110 | ADD $RPI_KERNEL_URL /tmp/qemu-rpi-kernel.zip 111 | 112 | RUN cd /tmp && \ 113 | echo "$RPI_KERNEL_CHECKSUM qemu-rpi-kernel.zip" | sha256sum -c && \ 114 | unzip qemu-rpi-kernel.zip && \ 115 | mkdir -p /root/qemu-rpi-kernel && \ 116 | cp qemu-rpi-kernel-*/kernel-qemu-4.19.50-buster /root/qemu-rpi-kernel/ && \ 117 | cp qemu-rpi-kernel-*/versatile-pb.dtb /root/qemu-rpi-kernel/ && \ 118 | rm -rf /tmp/* 119 | 120 | VOLUME /sdcard 121 | 122 | ADD ./entrypoint.sh /entrypoint.sh 123 | ENTRYPOINT ["./entrypoint.sh"] 124 | -------------------------------------------------------------------------------- /vm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Luke Childs 4 | Copyright (c) 2023 Carlos Pereira Atencio and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /vm/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # dockerpi Fork 6 | 7 | This is a fork of the original 8 | [dockerpi](https://github.com/lukechilds/dockerpi/) project, to be able to 9 | apply fixes and improvements, since the original upstream project hasn't been 10 | updated in two and a half years. 11 | 12 | List of changes: 13 | - [GitHub view of full diff](https://github.com/carlosperate/docker-qemu-rpi-os/compare/f0f1c1dd6c2470012a6588fae08e528198203710...main#diff-11dbc6371a321f05fc4ae47aa94884866787bc1427d9b5e4a9590b4cdf7f964c) 14 | (only files within the `vm` folder are from `dockerpi`) 15 | - Removed the `dockerpi` image and only kept the `vm` 16 | - As only the `vm` image is used by the docker-qemu-rpi-os project in the main [../Dockerfile](../Dockerfile) 17 | - commit [b91b284](https://github.com/carlosperate/docker-qemu-rpi-os/commit/b91b284ff848a7c265230ba5630bd7578074eec2) 18 | - Fix build issue `xz: Cannot exec: No such file or directory` 19 | - Fix from upstream PR: https://github.com/lukechilds/dockerpi/pull/59 20 | - commit [46deb95](https://github.com/carlosperate/docker-qemu-rpi-os/commit/46deb95ca5df09be1aec482e45f304025cba802e) 21 | - Fix build issue `Package python is not available, but is referred to by another package.` 22 | - Fix from upstream PR: https://github.com/lukechilds/dockerpi/pull/61 23 | - commit [0cca83a](https://github.com/carlosperate/docker-qemu-rpi-os/commit/0cca83af5c67a90b2ba646098496105e890346fe) 24 | - Fix run issue uncompressing OS image zip files larger than 4GB `unzip: bad length` 25 | - Fix from upstream PR: https://github.com/lukechilds/dockerpi/pull/48 26 | - commit [1d6745d](https://github.com/carlosperate/docker-qemu-rpi-os/commit/1d6745db79c300ce6445d049760a2e01f4ee43d0) 27 | - Updated Qemu to 8.2.0 28 | - commit [9837075](https://github.com/carlosperate/docker-qemu-rpi-os/commit/983707533f070b372d10d499ada7cad838fe0e16) 29 | - Fixes issue where Qemu for pi2/3 hangs on power down (before the container had to be manually killed) 30 | - Extra configure flags: 31 | - `--disable-gio`: https://gitlab.com/qemu-project/qemu/-/issues/1190 32 | - `--disable-docs`: To avoid needing the `sphinx` python dependencies 33 | - `--enable-slirp`: To resolve `network backend 'user' is not compiled into this binary` 34 | Since v7.2+ Qemu does not include the `slirp` networking lib 35 | Due to an issue in debian's `libslirp-dev` package, need to move image to Ubuntu 23.10 36 | https://stackoverflow.com/questions/75641274/network-backend-user-is-not-compiled-into-this-binary 37 | https://bugs.launchpad.net/ubuntu/+source/libslirp/+bug/2029431 38 | https://www.mail-archive.com/qemu-devel@nongnu.org/msg903610.html 39 | - `entrypoint.sh`: Output of `qemu-img info` now returns multiple `virtual-size` keys and only one needed 40 | - Create an additional board type for performance reasons 41 | - https://github.com/carlosperate/docker-qemu-rpi-os/issues/3 42 | - Uses the `virt` machine type: https://www.qemu.org/docs/master/system/arm/virt.html 43 | - This is not an accurate Pi emulation, but has better performance and 1 GB of RAM 44 | - Docker image has to build the kernel, as the pi kernel does not include the required configuration 45 | - commit [49c922b](https://github.com/carlosperate/docker-qemu-rpi-os/commit/49c922b8b9e30984767105cd8b9be960732ae095) 46 | - Added developer documentation for this fork to parent directory [../dev-docs.md](../dev-docs.md) 47 | 48 | Useful links: 49 | - [qemu-rpi-kernel](https://github.com/dhruvvyas90/qemu-rpi-kernel) 50 | - [Emulating a Raspberry Pi in QEMU](https://interrupt.memfault.com/blog/emulating-raspberry-pi-in-qemu) 51 | - [Emulating Raspberry Pi 4 with Qemu](https://gist.github.com/cGandom/23764ad5517c8ec1d7cd904b923ad863) 52 | - [Arm QEMU Debian 11 VM on x86/64 (amd64) Linux](https://www.willhaley.com/blog/debian-arm-qemu/) 53 | - [Raspberry Pi 4 emulation with QEMU virt](https://blog.grandtrunk.net/2023/03/raspberry-pi-4-emulation-with-qemu/) 54 | - [Raspberry Pi: How to cross-compile and use Mainline Kernel](https://gist.github.com/lategoodbye/c7317a42bf7f9c07f5a91baed8c68f75) 55 | - [Raspbian on QEMU with ARMv7](https://github.com/paulden/raspbian-on-qemu-armv7) 56 | - [QEMU for Beginner and Advanced](https://hackmd.io/@MarconiJiang/qemu_beginner) 57 | - [Installing Debian on QEMU’s 32-bit ARM “virt” board](https://translatedcode.wordpress.com/2016/11/03/installing-debian-on-qemus-32-bit-arm-virt-board/) 58 | - [Installing Debian on QEMU’s 64-bit ARM “virt” board](https://translatedcode.wordpress.com/2017/07/24/installing-debian-on-qemus-64-bit-arm-virt-board/) 59 | 60 | 61 | The rest of the original README can be seen below. 62 | 63 | ---------- 64 | 65 | > A Virtualised Raspberry Pi inside a Docker image 66 | 67 | Gives you access to a virtualised ARM based Raspberry Pi machine running the Raspian operating system. 68 | 69 | This is not just a Raspian Docker image, it's a full ARM based Raspberry Pi virtual machine environment. 70 | 71 |
72 | 73 |
74 | 75 | ## Usage 76 | 77 | ``` 78 | docker run -it lukechilds/dockerpi 79 | ``` 80 | 81 | By default all filesystem changes will be lost on shutdown. You can persist filesystem changes between reboots by mounting the `/sdcard` volume on your host: 82 | 83 | ``` 84 | docker run -it -v $HOME/.dockerpi:/sdcard lukechilds/dockerpi 85 | ``` 86 | 87 | If you have a specific image you want to mount you can mount it at `/sdcard/filesystem.img`: 88 | 89 | ``` 90 | docker run -it -v /2019-09-26-raspbian-buster-lite.img:/sdcard/filesystem.img lukechilds/dockerpi 91 | ``` 92 | 93 | If you only want to mount your own image, you can download a much slimmer VM only Docker container that doesn't contain the Raspbian filesystem image: 94 | 95 | [![Docker Image Size](https://badgen.net/docker/size/lukechilds/dockerpi/latest/amd64?icon=docker&label=lukechilds/dockerpi:latest)](https://hub.docker.com/r/lukechilds/dockerpi/tags?name=latest) 96 | [![Docker Image Size](https://badgen.net/docker/size/lukechilds/dockerpi/vm/amd64?icon=docker&label=lukechilds/dockerpi:vm)](https://hub.docker.com/r/lukechilds/dockerpi/tags?name=vm) 97 | 98 | ``` 99 | docker run -it -v /2019-09-26-raspbian-buster-lite.img:/sdcard/filesystem.img lukechilds/dockerpi:vm 100 | ``` 101 | 102 | ## Which machines are supported? 103 | 104 | By default a Raspberry Pi 1 is virtualised, however experimental support has been added for Pi 2 and Pi 3 machines. 105 | 106 | You can specify a machine by passing the name as a CLI argument: 107 | 108 | ``` 109 | docker run -it lukechilds/dockerpi pi1 110 | docker run -it lukechilds/dockerpi pi2 111 | docker run -it lukechilds/dockerpi pi3 112 | ``` 113 | 114 | > **Note:** In the Pi 2 and Pi 3 machines, 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. 115 | 116 | 117 | ## Wait, what? 118 | 119 | 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. 120 | 121 | You'll see the entire boot process logged to your TTY until you're prompted to log in with the username/password pi/raspberry. 122 | 123 | ``` 124 | pi@raspberrypi:~$ uname -a 125 | Linux raspberrypi 4.19.50+ #1 Tue Nov 26 01:49:16 CET 2019 armv6l GNU/Linux 126 | pi@raspberrypi:~$ cat /etc/os-release | head -n 1 127 | PRETTY_NAME="Raspbian GNU/Linux 10 (buster)" 128 | pi@raspberrypi:~$ cat /proc/cpuinfo 129 | processor : 0 130 | model name : ARMv6-compatible processor rev 7 (v6l) 131 | BogoMIPS : 798.31 132 | Features : half thumb fastmult vfp edsp java tls 133 | CPU implementer : 0x41 134 | CPU architecture: 7 135 | CPU variant : 0x0 136 | CPU part : 0xb76 137 | CPU revision : 7 138 | 139 | Hardware : ARM-Versatile (Device Tree Support) 140 | Revision : 0000 141 | Serial : 0000000000000000 142 | pi@raspberrypi:~$ free -h 143 | total used free shared buff/cache available 144 | Mem: 246Mi 20Mi 181Mi 1.0Mi 44Mi 179Mi 145 | Swap: 99Mi 0B 99Mi 146 | ``` 147 | 148 | ## Build 149 | 150 | Build this image yourself by checking out this repo, `cd` ing into it and running: 151 | 152 | ``` 153 | docker build -t lukechilds/dockerpi . 154 | ``` 155 | 156 | Build the VM only image with: 157 | 158 | ``` 159 | docker build -t lukechilds/dockerpi:vm --target dockerpi-vm . 160 | ``` 161 | 162 | ## Credit 163 | 164 | Thanks to [@dhruvvyas90](https://github.com/dhruvvyas90) for his [dhruvvyas90/qemu-rpi-kernel](https://github.com/dhruvvyas90/qemu-rpi-kernel) repo. 165 | 166 | ## License 167 | 168 | MIT © Luke Childs 169 | -------------------------------------------------------------------------------- /vm/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | GIB_IN_BYTES="1073741824" 4 | 5 | target="${1:-pivirt}" 6 | image_path="/sdcard/filesystem.img" 7 | zip_path="/filesystem.zip" 8 | 9 | if [ ! -e $image_path ]; then 10 | echo "No filesystem detected at ${image_path}!" 11 | if [ -e $zip_path ]; then 12 | echo "Extracting fresh filesystem..." 13 | unzip $zip_path 14 | mv -- *.img $image_path 15 | else 16 | exit 1 17 | fi 18 | fi 19 | 20 | qemu-img info $image_path 21 | image_size_in_bytes=$(qemu-img info --output json $image_path | grep "virtual-size" | awk '{print $2}' | sed 's/,//' | tail -n1) 22 | if [[ "$(($image_size_in_bytes % ($GIB_IN_BYTES * 2)))" != "0" ]]; then 23 | new_size_in_gib=$((($image_size_in_bytes / ($GIB_IN_BYTES * 2) + 1) * 2)) 24 | echo "Rounding image size up to ${new_size_in_gib}GiB so it's a multiple of 2GiB..." 25 | qemu-img resize $image_path "${new_size_in_gib}G" 26 | fi 27 | 28 | if [ "${target}" = "pi1" ]; then 29 | emulator=qemu-system-arm 30 | kernel="/root/qemu-rpi-kernel/kernel-qemu-4.19.50-buster" 31 | dtb="/root/qemu-rpi-kernel/versatile-pb.dtb" 32 | machine=versatilepb 33 | cpu=arm1176 34 | smp=1 35 | memory=256m 36 | root=/dev/sda2 37 | nic="--net nic --net user,hostfwd=tcp::5022-:22" 38 | elif [ "${target}" = "pi2" ]; then 39 | emulator=qemu-system-arm 40 | machine=raspi2b 41 | cpu=cortex-a7 42 | smp=4 43 | memory=1024m 44 | kernel_pattern=kernel7.img 45 | dtb_pattern=bcm2709-rpi-2-b.dtb 46 | append="dwc_otg.fiq_fsm_enable=0" 47 | nic="-netdev user,id=net0,hostfwd=tcp::5022-:22 -device usb-net,netdev=net0" 48 | elif [ "${target}" = "pi3" ]; then 49 | emulator=qemu-system-aarch64 50 | machine=raspi3b 51 | cpu=cortex-a53 52 | smp=4 53 | memory=1024m 54 | kernel_pattern=kernel8.img 55 | dtb_pattern=bcm2710-rpi-3-b-plus.dtb 56 | append="dwc_otg.fiq_fsm_enable=0" 57 | nic="-netdev user,id=net0,hostfwd=tcp::5022-:22 -device usb-net,netdev=net0" 58 | elif [ "${target}" = "pivirt" ]; then 59 | emulator=qemu-system-arm 60 | machine=virt 61 | cpu=cortex-a7 62 | smp="$(nproc)" 63 | memory=1024m 64 | dtb_pattern="" 65 | #dtb="/root/qemu-rpi-kernel/bcm2836-rpi-2-b.dtb" 66 | dtb="" 67 | kernel_pattern="" 68 | kernel="/root/zImage" 69 | append="" 70 | root=/dev/vda2 71 | nic="-netdev user,id=mynet,hostfwd=tcp::5022-:22 -device virtio-net-device,netdev=mynet" 72 | img_options=",if=none,id=hd0" 73 | drive_extra="-device virtio-blk-device,drive=hd0,bootindex=0" 74 | else 75 | echo "Target ${target} not supported" 76 | echo "Supported targets: pi1 pi2 pi3" 77 | exit 2 78 | fi 79 | 80 | if [ "${kernel_pattern}" ] && [ "${dtb_pattern}" ]; then 81 | fat_path="/fat.img" 82 | echo "Extracting partitions" 83 | fdisk -l ${image_path} \ 84 | | awk "/^[^ ]*1/{print \"dd if=${image_path} of=${fat_path} bs=512 skip=\"\$4\" count=\"\$6}" \ 85 | | sh 86 | 87 | echo "Extracting boot filesystem" 88 | fat_folder="/fat" 89 | mkdir -p "${fat_folder}" 90 | fatcat -x "${fat_folder}" "${fat_path}" 91 | 92 | root=/dev/mmcblk0p2 93 | 94 | echo "Searching for kernel='${kernel_pattern}'" 95 | kernel=$(find "${fat_folder}" -name "${kernel_pattern}") 96 | 97 | echo "Searching for dtb='${dtb_pattern}'" 98 | dtb=$(find "${fat_folder}" -name "${dtb_pattern}") 99 | fi 100 | 101 | if [ "${kernel}" = "" ] || ([ "${dtb}" = "" ] && [ "${dtb_pattern}" != "" ]); then 102 | echo "Missing kernel='${kernel}' or (dtb='${dtb}' for dtb_pattern='${dtb_pattern}')" 103 | exit 2 104 | fi 105 | 106 | # Some configurations don't need a dtb file and the flag should be skipped 107 | if [ -n "$dtb" ]; then 108 | dtb_flag="--dtb ${dtb}" 109 | else 110 | dtb_flag="" 111 | fi 112 | 113 | echo "Booting QEMU machine \"${machine}\" with kernel=${kernel} dtb=${dtb}" 114 | set -x 115 | exec ${emulator} \ 116 | --machine "${machine}" \ 117 | --cpu "${cpu}" \ 118 | --smp "${smp}" \ 119 | --m "${memory}" \ 120 | --drive "format=raw,file=${image_path}${img_options}" ${drive_extra} \ 121 | ${nic} \ 122 | ${dtb_flag} \ 123 | --kernel "${kernel}" \ 124 | --append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=${root} rootwait panic=1 ${append}" \ 125 | --no-reboot \ 126 | --display none \ 127 | --serial mon:stdio 128 | --------------------------------------------------------------------------------