Skip to content

Commit 9e28cb8

Browse files
committed
experimental support for riscv64
``` limactl start template://experimental/riscv64 ``` No support for containerd yet. Tested on macOS 12.3.1 Intel with QEMU 6.2.0_1 (Homebrew). Took 200 seconds to boot. Signed-off-by: Akihiro Suda <[email protected]>
1 parent dd7d59d commit 9e28cb8

File tree

10 files changed

+192
-41
lines changed

10 files changed

+192
-41
lines changed

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ binaries: clean \
2222
_output/bin/limactl \
2323
_output/bin/nerdctl.lima \
2424
_output/share/lima/lima-guestagent.Linux-x86_64 \
25-
_output/share/lima/lima-guestagent.Linux-aarch64
25+
_output/share/lima/lima-guestagent.Linux-aarch64 \
26+
_output/share/lima/lima-guestagent.Linux-riscv64
2627
cp -aL examples _output/share/lima
2728
mkdir -p _output/share/doc/lima
2829
cp -aL *.md LICENSE docs _output/share/doc/lima
@@ -55,6 +56,11 @@ _output/share/lima/lima-guestagent.Linux-aarch64:
5556
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 $(GO_BUILD) -o $@ ./cmd/lima-guestagent
5657
chmod 644 $@
5758

59+
.PHONY: _output/share/lima/lima-guestagent.Linux-riscv64
60+
_output/share/lima/lima-guestagent.Linux-riscv64:
61+
GOOS=linux GOARCH=riscv64 CGO_ENABLED=0 $(GO_BUILD) -o $@ ./cmd/lima-guestagent
62+
chmod 644 $@
63+
5864
.PHONY: diagrams
5965
diagrams: docs/lima-sequence-diagram.png
6066
docs/lima-sequence-diagram.png: docs/lima-sequence-diagram.puml

docs/internal.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ disk:
3636
- `basedisk`: the base image
3737
- `diffdisk`: the diff image (QCOW2)
3838

39+
kernel:
40+
- `kernel`: the kernel
41+
- `kernel.cmdline`: the kernel cmdline
42+
- `initrd`: the initrd
43+
3944
QEMU:
4045
- `qemu.pid`: QEMU PID
4146
- `qmp.sock`: QMP socket

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Others:
3535
- [`vmnet.yaml`](./vmnet.yaml): ⭐enable [`vmnet.framework`](../docs/network.md)
3636
- [`deprecated/centos-7.yaml`](./deprecated/centos-7.yaml): [deprecated] CentOS 7
3737
- [`experimental/9p.yaml`](experimental/9p.yaml): [experimental] use 9p mount type
38+
- [`experimental/riscv64.yaml`](experimental/riscv64.yaml): [experimental] RISC-V
3839

3940
## Tier 1
4041

examples/experimental/riscv64.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This example requires Lima v0.11.0 or later.
2+
3+
arch: "riscv64"
4+
images:
5+
- location: "https://cloud-images.ubuntu.com/releases/22.04/release-20220420/ubuntu-22.04-server-cloudimg-riscv64.img"
6+
digest: "sha256:6315140c5f6ab773bf135cff84c565ddaa21be25f80f845826bfb1c7df739417"
7+
kernel:
8+
# Extracted from http://http.us.debian.org/debian/pool/main/u/u-boot/u-boot-qemu_2022.04+dfsg-2_all.deb (GPL-2.0)
9+
location: "https://github.com/lima-vm/u-boot-qemu-mirror/releases/download/2022.04%2Bdfsg-2/qemu-riscv64_smode_uboot.elf"
10+
digest: "sha256:d250ede9b4d0ea1871714395edd38a7eb2bc8425b697673cfd15e62e7ee4529c"
11+
12+
mounts:
13+
- location: "~"
14+
- location: "/tmp/lima"
15+
writable: true
16+
mountType: "9p"
17+
18+
# We do not have riscv64 binaries of containerd
19+
containerd:
20+
system: false
21+
user: false

pkg/limayaml/defaults.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func defaultContainerdArchives() []File {
4545
Arch: AARCH64,
4646
Digest: "sha256:d07c5213a6789eb1d3d07febaa982a043611e8205264066388c43317924cf446",
4747
},
48+
// No riscv64
4849
}
4950
}
5051

@@ -89,12 +90,19 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
8990
if img.Arch == "" {
9091
img.Arch = *y.Arch
9192
}
93+
if img.Kernel != nil && img.Kernel.Arch == "" {
94+
img.Kernel.Arch = img.Arch
95+
}
96+
if img.Initrd != nil && img.Initrd.Arch == "" {
97+
img.Initrd.Arch = img.Arch
98+
}
9299
}
93100

94101
cpuType := map[Arch]string{
95102
AARCH64: "cortex-a72",
96103
// Since https://github.com/lima-vm/lima/pull/494, we use qemu64 cpu for better emulation of x86_64.
97-
X8664: "qemu64",
104+
X8664: "qemu64",
105+
RISCV64: "rv64", // FIXME: what is the right choice for riscv64?
98106
}
99107
for arch := range cpuType {
100108
if IsNativeArch(arch) {
@@ -563,6 +571,8 @@ func NewArch(arch string) Arch {
563571
return X8664
564572
case "arm64":
565573
return AARCH64
574+
case "riscv64":
575+
return RISCV64
566576
default:
567577
logrus.Warnf("Unknown arch: %s", arch)
568578
return arch
@@ -579,7 +589,8 @@ func ResolveArch(s *string) Arch {
579589
func IsNativeArch(arch Arch) bool {
580590
nativeX8664 := arch == X8664 && runtime.GOARCH == "amd64"
581591
nativeAARCH64 := arch == AARCH64 && runtime.GOARCH == "arm64"
582-
return nativeX8664 || nativeAARCH64
592+
nativeRISCV64 := arch == RISCV64 && runtime.GOARCH == "riscv64"
593+
return nativeX8664 || nativeAARCH64 || nativeRISCV64
583594
}
584595

585596
func Cname(host string) string {

pkg/limayaml/defaults_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func TestFillDefault(t *testing.T) {
5151
CPUType: map[Arch]string{
5252
AARCH64: "cortex-a72",
5353
X8664: "qemu64",
54+
RISCV64: "rv64",
5455
},
5556
CPUs: pointer.Int(4),
5657
Memory: pointer.String("4GiB"),
@@ -211,6 +212,7 @@ func TestFillDefault(t *testing.T) {
211212
CPUType: map[Arch]string{
212213
AARCH64: "arm64",
213214
X8664: "amd64",
215+
RISCV64: "riscv64",
214216
},
215217
CPUs: pointer.Int(7),
216218
Memory: pointer.String("5GiB"),
@@ -351,6 +353,7 @@ func TestFillDefault(t *testing.T) {
351353
CPUType: map[Arch]string{
352354
AARCH64: "uber-arm",
353355
X8664: "pentium",
356+
RISCV64: "sifive-u54",
354357
},
355358
CPUs: pointer.Int(12),
356359
Memory: pointer.String("7GiB"),

pkg/limayaml/limayaml.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
type LimaYAML struct {
1010
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty"`
11-
Images []File `yaml:"images" json:"images"` // REQUIRED
11+
Images []Image `yaml:"images" json:"images"` // REQUIRED
1212
CPUType map[Arch]string `yaml:"cpuType,omitempty" json:"cpuType,omitempty"`
1313
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty"`
1414
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes
@@ -39,6 +39,7 @@ type MountType = string
3939
const (
4040
X8664 Arch = "x86_64"
4141
AARCH64 Arch = "aarch64"
42+
RISCV64 Arch = "riscv64"
4243

4344
REVSSHFS MountType = "reverse-sshfs"
4445
NINEP MountType = "9p"
@@ -50,6 +51,17 @@ type File struct {
5051
Digest digest.Digest `yaml:"digest,omitempty" json:"digest,omitempty"`
5152
}
5253

54+
type Kernel struct {
55+
File `yaml:",inline"`
56+
Cmdline string `yaml:"cmdline,omitempty" json:"cmdline,omitempty"`
57+
}
58+
59+
type Image struct {
60+
File `yaml:",inline"`
61+
Kernel *Kernel `yaml:"kernel,omitempty" json:"kernel,omitempty"`
62+
Initrd *File `yaml:"initrd,omitempty" json:"initrd,omitempty"`
63+
}
64+
5365
type Mount struct {
5466
Location string `yaml:"location" json:"location"` // REQUIRED
5567
Writable *bool `yaml:"writable,omitempty" json:"writable,omitempty"`

pkg/limayaml/validate.go

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,41 +18,69 @@ import (
1818
"github.com/sirupsen/logrus"
1919
)
2020

21+
func validateFileObject(f File, fieldName string) error {
22+
if !strings.Contains(f.Location, "://") {
23+
if _, err := localpathutil.Expand(f.Location); err != nil {
24+
return fmt.Errorf("field `%s.location` refers to an invalid local file path: %q: %w", fieldName, f.Location, err)
25+
}
26+
// f.Location does NOT need to be accessible, so we do NOT check os.Stat(f.Location)
27+
}
28+
switch f.Arch {
29+
case X8664, AARCH64, RISCV64:
30+
default:
31+
return fmt.Errorf("field `arch` must be %q, %q, or %q; got %q", X8664, AARCH64, RISCV64, f.Arch)
32+
}
33+
if f.Digest != "" {
34+
if !f.Digest.Algorithm().Available() {
35+
return fmt.Errorf("field `%s.digest` refers to an unavailable digest algorithm", fieldName)
36+
}
37+
if err := f.Digest.Validate(); err != nil {
38+
return fmt.Errorf("field `%s.digest` is invalid: %s: %w", fieldName, f.Digest.String(), err)
39+
}
40+
}
41+
return nil
42+
}
43+
2144
func Validate(y LimaYAML, warn bool) error {
2245
switch *y.Arch {
23-
case X8664, AARCH64:
46+
case X8664, AARCH64, RISCV64:
2447
default:
25-
return fmt.Errorf("field `arch` must be %q or %q , got %q", X8664, AARCH64, *y.Arch)
48+
return fmt.Errorf("field `arch` must be %q, %q, or %q; got %q", X8664, AARCH64, RISCV64, *y.Arch)
2649
}
2750

2851
if len(y.Images) == 0 {
2952
return errors.New("field `images` must be set")
3053
}
3154
for i, f := range y.Images {
32-
if !strings.Contains(f.Location, "://") {
33-
if _, err := localpathutil.Expand(f.Location); err != nil {
34-
return fmt.Errorf("field `images[%d].location` refers to an invalid local file path: %q: %w", i, f.Location, err)
35-
}
36-
// f.Location does NOT need to be accessible, so we do NOT check os.Stat(f.Location)
55+
if err := validateFileObject(f.File, fmt.Sprintf("images[%d]", i)); err != nil {
56+
return err
3757
}
38-
switch f.Arch {
39-
case X8664, AARCH64:
40-
default:
41-
return fmt.Errorf("field `images.arch` must be %q or %q, got %q", X8664, AARCH64, f.Arch)
58+
if f.Kernel != nil {
59+
if err := validateFileObject(f.Kernel.File, fmt.Sprintf("images[%d].kernel", i)); err != nil {
60+
return err
61+
}
62+
if f.Kernel.Arch != *y.Arch {
63+
return fmt.Errorf("images[%d].kernel has unexpected architecture %q, must be %q", i, f.Kernel.Arch, *y.Arch)
64+
}
65+
} else if f.Arch == RISCV64 {
66+
return errors.New("riscv64 needs the kernel (e.g., \"uboot.elf\") to be specified")
4267
}
43-
if f.Digest != "" {
44-
if !f.Digest.Algorithm().Available() {
45-
return fmt.Errorf("field `images[%d].digest` refers to an unavailable digest algorithm", i)
68+
if f.Initrd != nil {
69+
if err := validateFileObject(*f.Initrd, fmt.Sprintf("images[%d].initrd", i)); err != nil {
70+
return err
71+
}
72+
if f.Kernel == nil {
73+
return errors.New("initrd requires the kernel to be specified")
4674
}
47-
if err := f.Digest.Validate(); err != nil {
48-
return fmt.Errorf("field `images[%d].digest` is invalid: %s: %w", i, f.Digest.String(), err)
75+
if f.Initrd.Arch != *y.Arch {
76+
return fmt.Errorf("images[%d].initrd has unexpected architecture %q, must be %q", i, f.Initrd.Arch, *y.Arch)
4977
}
5078
}
5179
}
5280

5381
for arch := range y.CPUType {
5482
switch arch {
55-
case AARCH64, X8664:
83+
case AARCH64, X8664, RISCV64:
5684
// these are the only supported architectures
5785
default:
5886
return fmt.Errorf("field `cpuType` uses unsupported arch %q", arch)

0 commit comments

Comments
 (0)