github.com/linuxboot/fiano@v1.2.0/pkg/intel/microcode/microcode.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 microcode 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io" 12 ) 13 14 const ( 15 DefaultDatasize = 2000 16 DefaultTotalSize = 2048 17 ) 18 19 type Microcode struct { 20 Header 21 Data []byte 22 ExtSigTable ExtendedSigTable 23 ExtendedSignatures []ExtendedSignature 24 } 25 26 func (m *Microcode) String() string { 27 s := fmt.Sprintf("sig=0x%x, pf=0x%x, rev=0x%x, total size=0x%x, date = %04x-%02x-%02x", 28 m.HeaderProcessorSignature, m.HeaderProcessorFlags, m.HeaderRevision, 29 getTotalSize(m.Header), m.HeaderDate&0xffff, m.HeaderDate>>24, (m.HeaderDate>>16)&0xff) 30 if len(m.ExtendedSignatures) > 0 { 31 s += "\n" 32 } 33 for i := range m.ExtendedSignatures { 34 s += fmt.Sprintf("Extended signature[%d]: %s\n", i, m.ExtendedSignatures[i].String()) 35 } 36 return s 37 } 38 39 type Header struct { 40 HeaderVersion uint32 // must be 0x1 41 HeaderRevision uint32 42 HeaderDate uint32 // packed BCD, MMDDYYYY 43 HeaderProcessorSignature uint32 44 HeaderChecksum uint32 45 HeaderLoaderRevision uint32 46 HeaderProcessorFlags uint32 47 HeaderDataSize uint32 // 0 means 2000 48 HeaderTotalSize uint32 // 0 means 2048 49 Reserved1 [3]uint32 50 } 51 52 type ExtendedSignature struct { 53 Signature uint32 54 ProcessorFlags uint32 55 Checksum uint32 56 } 57 58 func (e *ExtendedSignature) String() string { 59 return fmt.Sprintf("sig=0x%x, pf=0x%x", e.Signature, e.ProcessorFlags) 60 } 61 62 type ExtendedSigTable struct { 63 Count uint32 64 Checksum uint32 65 Reserved [3]uint32 66 } 67 68 func getTotalSize(h Header) uint32 { 69 if h.HeaderDataSize > 0 { 70 return h.HeaderTotalSize 71 } else { 72 return DefaultTotalSize 73 } 74 } 75 76 func getDataSize(h Header) uint32 { 77 if h.HeaderDataSize > 0 { 78 return h.HeaderDataSize 79 } else { 80 return DefaultDatasize 81 } 82 } 83 84 // ParseIntelMicrocode parses the Intel microcode update 85 func ParseIntelMicrocode(r io.Reader) (*Microcode, error) { 86 var m Microcode 87 88 if err := binary.Read(r, binary.LittleEndian, &m.Header); err != nil { 89 return nil, fmt.Errorf("Failed to read header: %v", err) 90 } 91 92 // Sanitychecks 93 if getTotalSize(m.Header) < getDataSize(m.Header)+uint32(binary.Size(Header{})) { 94 return nil, fmt.Errorf("Bad data file size") 95 } 96 if m.HeaderLoaderRevision != 1 || m.HeaderVersion != 1 { 97 return nil, fmt.Errorf("Invalid version or revision") 98 } 99 if getDataSize(m.Header)%4 > 0 { 100 return nil, fmt.Errorf("Data size not 32bit aligned") 101 } 102 if getTotalSize(m.Header)%4 > 0 { 103 return nil, fmt.Errorf("Total size not 32bit aligned") 104 } 105 // Read data 106 m.Data = make([]byte, getDataSize(m.Header)) 107 if err := binary.Read(r, binary.LittleEndian, &m.Data); err != nil { 108 return nil, fmt.Errorf("Failed to read data: %v", err) 109 } 110 111 // Calculcate checksum 112 buf := bytes.NewBuffer([]byte{}) 113 buf.Grow(int(getDataSize(m.Header)) + binary.Size(Header{})) 114 _ = binary.Write(buf, binary.LittleEndian, &m.Header) 115 _ = binary.Write(buf, binary.LittleEndian, &m.Data) 116 117 var checksum uint32 118 for { 119 var data uint32 120 if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { 121 break 122 } 123 checksum += data 124 } 125 if checksum != 0 { 126 return nil, fmt.Errorf("Checksum is not null: %#x", checksum) 127 } 128 129 if getTotalSize(m.Header) <= getDataSize(m.Header)+uint32(binary.Size(Header{})) { 130 return &m, nil 131 } 132 133 // Read extended header 134 if err := binary.Read(r, binary.LittleEndian, &m.ExtSigTable); err != nil { 135 return nil, fmt.Errorf("Failed to read extended sig table: %v", err) 136 } 137 for i := uint32(0); i < m.ExtSigTable.Count; i++ { 138 var signature ExtendedSignature 139 if err := binary.Read(r, binary.LittleEndian, &signature); err != nil { 140 return nil, fmt.Errorf("Failed to read extended signature: %v", err) 141 } 142 m.ExtendedSignatures = append(m.ExtendedSignatures, signature) 143 } 144 145 // Calculcate checksum 146 buf = bytes.NewBuffer([]byte{}) 147 buf.Grow(binary.Size(ExtendedSigTable{}) + 148 int(m.ExtSigTable.Count)*binary.Size(ExtendedSignature{})) 149 _ = binary.Write(buf, binary.LittleEndian, &m.ExtSigTable) 150 for i := uint32(0); i < m.ExtSigTable.Count; i++ { 151 _ = binary.Write(buf, binary.LittleEndian, &m.ExtendedSignatures[i]) 152 } 153 154 checksum = 0 155 for { 156 var data uint32 157 if err := binary.Read(buf, binary.LittleEndian, &data); err != nil { 158 break 159 } 160 checksum += data 161 } 162 if checksum != 0 { 163 return nil, fmt.Errorf("Extended header checksum is not null: %#x", checksum) 164 } 165 166 return &m, nil 167 }