@@ -7,12 +7,14 @@ import (
7
7
"path/filepath"
8
8
"runtime"
9
9
"strconv"
10
+ "strings"
10
11
11
12
"github.com/AkihiroSuda/lima/pkg/downloader"
12
13
"github.com/AkihiroSuda/lima/pkg/iso9660util"
13
14
"github.com/AkihiroSuda/lima/pkg/limayaml"
14
15
"github.com/AkihiroSuda/lima/pkg/store/filenames"
15
16
"github.com/docker/go-units"
17
+ "github.com/mattn/go-shellwords"
16
18
"github.com/pkg/errors"
17
19
"github.com/sirupsen/logrus"
18
20
)
@@ -81,38 +83,80 @@ func EnsureDisk(cfg Config) error {
81
83
return nil
82
84
}
83
85
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
+
84
130
func Cmdline (cfg Config ) (string , []string , error ) {
85
131
y := cfg .LimaYAML
86
- exeBase := "qemu-system-" + y .Arch
87
- exe , err := exec .LookPath (exeBase )
132
+ exe , args , err := getExe (y .Arch )
88
133
if err != nil {
89
134
return "" , nil , err
90
135
}
91
- var args []string
92
136
93
137
// Architecture
94
138
accel := getAccel (y .Arch )
95
139
switch y .Arch {
96
140
case limayaml .X8664 :
97
141
// NOTE: "-cpu host" seems to cause kernel panic
98
142
// (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 )
101
145
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" )
104
148
}
105
149
106
150
// SMP
107
- args = append (args , "-smp" ,
151
+ args = appendArgsIfNoConflict (args , "-smp" ,
108
152
fmt .Sprintf ("%d,sockets=1,cores=%d,threads=1" , y .CPUs , y .CPUs ))
109
153
110
154
// Memory
111
155
memBytes , err := units .RAMInBytes (y .Memory )
112
156
if err != nil {
113
157
return "" , nil , err
114
158
}
115
- args = append (args , "-m" , strconv .Itoa (int (memBytes >> 20 )))
159
+ args = appendArgsIfNoConflict (args , "-m" , strconv .Itoa (int (memBytes >> 20 )))
116
160
117
161
// Firmware
118
162
if ! y .Firmware .LegacyBIOS {
@@ -132,10 +176,10 @@ func Cmdline(cfg Config) (string, []string, error) {
132
176
return "" , nil , err
133
177
}
134
178
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" )
136
180
args = append (args , "-drive" , fmt .Sprintf ("file=%s,media=cdrom,readonly=on" , baseDisk ))
137
181
} 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" )
139
183
}
140
184
if diskSize , _ := units .RAMInBytes (cfg .LimaYAML .Disk ); diskSize > 0 {
141
185
args = append (args , "-drive" , fmt .Sprintf ("file=%s,if=virtio" , diffDisk ))
@@ -156,7 +200,7 @@ func Cmdline(cfg Config) (string, []string, error) {
156
200
157
201
// Graphics
158
202
if y .Video .Display != "" {
159
- args = append (args , "-display" , y .Video .Display )
203
+ args = appendArgsIfNoConflict (args , "-display" , y .Video .Display )
160
204
}
161
205
switch y .Arch {
162
206
case limayaml .X8664 :
@@ -205,6 +249,27 @@ func Cmdline(cfg Config) (string, []string, error) {
205
249
return exe , args , nil
206
250
}
207
251
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
+
208
273
func getAccel (arch limayaml.Arch ) string {
209
274
nativeX8664 := arch == limayaml .X8664 && runtime .GOARCH == "amd64"
210
275
nativeAARCH64 := arch == limayaml .AARCH64 && runtime .GOARCH == "arm64"
0 commit comments