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 }