Skip to content

Commit b0bcd65

Browse files
committed
qemu, aarch64: use EDK2 from "Firmware/edk2 20231213 patches"
The "Firmware/edk2 20231213" patches <https://lists.gnu.org/archive/html/qemu-devel/2023-12/msg01694.html> are necessary to boot most aarch64 images (except Debian, which does not use UEFI shim). The patches are proposed for the QEMU v8.2.0 milestone, but likely to be postponed to v8.2.1. Until the patches get accepted in the QEMU upstream, Lima fetches the patched edk2 binary from <https://gitlab.com/kraxel/qemu/-/tags/firmware%2Fedk2-20231213-pull-request>. Signed-off-by: Akihiro Suda <[email protected]>
1 parent 9e839a6 commit b0bcd65

File tree

8 files changed

+127
-6
lines changed

8 files changed

+127
-6
lines changed

examples/default.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ firmware:
263263
# Use legacy BIOS instead of UEFI. Ignored for aarch64.
264264
# 🟢 Builtin default: false
265265
legacyBIOS: null
266+
# # Override UEFI images
267+
# # 🟢 Builtin default: uses VM's default UEFI, except for qemu + aarch64.
268+
# # See <https://lists.gnu.org/archive/html/qemu-devel/2023-12/msg01694.html>
269+
# images:
270+
# - location: "~/Downloads/edk2-aarch64-code.fd.gz"
271+
# arch: "aarch64"
272+
# digest: "sha256:..."
273+
# vmType: "qemu"
266274

267275
audio:
268276
# EXPERIMENTAL

pkg/limayaml/defaults.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,37 @@ func defaultGuestInstallPrefix() string {
112112
return "/usr/local"
113113
}
114114

115+
func defaultFirmwareImages() []FileWithVMType {
116+
return []FileWithVMType{
117+
/*
118+
The "Firmware/edk2 20231213" patches <https://lists.gnu.org/archive/html/qemu-devel/2023-12/msg01694.html>
119+
are necessary to boot most aarch64 images (except Debian, which does not use UEFI shim).
120+
121+
The patches are proposed for the QEMU v8.2.0 milestone, but likely to be postponed to v8.2.1.
122+
Until the patches get accepted in the QEMU upstream, Lima fetches the patched edk2 binary from
123+
<https://gitlab.com/kraxel/qemu/-/tags/firmware%2Fedk2-20231213-pull-request>.
124+
*/
125+
{
126+
File: File{
127+
Location: "https://gitlab.com/kraxel/qemu/-/raw/704f7cad5105246822686f65765ab92045f71a3b/pc-bios/edk2-aarch64-code.fd.bz2",
128+
Arch: AARCH64,
129+
Digest: "sha256:a5fc228623891297f2d82e22ea56ec57cde93fea5ec01abf543e4ed5cacaf277",
130+
},
131+
VMType: QEMU,
132+
},
133+
// Mirror
134+
{
135+
File: File{
136+
Location: "https://github.com/AkihiroSuda/qemu/raw/704f7cad5105246822686f65765ab92045f71a3b/pc-bios/edk2-aarch64-code.fd.bz2",
137+
Arch: AARCH64,
138+
Digest: "sha256:a5fc228623891297f2d82e22ea56ec57cde93fea5ec01abf543e4ed5cacaf277",
139+
},
140+
VMType: QEMU,
141+
},
142+
// TODO: what about ARMv7?
143+
}
144+
}
145+
115146
// FillDefault updates undefined fields in y with defaults from d (or built-in default), and overwrites with values from o.
116147
// Both d and o may be empty.
117148
//
@@ -283,6 +314,17 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
283314
y.Firmware.LegacyBIOS = ptr.Of(false)
284315
}
285316

317+
y.Firmware.Images = append(append(o.Firmware.Images, y.Firmware.Images...), d.Firmware.Images...)
318+
if len(y.Firmware.Images) == 0 {
319+
y.Firmware.Images = defaultFirmwareImages()
320+
}
321+
for i := range y.Firmware.Images {
322+
f := &y.Firmware.Images[i]
323+
if f.Arch == "" {
324+
f.Arch = *y.Arch
325+
}
326+
}
327+
286328
if y.SSH.LocalPort == nil {
287329
y.SSH.LocalPort = d.SSH.LocalPort
288330
}

pkg/limayaml/defaults_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,27 @@ func TestFillDefault(t *testing.T) {
181181
"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
182182
},
183183
},
184+
Firmware: Firmware{
185+
LegacyBIOS: ptr.Of(false),
186+
Images: []FileWithVMType{
187+
{
188+
File: File{
189+
Location: "https://gitlab.com/kraxel/qemu/-/raw/704f7cad5105246822686f65765ab92045f71a3b/pc-bios/edk2-aarch64-code.fd.bz2",
190+
Arch: AARCH64,
191+
Digest: "sha256:a5fc228623891297f2d82e22ea56ec57cde93fea5ec01abf543e4ed5cacaf277",
192+
},
193+
VMType: QEMU,
194+
},
195+
{
196+
File: File{
197+
Location: "https://github.com/AkihiroSuda/qemu/raw/704f7cad5105246822686f65765ab92045f71a3b/pc-bios/edk2-aarch64-code.fd.bz2",
198+
Arch: AARCH64,
199+
Digest: "sha256:a5fc228623891297f2d82e22ea56ec57cde93fea5ec01abf543e4ed5cacaf277",
200+
},
201+
VMType: QEMU,
202+
},
203+
},
204+
},
184205
}
185206

186207
expect := builtin
@@ -252,6 +273,8 @@ func TestFillDefault(t *testing.T) {
252273
},
253274
}
254275

276+
expect.Firmware = y.Firmware
277+
255278
expect.Rosetta = Rosetta{
256279
Enabled: ptr.Of(false),
257280
BinFmt: ptr.Of(false),
@@ -299,6 +322,14 @@ func TestFillDefault(t *testing.T) {
299322
},
300323
Firmware: Firmware{
301324
LegacyBIOS: ptr.Of(true),
325+
Images: []FileWithVMType{
326+
{
327+
File: File{
328+
Location: "/dummy",
329+
Arch: X8664,
330+
},
331+
},
332+
},
302333
},
303334
Audio: Audio{
304335
Device: ptr.Of("coreaudio"),
@@ -427,6 +458,7 @@ func TestFillDefault(t *testing.T) {
427458
expect.CopyToHost = append(append([]CopyToHost{}, y.CopyToHost...), d.CopyToHost...)
428459
expect.Containerd.Archives = append(append([]File{}, y.Containerd.Archives...), d.Containerd.Archives...)
429460
expect.AdditionalDisks = append(append([]Disk{}, y.AdditionalDisks...), d.AdditionalDisks...)
461+
expect.Firmware.Images = append(append([]FileWithVMType{}, y.Firmware.Images...), d.Firmware.Images...)
430462

431463
// Mounts and Networks start with lowest priority first, so higher priority entries can overwrite
432464
expect.Mounts = append(append([]Mount{}, d.Mounts...), y.Mounts...)
@@ -580,6 +612,7 @@ func TestFillDefault(t *testing.T) {
580612
expect.CopyToHost = append(append(o.CopyToHost, y.CopyToHost...), d.CopyToHost...)
581613
expect.Containerd.Archives = append(append(o.Containerd.Archives, y.Containerd.Archives...), d.Containerd.Archives...)
582614
expect.AdditionalDisks = append(append(o.AdditionalDisks, y.AdditionalDisks...), d.AdditionalDisks...)
615+
expect.Firmware.Images = append(append(o.Firmware.Images, y.Firmware.Images...), d.Firmware.Images...)
583616

584617
expect.HostResolver.Hosts["default"] = d.HostResolver.Hosts["default"]
585618
expect.HostResolver.Hosts["MY.Host"] = d.HostResolver.Hosts["host.lima.internal"]

pkg/limayaml/limayaml.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ type File struct {
7777
Digest digest.Digest `yaml:"digest,omitempty" json:"digest,omitempty"`
7878
}
7979

80+
type FileWithVMType struct {
81+
File `yaml:",inline"`
82+
VMType VMType `yaml:"vmType,omitempty" json:"vmType,omitempty"`
83+
}
84+
8085
type Kernel struct {
8186
File `yaml:",inline"`
8287
Cmdline string `yaml:"cmdline,omitempty" json:"cmdline,omitempty"`
@@ -142,6 +147,10 @@ type Firmware struct {
142147
// LegacyBIOS disables UEFI if set.
143148
// LegacyBIOS is ignored for aarch64.
144149
LegacyBIOS *bool `yaml:"legacyBIOS,omitempty" json:"legacyBIOS,omitempty"`
150+
151+
// Images specify UEFI images (edk2-aarch64-code.fd.gz).
152+
// Defaults to built-in UEFI.
153+
Images []FileWithVMType `yaml:"images,omitempty" json:"images,omitempty"`
145154
}
146155

147156
type Audio struct {

pkg/qemu/qemu.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -569,12 +569,31 @@ func Cmdline(cfg Config) (exe string, args []string, err error) {
569569
logrus.Warnf("field `firmware.legacyBIOS` is not supported for architecture %q, ignoring", *y.Arch)
570570
legacyBIOS = false
571571
}
572-
if !legacyBIOS && *y.Arch != limayaml.RISCV64 {
573-
firmware, err := getFirmware(exe, *y.Arch)
574-
if err != nil {
575-
return "", nil, err
572+
if !legacyBIOS {
573+
var firmware string
574+
for _, f := range y.Firmware.Images {
575+
switch f.VMType {
576+
case "", limayaml.QEMU:
577+
if f.Arch == *y.Arch {
578+
firmwareCandidate := filepath.Join(cfg.InstanceDir, filenames.QemuEfiCodeFD)
579+
if _, err = fileutils.DownloadFile(firmwareCandidate, f.File, true, "UEFI code", *y.Arch); err != nil {
580+
logrus.WithError(err).Warnf("failed to download %q", f.Location)
581+
continue
582+
}
583+
firmware = firmwareCandidate
584+
break
585+
}
586+
}
587+
}
588+
if firmware == "" && *y.Arch != limayaml.RISCV64 {
589+
firmware, err = getFirmware(exe, *y.Arch)
590+
if err != nil {
591+
return "", nil, err
592+
}
593+
}
594+
if firmware != "" {
595+
args = append(args, "-drive", fmt.Sprintf("if=pflash,format=raw,readonly=on,file=%s", firmware))
576596
}
577-
args = append(args, "-drive", fmt.Sprintf("if=pflash,format=raw,readonly=on,file=%s", firmware))
578597
}
579598

580599
// Disk

pkg/store/filenames/filenames.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ const (
5353
HostAgentStdoutLog = "ha.stdout.log"
5454
HostAgentStderrLog = "ha.stderr.log"
5555
VzIdentifier = "vz-identifier"
56-
VzEfi = "vz-efi"
56+
VzEfi = "vz-efi" // efi variable store
57+
QemuEfiCodeFD = "qemu-efi-code.fd" // efi code; not always created
5758

5859
// SocketDir is the default location for forwarded sockets with a relative paths in HostSocket
5960
SocketDir = "sock"

pkg/vz/vz_driver_darwin.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ func (l *LimaVzDriver) Validate() error {
7878
if *l.Yaml.Firmware.LegacyBIOS {
7979
return fmt.Errorf("`firmware.legacyBIOS` configuration is not supported for VZ driver")
8080
}
81+
for _, f := range l.Yaml.Firmware.Images {
82+
switch f.VMType {
83+
case "", limayaml.VZ:
84+
if f.Arch == *l.Yaml.Arch {
85+
return fmt.Errorf("`firmware.images` configuration is not supported for VZ driver")
86+
}
87+
}
88+
}
8189
if unknown := reflectutil.UnknownNonEmptyFields(l.Yaml, knownYamlProperties...); len(unknown) > 0 {
8290
logrus.Warnf("vmType %s: ignoring %+v", *l.Yaml.VMType, unknown)
8391
}

website/content/en/docs/dev/Internals/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ kernel:
4848
QEMU:
4949
- `qemu.pid`: QEMU PID
5050
- `qmp.sock`: QMP socket
51+
- `qemu-efi-code.fd`: QEMU UEFI code (not always present)
5152

5253
VZ:
5354
- `vz.pid`: VZ PID

0 commit comments

Comments
 (0)