docs: document riscv64 kernel flavor and virt machine

This commit is contained in:
2026-09-21 01:03:21 +02:00
parent 810bf50814
commit 12f771d326
2 changed files with 9 additions and 4 deletions
+3 -3
View File
@@ -88,7 +88,7 @@ ecr [OPTIONS] <DISTRO[:VERSION]> [-- COMMAND...]
| `--no-cache` | Force a fresh download, bypassing the cache | | `--no-cache` | Force a fresh download, bypassing the cache |
| `-v, --verbose` | Print diagnostic output (URLs, layer info, extraction steps) | | `-v, --verbose` | Print diagnostic output (URLs, layer info, extraction steps) |
| `-a, --arch <ARCH>` | Target architecture (`amd64`, `arm64`, `armhf`, `riscv64`, …) | | `-a, --arch <ARCH>` | Target architecture (`amd64`, `arm64`, `armhf`, `riscv64`, …) |
| `--kernel[=PATH]` | Boot with QEMU system emulation. Downloads Alpine's `linux-virt` kernel if no `=PATH` given | | `--kernel[=PATH]` | Boot with QEMU system emulation. Downloads Alpine's default kernel if no `=PATH` given (`linux-virt`, or `linux-lts` on riscv64 where the virt flavor is not built) |
| `-m, --memory <SIZE>` | Memory for QEMU VM (default: 2G, only with `--kernel`) | | `-m, --memory <SIZE>` | Memory for QEMU VM (default: 2G, only with `--kernel`) |
## Examples ## Examples
@@ -124,7 +124,7 @@ ecr --kernel --memory 4G alpine
When `--kernel` is specified, ecr boots the rootfs in a full QEMU virtual machine instead of using namespaces: When `--kernel` is specified, ecr boots the rootfs in a full QEMU virtual machine instead of using namespaces:
```sh ```sh
# Auto-download Alpine's linux-virt kernel (recommended) # Auto-download Alpine's default kernel (recommended)
ecr --kernel alpine ecr --kernel alpine
# Use your own kernel # Use your own kernel
@@ -133,7 +133,7 @@ ecr --kernel=/boot/vmlinuz ubuntu
This mode: This mode:
- Creates an uncompressed CPIO initramfs from the rootfs (streamed to disk) - Creates an uncompressed CPIO initramfs from the rootfs (streamed to disk)
- Boots QEMU with your kernel (or auto-downloads Alpine's `linux-virt` kernel) - Boots QEMU with your kernel (or auto-downloads Alpine's default kernel: `linux-virt`, falling back to `linux-lts` on riscv64 where the virt flavor is not built; the downloaded image is stored decompressed so QEMU can load it)
- Provides full VM isolation - Provides full VM isolation
- Works for any architecture (no binfmt_misc needed) - Works for any architecture (no binfmt_misc needed)
- Caches the default kernel in `~/.cache/ecr/` - Caches the default kernel in `~/.cache/ecr/`
+6 -1
View File
@@ -80,7 +80,7 @@ ecr [OPTIONS] <DISTRO[:VERSION]> -- [COMMAND]...
| `--bind-rw <path>` | none | Read-write bind mount at `/mnt/<basename>` (can be specified multiple times, overrides `--bind` for same path) | | `--bind-rw <path>` | none | Read-write bind mount at `/mnt/<basename>` (can be specified multiple times, overrides `--bind` for same path) |
| `--no-cache` | false | Download fresh tarball, ignore cache | | `--no-cache` | false | Download fresh tarball, ignore cache |
| `--no-bind` | false | Skip mounting any directory | | `--no-bind` | false | Skip mounting any directory |
| `--kernel[=PATH]` | none | Boot with QEMU system emulation; downloads the default Alpine `linux-virt` kernel when no `=PATH` is given | | `--kernel[=PATH]` | none | Boot with QEMU system emulation; downloads the default Alpine kernel when no `=PATH` is given (`linux-virt`, falling back to `linux-lts` on architectures without a virt flavor, e.g. riscv64) |
| `-m, --memory <size>` | 2G | Memory size for QEMU VM (only used with `--kernel`) | | `-m, --memory <size>` | 2G | Memory size for QEMU VM (only used with `--kernel`) |
| `-v, --verbose` | false | Print diagnostic messages | | `-v, --verbose` | false | Print diagnostic messages |
| `-h, --help` | - | Show help | | `-h, --help` | - | Show help |
@@ -274,6 +274,7 @@ ecr --kernel=/boot/vmlinuz debian -- /bin/sh -c "echo hello"
2. Extract tarball to temporary directory 2. Extract tarball to temporary directory
3. Create uncompressed CPIO initramfs from rootfs (streamed to disk), including essential device nodes (/dev/ttyS0, /dev/null, /dev/tty) and an `/init` script that mounts proc/sys/dev, sets the hostname, execs the requested command argv verbatim (each argv element base64-encoded in the cmdline as `ECR_ARGV`), and powers off on exit 3. Create uncompressed CPIO initramfs from rootfs (streamed to disk), including essential device nodes (/dev/ttyS0, /dev/null, /dev/tty) and an `/init` script that mounts proc/sys/dev, sets the hostname, execs the requested command argv verbatim (each argv element base64-encoded in the cmdline as `ECR_ARGV`), and powers off on exit
4. Launch QEMU with: 4. Launch QEMU with:
- `-machine virt` on riscv64 only - qemu-system-riscv64's default machine is `spike`, which has neither a PCI bus (virtio-net-pci fails) nor a 16550 UART (console output is lost); `virt` has both plus bundled OpenSBI firmware
- `-kernel <path>` - provided (or downloaded) kernel - `-kernel <path>` - provided (or downloaded) kernel
- `-initrd initramfs.cpio` - rootfs as initramfs - `-initrd initramfs.cpio` - rootfs as initramfs
- `-append "console=ttyS0 [quiet] ECR_SHELL=... [ECR_ARGV=...] ECR_HOSTNAME=..."` - kernel command line (`quiet` unless `-v`) - `-append "console=ttyS0 [quiet] ECR_SHELL=... [ECR_ARGV=...] ECR_HOSTNAME=..."` - kernel command line (`quiet` unless `-v`)
@@ -284,6 +285,10 @@ ecr --kernel=/boot/vmlinuz debian -- /bin/sh -c "echo hello"
5. Wait for QEMU to exit (init powers the VM off when the command/shell exits; `-no-reboot` makes QEMU terminate) 5. Wait for QEMU to exit (init powers the VM off when the command/shell exits; `-no-reboot` makes QEMU terminate)
6. Cleanup temporary files 6. Cleanup temporary files
### Default Kernel Download
The default kernel (`--kernel` without `=PATH`) comes from Alpine's `main` repository. `linux-virt` is preferred; where it is not built (riscv64), the index lookup falls back to `linux-lts`. Some architectures package their kernel image gzipped (riscv64, aarch64 ship `Image.gz`), and QEMU's riscv `-kernel` loader understands only ELF, uImage and raw images, so the cached kernel is stored decompressed (gzip magic `1f 8b` detected and gunzipped at download time).
### Initramfs Creation ### Initramfs Creation
The rootfs directory is converted to an uncompressed CPIO archive (newc format) using the `cpio` crate, streamed entry by entry so large rootfs images never need to fit in memory. Hard links are preserved: the first occurrence of a (device, inode) pair carries the data with a synthetic inode, subsequent occurrences are zero-size entries sharing that inode, which the kernel's initramfs loader turns into real hard links. The rootfs directory is converted to an uncompressed CPIO archive (newc format) using the `cpio` crate, streamed entry by entry so large rootfs images never need to fit in memory. Hard links are preserved: the first occurrence of a (device, inode) pair carries the data with a synthetic inode, subsequent occurrences are zero-size entries sharing that inode, which the kernel's initramfs loader turns into real hard links.