├── .devcontainer.json ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── 1-issue.yml │ ├── 2-feature.yml │ ├── 3-bug.yml │ ├── 4-question.yml │ └── config.yml ├── dependabot.yml ├── logo.png ├── renovate.json └── workflows │ ├── build.yml │ ├── check.yml │ ├── hub.yml │ └── test.yml ├── .gitignore ├── Dockerfile ├── compose.yml ├── kubernetes.yml ├── license.md ├── readme.md └── src ├── boot.sh ├── config.sh ├── display.sh ├── entry.sh └── proc.sh /.devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qemu", 3 | "service": "qemu", 4 | "forwardPorts": [8006], 5 | "dockerComposeFile": "compose.yml" 6 | } 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .dockerignore 2 | .git 3 | .github 4 | .gitignore 5 | .gitlab-ci.yml 6 | .gitmodules 7 | Dockerfile 8 | Dockerfile.archive 9 | compose.yml 10 | compose.yaml 11 | docker-compose.yml 12 | docker-compose.yaml 13 | 14 | *.md 15 | 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-issue.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F6A8 Technical issue" 2 | description: When you're experiencing problems using the container 3 | body: 4 | - type: input 5 | id: os 6 | attributes: 7 | label: Operating system 8 | description: Your Linux distribution (can be shown by `lsb_release -a`). 9 | placeholder: e.g. Ubuntu 24.04 10 | validations: 11 | required: true 12 | - type: textarea 13 | id: summary 14 | attributes: 15 | label: Description 16 | description: A clear and concise description of your issue. 17 | validations: 18 | required: true 19 | - type: textarea 20 | id: compose 21 | attributes: 22 | label: Docker compose 23 | description: The compose file (or otherwise the `docker run` command used). 24 | render: yaml 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: log 29 | attributes: 30 | label: Docker log 31 | description: The logfile of the container (as shown by `docker logs qemu`). 32 | render: shell 33 | validations: 34 | required: true 35 | - type: textarea 36 | id: screenshot 37 | attributes: 38 | label: Screenshots (optional) 39 | description: Screenshots that might help to make the problem more clear. 40 | validations: 41 | required: false 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-feature.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F680 Feature request" 2 | description: Suggest an idea for improving the container 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: problem 8 | attributes: 9 | label: Is your proposal related to a problem? 10 | description: | 11 | Provide a clear and concise description of what the problem is. 12 | For example, "I'm always frustrated when..." 13 | validations: 14 | required: true 15 | - type: textarea 16 | id: solution 17 | attributes: 18 | label: Describe the solution you'd like. 19 | description: | 20 | Provide a clear and concise description of what you want to happen. 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: alternatives 25 | attributes: 26 | label: Describe alternatives you've considered. 27 | description: | 28 | Let us know about other solutions you've tried or researched. 29 | validations: 30 | required: true 31 | - type: textarea 32 | id: context 33 | attributes: 34 | label: Additional context 35 | description: | 36 | Is there anything else you can add about the proposal? 37 | You might want to link to related issues here, if you haven't already. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-bug.yml: -------------------------------------------------------------------------------- 1 | name: "\U0001F41E Bug report" 2 | description: Create a report to help us improve the container 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: input 7 | id: os 8 | attributes: 9 | label: Operating system 10 | description: Your Linux distribution (can be shown by `lsb_release -a`). 11 | placeholder: e.g. Ubuntu 24.04 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: summary 16 | attributes: 17 | label: Description 18 | description: Describe the expected behaviour, the actual behaviour, and the steps to reproduce. 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: compose 23 | attributes: 24 | label: Docker compose 25 | description: The compose file (or otherwise the `docker run` command used). 26 | render: yaml 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: log 31 | attributes: 32 | label: Docker log 33 | description: The logfile of the container (as shown by `docker logs qemu`). 34 | render: shell 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: screenshot 39 | attributes: 40 | label: Screenshots (optional) 41 | description: Screenshots that might help to make the problem more clear. 42 | validations: 43 | required: false 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4-question.yml: -------------------------------------------------------------------------------- 1 | name: "\U00002753 General question" 2 | description: Questions about the container not related to an issue 3 | title: "[Question]: " 4 | labels: ["question"] 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Is your question not already answered in the FAQ? 9 | description: Please read the [FAQ](https://github.com/qemus/qemu-arm/blob/master/readme.md) carefully to avoid asking duplicate questions. 10 | options: 11 | - label: I made sure the question is not listed in the [FAQ](https://github.com/qemus/qemu-arm/blob/master/readme.md). 12 | required: true 13 | - type: checkboxes 14 | attributes: 15 | label: Is this a general question and not a technical issue? 16 | description: For questions related to issues you must use the [technical issue](https://github.com/qemus/qemu-arm/issues/new?assignees=&labels=&projects=&template=1-issue.yml) form instead. It contains all the right fields (system info, logfiles, etc.) we need in order to be able to help you. 17 | options: 18 | - label: I am sure my question is not about a technical issue. 19 | required: true 20 | - type: textarea 21 | id: question 22 | attributes: 23 | label: Question 24 | description: What's the question you have about the container? 25 | validations: 26 | required: true 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: docker 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | - package-ecosystem: github-actions 8 | directory: / 9 | schedule: 10 | interval: weekly 11 | -------------------------------------------------------------------------------- /.github/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qemus/qemu-arm/9546b11150e563fbd40c2116188f0067edd19a12/.github/logo.png -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended", ":disableDependencyDashboard"] 4 | } 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths-ignore: 9 | - '**/*.md' 10 | - '**/*.yml' 11 | - '**/*.js' 12 | - '**/*.css' 13 | - '**/*.html' 14 | - 'web/**' 15 | - '.gitignore' 16 | - '.dockerignore' 17 | - '.github/**' 18 | - '.github/workflows/**' 19 | 20 | concurrency: 21 | group: build 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | shellcheck: 26 | name: Test 27 | uses: ./.github/workflows/check.yml 28 | build: 29 | name: Build 30 | needs: shellcheck 31 | runs-on: ubuntu-latest 32 | permissions: 33 | actions: write 34 | packages: write 35 | contents: read 36 | steps: 37 | - 38 | name: Checkout 39 | uses: actions/checkout@v4 40 | with: 41 | fetch-depth: 0 42 | - 43 | name: Docker metadata 44 | id: meta 45 | uses: docker/metadata-action@v5 46 | with: 47 | context: git 48 | images: | 49 | ghcr.io/${{ github.repository }} 50 | ${{ secrets.DOCKERHUB_REPO }} 51 | tags: | 52 | type=raw,value=latest,priority=100 53 | type=raw,value=${{ vars.MAJOR }}.${{ vars.MINOR }} 54 | labels: | 55 | org.opencontainers.image.title=${{ vars.NAME }} 56 | env: 57 | DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index 58 | - 59 | name: Set up Docker Buildx 60 | uses: docker/setup-buildx-action@v3 61 | - 62 | name: Login into Docker Hub 63 | uses: docker/login-action@v3 64 | with: 65 | username: ${{ secrets.DOCKERHUB_USERNAME }} 66 | password: ${{ secrets.DOCKERHUB_TOKEN }} 67 | - 68 | name: Login to GitHub Container Registry 69 | uses: docker/login-action@v3 70 | with: 71 | registry: ghcr.io 72 | username: ${{ github.actor }} 73 | password: ${{ secrets.GITHUB_TOKEN }} 74 | - 75 | name: Build Docker image 76 | uses: docker/build-push-action@v6 77 | with: 78 | context: . 79 | push: true 80 | provenance: false 81 | platforms: linux/amd64,linux/arm64 82 | tags: ${{ steps.meta.outputs.tags }} 83 | labels: ${{ steps.meta.outputs.labels }} 84 | annotations: ${{ steps.meta.outputs.annotations }} 85 | build-args: | 86 | VERSION_ARG=${{ steps.meta.outputs.version }} 87 | - 88 | name: Create a release 89 | uses: action-pack/github-release@v2 90 | with: 91 | tag: "v${{ steps.meta.outputs.version }}" 92 | title: "v${{ steps.meta.outputs.version }}" 93 | token: ${{ secrets.REPO_ACCESS_TOKEN }} 94 | - 95 | name: Increment version variable 96 | uses: action-pack/bump@v2 97 | with: 98 | token: ${{ secrets.REPO_ACCESS_TOKEN }} 99 | - 100 | name: Push to Gitlab mirror 101 | uses: action-pack/gitlab-sync@v3 102 | with: 103 | url: ${{ secrets.GITLAB_URL }} 104 | token: ${{ secrets.GITLAB_TOKEN }} 105 | username: ${{ secrets.GITLAB_USERNAME }} 106 | - 107 | name: Send mail 108 | uses: action-pack/send-mail@v1 109 | with: 110 | to: ${{secrets.MAILTO}} 111 | from: Github Actions <${{secrets.MAILTO}}> 112 | connection_url: ${{secrets.MAIL_CONNECTION}} 113 | subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed 114 | body: | 115 | The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully! 116 | 117 | See https://github.com/${{ github.repository }}/actions for more information. 118 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | on: [workflow_call] 2 | name: "Check" 3 | permissions: {} 4 | 5 | jobs: 6 | shellcheck: 7 | name: shellcheck 8 | runs-on: ubuntu-latest 9 | steps: 10 | - 11 | name: Checkout 12 | uses: actions/checkout@v4 13 | - 14 | name: Run ShellCheck 15 | uses: ludeeus/action-shellcheck@master 16 | env: 17 | SHELLCHECK_OPTS: -x --source-path=src -e SC1091 -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 18 | - 19 | name: Lint Dockerfile 20 | uses: hadolint/hadolint-action@v3.1.0 21 | with: 22 | dockerfile: Dockerfile 23 | ignore: DL3008,DL3003,DL3035,DL3059 24 | failure-threshold: warning 25 | -------------------------------------------------------------------------------- /.github/workflows/hub.yml: -------------------------------------------------------------------------------- 1 | name: Update 2 | on: 3 | push: 4 | branches: 5 | - master 6 | paths: 7 | - readme.md 8 | - README.md 9 | - .github/workflows/hub.yml 10 | 11 | jobs: 12 | dockerHubDescription: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - 17 | name: Docker Hub Description 18 | uses: peter-evans/dockerhub-description@v4 19 | with: 20 | username: ${{ secrets.DOCKERHUB_USERNAME }} 21 | password: ${{ secrets.DOCKERHUB_TOKEN }} 22 | repository: ${{ secrets.DOCKERHUB_REPO }} 23 | short-description: ${{ github.event.repository.description }} 24 | readme-filepath: ./readme.md 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | pull_request: 4 | paths: 5 | - '**/*.sh' 6 | - 'Dockerfile' 7 | - '.github/workflows/test.yml' 8 | - '.github/workflows/check.yml' 9 | 10 | name: "Test" 11 | permissions: {} 12 | 13 | jobs: 14 | shellcheck: 15 | name: Test 16 | uses: ./.github/workflows/check.yml 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION_ARG="latest" 2 | 3 | FROM qemux/qemu:${VERSION_ARG} AS src 4 | FROM debian:trixie-slim 5 | 6 | ARG VERSION_ARG="0.0" 7 | ARG VERSION_VNC="1.6.0" 8 | 9 | ARG DEBCONF_NOWARNINGS="yes" 10 | ARG DEBIAN_FRONTEND="noninteractive" 11 | ARG DEBCONF_NONINTERACTIVE_SEEN="true" 12 | 13 | RUN set -eu && \ 14 | apt-get update && \ 15 | apt-get --no-install-recommends -y install \ 16 | bc \ 17 | jq \ 18 | tini \ 19 | wget \ 20 | 7zip \ 21 | curl \ 22 | fdisk \ 23 | nginx \ 24 | procps \ 25 | seabios \ 26 | iptables \ 27 | iproute2 \ 28 | apt-utils \ 29 | dnsmasq \ 30 | xz-utils \ 31 | net-tools \ 32 | e2fsprogs \ 33 | qemu-utils \ 34 | iputils-ping \ 35 | genisoimage \ 36 | ca-certificates \ 37 | qemu-system-arm && \ 38 | apt-get clean && \ 39 | mkdir -p /etc/qemu && \ 40 | echo "allow br0" > /etc/qemu/bridge.conf && \ 41 | wget "https://snapshot.debian.org/archive/debian/20250128T092032Z/pool/main/e/edk2/qemu-efi-aarch64_2024.11-5_all.deb" -O /tmp/aavmf.deb -q --timeout=10 && \ 42 | dpkg -i /tmp/aavmf.deb && \ 43 | mkdir -p /usr/share/novnc && \ 44 | wget "https://github.com/novnc/noVNC/archive/refs/tags/v${VERSION_VNC}.tar.gz" -O /tmp/novnc.tar.gz -q --timeout=10 && \ 45 | tar -xf /tmp/novnc.tar.gz -C /tmp/ && \ 46 | cd "/tmp/noVNC-${VERSION_VNC}" && \ 47 | mv app core vendor package.json *.html /usr/share/novnc && \ 48 | unlink /etc/nginx/sites-enabled/default && \ 49 | sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf && \ 50 | echo "$VERSION_ARG" > /run/version && \ 51 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 52 | 53 | COPY --from=src /run/*.sh /run 54 | COPY --from=src /var/www /var/www 55 | COPY --from=src /usr/share/novnc /usr/share/novnc 56 | COPY --from=src /etc/nginx/sites-enabled /etc/nginx/sites-enabled 57 | 58 | COPY --chmod=755 ./src /run/ 59 | 60 | VOLUME /storage 61 | EXPOSE 22 5900 8006 62 | 63 | ENV BOOT="alpine" 64 | ENV CPU_CORES="2" 65 | ENV RAM_SIZE="2G" 66 | ENV DISK_SIZE="16G" 67 | 68 | ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"] 69 | -------------------------------------------------------------------------------- /compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | qemu: 3 | container_name: qemu 4 | image: qemux/qemu-arm 5 | environment: 6 | BOOT: "alpine" 7 | devices: 8 | - /dev/kvm 9 | - /dev/net/tun 10 | cap_add: 11 | - NET_ADMIN 12 | ports: 13 | - 8006:8006 14 | volumes: 15 | - ./qemu:/storage 16 | restart: always 17 | stop_grace_period: 2m 18 | -------------------------------------------------------------------------------- /kubernetes.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: qemu-pvc 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 16Gi 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: qemu 17 | labels: 18 | name: qemu 19 | spec: 20 | replicas: 1 21 | selector: 22 | matchLabels: 23 | app: qemu 24 | template: 25 | metadata: 26 | labels: 27 | app: qemu 28 | spec: 29 | containers: 30 | - name: qemu 31 | image: qemux/qemu-arm 32 | env: 33 | - name: BOOT 34 | value: "alpine" 35 | - name: DISK_SIZE 36 | value: "16G" 37 | ports: 38 | - containerPort: 8006 39 | name: http 40 | protocol: TCP 41 | - containerPort: 5900 42 | name: vnc 43 | protocol: TCP 44 | securityContext: 45 | capabilities: 46 | add: 47 | - NET_ADMIN 48 | privileged: true 49 | volumeMounts: 50 | - mountPath: /storage 51 | name: storage 52 | - mountPath: /dev/kvm 53 | name: dev-kvm 54 | - mountPath: /dev/net/tun 55 | name: dev-tun 56 | terminationGracePeriodSeconds: 120 57 | volumes: 58 | - name: storage 59 | persistentVolumeClaim: 60 | claimName: qemu-pvc 61 | - hostPath: 62 | path: /dev/kvm 63 | name: dev-kvm 64 | - hostPath: 65 | path: /dev/net/tun 66 | type: CharDevice 67 | name: dev-tun 68 | --- 69 | apiVersion: v1 70 | kind: Service 71 | metadata: 72 | name: qemu 73 | spec: 74 | internalTrafficPolicy: Cluster 75 | ports: 76 | - name: http 77 | port: 8006 78 | protocol: TCP 79 | targetPort: 8006 80 | - name: vnc 81 | port: 5900 82 | protocol: TCP 83 | targetPort: 5900 84 | selector: 85 | app: qemu 86 | type: ClusterIP 87 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

QEMU ARM64
2 |
3 | 4 |
5 |
6 | 7 | [![Build]][build_url] 8 | [![Version]][tag_url] 9 | [![Size]][tag_url] 10 | [![Package]][pkg_url] 11 | [![Pulls]][hub_url] 12 | 13 |

14 | 15 | Docker container for running ARM-based virtual machines using QEMU, for devices like the Raspberry Pi 5 and many others. 16 | 17 | ## Features ✨ 18 | 19 | - Web-based viewer to control the machine directly from your browser 20 | 21 | - Supports `.iso`, `.img`, `.qcow2`, `.vhd`, `.vhdx`, `.vdi`, `.vmdk` and `.raw` disk formats 22 | 23 | - High-performance options (like KVM acceleration, kernel-mode networking, IO threading, etc.) to achieve near-native speed 24 | 25 | ## Usage 🐳 26 | 27 | ##### Via Docker Compose: 28 | 29 | ```yaml 30 | services: 31 | qemu: 32 | container_name: qemu 33 | image: qemux/qemu-arm 34 | environment: 35 | BOOT: "alpine" 36 | devices: 37 | - /dev/kvm 38 | - /dev/net/tun 39 | cap_add: 40 | - NET_ADMIN 41 | ports: 42 | - 8006:8006 43 | volumes: 44 | - ./qemu:/storage 45 | restart: always 46 | stop_grace_period: 2m 47 | ``` 48 | 49 | ##### Via Docker CLI: 50 | 51 | ```bash 52 | docker run -it --rm --name qemu -e "BOOT=alpine" -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/qemu:/storage" --stop-timeout 120 qemux/qemu-arm 53 | ``` 54 | 55 | ##### Via Kubernetes: 56 | 57 | ```shell 58 | kubectl apply -f https://raw.githubusercontent.com/qemus/qemu-arm/refs/heads/master/kubernetes.yml 59 | ``` 60 | 61 | ##### Via Github Codespaces: 62 | 63 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/qemus/qemu) 64 | 65 | ## FAQ 💬 66 | 67 | ### How do I use it? 68 | 69 | Very simple! These are the steps: 70 | 71 | - Set the `BOOT` variable to the [operating system](#how-do-i-select-the-operating-system) you want to install. 72 | 73 | - Start the container and connect to [port 8006](http://127.0.0.1:8006/) using your web browser. 74 | 75 | - You will see the screen and can now install the OS of your choice using your keyboard and mouse. 76 | 77 | Enjoy your brand new machine, and don't forget to star this repo! 78 | 79 | ### How do I select the operating system? 80 | 81 | You can use the `BOOT` environment variable in order to specify the operating system that will be downloaded: 82 | 83 | ```yaml 84 | environment: 85 | BOOT: "alpine" 86 | ``` 87 | Select from the values below: 88 | 89 | | **Value** | **Operating System** | **Size** | 90 | |---|---|---| 91 | | `alma` | Alma Linux | 1.7 GB | 92 | | `alpine` | Alpine Linux | 60 MB | 93 | | `cachy` | CachyOS | 2.6 GB | 94 | | `centos` | CentOS | 6.4 GB | 95 | | `debian` | Debian | 3.7 GB | 96 | | `fedora` | Fedora | 2.9 GB | 97 | | `gentoo` | Gentoo | 1.3 GB | 98 | | `kali` | Kali Linux | 3.4 GB | 99 | | `nixos` | NixOS | 2.4 GB | 100 | | `suse` | OpenSUSE | 1.0 GB | 101 | | `oracle` | Oracle Linux | 1.0 GB | 102 | | `rocky` | Rocky Linux | 1.9 GB | 103 | | `ubuntu` | Ubuntu Desktop | 3.3 GB | 104 | | `ubuntus` | Ubuntu Server | 2.7 GB | 105 | 106 | ### How can I use my own image? 107 | 108 | If you want to download an operating system that is not in the list above, you can set the `BOOT` variable to the URL of the image: 109 | 110 | ```yaml 111 | environment: 112 | BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-virt-3.19.1-aarch64.iso" 113 | ``` 114 | 115 | The `BOOT` URL accepts files in any of the following formats: 116 | 117 | | **Extension** | **Format** | 118 | |---|---| 119 | | `.img` | Raw | 120 | | `.raw` | Raw | 121 | | `.iso` | Optical | 122 | | `.qcow2` | QEMU | 123 | | `.vmdk` | VMware | 124 | | `.vhd` | VirtualPC | 125 | | `.vhdx` | Hyper-V | 126 | | `.vdi` | VirtualBox | 127 | 128 | It will also accept files such as `.img.gz`, `.qcow2.xz`, `.iso.zip` and many more, because it will automaticly extract compressed files. 129 | 130 | Alternatively you can use a local image file directly, by binding it in your compose file: 131 | 132 | ```yaml 133 | volumes: 134 | - ./example.iso:/boot.iso 135 | ``` 136 | 137 | This way you can supply either a `/boot.iso`, `/boot.img` or a `/boot.qcow2` file. The value of `BOOT` will be ignored in this case. 138 | 139 | ### How do I change the storage location? 140 | 141 | To change the storage location, include the following bind mount in your compose file: 142 | 143 | ```yaml 144 | volumes: 145 | - ./qemu:/storage 146 | ``` 147 | 148 | Replace the example path `./qemu` with the desired storage folder or named volume. 149 | 150 | ### How do I change the size of the disk? 151 | 152 | To expand the default size of 16 GB, add the `DISK_SIZE` setting to your compose file and set it to your preferred capacity: 153 | 154 | ```yaml 155 | environment: 156 | DISK_SIZE: "128G" 157 | ``` 158 | 159 | > [!TIP] 160 | > This can also be used to resize the existing disk to a larger capacity without any data loss. 161 | 162 | ### How do I change the amount of CPU or RAM? 163 | 164 | By default, the container will be allowed to use a maximum of 2 CPU cores and 2 GB of RAM. 165 | 166 | If you want to adjust this, you can specify the desired amount using the following environment variables: 167 | 168 | ```yaml 169 | environment: 170 | RAM_SIZE: "8G" 171 | CPU_CORES: "4" 172 | ``` 173 | 174 | ### How do I increase the display resolution? 175 | 176 | For maximum compatibility, the display output will be a simple framebuffer by default. While this isn't the most optimal, it doesn't require any drivers. 177 | 178 | If your guest OS bundles the `virtio-gpu` driver (as most Linux distributions do), you can add the following to your compose file: 179 | 180 | ```yaml 181 | environment: 182 | VGA: "virtio-gpu" 183 | ``` 184 | 185 | to add a virtual graphics cards to your machine that allows for higher resolutions. 186 | 187 | > [!NOTE] 188 | > Using this method your screen will stay black during the boot process, until the point where the driver is actually loaded. 189 | 190 | ### How do I boot Windows? 191 | 192 | Use [dockur/windows-arm](https://github.com/dockur/windows-arm) instead, as it includes all the drivers required during installation, amongst many other features. 193 | 194 | ### How do I boot x86/x64 images? 195 | 196 | You can use the [qemu](https://github.com/qemus/qemu/) container to run x86 and x64 images on ARM. 197 | 198 | ### How do I verify if my system supports KVM? 199 | 200 | First check if your software is compatible using this chart: 201 | 202 | | **Product** | **Linux** | **Win11** | **Win10** | **macOS** | 203 | |---|---|---|---|---| 204 | | Docker CLI | ✅ | ✅ | ❌ | ❌ | 205 | | Docker Desktop | ❌ | ✅ | ❌ | ❌ | 206 | | Podman CLI | ✅ | ✅ | ❌ | ❌ | 207 | | Podman Desktop | ✅ | ✅ | ❌ | ❌ | 208 | 209 | After that you can run the following commands in Linux to check your system: 210 | 211 | ```bash 212 | sudo apt install cpu-checker 213 | sudo kvm-ok 214 | ``` 215 | 216 | If you receive an error from `kvm-ok` indicating that KVM cannot be used, please check whether: 217 | 218 | - the virtualization extensions (`Intel VT-x` or `AMD SVM`) are enabled in your BIOS. 219 | 220 | - you enabled "nested virtualization" if you are running the container inside a virtual machine. 221 | 222 | - you are not using a cloud provider, as most of them do not allow nested virtualization for their VPS's. 223 | 224 | If you did not receive any error from `kvm-ok` but the container still complains about a missing KVM device, it could help to add `privileged: true` to your compose file (or `sudo` to your `docker` command) to rule out any permission issue. 225 | 226 | ### How do I expose network ports? 227 | 228 | You can expose ports just by adding them to your compose file. If you want to be able to connect to the SSH service of the machine for example, you would add it like this: 229 | 230 | ```yaml 231 | ports: 232 | - 2222:22 233 | ``` 234 | 235 | This will make port 2222 on your host redirect to port 22 of the virtual machine. 236 | 237 | ### How do I assign an individual IP address to the container? 238 | 239 | By default, the container uses bridge networking, which shares the IP address with the host. 240 | 241 | If you want to assign an individual IP address to the container, you can create a macvlan network as follows: 242 | 243 | ```bash 244 | docker network create -d macvlan \ 245 | --subnet=192.168.0.0/24 \ 246 | --gateway=192.168.0.1 \ 247 | --ip-range=192.168.0.100/28 \ 248 | -o parent=eth0 vlan 249 | ``` 250 | 251 | Be sure to modify these values to match your local subnet. 252 | 253 | Once you have created the network, change your compose file to look as follows: 254 | 255 | ```yaml 256 | services: 257 | qemu: 258 | container_name: qemu 259 | .... 260 | networks: 261 | vlan: 262 | ipv4_address: 192.168.0.100 263 | 264 | networks: 265 | vlan: 266 | external: true 267 | ``` 268 | 269 | An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default. 270 | 271 | > [!IMPORTANT] 272 | > This IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround. 273 | 274 | ### How can the VM acquire an IP address from my router? 275 | 276 | After configuring the container for [macvlan](#how-do-i-assign-an-individual-ip-address-to-the-container), it is possible for the VM to become part of your home network by requesting an IP from your router, just like a real PC. 277 | 278 | To enable this mode, in which the container and the VM will have separate IP addresses, add the following lines to your compose file: 279 | 280 | ```yaml 281 | environment: 282 | DHCP: "Y" 283 | devices: 284 | - /dev/vhost-net 285 | device_cgroup_rules: 286 | - 'c *:* rwm' 287 | ``` 288 | 289 | ### How do I add multiple disks? 290 | 291 | To create additional disks, modify your compose file like this: 292 | 293 | ```yaml 294 | environment: 295 | DISK2_SIZE: "32G" 296 | DISK3_SIZE: "64G" 297 | volumes: 298 | - ./example2:/storage2 299 | - ./example3:/storage3 300 | ``` 301 | 302 | ### How do I pass-through a disk? 303 | 304 | It is possible to pass-through disk devices or partitions directly by adding them to your compose file in this way: 305 | 306 | ```yaml 307 | devices: 308 | - /dev/sdb:/disk1 309 | - /dev/sdc1:/disk2 310 | ``` 311 | 312 | Use `/disk1` if you want it to become your main drive, and use `/disk2` and higher to add them as secondary drives. 313 | 314 | ### How do I pass-through a USB device? 315 | 316 | To pass-through a USB device, first lookup its vendor and product id via the `lsusb` command, then add them to your compose file like this: 317 | 318 | ```yaml 319 | environment: 320 | ARGUMENTS: "-device usb-host,vendorid=0x1234,productid=0x1234" 321 | devices: 322 | - /dev/bus/usb 323 | ``` 324 | 325 | ### How do I share files with the host? 326 | 327 | To share files with the host, first ensure that your guest OS has `9pfs` support compiled in or available as a kernel module. If so, add the following volume to your compose file: 328 | 329 | ```yaml 330 | volumes: 331 | - ./example:/shared 332 | ``` 333 | 334 | Then start the container and execute the following command in the guest: 335 | 336 | ```shell 337 | mount -t 9p -o trans=virtio shared /mnt/example 338 | ``` 339 | 340 | Now the `./example` directory on the host will be available as `/mnt/example` in the guest. 341 | 342 | ### How can I provide custom arguments to QEMU? 343 | 344 | You can create the `ARGUMENTS` environment variable to provide additional arguments to QEMU at runtime: 345 | 346 | ```yaml 347 | environment: 348 | ARGUMENTS: "-device usb-tablet" 349 | ``` 350 | 351 | If you want to see the full command-line arguments used, you can set: 352 | 353 | ```yaml 354 | environment: 355 | DEBUG: "Y" 356 | ``` 357 | 358 | ## Stars 🌟 359 | [![Stars](https://starchart.cc/qemus/qemu-arm.svg?variant=adaptive)](https://starchart.cc/qemus/qemu-arm) 360 | 361 | [build_url]: https://github.com/qemus/qemu-arm/ 362 | [hub_url]: https://hub.docker.com/r/qemux/qemu-arm/ 363 | [tag_url]: https://hub.docker.com/r/qemux/qemu-arm/tags 364 | [pkg_url]: https://github.com/qemus/qemu-arm/pkgs/container/qemu-arm 365 | 366 | [Build]: https://github.com/qemus/qemu-arm/actions/workflows/build.yml/badge.svg 367 | [Size]: https://img.shields.io/docker/image-size/qemux/qemu-arm/latest?color=066da5&label=size 368 | [Pulls]: https://img.shields.io/docker/pulls/qemux/qemu-arm.svg?style=flat&label=pulls&logo=docker 369 | [Version]: https://img.shields.io/docker/v/qemux/qemu-arm/latest?arch=arm64&sort=semver&color=066da5 370 | [Package]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2Fqemus%2Fqemu-arm%2Fqemu-arm.json&query=%24.downloads&logo=github&style=flat&color=066da5&label=pulls 371 | -------------------------------------------------------------------------------- /src/boot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | # Docker environment variables 5 | : "${BIOS:=""}" # BIOS file 6 | : "${SECURE:="off"}" # Secure boot 7 | 8 | BOOT_DESC="" 9 | BOOT_OPTS="" 10 | [ -n "$BIOS" ] && BOOT_MODE="custom" 11 | 12 | case "${BOOT_MODE,,}" in 13 | "uefi" | "" ) 14 | BOOT_MODE="uefi" 15 | ROM="AAVMF_CODE.no-secboot.fd" 16 | VARS="AAVMF_VARS.fd" 17 | ;; 18 | "secure" ) 19 | SECURE="on" 20 | BOOT_DESC=" securely" 21 | ROM="AAVMF_CODE.secboot.fd" 22 | VARS="AAVMF_VARS.fd" 23 | ;; 24 | "windows" ) 25 | ROM="AAVMF_CODE.no-secboot.fd" 26 | VARS="AAVMF_VARS.fd" 27 | BOOT_OPTS="-rtc base=localtime" 28 | ;; 29 | "windows_secure" ) 30 | SECURE="on" 31 | BOOT_DESC=" securely" 32 | ROM="AAVMF_CODE.ms.fd" 33 | VARS="AAVMF_VARS.ms.fd" 34 | BOOT_OPTS="-rtc base=localtime" 35 | ;; 36 | "legacy" ) 37 | BOOT_DESC=" with SeaBIOS" 38 | ;; 39 | "custom" ) 40 | BOOT_OPTS="-bios $BIOS" 41 | BOOT_DESC=" with custom BIOS file" 42 | ;; 43 | *) 44 | error "Unknown BOOT_MODE, value \"${BOOT_MODE}\" is not recognized!" 45 | exit 33 46 | ;; 47 | esac 48 | 49 | case "${BOOT_MODE,,}" in 50 | "uefi" | "secure" | "windows" | "windows_secure" ) 51 | 52 | AAVMF="/usr/share/AAVMF/" 53 | DEST="$STORAGE/${BOOT_MODE,,}" 54 | 55 | if [ ! -s "$DEST.rom" ] || [ ! -f "$DEST.rom" ]; then 56 | [ ! -s "$AAVMF/$ROM" ] || [ ! -f "$AAVMF/$ROM" ] && error "UEFI boot file ($AAVMF/$ROM) not found!" && exit 44 57 | rm -f "$DEST.rom" 58 | dd if=/dev/zero "of=$DEST.rom" bs=1M count=64 status=none 59 | dd "if=$AAVMF/$ROM" "of=$DEST.rom" conv=notrunc status=none 60 | fi 61 | 62 | if [ ! -s "$DEST.vars" ] || [ ! -f "$DEST.vars" ]; then 63 | [ ! -s "$AAVMF/$VARS" ] || [ ! -f "$AAVMF/$VARS" ] && error "UEFI vars file ($AAVMF/$VARS) not found!" && exit 45 64 | rm -f "$DEST.vars" 65 | dd if=/dev/zero "of=$DEST.vars" bs=1M count=64 status=none 66 | dd "if=$AAVMF/$VARS" "of=$DEST.vars" conv=notrunc status=none 67 | fi 68 | 69 | BOOT_OPTS+=" -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on" 70 | BOOT_OPTS+=" -drive file=$DEST.vars,if=pflash,unit=1,format=raw" 71 | 72 | ;; 73 | esac 74 | 75 | MSRS="/sys/module/kvm/parameters/ignore_msrs" 76 | if [ -e "$MSRS" ]; then 77 | result=$(<"$MSRS") 78 | result="${result//[![:print:]]/}" 79 | if [[ "$result" == "0" ]] || [[ "${result^^}" == "N" ]]; then 80 | echo 1 | tee "$MSRS" > /dev/null 2>&1 || true 81 | fi 82 | fi 83 | 84 | CLOCKSOURCE="tsc" 85 | [[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter" 86 | CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource" 87 | 88 | if [ ! -f "$CLOCK" ]; then 89 | warn "file \"$CLOCK\" cannot not found?" 90 | else 91 | result=$(<"$CLOCK") 92 | result="${result//[![:print:]]/}" 93 | case "${result,,}" in 94 | "${CLOCKSOURCE,,}" ) ;; 95 | "kvm-clock" ) info "Nested KVM virtualization detected.." ;; 96 | "hyperv_clocksource_tsc_page" ) info "Nested Hyper-V virtualization detected.." ;; 97 | "hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;; 98 | *) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;; 99 | esac 100 | fi 101 | 102 | SM_BIOS="" 103 | PS="/sys/class/dmi/id/product_serial" 104 | 105 | if [ -s "$PS" ] && [ -r "$PS" ]; then 106 | 107 | BIOS_SERIAL=$(<"$PS") 108 | BIOS_SERIAL="${BIOS_SERIAL//[![:alnum:]]/}" 109 | 110 | if [ -n "$BIOS_SERIAL" ]; then 111 | SM_BIOS="-smbios type=1,serial=$BIOS_SERIAL" 112 | fi 113 | 114 | fi 115 | 116 | return 0 117 | -------------------------------------------------------------------------------- /src/config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | : "${UUID:=""}" 5 | : "${SERIAL:="mon:stdio"}" 6 | : "${USB:="qemu-xhci,id=xhci,p2=7,p3=7"}" 7 | : "${MONITOR:="telnet:localhost:7100,server,nowait,nodelay"}" 8 | : "${SMP:="$CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"}" 9 | 10 | DEF_OPTS="-nodefaults" 11 | SERIAL_OPTS="-serial $SERIAL" 12 | CPU_OPTS="-cpu $CPU_FLAGS -smp $SMP" 13 | RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g') 14 | MON_OPTS="-monitor $MONITOR -name $PROCESS,process=$PROCESS,debug-threads=on" 15 | MAC_OPTS="-machine type=${MACHINE},secure=${SECURE},dump-guest-core=off${KVM_OPTS}" 16 | 17 | [ -n "$UUID" ] && MAC_OPTS+=" -uuid $UUID" 18 | [ -n "$SM_BIOS" ] && MAC_OPTS+=" $SM_BIOS" 19 | 20 | DEV_OPTS="-object rng-random,id=objrng0,filename=/dev/urandom" 21 | DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0" 22 | 23 | if [[ "${BOOT_MODE,,}" != "windows"* ]]; then 24 | DEV_OPTS+=" -device virtio-balloon-pci,id=balloon0,bus=pcie.0" 25 | fi 26 | 27 | if [ -d "/shared" ] && [[ "${BOOT_MODE,,}" != "windows"* ]]; then 28 | DEV_OPTS+=" -fsdev local,id=fsdev0,path=/shared,security_model=none" 29 | DEV_OPTS+=" -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=shared" 30 | fi 31 | 32 | [ -n "$USB" ] && [[ "${USB,,}" != "no"* ]] && USB_OPTS="-device $USB -device usb-kbd -device usb-tablet" 33 | 34 | ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS ${USB_OPTS:-} $NET_OPTS $DISK_OPTS $BOOT_OPTS $DEV_OPTS $ARGUMENTS" 35 | ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ') 36 | 37 | if [[ "${DISPLAY,,}" == "web" ]]; then 38 | [ ! -f "$INFO" ] && error "File $INFO not found?!" 39 | rm -f "$INFO" 40 | [ ! -f "$PAGE" ] && error "File $PAGE not found?!" 41 | rm -f "$PAGE" 42 | else 43 | if [[ "${DISPLAY,,}" == "vnc" ]]; then 44 | html "You can now connect to VNC on port 5900." "0" 45 | else 46 | html "The virtual machine was booted successfully." "0" 47 | fi 48 | fi 49 | 50 | # Check available memory as the very last step 51 | 52 | if [[ "$RAM_CHECK" != [Nn]* ]]; then 53 | 54 | RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}') 55 | AVAIL_MEM=$(formatBytes "$RAM_AVAIL") 56 | 57 | if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then 58 | msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of memory available, please set a lower value." 59 | [[ "${FS,,}" != "zfs" ]] && error "$msg" && exit 17 60 | info "$msg" 61 | else 62 | if (( (RAM_WANTED + (RAM_SPARE * 3)) > RAM_AVAIL )); then 63 | msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $AVAIL_MEM of memory available, please consider a lower value." 64 | if [[ "${FS,,}" != "zfs" ]]; then 65 | warn "$msg" 66 | else 67 | info "$msg" 68 | fi 69 | fi 70 | fi 71 | 72 | fi 73 | 74 | if [[ "$DEBUG" == [Yy1]* ]]; then 75 | printf "Arguments:\n\n%s\n\n" "${ARGS// -/$'\n-'}" 76 | fi 77 | 78 | return 0 79 | -------------------------------------------------------------------------------- /src/display.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | # Docker environment variables 5 | 6 | : "${VGA:="ramfb"}" # VGA adaptor 7 | : "${DISPLAY:="web"}" # Display type 8 | 9 | [[ "$DISPLAY" == ":0" ]] && DISPLAY="web" 10 | 11 | case "${DISPLAY,,}" in 12 | "vnc" ) 13 | DISPLAY_OPTS="-display vnc=:0 -device $VGA" 14 | ;; 15 | "web" ) 16 | DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device $VGA" 17 | ;; 18 | "ramfb" ) 19 | DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device ramfb" 20 | ;; 21 | "disabled" ) 22 | DISPLAY_OPTS="-display none -device $VGA" 23 | ;; 24 | "none" ) 25 | DISPLAY_OPTS="-display none" 26 | ;; 27 | *) 28 | DISPLAY_OPTS="-display $DISPLAY -device $VGA" 29 | ;; 30 | esac 31 | 32 | return 0 33 | -------------------------------------------------------------------------------- /src/entry.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | : "${APP:="QEMU"}" 5 | : "${MACHINE:="virt"}" 6 | : "${PLATFORM:="arm64"}" 7 | : "${SUPPORT:="https://github.com/qemus/qemu-arm"}" 8 | 9 | cd /run 10 | 11 | . utils.sh # Load functions 12 | . reset.sh # Initialize system 13 | . define.sh # Define images 14 | . install.sh # Download image 15 | . disk.sh # Initialize disks 16 | . display.sh # Initialize graphics 17 | . network.sh # Initialize network 18 | . boot.sh # Configure boot 19 | . proc.sh # Initialize processor 20 | . config.sh # Configure arguments 21 | 22 | trap - ERR 23 | 24 | version=$(qemu-system-aarch64 --version | head -n 1 | cut -d '(' -f 1 | awk '{ print $NF }') 25 | info "Booting image${BOOT_DESC} using QEMU v$version..." 26 | 27 | if [ -z "$CPU_PIN" ]; then 28 | exec qemu-system-aarch64 ${ARGS:+ $ARGS} 29 | else 30 | exec taskset -c "$CPU_PIN" qemu-system-aarch64 ${ARGS:+ $ARGS} 31 | fi 32 | -------------------------------------------------------------------------------- /src/proc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | # Docker environment variables 5 | 6 | : "${KVM:="Y"}" 7 | : "${CPU_PIN:=""}" 8 | : "${CPU_FLAGS:=""}" 9 | : "${CPU_MODEL:=""}" 10 | : "${DEF_MODEL:="neoverse-n1"}" 11 | 12 | if [[ "$CPU" == "Cortex A53" ]] && [[ "$CORES" == "6" ]]; then 13 | # Pin to performance cores on Rockchip Orange Pi 4 14 | [ -z "$CPU_PIN" ] && CPU_PIN="4,5" 15 | fi 16 | 17 | if [[ "$CPU" == "Cortex A55" ]] && [[ "$CORES" == "8" ]]; then 18 | # Pin to performance cores on Rockchip Orange Pi 5 19 | [ -z "$CPU_PIN" ] && CPU_PIN="4,5,6,7" 20 | fi 21 | 22 | if [[ "$CPU" == "Rockchip RK3588"* ]] && [[ "$CORES" == "8" ]]; then 23 | # Pin to performance cores on Rockchip Orange Pi 5 Plus 24 | [ -z "$CPU_PIN" ] && CPU_PIN="4,5,6,7" 25 | fi 26 | 27 | if [[ "${ARCH,,}" != "arm64" ]]; then 28 | KVM="N" 29 | warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for ARM64 instructions, this will cause a major loss of performance." 30 | fi 31 | 32 | if [[ "$KVM" != [Nn]* ]]; then 33 | 34 | KVM_ERR="" 35 | 36 | if [ ! -e /dev/kvm ]; then 37 | KVM_ERR="(/dev/kvm is missing)" 38 | else 39 | if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then 40 | KVM_ERR="(/dev/kvm is unwriteable)" 41 | fi 42 | fi 43 | 44 | if [ -n "$KVM_ERR" ]; then 45 | KVM="N" 46 | if [[ "$OSTYPE" =~ ^darwin ]]; then 47 | warn "you are using macOS which has no KVM support, this will cause a major loss of performance." 48 | else 49 | kernel=$(uname -a) 50 | case "${kernel,,}" in 51 | *"microsoft"* ) 52 | error "Please bind '/dev/kvm' as a volume in the optional container settings when using Docker Desktop." ;; 53 | *"synology"* ) 54 | error "Please make sure that Synology VMM (Virtual Machine Manager) is installed and that '/dev/kvm' is binded to this container." ;; 55 | *) 56 | error "KVM acceleration is not available $KVM_ERR, this will cause a major loss of performance." 57 | error "See the FAQ for possible causes, or continue without it by adding KVM: \"N\" (not recommended)." ;; 58 | esac 59 | [[ "$DEBUG" != [Yy1]* ]] && exit 88 60 | fi 61 | fi 62 | 63 | fi 64 | 65 | if [[ "$KVM" != [Nn]* ]]; then 66 | 67 | CPU_FEATURES="" 68 | KVM_OPTS=",accel=kvm -enable-kvm" 69 | 70 | if [ -z "$CPU_MODEL" ]; then 71 | CPU_MODEL="host" 72 | fi 73 | 74 | else 75 | 76 | CPU_FEATURES="" 77 | KVM_OPTS=" -accel tcg,thread=multi" 78 | 79 | if [ -z "$CPU_MODEL" ]; then 80 | if [[ "${ARCH,,}" == "arm64" ]]; then 81 | CPU_MODEL="max,pauth-impdef=on" 82 | else 83 | CPU_MODEL="$DEF_MODEL" 84 | fi 85 | fi 86 | 87 | if [[ "${BOOT_MODE,,}" == "windows" ]]; then 88 | MACHINE+=",virtualization=on" 89 | fi 90 | 91 | fi 92 | 93 | if [ -z "$CPU_FLAGS" ]; then 94 | if [ -z "$CPU_FEATURES" ]; then 95 | CPU_FLAGS="$CPU_MODEL" 96 | else 97 | CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES" 98 | fi 99 | else 100 | if [ -z "$CPU_FEATURES" ]; then 101 | CPU_FLAGS="$CPU_MODEL,$CPU_FLAGS" 102 | else 103 | CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS" 104 | fi 105 | fi 106 | 107 | return 0 108 | --------------------------------------------------------------------------------