Documentation
¶
Index ¶
- Constants
- Variables
- func AddU32(x, y uint32) (uint32, error)
- func BytesSliceRange(s []byte, start, end uint32) ([]byte, error)
- func CRC16(data []byte) uint16
- func GetAllRegexSubexpMap(regEx, inputString string) ([](map[string]string), error)
- func GetBytesRegexSubexpMap(regEx string, buf []byte) (map[string]string, error)
- func GetRegexSubexpMap(regEx, inputString string) (map[string]string, error)
- func GetStringKeys(m map[string]interface{}) []string
- func GetStringKeysFromJSONData(data []byte) ([]string, error)
- func GetWord(data []byte, offset uint32) (uint32, error)
- func HealthdRemoveMemUtilRebootEntryIfExists(h *gabs.Container) error
- func HealthdWriteConfigToFile(h *gabs.Container) error
- func LogAndIgnoreErr(err error)
- func SafeAppendBytes(a, b []byte) []byte
- func SafeAppendString(a, b []string) []string
- func SetWord(data []byte, word, offset uint32) ([]byte, error)
- func StringDifference(a, b []string) []string
- func StringFind(val string, arr []string) int
- func Uint32Find(val uint32, arr []uint32) int
- type BmcMemThres
- type BmcMemUtil
- type MemInfo
- type MtdInfo
- type VbootEnforcementType
- type Vbs
Constants ¶
const ( VBOOT_NONE VbootEnforcementType = "NONE" VBOOT_SOFTWARE_ENFORCE = "SOFTWARE_ENFORCE" VBOOT_HARDWARE_ENFORCE = "HARDWARE_ENFORCE" )
const AST_SRAM_VBS_BASE = 0x1E720200 // ast2400, ast2500
AST_SRAM_VBS_BASE is the location in SRAM used for verified boot content/flags.
const AST_SRAM_VBS_BASE_G6 = 0x10015800 // ast2600
const AST_SRAM_VBS_SIZE = 56
AST_SRAM_VBS_SIZE is the size of verified boot content/flags.
const ProcMtdFilePath = "/proc/mtd"
Variables ¶
var BMCLitePlatforms = []string{
"acctonbmc",
"celesticabmc",
"fbdarwin",
"janga",
"meru",
"minipack3n",
"montblanc",
"morgan800cc",
"nexthopbmc",
"tahan",
}
BMCLitePlatforms contains the list of BMC lite platform names
var CheckOtherFlasherRunning = func(flashyStepBaseNames []string) error { allFlasherBaseNames := SafeAppendString(otherFlasherBaseNames, flashyStepBaseNames) otherProcCmdlinePaths := getOtherProcCmdlinePaths() err := checkNoBaseNameExistsInProcCmdlinePaths(allFlasherBaseNames, otherProcCmdlinePaths) if err != nil { return fmt.Errorf("Another flasher running: %v", err) } return nil }
CheckOtherFlasherRunning return an error if any other flashers are running. It takes in the baseNames of all flashy's steps (e.g. 00_truncate_logs) to make sure no other instance of flashy is running.
var GetBSMFlashManufacturerFromFile = func() (string, error) { spiManufacturerBuf, err := fileutils.ReadFile(spiManufacturerPath) if err != nil { return "", fmt.Errorf("Error reading '%v': %v", spiManufacturerPath, err) } if len(spiManufacturerBuf) == 0 { return "", fmt.Errorf("'%v' file is empty", spiManufacturerPath) } return strings.TrimSpace(string(spiManufacturerBuf)), nil }
Checks SPI flash manufacturer on BSM (ie Winbond or Macronix). Related to S483584, which is a SEV affecting specific versions on Winbond chips
var GetHealthdConfig = func() (*gabs.Container, error) { buf, err := fileutils.ReadFile(healthdConfigFilePath) if err != nil { return nil, fmt.Errorf("Unable to open healthd-config.json: %w", err) } healthdConfig, err := gabs.ParseJSON(buf) if err != nil { return nil, fmt.Errorf("Unable to parse healthd-config.json: %w", err) } return healthdConfig, nil }
GetHealthdConfig gets the healthd config in a JSON container.
var GetMTDInfoFromSpecifier = func(deviceSpecifier string) (MtdInfo, error) { var mtdInfo MtdInfo procMTDBuf, err := fileutils.ReadFile(ProcMtdFilePath) if err != nil { return mtdInfo, fmt.Errorf("Unable to read from /proc/mtd: %v", err) } procMTD := string(procMTDBuf) const rDev = "dev" const rSize = "size" const rErasesize = "erasesize" regEx := fmt.Sprintf("(?m)^(?P<%v>mtd[0-9a-f]+): (?P<%v>[0-9a-f]+) (?P<%v>[0-9a-f]+) \"%v\"$", rDev, rSize, rErasesize, deviceSpecifier) mtdMap, err := GetRegexSubexpMap(regEx, procMTD) if err != nil { return mtdInfo, fmt.Errorf("Error finding MTD entry in /proc/mtd for flash device 'mtd:%v'", deviceSpecifier) } size, err := strconv.ParseUint(mtdMap[rSize], 16, 32) if err != nil { return mtdInfo, fmt.Errorf("Failed to parse size: %v", err) } erasesize, err := strconv.ParseUint(mtdMap[rErasesize], 16, 32) if err != nil { return mtdInfo, fmt.Errorf("Failed to parse erasesize: %v", err) } return MtdInfo{ Dev: mtdMap[rDev], Size: uint32(size), Erasesize: uint32(erasesize), }, nil }
GetMtdInfoFromSpecifier MtdInfo for the mtd device specifier. Information is obtained from /proc/mtd.
var GetMachine = func() (string, error) { var uts syscall.Utsname err := syscall.Uname(&uts) if err != nil { return "unknown", err } machine := make([]byte, 0, len(uts.Machine)) for _, v := range uts.Machine { if v == 0 { break } machine = append(machine, byte(v)) } return string(machine), nil }
var GetMemInfo = func() (*MemInfo, error) { buf, err := fileutils.ReadFile("/proc/meminfo") if err != nil { return nil, fmt.Errorf("Unable to open /proc/meminfo: %v", err) } memInfoStr := string(buf) memFreeRegex := regexp.MustCompile(`(?m)^MemFree: +([0-9]+) kB$`) memTotalRegex := regexp.MustCompile(`(?m)^MemTotal: +([0-9]+) kB$`) memFreeMatch := memFreeRegex.FindStringSubmatch(memInfoStr) if len(memFreeMatch) < 2 { return nil, fmt.Errorf("Unable to get MemFree in /proc/meminfo") } memFree, _ := strconv.ParseUint(memFreeMatch[1], 10, 64) memFree *= 1024 memTotalMatch := memTotalRegex.FindStringSubmatch(memInfoStr) if len(memTotalMatch) < 2 { return nil, fmt.Errorf("Unable to get MemTotal in /proc/meminfo") } memTotal, _ := strconv.ParseUint(memTotalMatch[1], 10, 64) memTotal *= 1024 return &MemInfo{ memTotal, memFree, }, nil }
GetMemInfo gets MemInfo from /proc/meminfo. Note that this assumes kB units for MemFree and MemTotal and will fail otherwise.
var GetOpenBMCPlatformFromIssueFile = func() (string, error) { const rPlatform = "platform" const re = `(?i)(?:.*\s)?(?P<%v>[^\s-]+)-v[0-9]+(?:\.[0-9]+)*(?:[^\s]*)?` etcIssuePlatformRegEx := fmt.Sprintf(re, rPlatform) etcIssueBuf, err := fileutils.ReadFile(etcIssueFilePath) if err != nil { return "", fmt.Errorf("Error reading %v: %v", etcIssueFilePath, err) } etcIssueStr := string(etcIssueBuf) if strings.HasPrefix(strings.ToLower(etcIssueStr), "openbmc release \n") { return "unknown", nil } etcIssueMap, err := GetRegexSubexpMap( etcIssuePlatformRegEx, etcIssueStr) if err != nil { fallbackPatterns := []string{ `(?i)(?:.*\s)?(?P<platform>[^\s-]+)-[a-f0-9]{8,}`, `(?i)(?:.*\s)?(?P<platform>[^\s-]+)\s+v[0-9]+`, } for _, pattern := range fallbackPatterns { fallbackRegEx := fmt.Sprintf(pattern) etcIssueMap, err = GetRegexSubexpMap(fallbackRegEx, etcIssueStr) if err == nil { break } } if err != nil { return "", fmt.Errorf("Unable to get platform from %v: %v", etcIssueFilePath, err) } } platform := etcIssueMap[rPlatform] if platform == "" { return "", fmt.Errorf("Unable to get platform from %v: missing platform info", etcIssueFilePath) } return strings.ToLower(platform), nil }
GetOpenBMCPlatformFromIssueFile gets OpenBMC platform from /etc/issue. examples: fbtp, wedge100 WARNING: There is no guarantee that /etc/issue is well-formed in old images.
var GetOpenBMCVersionFromIssueFile = func() (string, error) { const rVersion = "version" const re = `^(?P<facebook>facebook )?open ?bmc(?P<release> release)? ?(?P<%v>[^\s]+)` etcIssueVersionRegEx := fmt.Sprintf(re, rVersion) etcIssueBuf, err := fileutils.ReadFile(etcIssueFilePath) if err != nil { return "", fmt.Errorf("Error reading %v: %v", etcIssueFilePath, err) } etcIssueStr := strings.ToLower(string(etcIssueBuf)) if strings.HasPrefix(etcIssueStr, "openbmc release \n") { return "unknown-v1", nil } etcIssueMap, err := GetRegexSubexpMap( etcIssueVersionRegEx, etcIssueStr) if err != nil { return "", fmt.Errorf("Unable to get version from %v: %v", etcIssueFilePath, err) } version := etcIssueMap[rVersion] if version == "release" { return "", fmt.Errorf("Unable to get version from %v: missing version info", etcIssueFilePath) } if version[0] == 'v' && !strings.Contains(version, "-") { version = "unknown-" + version } return version, nil }
GetOpenBMCVersionFromIssueFile gets OpenBMC version from /etc/issue. examples: fbtp-v2020.09.1, wedge100-v2020.07.1 WARNING: There is no guarantee that /etc/issue is well-formed in old images.
var GetVbootEnforcement = func() VbootEnforcementType { vbs, err := GetVbs() if err != nil { log.Printf("Assuming this is not a vboot system because: %v", err) return VBOOT_NONE } if vbs.Hardware_enforce == 1 { return VBOOT_HARDWARE_ENFORCE } else if vbs.Software_enforce == 1 { return VBOOT_SOFTWARE_ENFORCE } return VBOOT_NONE }
GetVbootEnforcement gets the vboot enforcement type of the system.
var GetVbs = func() (Vbs, error) { var vbs Vbs var baseaddr uint32 if !vbootPartitionExists() { return vbs, fmt.Errorf("Not a Vboot system: vboot partition (rom) does not exist.") } machine, err := GetMachine() if err != nil { return vbs, fmt.Errorf("Unable to fetch utsinfo: %w", err) } if machine == "armv7l" { baseaddr = AST_SRAM_VBS_BASE_G6 } else { baseaddr = AST_SRAM_VBS_BASE } log.Printf("Machine type from utsinfo: %v, base address: 0x%x", machine, baseaddr) mmapOffset := fileutils.GetPageOffsettedBase(baseaddr) length := fileutils.Pagesize pageData, err := fileutils.MmapFileRange("/dev/mem", int64(mmapOffset), length, syscall.PROT_READ, syscall.MAP_SHARED) if err != nil { return vbs, fmt.Errorf("Unable to mmap /dev/mem: %w", err) } defer fileutils.Munmap(pageData) dataOffset := fileutils.GetPageOffsettedOffset(baseaddr) vbsEndOffset, err := AddU32(dataOffset, AST_SRAM_VBS_SIZE) if err != nil { return vbs, fmt.Errorf("VBS end offset overflowed: %w", err) } vbsData, err := BytesSliceRange(pageData, dataOffset, vbsEndOffset) if err != nil { return vbs, fmt.Errorf("Failed to get vbs data: %w", err) } return decodeVbs(vbsData) }
GetVbs tries to get the Vbs struct by reading off /dev/mem. This errors out if the vboot partition ("rom") does not exist.
var HealthdExists = func() bool { return fileutils.FileExists(healthdConfigFilePath) }
HealthdExists checks if healthd exists in this system by checking existence of the healthd config file.
var IsBMCLite = func() bool { issueBuf, err := fileutils.ReadFile(etcIssueFilePath) if err != nil { return false } for _, platform := range BMCLitePlatforms { if strings.Contains(string(issueBuf), platform) { return true } } return false }
IsBMCLite check whether the system is running BMC-lite For S368275. Uses dynamically generated list.
var IsDataPartitionMounted = func() (bool, error) { procMountsDat, err := fileutils.ReadFile(procMountsPath) if err != nil { return false, fmt.Errorf("Cannot read /proc/mounts: %v", err) } regEx := `(?m)^[^ ]+ /mnt/data [^ ]+ [^ ]+ [0-9]+ [0-9]+$` regExMap, err := GetAllRegexSubexpMap(regEx, string(procMountsDat)) if err != nil { return false, fmt.Errorf("regex error: %v", err) } return len(regExMap) != 0, nil }
IsDataPartitionMounted checks if /mnt/data is mounted
var IsLFOpenBMC = func() bool { const magic = "OPENBMC_TARGET_MACHINE" osReleaseBuf, err := fileutils.ReadFile(etcOsReleaseFilePath) if err != nil { return false } return strings.Contains(string(osReleaseBuf), magic) }
IsLFOpenBMC check whether the system is running LF-OpenBMC by checking whether the string "OPENBMC_TARGET_MACHINE" exists in /etc/os-release.
var IsOpenBMC = func() (bool, error) { const magic = "OpenBMC" const ancient_magic = "Open BMC Release" etcIssueBuf, err := fileutils.ReadFile(etcIssueFilePath) if err != nil { return false, fmt.Errorf("Error reading '%v': %v", etcIssueFilePath, err) } isOpenBMC := strings.Contains(string(etcIssueBuf), magic) if !isOpenBMC { isOpenBMC = strings.Contains(string(etcIssueBuf), ancient_magic) } return isOpenBMC, nil }
IsOpenBMC check whether the system is an OpenBMC by checking whether the string "OpenBMC" exists in /etc/issue.
var IsPfrSystem = func() bool { log.Printf("Checking whether the system is PFR-enabled") exitCode, _, _, _ := RunCommand( []string{"i2craw", "12", "0x38", "-r", "1", "-w", "0x0A"}, 30*time.Second, ) isPfr := exitCode == 0 if isPfr { log.Printf("This system is PFR-enabled") } else { log.Printf("This system is not PFR-enabled") } return isPfr }
IsPfrSystem checks whether the system is a PFR-enabled system or not. This is just a temporary method, due to be replaced by pfr-util.
var ListProcessesMatchingRegex = func(regex *regexp.Regexp) ([]*os.Process, error) { allProcCmdlines, _ := fileutils.Glob("/proc/[0-9]*/cmdline") procs := []*os.Process{} pidRegex := regexp.MustCompile(`/proc/([0-9]+)/`) for _, cmdlinePath := range allProcCmdlines { buf, err := fileutils.ReadFile(cmdlinePath) if err == nil && regex.Match(buf) { pidRegexMatch := pidRegex.FindStringSubmatch(cmdlinePath) pid, _ := strconv.Atoi(pidRegexMatch[1]) if proc, err := os.FindProcess(pid); err == nil { procs = append(procs, proc) } } } return procs, nil }
var PetWatchdog = func() { if IsBMCLite() { log.Printf("Watchdog not petted; BMC Lite") return } for i := 0; i < 10; i++ { if tryPetWatchdog(false) { log.Printf("Watchdog petted") return } time.Sleep(1 * time.Second) } log.Printf("Watchdog not petted; yielded CPU instead") }
Try to pet the watchdog and increase its timeout. This works in two ways:
When /dev/watchdog is busy because it's held open by healthd / systemd / fscd, the delay here will hopefully allow the thread petting the watchdog to get some CPU time.
When /dev/watchdog it NOT busy and there are no concurrent instances of wdtcli, the watchdog timeout will be extended and the watchdog petted.
var PetWatchdogLoop = func() { if IsBMCLite() { log.Printf("Not starting PetWatchdogLoop; BMC Lite") return } log.Printf("PetWatchdogLoop started") for { if tryPetWatchdog(true) { log.Printf("Watchdog petted") } time.Sleep(5 * time.Second) } }
var RestartHealthd = func(wait bool, supervisor string) error { if !fileutils.PathExists("/etc/sv/healthd") { return fmt.Errorf("Error restarting healthd: '/etc/sv/healthd' does not exist") } code, err, _, _ := RunCommand([]string{supervisor, "status", "healthd"}, 60*time.Second) if err != nil || code != 0 { log.Printf("healthd doesn't seem to be running. Wait for 30s to " + "ensure watchdog is stable.") Sleep(30 * time.Second) return nil } RunCommand([]string{supervisor, "stop", "healthd"}, 60*time.Second) PetWatchdog() _, err, _, _ = RunCommand([]string{supervisor, "start", "healthd"}, 60*time.Second) if wait { log.Printf("Sleeping for 30s after healthd restart to make sure " + "healthd is stable.") Sleep(30 * time.Second) } return err }
RestartHealthd restarts the healthd process.
var RunCommand = func(cmdArr []string, timeout time.Duration) (int, error, string, string) { start := time.Now() ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() if len(cmdArr) == 0 { return 1, fmt.Errorf("Cannot run empty command"), "", "" } fullCmdStr := strings.Join(cmdArr[:], " ") log.Printf("Running command '%v' with %v timeout", fullCmdStr, timeout) cmd := exec.CommandContext(ctx, cmdArr[0], cmdArr[1:]...) var stdoutStr, stderrStr string stdout, err := cmd.StdoutPipe() if err != nil { return 1, fmt.Errorf("Unable to open stdout pipe: %v", err), "", "" } stderr, err := cmd.StderrPipe() if err != nil { return 1, fmt.Errorf("Unable to open stderr pipe: %v", err), "", "" } stdoutScanner := bufio.NewScanner(stdout) stderrScanner := bufio.NewScanner(stderr) stdoutDone := make(chan struct{}) stderrDone := make(chan struct{}) go logScanner(stdoutScanner, stdoutDone, "stdout: ", &stdoutStr) go logScanner(stderrScanner, stderrDone, "stderr: ", &stderrStr) exitCode := 1 if err := cmd.Start(); err != nil { log.Printf("Command '%v' failed to start: %v", fullCmdStr, err) return exitCode, err, stdoutStr, stderrStr } <-stdoutDone <-stderrDone err = cmd.Wait() if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { waitStatus := exitErr.Sys().(syscall.WaitStatus) exitCode = waitStatus.ExitStatus() } else { log.Printf("Could not get exit code, defaulting to '1'") } } else { waitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus) exitCode = waitStatus.ExitStatus() } elapsed := time.Since(start) if ctx.Err() == context.DeadlineExceeded { log.Printf("Command '%v' timed out after %v", fullCmdStr, timeout) err = ctx.Err() } else { log.Printf("Command '%v' exited with code %v after %v", fullCmdStr, exitCode, elapsed) } return exitCode, err, stdoutStr, stderrStr }
RunCommand runs command and pipes live output. Returns exitcode, error, stdout (string), stderr (string) if non-zero/error returned or timed out. Returns 0, nil, stdout (string), stderr (string) if successfully run.
var RunCommandWithRetries = func(cmdArr []string, timeout time.Duration, maxAttempts int, interval time.Duration) (int, error, string, string) { exitCode, err, stdoutStr, stderrStr := 1, fmt.Errorf("Command failed to run"), "", "" if maxAttempts < 1 { err = fmt.Errorf("Command failed to run: maxAttempts must be > 0 (got %v)", maxAttempts) return exitCode, err, stdoutStr, stderrStr } fullCmdStr := strings.Join(cmdArr[:], " ") for attempt := 1; attempt <= maxAttempts; attempt++ { log.Printf("Attempt %v of %v: Running command '%v' with timeout %v and retry interval %v", attempt, maxAttempts, fullCmdStr, timeout, interval) exitCode, err, stdoutStr, stderrStr = RunCommand(cmdArr, timeout) if err == nil { log.Printf("Attempt %v of %v succeeded", attempt, maxAttempts) break } else { log.Printf("Attempt %v of %v failed", attempt, maxAttempts) if attempt < maxAttempts { log.Printf("Sleeping for %v before retrying", interval) Sleep(interval) } else { log.Printf("Max attempts (%v) reached. Returning with error.", maxAttempts) } } } return exitCode, err, stdoutStr, stderrStr }
RunCommandWithRetries calls RunCommand repeatedly until succeeded or maxAttempts is reached. Between attempts, an interval is applied. Returns the results from the first succeeding run or last tried run.
var Sleep = time.Sleep
Sleep function variable for mocking purposes.
var SystemdAvailable = func() (bool, error) { const cmdlinePath = "/proc/1/cmdline" if fileutils.FileExists(cmdlinePath) { buf, err := fileutils.ReadFile(cmdlinePath) if err != nil { return false, fmt.Errorf("%v exists but cannot be read: %v", cmdlinePath, err) } contains := strings.Contains(string(buf), "systemd") return contains, nil } return false, nil }
SystemdAvailable checks whether systemd is available.
Functions ¶
func BytesSliceRange ¶
BytesSliceRange returns s[start:end] but with bounds checks
func GetAllRegexSubexpMap ¶
GetAllRegexSubexpMap is the 'All' version of GetRegexSubexpMap that tries to match as many strings as possible. Returns an empty list of subexpMap if no matches are found.
func GetBytesRegexSubexpMap ¶
GetBytesRegexSubexpMap is the bytes version of GetRegexSubexpMap for convenience, it is used on image/mtds that have long slices of bytes. For convenience, map[string]string is returned.
func GetRegexSubexpMap ¶
GetRegexSubexpMap takes a regex with capturing groups and an input string, and returns a map of the regex subexpNames to their respective matched values. NOTE: this function is used only for regex with valid capturing groups uses beyond well-defined regexes with valid capturing groups will result in errors or undefined behavior e.g. regex: "(?P<type>[a-z]+):(?P<specifier>.+)"
inputString: "mtd:flash0"
-> map[string]string { "type": "mtd", "specifier": "flash0" } Returns an error if match was not successful.
func GetStringKeys ¶
GetStringKeys gets all the string keys in a string-keyed map. The sequence of the keys is not guaranteed.
func GetStringKeysFromJSONData ¶
GetStringKeysFromJSONData takes in data which contains JSON data and returns all the string keys. The sequence of the keys is not guaranteed.
func GetWord ¶
GetWord gets a 4 byte uint32 from a byte slice 'data' from offset to offset+4. It returns an error if the offset is out of range.
func HealthdRemoveMemUtilRebootEntryIfExists ¶
HealthdRemoveMemUtilRebootEntryIfExists removes the "reboot" entry that will trigger system reboot after mem util reaches a threshold. This is to prevent healthd reboots during flashing. If the "reboot" entry exists, remove it and write back to the file.
func HealthdWriteConfigToFile ¶
HealthdWriteConfigToFile writes back into /etc/healthd-config.json.
func LogAndIgnoreErr ¶
func LogAndIgnoreErr(err error)
LogAndIgnoreErr logs the error info and ignores the error
func SafeAppendBytes ¶
SafeAppendBytes safely appends byte slices b to a. c := append(a, b...) is unsafe, if a has enough capacity, b will be directly appended. SafeAppendBytes makes guarantees that a is not changed.
func SafeAppendString ¶
SafeAppendString is the string version of SafeAppendBytes.
func SetWord ¶
SetWord sets a 4 byte uint32 in a byte slice 'data' from offset to offset+4. It returns an error if offset will cause an out of range write. Warning: make an explicit copy if the original array is required again after SetWord.
func StringDifference ¶
StringDifference returns the elements in 'a' not in 'b'
func StringFind ¶
StringFind takes a string slice and looks if a given item is in it. If found it will return its index, otherwise it will return -1.
func Uint32Find ¶
Uint32Find takes a uint32 slice and looks if a given item is in it. If found it will return its index, otherwise it will return -1.
Types ¶
type BmcMemThres ¶
BmcMemThres is a struct for parsing the healthd-config.json.
type BmcMemUtil ¶
type BmcMemUtil struct {
Threshold []BmcMemThres `json:"threshold"`
}
BmcMemUtil is a struct for parsing the healthd-config.json.
type VbootEnforcementType ¶
type VbootEnforcementType = string
VbootEnforcementType is an enum representing the vboot type of the system
type Vbs ¶
type Vbs struct {
Uboot_exec_address uint32 /* Location in MMIO where U-Boot/Recovery U-Boot is execution */
Rom_exec_address uint32 /* Location in MMIO where ROM is executing from */
Rom_keys uint32 /* Location in MMIO where the ROM FDT is located */
Subordinate_keys uint32 /* Location in MMIO where subordinate FDT is located */
Rom_handoff uint32 /* Marker set when ROM is handing execution to U-Boot. */
Force_recovery uint8 /* Set by ROM when recovery is requested */
Hardware_enforce uint8 /* Set by ROM when WP pin of SPI0.0 is active low */
Software_enforce uint8 /* Set by ROM when RW environment uses verify=yes */
Recovery_boot uint8 /* Set by ROM when recovery is used */
Recovery_retries uint8 /* Number of attempts to recovery from verification failure */
Error_type uint8 /* Type of error, or 0 for success */
Error_code uint8 /* Unique error code, or 0 for success */
Error_tpm uint8 /* The last-most-recent error from the TPM. */
Crc uint16 /* A CRC of the vbs structure */
Error_tpm2 uint16 /* The last-most-recent error from the TPM2. */
Subordinate_last uint32 /* Status reporting only: the last booted subordinate. */
Uboot_last uint32 /* Status reporting only: the last booted U-Boot. */
Kernel_last uint32 /* Status reporting only: the last booted kernel. */
Subordinate_current uint32 /* Status reporting only: the current booted subordinate. */
Uboot_current uint32 /* Status reporting only: the current booted U-Boot. */
Kernel_current uint32 /* Status reporting only: the current booted kernel. */
}
Vbs represents the verified content flags. This is taken from common/recipes-utils/vboot-utils/files/vbs.