github.com/linuxboot/fiano@v1.2.0/pkg/amd/psb/pspentries.go (about) 1 // Copyright 2023 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 psb 6 7 import ( 8 "errors" 9 "fmt" 10 "os" 11 "strings" 12 13 amd_manifest "github.com/linuxboot/fiano/pkg/amd/manifest" 14 15 "github.com/jedib0t/go-pretty/v6/table" 16 ) 17 18 const ( 19 // AMDPublicKeyEntry denotes AMD public key entry in PSP Directory table 20 AMDPublicKeyEntry amd_manifest.PSPDirectoryTableEntryType = 0x00 21 22 // PSPRecoveryBootloader is a recovery instance of PSP bootloader 23 PSPRecoveryBootloader amd_manifest.PSPDirectoryTableEntryType = 0x03 24 25 // SMUOffChipFirmwareEntry points to a region of firmware containing SMU offchip firmware 26 SMUOffChipFirmwareEntry amd_manifest.PSPDirectoryTableEntryType = 0x08 27 28 // ABLPublicKey represents the key used to sign ABL firmware 29 ABLPublicKey amd_manifest.PSPDirectoryTableEntryType = 0x0A 30 31 // SMUOffChipFirmware2Entry points to a region of firmware containing SMU offchip firmware 32 SMUOffChipFirmware2Entry amd_manifest.PSPDirectoryTableEntryType = 0x12 33 34 // UnlockDebugImageEntry points to a region of firmware containing PSP early secure unlock debug image 35 UnlockDebugImageEntry amd_manifest.PSPDirectoryTableEntryType = 0x13 36 37 // SecurityPolicyBinaryEntry points to a region of firmware containing Security Policy Binary 38 SecurityPolicyBinaryEntry amd_manifest.PSPDirectoryTableEntryType = 0x24 39 40 // MP5FirmwareEntry points to a region of firmware containing MP5 Firmware 41 MP5FirmwareEntry amd_manifest.PSPDirectoryTableEntryType = 0x2A 42 43 // AGESABinary0Entry points to a region of firmware containing PSP AGESA Binary 0 44 AGESABinary0Entry amd_manifest.PSPDirectoryTableEntryType = 0x30 45 46 // SEVCodeEntry points to a region of firmware containing SEV Code 47 SEVCodeEntry amd_manifest.PSPDirectoryTableEntryType = 0x39 48 49 // DXIOPHYSRAMFirmwareEntry points to a region of firmware containing DXIO PHY SRAM firmware 50 DXIOPHYSRAMFirmwareEntry amd_manifest.PSPDirectoryTableEntryType = 0x42 51 52 //DRTMTAEntry points to a region of firmware containing DRTM TA 53 DRTMTAEntry amd_manifest.PSPDirectoryTableEntryType = 0x47 54 55 // KeyDatabaseEntry points to region of firmware containing key database 56 KeyDatabaseEntry amd_manifest.PSPDirectoryTableEntryType = 0x50 57 58 // OEMSigningKeyEntry represents the OEM signing key 59 OEMSigningKeyEntry amd_manifest.BIOSDirectoryTableEntryType = 0x05 60 61 // BIOSRTMVolumeEntry represents the RTM volume 62 BIOSRTMVolumeEntry amd_manifest.BIOSDirectoryTableEntryType = 0x62 63 64 // BIOSRTMSignatureEntry represents the entry holding the RTM volume signature 65 BIOSRTMSignatureEntry amd_manifest.BIOSDirectoryTableEntryType = 0x07 66 ) 67 68 // PSPEntryType defines the type to hold PSP Entry Type fields 69 type PSPEntryType uint8 70 71 /* 72 * Nicely output human-readable names for PSP Entry Types 73 * 74 * This doesn't have all the entries mapped, there are still 75 * several more pages left. It does have all the types 76 * encountered in the firmware images used to test 77 * however. 78 * 79 */ 80 func (_type PSPEntryType) String() string { 81 switch _type { 82 case 0x00: 83 return "AMD_PUBLIC_KEYS" 84 case 0x01: 85 return "PSP_BOOT_LOADER" 86 case 0x02: 87 return "PSP_SECURE_OS" 88 case 0x03: 89 return "PSP_RECOVERY_BOOTLOADER" 90 case 0x04: 91 return "PSP_NON_VOLATILE_DATA" 92 case 0x08: 93 return "SMU_OFF_CHIP_FIRMWARE" 94 case 0x09: 95 return "AMD_SECURE_DEBUG_KEY" 96 case 0x0A: 97 return "ABL_PUBLIC_KEY" 98 case 0x0B: 99 return "PSP_SOFT_FUSE_CHAIN" 100 case 0x0C: 101 return "PSP_BOOT_LOADED_TRUSTLETS" 102 case 0x0D: 103 return "PSP_TRUSTLET_PUBLIC_KEY" 104 case 0x12: 105 return "SMU_OFF_CHIP_FIRMWARE" 106 case 0x13: 107 return "UNLOCK_DEBUG_IMAGE" 108 case 0x20: 109 return "IP_DISCOVERY_BINARY" 110 case 0x21: 111 return "WRAPPED_IKEK" 112 case 0x22: 113 return "PSP_TOKEN_UNLOCK_DATA" 114 case 0x24: 115 return "SEC_POLICY_BINARY" 116 case 0x25: 117 return "MP2_FIRMWARE" 118 case 0x26: 119 return "MP2_FIRMWARE_PART_TWO" 120 case 0x27: 121 return "USER_MODE_UNIT_TESTS" 122 case 0x28: 123 return "SYSTEM_DRIVER_IN_SPI" 124 case 0x29: 125 return "KVM_IMAGE" 126 case 0x2A: 127 return "MP5_FIRMWARE" 128 case 0x2B: 129 return "EMBEDDED_FIRMWARE_STRUCTURE" 130 case 0x2C: 131 return "TEE_WRITE_ONCE_NVRAM" 132 case 0x2D: 133 return "EXTERNAL_PSP_BOOTLOADER" 134 case 0x2E: 135 return "EXTERNAL_MP0" 136 case 0x2F: 137 return "EXTERNAL_MP1" 138 case 0x30: 139 return "AGESA_BINARY_0" 140 case 0x31: 141 return "AGESA_BINARY_1" 142 case 0x32: 143 return "AGESA_BINARY_2" 144 case 0x33: 145 return "AGESA_BINARY_3" 146 case 0x34: 147 return "AGESA_BINARY_4" 148 case 0x35: 149 return "AGESA_BINARY_5" 150 case 0x36: 151 return "AGESA_BINARY_6" 152 case 0x37: 153 return "AGESA_BINARY_7" 154 case 0x38: 155 return "SEV_DATA" 156 case 0x39: 157 return "SEV_CODE" 158 case 0x3A: 159 return "PROCESSOR_SERIAL_WHITELIST" 160 case 0x3B: 161 return "SERDES_MICROCODE" 162 case 0x3C: 163 return "VBIOS_PRELOAD" 164 case 0x3D: 165 return "WLAN_UMAC" 166 case 0x3E: 167 return "WLAN_IMAC" 168 case 0x3F: 169 return "WLAN_BLUETOOTH" 170 case 0x40: 171 return "PSP_DIRECTORY_LEVEL_2" 172 case 0x41: 173 return "EXTERNAL_MP0_BOOTLOADER" 174 case 0x42: 175 return "EXTERNAL_DXIO_SRAM_FIRMWARE" 176 case 0x43: 177 return "EXTERNAL_DXIO_SRAM_PUBLIC_KEY" 178 case 0x44: 179 return "USB_UNIFIED_PHY_FIRMWARE" 180 case 0x45: 181 return "SEC_POLICY_BINARY_TOS" 182 case 0x46: 183 return "EXTERNAL_PSP_BOOTLOADER" 184 case 0x47: 185 return "DRTM_TA" 186 // ... skipped entries ... 187 case 0x50: 188 return "SPI_ROM_PUBLIC_KEYS" 189 } 190 return "UNKNOWN" 191 } 192 193 func getPSPTable(pspFirmware *amd_manifest.PSPFirmware, pspLevel uint) (*amd_manifest.PSPDirectoryTable, error) { 194 switch pspLevel { 195 case 1: 196 return pspFirmware.PSPDirectoryLevel1, nil 197 case 2: 198 return pspFirmware.PSPDirectoryLevel2, nil 199 } 200 return nil, fmt.Errorf("cannot extract raw PSP entry, invalid PSP Directory Level requested: %d", pspLevel) 201 } 202 203 // OutputPSPEntries outputs the PSP entries in an ASCII table format 204 func OutputPSPEntries(amdFw *amd_manifest.AMDFirmware) error { 205 pspDirectoryLevel1Table, err := getPSPTable(amdFw.PSPFirmware(), 1) 206 if err != nil { 207 return fmt.Errorf("unable to retrieve PSP Directory Level 1 Entries: %w", err) 208 } 209 210 pspDirectoryLevel2Table, err := getPSPTable(amdFw.PSPFirmware(), 2) 211 if err != nil { 212 return fmt.Errorf("unable to retrieve PSP Directory Level 2 Entries: %w", err) 213 } 214 215 pspDirectories := []amd_manifest.PSPDirectoryTable{*pspDirectoryLevel1Table, *pspDirectoryLevel2Table} 216 217 for idx, directory := range pspDirectories { 218 // PSP Header 219 h := table.NewWriter() 220 h.SetOutputMirror(os.Stdout) 221 h.SetTitle("PSP Directory Level %d Header", idx+1) 222 pspCookie := fmt.Sprintf("0x%x", directory.PSPCookie) 223 pspChecksum := directory.Checksum 224 pspTotalEntries := directory.TotalEntries 225 pspAdditionalInfo := fmt.Sprintf("0x%x", directory.AdditionalInfo) 226 h.AppendHeader(table.Row{"PSP Cookie", "Checksum", "Total Entries", "Additional Info"}) 227 h.AppendRow([]interface{}{pspCookie, pspChecksum, pspTotalEntries, pspAdditionalInfo}) 228 h.Render() 229 230 // PSP Entries 231 t := table.NewWriter() 232 t.SetOutputMirror(os.Stdout) 233 t.SetTitle("PSP Directory Level %d", idx+1) 234 t.AppendHeader(table.Row{"Type", "Hex Type", "SubProgram", "ROM ID", "Size", "Location/Value"}) 235 for _, entry := range directory.Entries { 236 entryType := PSPEntryType(entry.Type) 237 entryTypeHex := fmt.Sprintf("0x%-3x", entry.Type) 238 entrySubprogram := fmt.Sprintf("0x%-8x", entry.Subprogram) 239 entryRomID := fmt.Sprintf("0x%-3x", entry.ROMId) 240 entrySize := fmt.Sprintf("%-10d", entry.Size) 241 entryLocation := fmt.Sprintf("0x%-10x", entry.LocationOrValue) 242 t.AppendRow([]interface{}{entryType, entryTypeHex, entrySubprogram, entryRomID, entrySize, entryLocation}) 243 } 244 t.Render() 245 } 246 return nil 247 } 248 249 // ValidatePSPEntries validates signature of PSP entries given their entry values in PSP/BIOS Table 250 func ValidatePSPEntries(amdFw *amd_manifest.AMDFirmware, keyDB KeySet, directory DirectoryType, entries []uint32) ([]SignatureValidationResult, error) { 251 validationResults := make([]SignatureValidationResult, 0, len(entries)) 252 253 for _, entry := range entries { 254 entries, err := GetEntries(amdFw.PSPFirmware(), directory, entry) 255 if err != nil { 256 return nil, fmt.Errorf("could not extract entry 0x%x from PSP table: %w", entry, err) 257 } 258 if len(entries) == 0 { 259 return nil, fmt.Errorf("no entries %d are found in '%s'", entry, directory) 260 } 261 262 for _, entry := range entries { 263 validationResult, err := ValidatePSPEntry(amdFw, keyDB, entry.Offset, entry.Length) 264 if err != nil { 265 return nil, err 266 } 267 validationResults = append(validationResults, validationResult) 268 } 269 } 270 return validationResults, nil 271 } 272 273 // ValidatePSPEntry validates signature of a PSP entry 274 func ValidatePSPEntry(amdFw *amd_manifest.AMDFirmware, keyDB KeySet, offset, length uint64) (SignatureValidationResult, error) { 275 image := amdFw.Firmware().ImageBytes() 276 data, err := GetRangeBytes(image, offset, length) 277 if err != nil { 278 return SignatureValidationResult{}, err 279 } 280 281 binary, err := newPSPBinary(data) 282 if err != nil { 283 return SignatureValidationResult{}, fmt.Errorf("could not create PSB binary from raw data for entry: 0x%x-0x%x: %w", offset, offset+length, err) 284 } 285 signedBlob, err := binary.getSignedBlob(keyDB) 286 var signedElement strings.Builder 287 fmt.Fprintf(&signedElement, "PSP entry 0x%x-0x%x", offset, offset+length) 288 289 if err != nil { 290 var sigError *SignatureCheckError 291 if errors.As(err, &sigError) { 292 return SignatureValidationResult{signedElement: signedElement.String(), signingKey: sigError.SigningKey(), err: err}, nil 293 } 294 return SignatureValidationResult{signedElement: signedElement.String(), err: err}, nil 295 } 296 297 signature := signedBlob.Signature() 298 return SignatureValidationResult{signedElement: signedElement.String(), signingKey: signature.SigningKey()}, nil 299 }