Skip to content

Commit

Permalink
VM: Firmware detection fixes (from Incus) (#14050)
Browse files Browse the repository at this point in the history
Based on:

- lxc/incus#1187
- lxc/incus#1193

Follows on from #14032

Also improves the removal of old firmware vars files by not checking the
if the associated firmwares exist on the host and not trying to remove
the same files multiple times.
  • Loading branch information
tomponline authored Sep 6, 2024
2 parents 94256d3 + f92bde3 commit be65fe0
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 22 deletions.
19 changes: 9 additions & 10 deletions lxd/instance/drivers/driver_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -1938,11 +1938,11 @@ func (d *qemu) setupNvram() error {

d.logger.Debug("Generating NVRAM")

// Cleanup existing variables.
for _, firmwarePair := range edk2.GetAchitectureFirmwarePairs(d.architecture) {
err := os.Remove(filepath.Join(d.Path(), filepath.Base(firmwarePair.Vars)))
// Cleanup existing variables file.
for _, varsName := range edk2.GetAchitectureFirmwareVarsCandidates(d.architecture) {
err := os.Remove(filepath.Join(d.Path(), varsName))
if err != nil && !os.IsNotExist(err) {
return err
return fmt.Errorf("Failed removing firmware vars file %q: %w", varsName, err)
}
}

Expand Down Expand Up @@ -1982,14 +1982,13 @@ func (d *qemu) setupNvram() error {
return err
}

// Generate a symlink if needed.
// Generate a symlink.
// This is so qemu.nvram can always be assumed to be the EDK2 vars file.
// The real file name is then used to determine what firmware must be selected.
if !shared.PathExists(d.nvramPath()) {
err = os.Symlink(vmFirmwareName, d.nvramPath())
if err != nil {
return err
}
_ = os.Remove(d.nvramPath())
err = os.Symlink(vmFirmwareName, d.nvramPath())
if err != nil {
return err
}

return nil
Expand Down
38 changes: 26 additions & 12 deletions lxd/instance/drivers/edk2/edk2.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"path/filepath"
"strings"

"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/osarch"
)

Expand Down Expand Up @@ -148,20 +149,25 @@ var architectureInstallations = map[int][]Installation{
}},
}

// GetAchitectureFirmwarePairs creates an array of FirmwarePair for a
// specific host architecture.
func GetAchitectureFirmwarePairs(hostArch int) []FirmwarePair {
firmwares := make([]FirmwarePair, 0)

for _, usage := range []FirmwareUsage{GENERIC, SECUREBOOT, CSM} {
firmwares = append(firmwares, GetArchitectureFirmwarePairsForUsage(hostArch, usage)...)
// GetAchitectureFirmwareVarsCandidates returns a unique list of candidate vars names for hostArch for all usages.
// It does not check whether the associated firmware files are present on the host now.
// This can be used to check for the existence of previously used firmware vars files in an existing VM instance.
func GetAchitectureFirmwareVarsCandidates(hostArch int) (varsNames []string) {
for _, installation := range architectureInstallations[hostArch] {
for _, usage := range installation.Usage {
for _, fwPair := range usage {
if !shared.ValueInSlice(fwPair.Vars, varsNames) {
varsNames = append(varsNames, fwPair.Vars)
}
}
}
}

return firmwares
return varsNames
}

// GetArchitectureFirmwarePairsForUsage creates an array of FirmwarePair
// for a specific host architecture and usage combination.
// GetArchitectureFirmwarePairsForUsage returns FirmwarePair slice for a host architecture and usage combination.
// It only includes FirmwarePairs where both the firmware and its vars file are found on the host.
func GetArchitectureFirmwarePairsForUsage(hostArch int, usage FirmwareUsage) []FirmwarePair {
firmwares := make([]FirmwarePair, 0)

Expand All @@ -170,9 +176,17 @@ func GetArchitectureFirmwarePairsForUsage(hostArch int, usage FirmwareUsage) []F
if found {
for _, firmwarePair := range usage {
for _, searchPath := range installation.Paths {
codePath := filepath.Join(searchPath, firmwarePair.Code)
varsPath := filepath.Join(searchPath, firmwarePair.Vars)

// Check both firmware code and vars paths exist - otherwise skip pair.
if !shared.PathExists(codePath) || !shared.PathExists(varsPath) {
continue
}

firmwares = append(firmwares, FirmwarePair{
Code: filepath.Join(searchPath, firmwarePair.Code),
Vars: filepath.Join(searchPath, firmwarePair.Vars),
Code: codePath,
Vars: varsPath,
})
}
}
Expand Down

0 comments on commit be65fe0

Please sign in to comment.