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  }