github.com/linuxboot/fiano@v1.2.0/pkg/amd/manifest/firmware.go (about)

     1  // Copyright 2019 the LinuxBoot 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 manifest
     6  
     7  import (
     8  	"fmt"
     9  
    10  	bytes2 "github.com/linuxboot/fiano/pkg/bytes"
    11  )
    12  
    13  // Firmware is an abstraction of a firmware image, obtained for example via flashrom
    14  type Firmware interface {
    15  	ImageBytes() []byte
    16  	PhysAddrToOffset(physAddr uint64) uint64
    17  	OffsetToPhysAddr(offset uint64) uint64
    18  }
    19  
    20  // PSPFirmware contains essential parts of the AMD's PSP firmware internals
    21  type PSPFirmware struct {
    22  	EmbeddedFirmware      EmbeddedFirmwareStructure
    23  	EmbeddedFirmwareRange bytes2.Range
    24  
    25  	PSPDirectoryLevel1      *PSPDirectoryTable
    26  	PSPDirectoryLevel1Range bytes2.Range
    27  	PSPDirectoryLevel2      *PSPDirectoryTable
    28  	PSPDirectoryLevel2Range bytes2.Range
    29  
    30  	BIOSDirectoryLevel1      *BIOSDirectoryTable
    31  	BIOSDirectoryLevel1Range bytes2.Range
    32  	BIOSDirectoryLevel2      *BIOSDirectoryTable
    33  	BIOSDirectoryLevel2Range bytes2.Range
    34  }
    35  
    36  // AMDFirmware represents an instance of firmware that exposes AMD specific
    37  // meatadata and structure.
    38  type AMDFirmware struct {
    39  	// firmware is a reference to a generic firmware interface
    40  	firmware Firmware
    41  
    42  	// pspFirmware is a reference to PSPFirmware structure. It is built at
    43  	// construction time and not exported.
    44  	pspFirmware *PSPFirmware
    45  }
    46  
    47  // Firmware returns the internal reference to Firmawre interface
    48  func (a *AMDFirmware) Firmware() Firmware {
    49  	return a.firmware
    50  }
    51  
    52  // PSPFirmware returns the PSPFirmware reference held by the AMDFirmware object
    53  func (a *AMDFirmware) PSPFirmware() *PSPFirmware {
    54  	return a.pspFirmware
    55  }
    56  
    57  // parsePSPFirmware parses input firmware as PSP firmware image and
    58  // collects Embedded firmware, PSP directory and BIOS directory structures
    59  func parsePSPFirmware(firmware Firmware) (*PSPFirmware, error) {
    60  	image := firmware.ImageBytes()
    61  
    62  	var result PSPFirmware
    63  	efs, r, err := FindEmbeddedFirmwareStructure(firmware)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	result.EmbeddedFirmware = *efs
    68  	result.EmbeddedFirmwareRange = r
    69  
    70  	var pspDirectoryLevel1 *PSPDirectoryTable
    71  	var pspDirectoryLevel1Range bytes2.Range
    72  	if efs.PSPDirectoryTablePointer != 0 && efs.PSPDirectoryTablePointer < uint32(len(image)) {
    73  		var length uint64
    74  		pspDirectoryLevel1, length, err = ParsePSPDirectoryTable(image[efs.PSPDirectoryTablePointer:])
    75  		if err == nil {
    76  			pspDirectoryLevel1Range.Offset = uint64(efs.PSPDirectoryTablePointer)
    77  			pspDirectoryLevel1Range.Length = length
    78  		}
    79  	}
    80  	if pspDirectoryLevel1 == nil {
    81  		pspDirectoryLevel1, pspDirectoryLevel1Range, _ = FindPSPDirectoryTable(image)
    82  	}
    83  	if pspDirectoryLevel1 != nil {
    84  		result.PSPDirectoryLevel1 = pspDirectoryLevel1
    85  		result.PSPDirectoryLevel1Range = pspDirectoryLevel1Range
    86  
    87  		for _, entry := range pspDirectoryLevel1.Entries {
    88  			if entry.Type != PSPDirectoryTableLevel2Entry {
    89  				continue
    90  			}
    91  			if entry.LocationOrValue != 0 && entry.LocationOrValue < uint64(len(image)) {
    92  				pspDirectoryLevel2, length, err := ParsePSPDirectoryTable(image[entry.LocationOrValue:])
    93  				if err == nil {
    94  					result.PSPDirectoryLevel2 = pspDirectoryLevel2
    95  					result.PSPDirectoryLevel2Range.Offset = entry.LocationOrValue
    96  					result.PSPDirectoryLevel2Range.Length = length
    97  				}
    98  			}
    99  			break
   100  		}
   101  	}
   102  
   103  	var biosDirectoryLevel1 *BIOSDirectoryTable
   104  	var biosDirectoryLevel1Range bytes2.Range
   105  
   106  	biosDirectoryOffsets := []uint32{
   107  		efs.BIOSDirectoryTableFamily17hModels00h0FhPointer,
   108  		efs.BIOSDirectoryTableFamily17hModels10h1FhPointer,
   109  		efs.BIOSDirectoryTableFamily17hModels30h3FhPointer,
   110  		efs.BIOSDirectoryTableFamily17hModels60h3FhPointer,
   111  	}
   112  	for _, offset := range biosDirectoryOffsets {
   113  		if offset == 0 || int(offset) > len(image) {
   114  			continue
   115  		}
   116  		var length uint64
   117  		biosDirectoryLevel1, length, err = ParseBIOSDirectoryTable(image[offset:])
   118  		if err != nil {
   119  			continue
   120  		}
   121  		biosDirectoryLevel1Range.Offset = uint64(offset)
   122  		biosDirectoryLevel1Range.Length = length
   123  		break
   124  	}
   125  
   126  	if biosDirectoryLevel1 == nil {
   127  		biosDirectoryLevel1, biosDirectoryLevel1Range, _ = FindBIOSDirectoryTable(image)
   128  	}
   129  
   130  	if biosDirectoryLevel1 != nil {
   131  		result.BIOSDirectoryLevel1 = biosDirectoryLevel1
   132  		result.BIOSDirectoryLevel1Range = biosDirectoryLevel1Range
   133  
   134  		for _, entry := range biosDirectoryLevel1.Entries {
   135  			if entry.Type != BIOSDirectoryTableLevel2Entry {
   136  				continue
   137  			}
   138  			if entry.SourceAddress != 0 && entry.SourceAddress < uint64(len(image)) {
   139  				biosDirectoryLevel2, length, err := ParseBIOSDirectoryTable(image[entry.SourceAddress:])
   140  				if err == nil {
   141  					result.BIOSDirectoryLevel2 = biosDirectoryLevel2
   142  					result.BIOSDirectoryLevel2Range.Offset = entry.SourceAddress
   143  					result.BIOSDirectoryLevel2Range.Length = length
   144  				}
   145  			}
   146  			break
   147  		}
   148  	}
   149  
   150  	return &result, nil
   151  }
   152  
   153  // NewAMDFirmware returns an AMDFirmware structure or an error if internal firmware structures cannot be parsed
   154  func NewAMDFirmware(firmware Firmware) (*AMDFirmware, error) {
   155  	pspFirmware, err := parsePSPFirmware(firmware)
   156  	if err != nil {
   157  		return nil, fmt.Errorf("could not construct AMDFirmware, cannot parse PSP firmware: %w", err)
   158  	}
   159  	return &AMDFirmware{firmware: firmware, pspFirmware: pspFirmware}, nil
   160  
   161  }
   162  
   163  // FirmwareImage implements Firmware given image content.
   164  type FirmwareImage []byte
   165  
   166  var _ Firmware = (*FirmwareImage)(nil)
   167  
   168  const basePhysAddr = 1 << 32 // "4GB"
   169  
   170  // ImageBytes returns image content.
   171  func (img FirmwareImage) ImageBytes() []byte {
   172  	return []byte(img)
   173  }
   174  
   175  // PhysAddrToOffset maps a physical address to the offset in the image.
   176  func (img FirmwareImage) PhysAddrToOffset(physAddr uint64) uint64 {
   177  	startAddr := uint64(basePhysAddr - len(img))
   178  	return physAddr - startAddr
   179  }
   180  
   181  // OffsetToPhysAddr maps an offset in the image to the physical address.
   182  func (img FirmwareImage) OffsetToPhysAddr(offset uint64) uint64 {
   183  	startAddr := uint64(basePhysAddr - len(img))
   184  	return offset + startAddr
   185  }