├── .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 | [](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 | [](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 |
--------------------------------------------------------------------------------