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 }