github.com/linuxboot/fiano@v1.2.0/pkg/amd/manifest/psp_directory_table.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 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io" 12 "strings" 13 14 bytes2 "github.com/linuxboot/fiano/pkg/bytes" 15 ) 16 17 // Refer to: AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h and Family 19h 18 // Processors (NDA), Publication # 55758 Revision: 1.11 Issue Date: August 2020 (1) 19 20 // PSPDirectoryTableCookie is a special identifier of PSP Directory table level 1 21 const PSPDirectoryTableCookie = 0x50535024 // "$PSP" 22 // PSPDirectoryTableLevel2Cookie is a special identifier of PSP Directory table level 2 23 const PSPDirectoryTableLevel2Cookie = 0x324C5024 // "$PL2" 24 25 // PSPDirectoryTableEntryType is an entry type of PSP Directory table 26 type PSPDirectoryTableEntryType uint8 27 28 const ( 29 // AMDPublicKeyEntry denotes AMD public key entry in PSP Directory table 30 AMDPublicKeyEntry PSPDirectoryTableEntryType = 0x00 31 // PSPBootloaderFirmwareEntry denotes a PSP bootloader firmware entry in PSP Directory table 32 PSPBootloaderFirmwareEntry PSPDirectoryTableEntryType = 0x01 33 // PSPDirectoryTableLevel2Entry denotes an entry that points to PSP Directory table level 2 34 PSPDirectoryTableLevel2Entry PSPDirectoryTableEntryType = 0x40 35 ) 36 37 // PSPDirectoryTableEntry represents a single entry in PSP Directory Table 38 // Table 5 in (1) 39 type PSPDirectoryTableEntry struct { 40 Type PSPDirectoryTableEntryType 41 Subprogram uint8 42 ROMId uint8 43 Size uint32 44 LocationOrValue uint64 45 } 46 47 const PSPDirectoryTableEntrySize = 16 48 49 // PSPDirectoryTableHeader represents a BIOS Directory Table Header 50 // Tables 3&4 from (1) 51 type PSPDirectoryTableHeader struct { 52 PSPCookie uint32 53 Checksum uint32 54 TotalEntries uint32 55 AdditionalInfo uint32 56 } 57 58 // PSPDirectoryTable represents PSP Directory Table Header with all entries 59 // Table 5 in (1) 60 type PSPDirectoryTable struct { 61 PSPDirectoryTableHeader 62 63 Entries []PSPDirectoryTableEntry 64 } 65 66 func (p PSPDirectoryTable) String() string { 67 var s strings.Builder 68 cookieBytes := make([]byte, 4) 69 binary.LittleEndian.PutUint32(cookieBytes, p.PSPCookie) 70 fmt.Fprintf(&s, "PSP Cookie: 0x%x (%s)\n", p.PSPCookie, cookieBytes) 71 fmt.Fprintf(&s, "Checksum: %d\n", p.Checksum) 72 fmt.Fprintf(&s, "Total Entries: %d\n", p.TotalEntries) 73 fmt.Fprintf(&s, "Additional Info: 0x%x\n\n", p.AdditionalInfo) 74 fmt.Fprintf(&s, "%-5s | %-8s | %-5s | %-10s | %-10s\n", 75 "Type", 76 "Subprogram", 77 "ROMId", 78 "Size", 79 "Location/Value") 80 fmt.Fprintf(&s, "%s\n", "------------------------------------------------------------------------") 81 for _, entry := range p.Entries { 82 fmt.Fprintf(&s, "0x%-3x | 0x%-8x | 0x%-3x | %-10d | 0x%-10x\n", 83 entry.Type, 84 entry.Subprogram, 85 entry.ROMId, 86 entry.Size, 87 entry.LocationOrValue) 88 } 89 return s.String() 90 } 91 92 // FindPSPDirectoryTable scans firmware for PSPDirectoryTableCookie 93 // and treats remaining bytes as PSPDirectoryTable 94 func FindPSPDirectoryTable(image []byte) (*PSPDirectoryTable, bytes2.Range, error) { 95 // there is no predefined address, search through the whole memory 96 cookieBytes := make([]byte, 4) 97 binary.LittleEndian.PutUint32(cookieBytes, PSPDirectoryTableCookie) 98 99 var offset uint64 100 for { 101 idx := bytes.Index(image, cookieBytes) 102 if idx == -1 { 103 break 104 } 105 106 table, length, err := ParsePSPDirectoryTable(image[idx:]) 107 if err != nil { 108 shift := uint64(idx + len(cookieBytes)) 109 image = image[idx+len(cookieBytes):] 110 offset += shift 111 continue 112 } 113 return table, bytes2.Range{Offset: offset + uint64(idx), Length: length}, err 114 } 115 return nil, bytes2.Range{}, fmt.Errorf("PSPDirectoryTable is not found") 116 } 117 118 // ParsePSPDirectoryTable converts input bytes into PSPDirectoryTable 119 func ParsePSPDirectoryTable(data []byte) (*PSPDirectoryTable, uint64, error) { 120 var table PSPDirectoryTable 121 var totalLength uint64 122 123 r := bytes.NewBuffer(data) 124 if err := readAndCountSize(r, binary.LittleEndian, &table.PSPCookie, &totalLength); err != nil { 125 return nil, 0, err 126 } 127 if table.PSPCookie != PSPDirectoryTableCookie && table.PSPCookie != PSPDirectoryTableLevel2Cookie { 128 return nil, 0, fmt.Errorf("incorrect cookie: %d", table.PSPCookie) 129 } 130 if err := readAndCountSize(r, binary.LittleEndian, &table.Checksum, &totalLength); err != nil { 131 return nil, 0, err 132 } 133 if err := readAndCountSize(r, binary.LittleEndian, &table.TotalEntries, &totalLength); err != nil { 134 return nil, 0, err 135 } 136 if err := readAndCountSize(r, binary.LittleEndian, &table.AdditionalInfo, &totalLength); err != nil { 137 return nil, 0, err 138 } 139 140 sizeRequired := uint64(table.TotalEntries) * PSPDirectoryTableEntrySize 141 if uint64(r.Len()) < sizeRequired { 142 return nil, 0, fmt.Errorf("not enough data, required: %d, actual: %d", sizeRequired+totalLength, len(data)) 143 } 144 145 for idx := uint32(0); idx < table.TotalEntries; idx++ { 146 entry, length, err := ParsePSPDirectoryTableEntry(r) 147 if err != nil { 148 return nil, 0, err 149 } 150 totalLength += length 151 table.Entries = append(table.Entries, *entry) 152 } 153 return &table, totalLength, nil 154 } 155 156 // ParsePSPDirectoryTableEntry converts input bytes into PSPDirectoryTableEntry 157 func ParsePSPDirectoryTableEntry(r io.Reader) (*PSPDirectoryTableEntry, uint64, error) { 158 var entry PSPDirectoryTableEntry 159 var length uint64 160 161 if err := readAndCountSize(r, binary.LittleEndian, &entry.Type, &length); err != nil { 162 return nil, 0, err 163 } 164 if err := readAndCountSize(r, binary.LittleEndian, &entry.Subprogram, &length); err != nil { 165 return nil, 0, err 166 } 167 168 var flags uint16 169 if err := readAndCountSize(r, binary.LittleEndian, &flags, &length); err != nil { 170 return nil, 0, err 171 } 172 entry.ROMId = uint8(flags>>14) & 0x3 173 174 if err := readAndCountSize(r, binary.LittleEndian, &entry.Size, &length); err != nil { 175 return nil, 0, err 176 } 177 if err := readAndCountSize(r, binary.LittleEndian, &entry.LocationOrValue, &length); err != nil { 178 return nil, 0, err 179 } 180 return &entry, length, nil 181 }