github.com/linuxboot/fiano@v1.2.0/pkg/fsp/header.go (about)

     1  // Copyright 2018 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 fsp implements FSP info header parsing
     6  package fsp
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/binary"
    11  	"encoding/json"
    12  	"fmt"
    13  	"strings"
    14  
    15  	"github.com/linuxboot/fiano/pkg/log"
    16  )
    17  
    18  // TODO support FSP versions < 2.0
    19  // TODO implement FSP_INFO_EXTENDED_HEADER
    20  
    21  // FSP 2.0 specification
    22  // https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/fsp-architecture-spec-v2.pdf
    23  
    24  // values from the FSP 2.0 spec
    25  var (
    26  	Signature = [4]byte{'F', 'S', 'P', 'H'}
    27  )
    28  
    29  // constants from the FSP 2.0 spec
    30  const (
    31  	// size of the shared part of the header across FSP spec revisions
    32  	FixedInfoHeaderLength = 12
    33  	HeaderV3Length        = 72
    34  	HeaderV4Length        = 72
    35  	HeaderV5Length        = 76
    36  	HeaderV6Length        = 80
    37  	// FSP 2.0
    38  	CurrentSpecVersion = SpecVersion(0x20)
    39  	HeaderMinRevision  = 3
    40  	HeaderMaxRevision  = 6
    41  	// FSP 3.0
    42  	UnsupportedSpecVersion = SpecVersion(0x30)
    43  )
    44  
    45  // FixedInfoHeader is the common header among the various revisions of the FSP
    46  // info header.
    47  type FixedInfoHeader struct {
    48  	Signature      [4]byte
    49  	HeaderLength   uint32
    50  	Reserved1      [2]uint8
    51  	SpecVersion    SpecVersion
    52  	HeaderRevision uint8
    53  }
    54  
    55  // InfoHeaderRev3 represents the FSP_INFO_HEADER structure revision 3 + 4 (FSP
    56  // 2.0) as defined by Intel.
    57  type InfoHeaderRev3 struct {
    58  	FixedInfoHeader
    59  	ImageRevisionLowBytes     uint32
    60  	ImageID                   [8]byte
    61  	ImageSize                 uint32
    62  	ImageBase                 uint32
    63  	ImageAttribute            ImageAttribute
    64  	ComponentAttribute        ComponentAttribute
    65  	CfgRegionOffset           uint32
    66  	CfgRegionSize             uint32
    67  	Reserved2                 [4]byte
    68  	TempRAMInitEntryOffset    uint32
    69  	Reserved3                 [4]byte
    70  	NotifyPhaseEntryOffset    uint32
    71  	FSPMemoryInitEntryOffset  uint32
    72  	TempRAMExitEntryOffset    uint32
    73  	FSPSiliconInitEntryOffset uint32
    74  }
    75  
    76  // InfoHeaderRev5 represents the FSP_INFO_HEADER structure revision 5 (FSP
    77  // 2.0) as defined by Intel.
    78  type InfoHeaderRev5 struct {
    79  	InfoHeaderRev3
    80  	FspMultiPhaseSiInitEntryOffset uint32
    81  }
    82  
    83  // InfoHeaderRev6 represents the FSP_INFO_HEADER structure revision 6 (FSP
    84  // 2.0) as defined by Intel.
    85  type InfoHeaderRev6 struct {
    86  	InfoHeaderRev5
    87  	ExtendedImageRevision uint16
    88  	Reserved4             uint16
    89  }
    90  
    91  // CommonInfoHeader represents the FSP_INFO_HEADER structure
    92  // revision independent
    93  type CommonInfoHeader struct {
    94  	Signature                      [4]byte
    95  	HeaderLength                   uint32
    96  	SpecVersion                    SpecVersion
    97  	HeaderRevision                 uint8
    98  	ImageRevision                  ImageRevision
    99  	ImageID                        [8]byte
   100  	ImageSize                      uint32
   101  	ImageBase                      uint32
   102  	ImageAttribute                 ImageAttribute
   103  	ComponentAttribute             ComponentAttribute
   104  	CfgRegionOffset                uint32
   105  	CfgRegionSize                  uint32
   106  	TempRAMInitEntryOffset         uint32
   107  	NotifyPhaseEntryOffset         uint32
   108  	FSPMemoryInitEntryOffset       uint32
   109  	TempRAMExitEntryOffset         uint32
   110  	FSPSiliconInitEntryOffset      uint32
   111  	FspMultiPhaseSiInitEntryOffset uint32
   112  	ExtendedImageRevision          uint16
   113  }
   114  
   115  // Summary prints a multi-line summary of the header's content.
   116  func (ih CommonInfoHeader) Summary() string {
   117  	s := fmt.Sprintf("Signature                        : %s\n", ih.Signature)
   118  	s += fmt.Sprintf("Header Length                    : %d\n", ih.HeaderLength)
   119  	s += fmt.Sprintf("Spec Version                     : %s\n", ih.SpecVersion)
   120  	s += fmt.Sprintf("Header Revision                  : %d\n", ih.HeaderRevision)
   121  	s += fmt.Sprintf("Image Revision                   : %s\n", ih.ImageRevision)
   122  	s += fmt.Sprintf("Image ID                         : %s\n", ih.ImageID)
   123  	s += fmt.Sprintf("Image Size                       : %#08x %d\n", ih.ImageSize, ih.ImageSize)
   124  	s += fmt.Sprintf("Image Base                       : %#08x %d\n", ih.ImageBase, ih.ImageBase)
   125  	s += fmt.Sprintf("Image Attribute                  : %s\n", ih.ImageAttribute)
   126  	s += fmt.Sprintf("Component Attribute              : %s\n", ih.ComponentAttribute)
   127  	s += fmt.Sprintf("Cfg Region Offset                : %#08x %d\n", ih.CfgRegionOffset, ih.CfgRegionOffset)
   128  	s += fmt.Sprintf("Cfg Region Size                  : %#08x %d\n", ih.CfgRegionSize, ih.CfgRegionSize)
   129  	s += fmt.Sprintf("TempRAMInit Entry Offset         : %#08x %d\n", ih.TempRAMInitEntryOffset, ih.TempRAMInitEntryOffset)
   130  	s += fmt.Sprintf("NotifyPhase Entry Offset         : %#08x %d\n", ih.NotifyPhaseEntryOffset, ih.NotifyPhaseEntryOffset)
   131  	s += fmt.Sprintf("FSPMemoryInit Entry Offset       : %#08x %d\n", ih.FSPMemoryInitEntryOffset, ih.FSPMemoryInitEntryOffset)
   132  	s += fmt.Sprintf("TempRAMExit Entry Offset         : %#08x %d\n", ih.TempRAMExitEntryOffset, ih.TempRAMExitEntryOffset)
   133  	s += fmt.Sprintf("FSPSiliconInit Entry Offset      : %#08x %d\n", ih.FSPSiliconInitEntryOffset, ih.FSPSiliconInitEntryOffset)
   134  	s += fmt.Sprintf("FspMultiPhaseSiInit Entry Offset : %#08x %d\n", ih.FspMultiPhaseSiInitEntryOffset, ih.FspMultiPhaseSiInitEntryOffset)
   135  	s += fmt.Sprintf("ExtendedImageRevision            : %#08x %d\n", ih.ExtendedImageRevision, ih.ExtendedImageRevision)
   136  
   137  	return s
   138  }
   139  
   140  // ImageRevision is the image revision field of the FSP info header.
   141  type ImageRevision uint64
   142  
   143  func (ir ImageRevision) String() string {
   144  	return fmt.Sprintf("%d.%d.%d.%d",
   145  		(ir>>48)&0xffff,
   146  		(ir>>32)&0xffff,
   147  		(ir>>16)&0xffff,
   148  		ir&0xffff,
   149  	)
   150  }
   151  
   152  func DecodeImageRevision(HeaderRevision uint8, Revision uint32, ExtendedRevision uint16) ImageRevision {
   153  	///            Major.Minor.Revision.Build
   154  	///            If FSP HeaderRevision is <= 5, the ImageRevision can be decoded as follows:
   155  	///               7 : 0  - Build Number
   156  	///              15 : 8  - Revision
   157  	///              23 : 16 - Minor Version
   158  	///              31 : 24 - Major Version
   159  	///            If FSP HeaderRevision is >= 6, ImageRevision specifies the low-order bytes of the build number and revision
   160  	///            while ExtendedImageRevision specifies the high-order bytes of the build number and revision.
   161  	///               7 : 0  - Low Byte of Build Number
   162  	///              15 : 8  - Low Byte of Revision
   163  	///              23 : 16 - Minor Version
   164  	///              31 : 24 - Major Version
   165  	///            This value is only valid if FSP HeaderRevision is >= 6.
   166  	///
   167  	///            ExtendedImageRevision specifies the high-order byte of the revision and build number in the FSP binary revision.
   168  	///               7 : 0 - High Byte of Build Number
   169  	///              15 : 8 - High Byte of Revision
   170  	///            The FSP binary build number can be decoded as follows:
   171  	///            Build Number = (ExtendedImageRevision[7:0] << 8) | ImageRevision[7:0]
   172  	///            Revision = (ExtendedImageRevision[15:8] << 8) | ImageRevision[15:8]
   173  	///            Minor Version = ImageRevision[23:16]
   174  	///            Major Version = ImageRevision[31:24]
   175  
   176  	if HeaderRevision < 6 {
   177  		ExtendedRevision = 0
   178  	}
   179  	return ImageRevision((uint64(Revision)&0xff)<<0 |
   180  		(uint64(Revision)&0xff00)<<8 |
   181  		(uint64(Revision)&0xff0000)<<16 |
   182  		(uint64(Revision)&0xff000000)<<24 |
   183  		(uint64(ExtendedRevision)&0xff)<<8 |
   184  		(uint64(ExtendedRevision)&0xff00)<<16)
   185  }
   186  
   187  // SpecVersion represents the spec version as a packed BCD two-digit,
   188  // dot-separated unsigned integer.
   189  type SpecVersion uint8
   190  
   191  func (sv SpecVersion) String() string {
   192  	return fmt.Sprintf("%d.%d", (sv>>4)&0x0f, sv&0x0f)
   193  }
   194  
   195  // ImageAttribute represents the image attributes.
   196  type ImageAttribute uint16
   197  
   198  func (ia ImageAttribute) String() string {
   199  	ret := fmt.Sprintf("%#04x ", uint16(ia))
   200  	if ia.IsGraphicsDisplaySupported() {
   201  		ret += "GraphicsDisplaySupported"
   202  	} else {
   203  		ret += "GraphicsDisplayNotSupported"
   204  	}
   205  	if ia.IsDispatchModeSupported() {
   206  		ret += " DispatchModeSupported"
   207  	} else {
   208  		ret += " DispatchModeNotSupported"
   209  	}
   210  	if uint16(ia) & ^(uint16(1)) != 0 {
   211  		ret += " (reserved bits are not zeroed)"
   212  	}
   213  	return ret
   214  }
   215  
   216  // IsGraphicsDisplaySupported returns true if FSP supports enabling graphics display.
   217  func (ia ImageAttribute) IsGraphicsDisplaySupported() bool {
   218  	return uint16(ia)&0x1 == 1
   219  }
   220  
   221  // IsDispatchModeSupported returns true if FSP supports Dispatch mode.
   222  func (ia ImageAttribute) IsDispatchModeSupported() bool {
   223  	return uint16(ia)&0x2 == 2
   224  }
   225  
   226  // Type identifies the FSP type.
   227  type Type uint8
   228  
   229  // FSP types. All the other values are reserved.
   230  var (
   231  	TypeT Type = 1
   232  	TypeM Type = 2
   233  	TypeS Type = 3
   234  	TypeO Type = 8
   235  	// TypeReserved is a fake type that represents a reserved FSP type.
   236  	TypeReserved Type
   237  )
   238  
   239  var fspTypeNames = map[Type]string{
   240  	TypeT:        "FSP-T",
   241  	TypeM:        "FSP-M",
   242  	TypeS:        "FSP-S",
   243  	TypeO:        "FSP-O",
   244  	TypeReserved: "FSP-ReservedType",
   245  }
   246  
   247  // ComponentAttribute represents the component attribute.
   248  type ComponentAttribute uint16
   249  
   250  // IsDebugBuild returns true if the FSP build is a debug build, and false
   251  // if it's a release build.
   252  func (ca ComponentAttribute) IsDebugBuild() bool {
   253  	return uint16(ca)&0x01 == 0
   254  }
   255  
   256  // IsTestRelease returns true if the release is a test release, and false if
   257  // it's an official release.
   258  func (ca ComponentAttribute) IsTestRelease() bool {
   259  	return uint16(ca)&0x03 == 0
   260  }
   261  
   262  // Type returns the FSP type.
   263  func (ca ComponentAttribute) Type() Type {
   264  	typ := Type(uint16(ca) >> 12)
   265  	if _, ok := fspTypeNames[typ]; ok {
   266  		return typ
   267  	}
   268  	return TypeReserved
   269  }
   270  
   271  func (ca ComponentAttribute) String() string {
   272  	var attrs []string
   273  	if ca.IsDebugBuild() {
   274  		attrs = append(attrs, "DebugBuild")
   275  	} else {
   276  		attrs = append(attrs, "ReleaseBuild")
   277  	}
   278  	if ca.IsTestRelease() {
   279  		attrs = append(attrs, "TestRelease")
   280  	} else {
   281  		attrs = append(attrs, "OfficialRelease")
   282  	}
   283  	if typeName, ok := fspTypeNames[ca.Type()]; ok {
   284  		attrs = append(attrs, typeName)
   285  	} else {
   286  		attrs = append(attrs, fmt.Sprintf("TypeUnknown(%v)", ca.Type()))
   287  	}
   288  	ret := fmt.Sprintf("%#04x %s", uint16(ca), strings.Join(attrs, "|"))
   289  	// bits 11:2 are reserved
   290  	if uint16(ca)&0x0ffe != 0 {
   291  		ret += " (reserved bits are not zeroed)"
   292  	}
   293  	return ret
   294  }
   295  
   296  // NewInfoHeader creates an CommonInfoHeader from a byte buffer.
   297  func NewInfoHeader(b []byte) (*CommonInfoHeader, error) {
   298  	if len(b) < FixedInfoHeaderLength {
   299  		return nil, fmt.Errorf("short FSP Info Header length %d; want at least %d", len(b), FixedInfoHeaderLength)
   300  	}
   301  	var hdr FixedInfoHeader
   302  
   303  	reader := bytes.NewReader(b)
   304  	if err := binary.Read(reader, binary.LittleEndian, &hdr); err != nil {
   305  		return nil, err
   306  	}
   307  
   308  	// check signature
   309  	if !bytes.Equal(hdr.Signature[:], Signature[:]) {
   310  		return nil, fmt.Errorf("invalid signature %v; want %v", hdr.Signature, Signature)
   311  	}
   312  	// reserved bytes must be zero'ed
   313  	if !bytes.Equal(hdr.Reserved1[:], []byte{0, 0}) {
   314  		log.Warnf("reserved bytes must be zero, got %v", hdr.Reserved1)
   315  	}
   316  	// check spec version
   317  	// TODO currently, only FSP 2.x is supported
   318  	if hdr.SpecVersion < CurrentSpecVersion || hdr.SpecVersion >= UnsupportedSpecVersion {
   319  		return nil, fmt.Errorf("cannot handle spec version %s; want %s", hdr.SpecVersion, CurrentSpecVersion)
   320  	}
   321  
   322  	// check header revision
   323  	if hdr.HeaderRevision < HeaderMinRevision {
   324  		return nil, fmt.Errorf("cannot handle header revision %d; want min %d", hdr.HeaderRevision, HeaderMinRevision)
   325  	}
   326  
   327  	l := uint32(0)
   328  	switch hdr.HeaderRevision {
   329  	case 3:
   330  		l = HeaderV3Length
   331  	case 4:
   332  		l = HeaderV4Length
   333  	case 5:
   334  		l = HeaderV5Length
   335  	case 6:
   336  		l = HeaderV6Length
   337  	default:
   338  		l = HeaderV6Length
   339  	}
   340  	if hdr.HeaderRevision <= HeaderMaxRevision {
   341  		// Intel violates their own spec! Warn here and don't care about additional fields.
   342  		if l != hdr.HeaderLength {
   343  			log.Warnf("Spec violation. header length is %d; expected %d", hdr.HeaderLength, l)
   344  		}
   345  	}
   346  	if hdr.HeaderLength < l {
   347  		return nil, fmt.Errorf("invalid header length %d; want at least %d", hdr.HeaderLength, l)
   348  	}
   349  
   350  	// now that we know it's an info header spec 2.0, re-read the
   351  	// buffer to fill the whole header.
   352  	reader = bytes.NewReader(b)
   353  	var InfoHeader InfoHeaderRev6
   354  
   355  	if hdr.HeaderRevision >= 6 {
   356  		if err := binary.Read(reader, binary.LittleEndian, &InfoHeader); err != nil {
   357  			return nil, err
   358  		}
   359  	} else if hdr.HeaderRevision >= 5 {
   360  		if err := binary.Read(reader, binary.LittleEndian, &InfoHeader.InfoHeaderRev5); err != nil {
   361  			return nil, err
   362  		}
   363  	} else {
   364  		if err := binary.Read(reader, binary.LittleEndian, &InfoHeader.InfoHeaderRev3); err != nil {
   365  			return nil, err
   366  		}
   367  	}
   368  
   369  	// Fill common info header
   370  	j, _ := json.Marshal(InfoHeader)
   371  	var c CommonInfoHeader
   372  	if err := json.Unmarshal(j, &c); err != nil {
   373  		return nil, err
   374  	}
   375  
   376  	// Update custom types
   377  	c.ImageRevision = DecodeImageRevision(hdr.HeaderRevision,
   378  		InfoHeader.ImageRevisionLowBytes,
   379  		InfoHeader.ExtendedImageRevision)
   380  
   381  	return &c, nil
   382  }