Skip to content

Commit

Permalink
EFI firmware/bootloader support
Browse files Browse the repository at this point in the history
This requires macOS 13.0+ and does not need/use a kernel, initrd or
command-line, it just boots e.g. Grub or a similar EFI bootloader from
the provided disk image. A path to store the EFI variables is required.
  • Loading branch information
sigmaris committed Oct 20, 2023
1 parent b5efa8f commit 4a4f794
Showing 1 changed file with 36 additions and 3 deletions.
39 changes: 36 additions & 3 deletions vmcli/Sources/vmcli/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Virtualization

enum BootLoader: String, ExpressibleByArgument {
case linux
@available(macOS 13, *)
case efi
}

enum SizeSuffix: UInt64, ExpressibleByArgument {
Expand Down Expand Up @@ -175,13 +177,16 @@ Omit mac address for a generated address.
@Option(name: .shortAndLong, help: "Bootloader to use")
var bootloader: BootLoader = BootLoader.linux

@Option(name: .shortAndLong, help: "Kernel to use")
@Option(name: .shortAndLong, help: "EFI variable store location (EFI bootloader only)")
var efiVars: String?

@Option(name: .shortAndLong, help: "Kernel to use (Linux bootloader only)")
var kernel: String?

@Option(help: "Initrd to use")
@Option(help: "Initrd to use (Linux bootloader only)")
var initrd: String?

@Option(help: "Kernel cmdline to use")
@Option(help: "Kernel cmdline to use (Linux bootloader only)")
var cmdline: String?

@Option(help: "Escape Sequence, when using a tty")
Expand All @@ -200,6 +205,9 @@ Omit mac address for a generated address.
if kernel == nil {
throw ValidationError("Kernel not specified")
}
if efiVars != nil {
throw ValidationError("EFI variable store cannot be used with Linux bootloader")
}
let vmKernelURL = URL(fileURLWithPath: kernel!)
let vmBootLoader = VZLinuxBootLoader(kernelURL: vmKernelURL)
if initrd != nil {
Expand All @@ -209,6 +217,31 @@ Omit mac address for a generated address.
vmBootLoader.commandLine = cmdline!
}
vmCfg.bootLoader = vmBootLoader
case BootLoader.efi:
#if canImport(Virtualization.VZEFIBootLoader)
if #available(macOS 13, *) {
if efiVars == nil {
throw ValidationError("EFI variable store must be specified if using EFI bootloader")
}
if kernel != nil || initrd != nil || cmdline != nil {
throw ValidationError("Kernel, initrd and cmdline options cannot be used with EFI bootloader")
}
let efiVarStoreURL = URL(fileURLWithPath: efiVars!)
var efiVarStore: VZEFIVariableStore
if FileManager.default.fileExists(atPath: efiVars!) {
efiVarStore = VZEFIVariableStore(url: efiVarStoreURL)
} else {
efiVarStore = try VZEFIVariableStore(creatingVariableStoreAt: efiVarStoreURL)
}
let vmBootLoader = VZEFIBootLoader()
vmBootLoader.variableStore = efiVarStore
vmCfg.bootLoader = vmBootLoader
} else {
throw ValidationError("EFI bootloader is only available on macOS 13 and later versions")
}
#else
throw ValidationError("vmcli was not compiled with EFI bootloader support (requires macOS >=13 SDK)")
#endif
}

// set up tty
Expand Down

0 comments on commit 4a4f794

Please sign in to comment.