github.com/linuxboot/fiano@v1.2.0/pkg/uefi/biosregion.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 6 7 import ( 8 "errors" 9 ) 10 11 // BIOSPadding holds the padding in between firmware volumes 12 // This may sometimes hold data, even though it shouldn't. We need 13 // to preserve it though. 14 type BIOSPadding struct { 15 buf []byte 16 Offset uint64 17 18 // Metadata 19 ExtractPath string 20 } 21 22 // NewBIOSPadding parses a sequence of bytes and returns a BIOSPadding 23 // object. 24 func NewBIOSPadding(buf []byte, offset uint64) (*BIOSPadding, error) { 25 bp := &BIOSPadding{buf: buf, Offset: offset} 26 return bp, nil 27 } 28 29 // Buf returns the buffer 30 func (bp *BIOSPadding) Buf() []byte { 31 return bp.buf 32 } 33 34 // SetBuf sets the buffer 35 func (bp *BIOSPadding) SetBuf(buf []byte) { 36 bp.buf = buf 37 } 38 39 // Apply a visitor to the BIOSPadding. 40 func (bp *BIOSPadding) Apply(v Visitor) error { 41 return v.Visit(bp) 42 } 43 44 // ApplyChildren applies a visitor to all the direct children of the BIOSPadding 45 func (bp *BIOSPadding) ApplyChildren(v Visitor) error { 46 return nil 47 } 48 49 // BIOSRegion represents the Bios Region in the firmware. 50 // It holds all the FVs as well as padding 51 type BIOSRegion struct { 52 // holds the raw data 53 buf []byte 54 Elements []*TypedFirmware `json:",omitempty"` 55 56 // Metadata for extraction and recovery 57 ExtractPath string 58 Length uint64 59 // This is a pointer to the FlashRegion struct laid out in the ifd. 60 FRegion *FlashRegion 61 RegionType FlashRegionType 62 } 63 64 // Type returns the flash region type. 65 func (br *BIOSRegion) Type() FlashRegionType { 66 return RegionTypeBIOS 67 } 68 69 // SetFlashRegion sets the Flash Region. 70 func (br *BIOSRegion) SetFlashRegion(fr *FlashRegion) { 71 br.FRegion = fr 72 } 73 74 // FlashRegion gets the Flash Region. 75 func (br *BIOSRegion) FlashRegion() (fr *FlashRegion) { 76 return br.FRegion 77 } 78 79 // NewBIOSRegion parses a sequence of bytes and returns a Region 80 // object, if a valid one is passed, or an error. It also points to the 81 // Region struct uncovered in the ifd. 82 func NewBIOSRegion(buf []byte, r *FlashRegion, _ FlashRegionType) (Region, error) { 83 br := BIOSRegion{FRegion: r, Length: uint64(len(buf)), 84 RegionType: RegionTypeBIOS} 85 var absOffset uint64 86 87 // Copy the buffer 88 if ReadOnly { 89 br.buf = buf 90 } else { 91 br.buf = make([]byte, len(buf)) 92 copy(br.buf, buf) 93 } 94 95 for { 96 offset := FindFirmwareVolumeOffset(buf) 97 if offset < 0 { 98 // no firmware volume found, stop searching 99 // There shouldn't be padding near the end, but store it in case anyway 100 if len(buf) != 0 { 101 bp, err := NewBIOSPadding(buf, absOffset) 102 if err != nil { 103 return nil, err 104 } 105 br.Elements = append(br.Elements, MakeTyped(bp)) 106 } 107 break 108 } 109 if offset > 0 { 110 // There is some padding here, store it in case there is data. 111 // We could check and conditionally store, but that makes things more complicated 112 bp, err := NewBIOSPadding(buf[:offset], absOffset) 113 if err != nil { 114 return nil, err 115 } 116 br.Elements = append(br.Elements, MakeTyped(bp)) 117 } 118 absOffset += uint64(offset) // Find start of volume relative to bios region. 119 fv, err := NewFirmwareVolume(buf[offset:], absOffset, false) // False as top level FVs are not resizable 120 if err != nil { 121 return nil, err 122 } 123 absOffset += fv.Length 124 buf = buf[uint64(offset)+fv.Length:] 125 br.Elements = append(br.Elements, MakeTyped(fv)) 126 } 127 return &br, nil 128 } 129 130 // Buf returns the buffer. 131 // Used mostly for things interacting with the Firmware interface. 132 func (br *BIOSRegion) Buf() []byte { 133 return br.buf 134 } 135 136 // SetBuf sets the buffer. 137 // Used mostly for things interacting with the Firmware interface. 138 func (br *BIOSRegion) SetBuf(buf []byte) { 139 br.buf = buf 140 } 141 142 // Apply calls the visitor on the BIOSRegion. 143 func (br *BIOSRegion) Apply(v Visitor) error { 144 return v.Visit(br) 145 } 146 147 // ApplyChildren calls the visitor on each child node of BIOSRegion. 148 func (br *BIOSRegion) ApplyChildren(v Visitor) error { 149 for _, f := range br.Elements { 150 if err := f.Value.Apply(v); err != nil { 151 return err 152 } 153 } 154 return nil 155 } 156 157 // FirstFV finds the first firmware volume in the BIOSRegion. 158 func (br *BIOSRegion) FirstFV() (*FirmwareVolume, error) { 159 for _, e := range br.Elements { 160 if f, ok := e.Value.(*FirmwareVolume); ok { 161 return f, nil 162 } 163 } 164 return nil, errors.New("no firmware volumes in BIOS Region") 165 }