github.com/linuxboot/fiano@v1.2.0/pkg/uefi/uefi.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 uefi contents data types for the components found in UEFI and an
     6  // Parse function for reading an image.
     7  package uefi
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/binary"
    12  	"encoding/json"
    13  	"fmt"
    14  	"reflect"
    15  )
    16  
    17  var (
    18  	// ReadOnly breaks firmware modification operations, but optimizes
    19  	// memory and CPU consumption for read-only operations.
    20  	//
    21  	// DO NOT USE THIS OPTION UNLESS YOU KNOW WHAT ARE YOU DOING. IF YOU
    22  	// WILL MODIFY A FIRMWARE WITH THIS OPTION BEING ENABLED, THIS FIRMWARE
    23  	// MIGHT BRICK YOUR DEVICE.
    24  	ReadOnly = false
    25  
    26  	// DisableDecompression disables section decompression.
    27  	//
    28  	// DO NOT USE THIS OPTION UNLESS YOU KNOW WHAT ARE YOU DOING. IF YOU
    29  	// WILL MODIFY A FIRMWARE WITH THIS OPTION BEING ENABLED, THIS FIRMWARE
    30  	// MIGHT BRICK YOUR DEVICE.
    31  	DisableDecompression = false
    32  )
    33  
    34  // ROMAttributes is used to hold global variables that apply across the whole image.
    35  // We have to do this to avoid passing too many things down each time.
    36  type ROMAttributes struct {
    37  	ErasePolarity byte // Either 0xFF or 0
    38  }
    39  
    40  const poisonedPolarity byte = 0xF0
    41  
    42  // Attributes holds the global attributes
    43  var Attributes = ROMAttributes{ErasePolarity: poisonedPolarity}
    44  
    45  // SuppressErasePolarityError forces to ignore the "conflicting erase polarities"
    46  // error.
    47  //
    48  // See also: https://github.com/linuxboot/fiano/issues/329
    49  var SuppressErasePolarityError = false
    50  
    51  // SetErasePolarity sets the Erase Polarity for the flash image.
    52  // It checks to see if there are conflicting Erase Polarities.
    53  func SetErasePolarity(ep byte) error {
    54  	if ep != 0xFF && ep != 0 {
    55  		// Invalid erase polarity requested.
    56  		return fmt.Errorf("invalid erase polarity requested, should only be 0x00 or 0xFF, got 0x%02X",
    57  			ep)
    58  	}
    59  	// Set it only once.
    60  	if Attributes.ErasePolarity != poisonedPolarity && !SuppressErasePolarityError {
    61  		// it's already been set. Check that they are the same.
    62  		if Attributes.ErasePolarity != ep {
    63  			return fmt.Errorf("conflicting erase polarities, was 0x%02X, requested 0x%02X",
    64  				Attributes.ErasePolarity, ep)
    65  		}
    66  		return nil
    67  	}
    68  	Attributes.ErasePolarity = ep
    69  	return nil
    70  }
    71  
    72  // Firmware is an interface to describe generic firmware types. When the
    73  // firmware is parsed, all the Firmware objects are laid out in a tree (similar
    74  // to an AST). This interface represents one node in said tree. The
    75  // implementations (e.g. Flash image, or FirmwareVolume) must implement this
    76  // interface.
    77  type Firmware interface {
    78  	Buf() []byte
    79  	SetBuf(buf []byte)
    80  
    81  	// Apply a visitor to the Firmware.
    82  	Apply(v Visitor) error
    83  
    84  	// Apply a visitor to all the direct children of the Firmware
    85  	// (excluding the Firmware itself).
    86  	ApplyChildren(v Visitor) error
    87  }
    88  
    89  // TypedFirmware includes the Firmware interface's type when exporting it to
    90  // JSON. The type is required when unmarshalling.
    91  type TypedFirmware struct {
    92  	Type  string
    93  	Value Firmware
    94  }
    95  
    96  // MakeTyped takes a Firmware interface and makes a (type, value) pair.
    97  func MakeTyped(f Firmware) *TypedFirmware {
    98  	return &TypedFirmware{
    99  		Type:  reflect.TypeOf(f).String(),
   100  		Value: f,
   101  	}
   102  }
   103  
   104  // UnmarshalJSON unmarshals a TypedFirmware struct and correctly deduces the
   105  // type of the interface.
   106  func (f *TypedFirmware) UnmarshalJSON(b []byte) error {
   107  	var getType struct {
   108  		Type  string
   109  		Value json.RawMessage
   110  	}
   111  	if err := json.Unmarshal(b, &getType); err != nil {
   112  		return err
   113  	}
   114  	factory, ok := firmwareTypes[getType.Type]
   115  	if !ok {
   116  		return fmt.Errorf("unknown TypedFirmware type '%s', unable to unmarshal", getType.Type)
   117  	}
   118  	f.Type = getType.Type
   119  	f.Value = factory()
   120  	return json.Unmarshal(getType.Value, &f.Value)
   121  }
   122  
   123  // This should never be exposed, it is only used for marshalling different types to json.
   124  type marshalFirmware struct {
   125  	FType           string
   126  	FirmwareElement json.RawMessage
   127  }
   128  
   129  var firmwareTypes = map[string]func() Firmware{
   130  	"*uefi.BIOSRegion":      func() Firmware { return &BIOSRegion{} },
   131  	"*uefi.BIOSPadding":     func() Firmware { return &BIOSPadding{} },
   132  	"*uefi.File":            func() Firmware { return &File{} },
   133  	"*uefi.FirmwareVolume":  func() Firmware { return &FirmwareVolume{} },
   134  	"*uefi.FlashDescriptor": func() Firmware { return &FlashDescriptor{} },
   135  	"*uefi.FlashImage":      func() Firmware { return &FlashImage{} },
   136  	"*uefi.MERegion":        func() Firmware { return &MERegion{} },
   137  	"*uefi.RawRegion":       func() Firmware { return &RawRegion{} },
   138  	"*uefi.Section":         func() Firmware { return &Section{} },
   139  }
   140  
   141  // MarshalFirmware marshals the firmware element to JSON, including the type information at the top.
   142  func MarshalFirmware(f Firmware) ([]byte, error) {
   143  	b, err := json.MarshalIndent(f, "", "    ")
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	m := marshalFirmware{FType: reflect.TypeOf(f).String(), FirmwareElement: json.RawMessage(b)}
   149  	return json.MarshalIndent(m, "", "    ")
   150  }
   151  
   152  // UnmarshalFirmware unmarshals the firmware element from JSON, using the type information at the top.
   153  func UnmarshalFirmware(b []byte) (Firmware, error) {
   154  	var m marshalFirmware
   155  	if err := json.Unmarshal(b, &m); err != nil {
   156  		return nil, err
   157  	}
   158  	factory, ok := firmwareTypes[m.FType]
   159  	if !ok {
   160  		return nil, fmt.Errorf("unknown Firmware type '%s', unable to unmarshal", m.FType)
   161  	}
   162  	f := factory()
   163  	err := json.Unmarshal(m.FirmwareElement, &f)
   164  	return f, err
   165  }
   166  
   167  // Parse exposes a high-level parser for generic firmware types. It does not
   168  // implement any parser itself, but it calls known parsers that implement the
   169  // Firmware interface.
   170  func Parse(buf []byte) (Firmware, error) {
   171  	if _, err := FindSignature(buf); err == nil {
   172  		// Intel rom.
   173  		return NewFlashImage(buf)
   174  	}
   175  	// Non intel image such as edk2's OVMF
   176  	// We don't know how to parse this header, so treat it as a large BIOSRegion
   177  	return NewBIOSRegion(buf, nil, RegionTypeBIOS)
   178  }
   179  
   180  // Checksum8 does a 8 bit checksum of the slice passed in.
   181  func Checksum8(buf []byte) uint8 {
   182  	var sum uint8
   183  	for _, val := range buf {
   184  		sum += val
   185  	}
   186  	return sum
   187  }
   188  
   189  // Checksum16 does a 16 bit checksum of the byte slice passed in.
   190  func Checksum16(buf []byte) (uint16, error) {
   191  	r := bytes.NewReader(buf)
   192  	buflen := len(buf)
   193  	if buflen%2 != 0 {
   194  		return 0, fmt.Errorf("byte slice does not have even length, not able to do 16 bit checksum. Length was %v",
   195  			buflen)
   196  	}
   197  	var temp, sum uint16
   198  	for i := 0; i < buflen; i += 2 {
   199  		if err := binary.Read(r, binary.LittleEndian, &temp); err != nil {
   200  			return 0, err
   201  		}
   202  		sum += temp
   203  	}
   204  	return sum, nil
   205  }
   206  
   207  // Read3Size reads a 3-byte size and returns it as a uint64
   208  func Read3Size(size [3]uint8) uint64 {
   209  	return uint64(size[2])<<16 |
   210  		uint64(size[1])<<8 | uint64(size[0])
   211  }
   212  
   213  // Write3Size writes a size into a 3-byte array
   214  func Write3Size(size uint64) [3]uint8 {
   215  	if size >= 0xFFFFFF {
   216  		return [3]uint8{0xFF, 0xFF, 0xFF}
   217  	}
   218  	b := [3]uint8{uint8(size), uint8(size >> 8), uint8(size >> 16)}
   219  	return b
   220  }
   221  
   222  // Align aligns an address
   223  func Align(val uint64, base uint64) uint64 {
   224  	return (val + base - 1) & ^(base - 1)
   225  }
   226  
   227  // Align4 aligns an address to 4 bytes
   228  func Align4(val uint64) uint64 {
   229  	return Align(val, 4)
   230  }
   231  
   232  // Align8 aligns an address to 8 bytes
   233  func Align8(val uint64) uint64 {
   234  	return Align(val, 8)
   235  }
   236  
   237  // Erase sets the buffer to be ErasePolarity
   238  func Erase(buf []byte, polarity byte) {
   239  	for j, blen := 0, len(buf); j < blen; j++ {
   240  		buf[j] = Attributes.ErasePolarity
   241  	}
   242  }
   243  
   244  // IsErased check if the buffer is ErasePolarity
   245  func IsErased(buf []byte, polarity byte) bool {
   246  	for _, c := range buf {
   247  		if c != polarity {
   248  			return false
   249  		}
   250  	}
   251  	return true
   252  }