Skip to content

Commit eec5682

Browse files
authored
Merge pull request #80 from AkihiroSuda/dev-override-qemu
2 parents 2405f30 + cb03fda commit eec5682

File tree

6 files changed

+137
-14
lines changed

6 files changed

+137
-14
lines changed

docs/internal.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ The directory contains the following files:
5959
- `$LIMA_INSTANCE`: `lima ...` is expanded to `limactl shell ${LIMA_INSTANCE} ...`.
6060
- Default : `default`
6161

62+
- `$QEMU_SYSTEM_X86_64`: path of `qemu-system-x86_64`
63+
- Default: `qemu-system-x86_64` in `$PATH`
64+
65+
- `$QEMU_SYSTEM_AARCH64`: path of `qemu-system-aarch64`
66+
- Default: `qemu-system-aarch64` in `$PATH`
67+
6268
## `cidata.iso`
6369
`cidata.iso` contains the following files:
6470

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/gorilla/mux v1.8.0
1515
github.com/hashicorp/go-multierror v1.1.1
1616
github.com/mattn/go-isatty v0.0.13
17+
github.com/mattn/go-shellwords v1.0.12
1718
github.com/norouter/norouter v0.6.3
1819
github.com/nxadm/tail v1.4.8
1920
github.com/pkg/errors v0.9.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,8 @@ github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1y
496496
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
497497
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
498498
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
499+
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
500+
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
499501
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
500502
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
501503
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=

pkg/hostagent/hostagent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ func (a *HostAgent) Run(ctx context.Context) error {
133133
if err != nil {
134134
return err
135135
}
136-
defer logPipeRoutine(a.l, qStdout, "qemu[stdout]")
136+
go logPipeRoutine(a.l, qStdout, "qemu[stdout]")
137137
qStderr, err := qCmd.StderrPipe()
138138
if err != nil {
139139
return err
140140
}
141-
defer logPipeRoutine(a.l, qStderr, "qemu[stderr]")
141+
go logPipeRoutine(a.l, qStderr, "qemu[stderr]")
142142

143143
a.l.Infof("Starting QEMU (hint: to watch the boot progress, see %q)", filepath.Join(a.instDir, filenames.SerialLog))
144144
a.l.Debugf("qCmd.Args: %v", qCmd.Args)

pkg/qemu/qemu.go

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import (
77
"path/filepath"
88
"runtime"
99
"strconv"
10+
"strings"
1011

1112
"github.com/AkihiroSuda/lima/pkg/downloader"
1213
"github.com/AkihiroSuda/lima/pkg/iso9660util"
1314
"github.com/AkihiroSuda/lima/pkg/limayaml"
1415
"github.com/AkihiroSuda/lima/pkg/store/filenames"
1516
"github.com/docker/go-units"
17+
"github.com/mattn/go-shellwords"
1618
"github.com/pkg/errors"
1719
"github.com/sirupsen/logrus"
1820
)
@@ -81,38 +83,80 @@ func EnsureDisk(cfg Config) error {
8183
return nil
8284
}
8385

86+
func argValue(args []string, key string) (string, bool) {
87+
if !strings.HasPrefix(key, "-") {
88+
panic(errors.Errorf("got unexpected key %q", key))
89+
}
90+
for i, s := range args {
91+
if s == key {
92+
if i == len(args)-1 {
93+
return "", true
94+
}
95+
value := args[i+1]
96+
if strings.HasPrefix(value, "-") {
97+
return "", true
98+
}
99+
return value, true
100+
}
101+
}
102+
return "", false
103+
}
104+
105+
// appendArgsIfNoConflict can be used for: -cpu, -machine, -m, -boot ...
106+
// appendArgsIfNoConflict cannot be used for: -drive, -cdrom, ...
107+
func appendArgsIfNoConflict(args []string, k, v string) []string {
108+
if !strings.HasPrefix(k, "-") {
109+
panic(errors.Errorf("got unexpected key %q", k))
110+
}
111+
switch k {
112+
case "-drive", "-cdrom", "-chardev", "-blockdev", "-netdev", "-device":
113+
panic(errors.Errorf("appendArgsIfNoConflict() must not be called with k=%q", k))
114+
}
115+
116+
if v == "" {
117+
if _, ok := argValue(args, k); ok {
118+
return args
119+
}
120+
return append(args, k)
121+
}
122+
123+
if origV, ok := argValue(args, k); ok {
124+
logrus.Warnf("Not adding QEMU argument %q %q, as it conflicts with %q %q", k, v, k, origV)
125+
return args
126+
}
127+
return append(args, k, v)
128+
}
129+
84130
func Cmdline(cfg Config) (string, []string, error) {
85131
y := cfg.LimaYAML
86-
exeBase := "qemu-system-" + y.Arch
87-
exe, err := exec.LookPath(exeBase)
132+
exe, args, err := getExe(y.Arch)
88133
if err != nil {
89134
return "", nil, err
90135
}
91-
var args []string
92136

93137
// Architecture
94138
accel := getAccel(y.Arch)
95139
switch y.Arch {
96140
case limayaml.X8664:
97141
// NOTE: "-cpu host" seems to cause kernel panic
98142
// (MacBookPro 2020, Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz, macOS 11.3, Ubuntu 21.04)
99-
args = append(args, "-cpu", "Haswell-v4")
100-
args = append(args, "-machine", "q35,accel="+accel)
143+
args = appendArgsIfNoConflict(args, "-cpu", "Haswell-v4")
144+
args = appendArgsIfNoConflict(args, "-machine", "q35,accel="+accel)
101145
case limayaml.AARCH64:
102-
args = append(args, "-cpu", "cortex-a72")
103-
args = append(args, "-machine", "virt,accel="+accel+",highmem=off")
146+
args = appendArgsIfNoConflict(args, "-cpu", "cortex-a72")
147+
args = appendArgsIfNoConflict(args, "-machine", "virt,accel="+accel+",highmem=off")
104148
}
105149

106150
// SMP
107-
args = append(args, "-smp",
151+
args = appendArgsIfNoConflict(args, "-smp",
108152
fmt.Sprintf("%d,sockets=1,cores=%d,threads=1", y.CPUs, y.CPUs))
109153

110154
// Memory
111155
memBytes, err := units.RAMInBytes(y.Memory)
112156
if err != nil {
113157
return "", nil, err
114158
}
115-
args = append(args, "-m", strconv.Itoa(int(memBytes>>20)))
159+
args = appendArgsIfNoConflict(args, "-m", strconv.Itoa(int(memBytes>>20)))
116160

117161
// Firmware
118162
if !y.Firmware.LegacyBIOS {
@@ -132,10 +176,10 @@ func Cmdline(cfg Config) (string, []string, error) {
132176
return "", nil, err
133177
}
134178
if isBaseDiskCDROM {
135-
args = append(args, "-boot", "order=d,splash-time=0,menu=on")
179+
args = appendArgsIfNoConflict(args, "-boot", "order=d,splash-time=0,menu=on")
136180
args = append(args, "-drive", fmt.Sprintf("file=%s,media=cdrom,readonly=on", baseDisk))
137181
} else {
138-
args = append(args, "-boot", "order=c,splash-time=0,menu=on")
182+
args = appendArgsIfNoConflict(args, "-boot", "order=c,splash-time=0,menu=on")
139183
}
140184
if diskSize, _ := units.RAMInBytes(cfg.LimaYAML.Disk); diskSize > 0 {
141185
args = append(args, "-drive", fmt.Sprintf("file=%s,if=virtio", diffDisk))
@@ -156,7 +200,7 @@ func Cmdline(cfg Config) (string, []string, error) {
156200

157201
// Graphics
158202
if y.Video.Display != "" {
159-
args = append(args, "-display", y.Video.Display)
203+
args = appendArgsIfNoConflict(args, "-display", y.Video.Display)
160204
}
161205
switch y.Arch {
162206
case limayaml.X8664:
@@ -205,6 +249,27 @@ func Cmdline(cfg Config) (string, []string, error) {
205249
return exe, args, nil
206250
}
207251

252+
func getExe(arch limayaml.Arch) (string, []string, error) {
253+
exeBase := "qemu-system-" + arch
254+
var args []string
255+
envK := "QEMU_SYSTEM_" + strings.ToUpper(arch)
256+
if envV := os.Getenv(envK); envV != "" {
257+
ss, err := shellwords.Parse(envV)
258+
if err != nil {
259+
return "", nil, errors.Wrapf(err, "failed to parse %s value %q", envK, envV)
260+
}
261+
exeBase, args = ss[0], ss[1:]
262+
if len(args) != 0 {
263+
logrus.Warnf("Specifying args (%v) via $%s is supported only for debugging!", args, envK)
264+
}
265+
}
266+
exe, err := exec.LookPath(exeBase)
267+
if err != nil {
268+
return "", nil, err
269+
}
270+
return exe, args, nil
271+
}
272+
208273
func getAccel(arch limayaml.Arch) string {
209274
nativeX8664 := arch == limayaml.X8664 && runtime.GOARCH == "amd64"
210275
nativeAARCH64 := arch == limayaml.AARCH64 && runtime.GOARCH == "arm64"

pkg/qemu/qemu_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package qemu
2+
3+
import (
4+
"testing"
5+
6+
"gotest.tools/v3/assert"
7+
)
8+
9+
func TestArgValue(t *testing.T) {
10+
type testCase struct {
11+
key string
12+
expectedValue string
13+
expectedOK bool
14+
}
15+
args := []string{"-cpu", "foo", "-no-reboot", "-m", "2G", "-s"}
16+
testCases := []testCase{
17+
{
18+
key: "-cpu",
19+
expectedValue: "foo",
20+
expectedOK: true,
21+
},
22+
{
23+
key: "-no-reboot",
24+
expectedValue: "",
25+
expectedOK: true,
26+
},
27+
{
28+
key: "-m",
29+
expectedValue: "2G",
30+
expectedOK: true,
31+
},
32+
{
33+
key: "-machine",
34+
expectedValue: "",
35+
expectedOK: false,
36+
},
37+
{
38+
key: "-s",
39+
expectedValue: "",
40+
expectedOK: true,
41+
},
42+
}
43+
44+
for _, tc := range testCases {
45+
v, ok := argValue(args, tc.key)
46+
assert.Equal(t, tc.expectedValue, v)
47+
assert.Equal(t, tc.expectedOK, ok)
48+
}
49+
}

0 commit comments

Comments
 (0)