github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/uefivars/boot/efiDppMedia.go (about) 1 // Copyright 2020 the u-root 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 // SPDX-License-Identifier: BSD-3-Clause 6 // 7 8 package boot 9 10 import ( 11 "encoding/binary" 12 "fmt" 13 "log" 14 "os" 15 fp "path/filepath" 16 "strings" 17 18 "github.com/u-root/u-root/pkg/mount/block" 19 "github.com/u-root/u-root/pkg/uefivars" 20 ) 21 22 type EfiDppMediaSubType EfiDevPathProtoSubType 23 24 const ( 25 //DppTypeMedia, pg 319 + 26 DppMTypeHdd EfiDppMediaSubType = iota + 1 //0x01 27 DppMTypeCd //0x02 28 DppMTypeVendor //0x03 29 DppMTypeFilePath //0x04 //p321 30 DppMTypeMedia //0x05 //media protocol i.e. filesystem format?? 31 DppMTypePIWGFF //0x06 32 DppMTypePIWGFV //0x07 33 DppMTypeRelOff //0x08 34 DppMTypeRAM //0x09 35 ) 36 37 var efiDppMediaSubTypeStrings = map[EfiDppMediaSubType]string{ 38 DppMTypeHdd: "HDD", 39 DppMTypeCd: "CD", 40 DppMTypeVendor: "Vendor", 41 DppMTypeFilePath: "FilePath", 42 DppMTypeMedia: "Media", 43 DppMTypePIWGFF: "PIWG Firmware File", 44 DppMTypePIWGFV: "PIWG Firmware Volume", 45 DppMTypeRelOff: "Relative Offset", 46 DppMTypeRAM: "RAMDisk", 47 } 48 49 func (e EfiDppMediaSubType) String() string { 50 if s, ok := efiDppMediaSubTypeStrings[e]; ok { 51 return s 52 } 53 return fmt.Sprintf("UNKNOWN-0x%x", uint8(e)) 54 } 55 56 // DppMediaHDD is the struct in EfiDevicePathProtocol for DppMTypeHdd 57 type DppMediaHDD struct { 58 Hdr EfiDevicePathProtocolHdr 59 60 PartNum uint32 //index into partition table for MBR or GPT; 0 indicates entire disk 61 PartStart uint64 //starting LBA. only used for MBR? 62 PartSize uint64 //size in LB's. only used for MBR? 63 PartSig uefivars.MixedGUID //format determined by SigType below. unused bytes must be 0x0. 64 PartFmt uint8 //0x01 for MBR, 0x02 for GPT 65 SigType uint8 //0x00 - none; 0x01 - 32bit MBR sig (@ 0x1b8); 0x02 - GUID 66 } 67 68 var _ EfiDevicePathProtocol = (*DppMediaHDD)(nil) 69 70 // ParseDppMediaHdd parses input into a DppMediaHDD struct. 71 func ParseDppMediaHdd(h EfiDevicePathProtocolHdr, b []byte) (*DppMediaHDD, error) { 72 if len(b) < 38 { 73 return nil, ErrParse 74 } 75 hdd := &DppMediaHDD{ 76 Hdr: h, 77 PartNum: binary.LittleEndian.Uint32(b[:4]), 78 PartStart: binary.LittleEndian.Uint64(b[4:12]), 79 PartSize: binary.LittleEndian.Uint64(b[12:20]), 80 //PartSig: b[20:36], //cannot assign slice to array 81 PartFmt: b[36], 82 SigType: b[37], 83 } 84 copy(hdd.PartSig[:], b[20:36]) 85 return hdd, nil 86 } 87 88 func (e *DppMediaHDD) Header() EfiDevicePathProtocolHdr { return e.Hdr } 89 90 // ProtoSubTypeStr returns the subtype as human readable. 91 func (e *DppMediaHDD) ProtoSubTypeStr() string { 92 return EfiDppMediaSubType(e.Hdr.ProtoSubType).String() 93 } 94 95 func (e *DppMediaHDD) String() string { 96 // (part#,pttype,guid,begin,length) 97 return fmt.Sprintf("HD(%d,%s,%s,0x%x,0x%x)", e.PartNum, e.pttype(), e.sig(), e.PartStart, e.PartSize) 98 } 99 100 // Resolver returns an EfiPathSegmentResolver which can find and mount the 101 // partition described by DppMediaHDD. 102 func (e *DppMediaHDD) Resolver() (EfiPathSegmentResolver, error) { 103 allBlocks, err := block.GetBlockDevices() 104 if err != nil { 105 return nil, err 106 } 107 var blocks block.BlockDevices 108 if e.SigType == 2 { 109 guid := e.PartSig.ToStdEnc().String() 110 blocks = allBlocks.FilterPartID(guid) 111 } else if e.SigType == 1 { 112 // use MBR ID (e.PartSig[:4]) and partition number (e.PartNum) 113 // see PartSig comments and UEFI documentation for location of MBR ID 114 log.Printf("Sig Type 1: unimplemented/cannot identify") 115 return nil, ErrNotFound 116 } else { 117 // SigType==0: no sig, would need to compare partition #/start/len 118 log.Printf("Sig Type %d: unimplemented/cannot identify", e.SigType) 119 return nil, ErrNotFound 120 } 121 if len(blocks) != 1 { 122 log.Printf("blocks: %#v", blocks) 123 return nil, ErrNotFound 124 } 125 return &HddResolver{BlockDev: blocks[0]}, nil 126 } 127 128 //return the partition table type as a string 129 func (e *DppMediaHDD) pttype() string { 130 switch e.PartFmt { 131 case 1: 132 return "MBR" 133 case 2: 134 return "GPT" 135 default: 136 return "UNKNOWN" 137 } 138 } 139 140 //return the signature as a string 141 func (e *DppMediaHDD) sig() string { 142 switch e.SigType { 143 case 1: //32-bit MBR sig 144 return fmt.Sprintf("%x", binary.LittleEndian.Uint32(e.PartSig[:4])) 145 case 2: //GUID 146 return e.PartSig.ToStdEnc().String() 147 default: 148 return "(NO SIG)" 149 } 150 } 151 152 // DppMediaFilePath is a struct in EfiDevicePathProtocol for DppMTypeFilePath. 153 // 154 // If multiple are included in a load option, the docs say to concatenate them. 155 type DppMediaFilePath struct { 156 Hdr EfiDevicePathProtocolHdr 157 158 PathNameDecoded string //stored as utf16 159 } 160 161 var _ EfiDevicePathProtocol = (*DppMediaFilePath)(nil) 162 163 func ParseDppMediaFilePath(h EfiDevicePathProtocolHdr, b []byte) (*DppMediaFilePath, error) { 164 if len(b) < int(h.Length)-4 { 165 return nil, ErrParse 166 } 167 path, err := uefivars.DecodeUTF16(b[:h.Length-4]) 168 if err != nil { 169 return nil, err 170 } 171 //remove null termination byte, replace windows slashes 172 path = strings.TrimSuffix(path, "\000") 173 path = strings.Replace(path, "\\", string(os.PathSeparator), -1) 174 fp := &DppMediaFilePath{ 175 Hdr: h, 176 PathNameDecoded: path, 177 } 178 return fp, nil 179 } 180 181 func (e *DppMediaFilePath) Header() EfiDevicePathProtocolHdr { return e.Hdr } 182 183 // ProtoSubTypeStr returns the subtype as human readable. 184 func (e *DppMediaFilePath) ProtoSubTypeStr() string { 185 return EfiDppMediaSubType(e.Hdr.ProtoSubType).String() 186 } 187 188 func (e *DppMediaFilePath) String() string { 189 return fmt.Sprintf("File(%s)", e.PathNameDecoded) 190 } 191 192 // Resolver returns an EfiPathSegmentResolver decoding the DppMediaFilePath. 193 func (e *DppMediaFilePath) Resolver() (EfiPathSegmentResolver, error) { 194 fp.Clean(e.PathNameDecoded) 195 pr := PathResolver(e.PathNameDecoded) 196 return &pr, nil 197 } 198 199 //struct in EfiDevicePathProtocol for DppMTypePIWGFV 200 type DppMediaPIWGFV struct { 201 Hdr EfiDevicePathProtocolHdr 202 Fv []byte 203 } 204 205 var _ EfiDevicePathProtocol = (*DppMediaPIWGFV)(nil) 206 207 // ParseDppMediaPIWGFV parses input into a DppMediaPIWGFV. 208 func ParseDppMediaPIWGFV(h EfiDevicePathProtocolHdr, b []byte) (*DppMediaPIWGFV, error) { 209 if h.Length != 20 { 210 return nil, ErrParse 211 } 212 fv := &DppMediaPIWGFV{ 213 Hdr: h, 214 Fv: b, 215 } 216 return fv, nil 217 } 218 func (e *DppMediaPIWGFV) Header() EfiDevicePathProtocolHdr { return e.Hdr } 219 220 // ProtoSubTypeStr returns the subtype as human readable. 221 func (e *DppMediaPIWGFV) ProtoSubTypeStr() string { 222 return EfiDppMediaSubType(e.Hdr.ProtoSubType).String() 223 } 224 225 func (e *DppMediaPIWGFV) String() string { 226 var g uefivars.MixedGUID 227 copy(g[:], e.Fv) 228 return fmt.Sprintf("Fv(%s)", g.ToStdEnc().String()) 229 } 230 231 // Resolver returns a nil EfiPathSegmentResolver and ErrUnimpl. See the comment 232 // associated with ErrUnimpl. 233 func (e *DppMediaPIWGFV) Resolver() (EfiPathSegmentResolver, error) { 234 return nil, ErrUnimpl 235 } 236 237 //struct in EfiDevicePathProtocol for DppMTypePIWGFF 238 type DppMediaPIWGFF struct { 239 Hdr EfiDevicePathProtocolHdr 240 Ff []byte 241 } 242 243 var _ EfiDevicePathProtocol = (*DppMediaPIWGFF)(nil) 244 245 // ParseDppMediaPIWGFF parses the input into a DppMediaPIWGFF. 246 func ParseDppMediaPIWGFF(h EfiDevicePathProtocolHdr, b []byte) (*DppMediaPIWGFF, error) { 247 if h.Length != 20 { 248 return nil, ErrParse 249 } 250 fv := &DppMediaPIWGFF{ 251 Hdr: h, 252 Ff: b, 253 } 254 return fv, nil 255 } 256 257 func (e *DppMediaPIWGFF) Header() EfiDevicePathProtocolHdr { return e.Hdr } 258 259 // ProtoSubTypeStr returns the subtype as human readable. 260 func (e *DppMediaPIWGFF) ProtoSubTypeStr() string { 261 return EfiDppMediaSubType(e.Hdr.ProtoSubType).String() 262 } 263 264 func (e *DppMediaPIWGFF) String() string { 265 var g uefivars.MixedGUID 266 copy(g[:], e.Ff) 267 return fmt.Sprintf("FvFile(%s)", g.ToStdEnc().String()) 268 } 269 270 // Resolver returns a nil EfiPathSegmentResolver and ErrUnimpl. See the comment 271 // associated with ErrUnimpl. 272 func (e *DppMediaPIWGFF) Resolver() (EfiPathSegmentResolver, error) { 273 return nil, ErrUnimpl 274 }