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  }