github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/systembooter/bootentry.go (about)

     1  // Copyright 2017-2019 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package systembooter
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  
    11  	"github.com/mvdan/u-root-coreutils/pkg/crypto"
    12  	"github.com/mvdan/u-root-coreutils/pkg/vpd"
    13  )
    14  
    15  // Get, Set and GetAll are defined here as variables so they can be overridden
    16  // for testing, or for using a key-value store other than VPD.
    17  var (
    18  	Get    = vpd.Get
    19  	Set    = vpd.Set
    20  	GetAll = vpd.GetAll
    21  )
    22  
    23  // BootEntry represents a boot entry, with its name, configuration, and Booter
    24  // instance. It can map to existing key-value stores like VPD or EFI vars.
    25  type BootEntry struct {
    26  	Name   string
    27  	Config []byte
    28  	Booter Booter
    29  }
    30  
    31  var supportedBooterParsers = []func([]byte) (Booter, error){
    32  	NewNetBooter,
    33  	NewLocalBooter,
    34  }
    35  
    36  // GetBooterFor looks for a supported Booter implementation and returns it, if
    37  // found. If not found, a NullBooter is returned.
    38  func GetBooterFor(entry BootEntry) Booter {
    39  	var (
    40  		booter Booter
    41  		err    error
    42  	)
    43  	for idx, booterParser := range supportedBooterParsers {
    44  		log.Printf("Trying booter #%d", idx)
    45  		booter, err = booterParser(entry.Config)
    46  		if err != nil {
    47  			log.Printf("This config is not valid for this booter (#%d)", idx)
    48  			continue
    49  		}
    50  		break
    51  	}
    52  	if booter == nil {
    53  		log.Printf("No booter found for entry: %+v", entry)
    54  		return &NullBooter{}
    55  	}
    56  	return booter
    57  }
    58  
    59  // GetBootEntries returns a list of BootEntry objects stored in the VPD
    60  // partition of the flash chip
    61  func GetBootEntries() []BootEntry {
    62  	var bootEntries []BootEntry
    63  	for idx := 0; idx < 9999; idx++ {
    64  		key := fmt.Sprintf("Boot%04d", idx)
    65  		// try the RW entries first
    66  		value, err := Get(key, false)
    67  		if err == nil {
    68  			crypto.TryMeasureData(crypto.NvramVarsPCR, value, key)
    69  			bootEntries = append(bootEntries, BootEntry{Name: key, Config: value})
    70  			// WARNING WARNING WARNING this means that read-write boot entries
    71  			// have priority over read-only ones
    72  			continue
    73  		}
    74  		// try the RO entries then
    75  		value, err = Get(key, true)
    76  		if err == nil {
    77  			crypto.TryMeasureData(crypto.NvramVarsPCR, value, key)
    78  			bootEntries = append(bootEntries, BootEntry{Name: key, Config: value})
    79  		}
    80  	}
    81  	// look for a Booter that supports the given configuration
    82  	for idx, entry := range bootEntries {
    83  		entry.Booter = GetBooterFor(entry)
    84  		if entry.Booter == nil {
    85  			log.Printf("No booter found for entry: %+v", entry)
    86  		}
    87  		bootEntries[idx] = entry
    88  	}
    89  	return bootEntries
    90  }