chore: aarch64 qemu local secureboot support
Support booting with SecureBoot on aarch64 with `talosctl cluster create` with QEMU provisioner. Signed-off-by: Noel Georgi <git@frezbo.dev>
This commit is contained in:
parent
da6263506a
commit
106c17d0b5
@ -5,8 +5,10 @@
|
|||||||
package qemu
|
package qemu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Arch abstracts away differences between different architectures.
|
// Arch abstracts away differences between different architectures.
|
||||||
@ -74,18 +76,47 @@ type PFlash struct {
|
|||||||
func (arch Arch) PFlash(uefiEnabled bool, extraUEFISearchPaths []string) []PFlash {
|
func (arch Arch) PFlash(uefiEnabled bool, extraUEFISearchPaths []string) []PFlash {
|
||||||
switch arch {
|
switch arch {
|
||||||
case ArchArm64:
|
case ArchArm64:
|
||||||
uefiSourcePaths := []string{"/usr/share/qemu-efi-aarch64/QEMU_EFI.fd", "/usr/share/OVMF/QEMU_EFI.fd", "/usr/share/edk2/aarch64/QEMU_EFI.fd"}
|
// default search paths
|
||||||
for _, p := range extraUEFISearchPaths {
|
uefiSourcePathPrefixes := []string{
|
||||||
uefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, "QEMU_EFI.fd"))
|
"/usr/share/AAVMF", // most standard location
|
||||||
|
"/usr/share/qemu-efi-aarch64",
|
||||||
|
"/usr/share/OVMF",
|
||||||
|
"/usr/share/edk2/aarch64", // Fedora
|
||||||
|
"/usr/share/edk2/experimental", // Fedora
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secure boot enabled firmware files
|
||||||
|
uefiSourceFiles := []string{
|
||||||
|
"AAVMF_CODE.secboot.fd", // debian, EFI vars not protected
|
||||||
|
"QEMU_EFI.secboot.testonly.fd", // Fedora, ref: https://bugzilla.redhat.com/show_bug.cgi?id=1882135
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-secure boot firmware files
|
||||||
|
uefiSourceFilesInsecure := []string{
|
||||||
|
"AAVMF_CODE.fd",
|
||||||
|
"QEMU_EFI.fd",
|
||||||
|
"OVMF.stateless.fd",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty vars files
|
||||||
|
uefiVarsFiles := []string{
|
||||||
|
"AAVMF_VARS.fd",
|
||||||
|
"QEMU_VARS.fd",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append extra search paths
|
||||||
|
uefiSourcePathPrefixes = append(uefiSourcePathPrefixes, extraUEFISearchPaths...)
|
||||||
|
|
||||||
|
uefiSourcePaths, uefiVarsPaths := generateUEFIPFlashList(uefiSourcePathPrefixes, uefiSourceFiles, uefiVarsFiles, uefiSourceFilesInsecure)
|
||||||
|
|
||||||
return []PFlash{
|
return []PFlash{
|
||||||
{
|
{
|
||||||
Size: 64 * 1024 * 1024,
|
Size: 64 * 1024 * 1024,
|
||||||
SourcePaths: uefiSourcePaths,
|
SourcePaths: uefiSourcePaths,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Size: 64 * 1024 * 1024,
|
SourcePaths: uefiVarsPaths,
|
||||||
|
Size: 64 * 1024 * 1024,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case ArchAmd64:
|
case ArchAmd64:
|
||||||
@ -127,25 +158,7 @@ func (arch Arch) PFlash(uefiEnabled bool, extraUEFISearchPaths []string) []PFlas
|
|||||||
// Append extra search paths
|
// Append extra search paths
|
||||||
uefiSourcePathPrefixes = append(uefiSourcePathPrefixes, extraUEFISearchPaths...)
|
uefiSourcePathPrefixes = append(uefiSourcePathPrefixes, extraUEFISearchPaths...)
|
||||||
|
|
||||||
var uefiSourcePaths []string
|
uefiSourcePaths, uefiVarsPaths := generateUEFIPFlashList(uefiSourcePathPrefixes, uefiSourceFiles, uefiVarsFiles, uefiSourceFilesInsecure)
|
||||||
|
|
||||||
var uefiVarsPaths []string
|
|
||||||
|
|
||||||
for _, p := range uefiSourcePathPrefixes {
|
|
||||||
for _, f := range uefiSourceFiles {
|
|
||||||
uefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, f))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range uefiVarsFiles {
|
|
||||||
uefiVarsPaths = append(uefiVarsPaths, filepath.Join(p, f))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range uefiSourcePathPrefixes {
|
|
||||||
for _, f := range uefiSourceFilesInsecure {
|
|
||||||
uefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, f))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return []PFlash{
|
return []PFlash{
|
||||||
{
|
{
|
||||||
@ -162,6 +175,26 @@ func (arch Arch) PFlash(uefiEnabled bool, extraUEFISearchPaths []string) []PFlas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateUEFIPFlashList(uefiSourcePathPrefixes, uefiSourceFiles, uefiVarsFiles, uefiSourceFilesInsecure []string) (uefiSourcePaths, uefiVarsPaths []string) {
|
||||||
|
for _, p := range uefiSourcePathPrefixes {
|
||||||
|
for _, f := range uefiSourceFiles {
|
||||||
|
uefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range uefiVarsFiles {
|
||||||
|
uefiVarsPaths = append(uefiVarsPaths, filepath.Join(p, f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range uefiSourcePathPrefixes {
|
||||||
|
for _, f := range uefiSourceFilesInsecure {
|
||||||
|
uefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uefiSourcePaths, uefiVarsPaths
|
||||||
|
}
|
||||||
|
|
||||||
// QemuExecutable returns name of qemu executable for the arch.
|
// QemuExecutable returns name of qemu executable for the arch.
|
||||||
func (arch Arch) QemuExecutable() string {
|
func (arch Arch) QemuExecutable() string {
|
||||||
binaries := []string{
|
binaries := []string{
|
||||||
@ -179,7 +212,43 @@ func (arch Arch) QemuExecutable() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Architecture returns the architecture.
|
// TPMDeviceArgs returns arguments for qemu to enable TPM device.
|
||||||
func (arch Arch) Architecture() string {
|
func (arch Arch) TPMDeviceArgs(socketPath string) []string {
|
||||||
return string(arch)
|
tpmDeviceArgs := []string{
|
||||||
|
"-chardev",
|
||||||
|
fmt.Sprintf("socket,id=chrtpm,path=%s", socketPath),
|
||||||
|
"-tpmdev",
|
||||||
|
"emulator,id=tpm0,chardev=chrtpm",
|
||||||
|
"-device",
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arch {
|
||||||
|
case ArchAmd64:
|
||||||
|
return slices.Concat(tpmDeviceArgs, []string{"tpm-tis,tpmdev=tpm0"})
|
||||||
|
case ArchArm64:
|
||||||
|
return slices.Concat(tpmDeviceArgs, []string{"tpm-tis-device,tpmdev=tpm0"})
|
||||||
|
default:
|
||||||
|
panic("unsupported architecture")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// KVMArgs returns arguments for qemu to enable KVM.
|
||||||
|
func (arch Arch) KVMArgs(kvmEnabled bool) []string {
|
||||||
|
if !kvmEnabled {
|
||||||
|
return []string{"-machine", arch.QemuMachine()}
|
||||||
|
}
|
||||||
|
|
||||||
|
machineArg := arch.QemuMachine() + ",accel=kvm"
|
||||||
|
|
||||||
|
switch arch {
|
||||||
|
case ArchAmd64:
|
||||||
|
machineArg += ",smm=on"
|
||||||
|
|
||||||
|
return []string{"-machine", machineArg}
|
||||||
|
case ArchArm64:
|
||||||
|
// smm is not supported on aarch64
|
||||||
|
return []string{"-machine", machineArg}
|
||||||
|
default:
|
||||||
|
panic("unsupported architecture")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,14 +43,11 @@ type LaunchConfig struct {
|
|||||||
DiskDrivers []string
|
DiskDrivers []string
|
||||||
VCPUCount int64
|
VCPUCount int64
|
||||||
MemSize int64
|
MemSize int64
|
||||||
QemuExecutable string
|
|
||||||
Architecture string
|
|
||||||
KernelImagePath string
|
KernelImagePath string
|
||||||
InitrdPath string
|
InitrdPath string
|
||||||
ISOPath string
|
ISOPath string
|
||||||
PFlashImages []string
|
PFlashImages []string
|
||||||
KernelArgs string
|
KernelArgs string
|
||||||
MachineType string
|
|
||||||
MonitorPath string
|
MonitorPath string
|
||||||
DefaultBootOrder string
|
DefaultBootOrder string
|
||||||
EnableKVM bool
|
EnableKVM bool
|
||||||
@ -58,6 +55,7 @@ type LaunchConfig struct {
|
|||||||
TPM2Config tpm2Config
|
TPM2Config tpm2Config
|
||||||
NodeUUID uuid.UUID
|
NodeUUID uuid.UUID
|
||||||
BadRTC bool
|
BadRTC bool
|
||||||
|
ArchitectureData Arch
|
||||||
|
|
||||||
// Talos config
|
// Talos config
|
||||||
Config string
|
Config string
|
||||||
@ -390,18 +388,7 @@ func launchVM(config *LaunchConfig) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
machineArg := config.MachineType
|
args = append(args, config.ArchitectureData.KVMArgs(config.EnableKVM)...)
|
||||||
|
|
||||||
if config.EnableKVM {
|
|
||||||
machineArg += ",accel=kvm"
|
|
||||||
|
|
||||||
// smm is not supported on aarch64
|
|
||||||
if Arch(config.QemuExecutable) == ArchAmd64 {
|
|
||||||
machineArg += ",smm=on"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args = append(args, "-machine", machineArg)
|
|
||||||
|
|
||||||
pflashArgs := make([]string, 2*len(config.PFlashImages))
|
pflashArgs := make([]string, 2*len(config.PFlashImages))
|
||||||
for i := range config.PFlashImages {
|
for i := range config.PFlashImages {
|
||||||
@ -440,12 +427,7 @@ func launchVM(config *LaunchConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
args = append(args,
|
args = append(args,
|
||||||
"-chardev",
|
config.ArchitectureData.TPMDeviceArgs(tpm2SocketPath)...,
|
||||||
fmt.Sprintf("socket,id=chrtpm,path=%s", tpm2SocketPath),
|
|
||||||
"-tpmdev",
|
|
||||||
"emulator,id=tpm0,chardev=chrtpm",
|
|
||||||
"-device",
|
|
||||||
"tpm-tis,tpmdev=tpm0",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,9 +452,9 @@ func launchVM(config *LaunchConfig) error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "starting %s with args:\n%s\n", config.QemuExecutable, strings.Join(args, " "))
|
fmt.Fprintf(os.Stderr, "starting %s with args:\n%s\n", config.ArchitectureData.QemuExecutable(), strings.Join(args, " "))
|
||||||
cmd := exec.Command(
|
cmd := exec.Command(
|
||||||
config.QemuExecutable,
|
config.ArchitectureData.QemuExecutable(),
|
||||||
args...,
|
args...,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -129,16 +129,14 @@ func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
launchConfig := LaunchConfig{
|
launchConfig := LaunchConfig{
|
||||||
QemuExecutable: arch.QemuExecutable(),
|
ArchitectureData: arch,
|
||||||
Architecture: arch.Architecture(),
|
DiskPaths: diskPaths,
|
||||||
DiskPaths: diskPaths,
|
|
||||||
DiskDrivers: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string {
|
DiskDrivers: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string {
|
||||||
return disk.Driver
|
return disk.Driver
|
||||||
}),
|
}),
|
||||||
VCPUCount: vcpuCount,
|
VCPUCount: vcpuCount,
|
||||||
MemSize: memSize,
|
MemSize: memSize,
|
||||||
KernelArgs: cmdline.String(),
|
KernelArgs: cmdline.String(),
|
||||||
MachineType: arch.QemuMachine(),
|
|
||||||
PFlashImages: pflashImages,
|
PFlashImages: pflashImages,
|
||||||
MonitorPath: state.GetRelativePath(fmt.Sprintf("%s.monitor", nodeReq.Name)),
|
MonitorPath: state.GetRelativePath(fmt.Sprintf("%s.monitor", nodeReq.Name)),
|
||||||
EnableKVM: opts.TargetArch == runtime.GOARCH,
|
EnableKVM: opts.TargetArch == runtime.GOARCH,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user