github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/multiboot/header.go (about)

     1  // Copyright 2018 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  package multiboot
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"errors"
    11  	"io"
    12  	"log"
    13  
    14  	"github.com/u-root/u-root/pkg/ubinary"
    15  )
    16  
    17  var (
    18  	// ErrHeaderNotFound indicates that a multiboot header magic was not
    19  	// found in the given binary.
    20  	ErrHeaderNotFound = errors.New("multiboot header not found")
    21  
    22  	// ErrFlagsNotSupported indicates that a valid multiboot header
    23  	// contained flags this package does not support (yet).
    24  	ErrFlagsNotSupported = errors.New("multiboot header flags not supported	yet")
    25  )
    26  
    27  const (
    28  	// headerMagic is the magic value found in a multiboot kernel header.
    29  	headerMagic = 0x1BADB002
    30  
    31  	// bootMagic is the magic expected by the loaded OS in EAX at boot handover.
    32  	bootMagic = 0x2BADB002
    33  )
    34  
    35  type headerFlag uint32
    36  
    37  const (
    38  	flagHeaderPageAlign          headerFlag = 0x00000001
    39  	flagHeaderMemoryInfo         headerFlag = 0x00000002
    40  	flagHeaderMultibootVideoMode headerFlag = 0x00000004
    41  	flagHeaderUnsupported        headerFlag = 0x0000FFF8
    42  )
    43  
    44  // mandatory is a mandatory part of Multiboot v1 header.
    45  type mandatory struct {
    46  	Magic    uint32
    47  	Flags    headerFlag
    48  	Checksum uint32
    49  }
    50  
    51  // optional is an optional part of Multiboot v1 header.
    52  type optional struct {
    53  	HeaderAddr  uint32
    54  	LoadAddr    uint32
    55  	LoadEndAddr uint32
    56  	BSSEndAddr  uint32
    57  	EntryAddr   uint32
    58  
    59  	ModeType uint32
    60  	Width    uint32
    61  	Height   uint32
    62  	Depth    uint32
    63  }
    64  
    65  // header represents a Multiboot v1 header loaded from the file.
    66  type header struct {
    67  	mandatory
    68  	optional
    69  }
    70  
    71  type imageType interface {
    72  	addInfo(m *multiboot) (uintptr, error)
    73  	name() string
    74  	bootMagic() uintptr
    75  }
    76  
    77  func (h *header) name() string {
    78  	return "multiboot"
    79  }
    80  
    81  func (h *header) bootMagic() uintptr {
    82  	return bootMagic
    83  }
    84  
    85  // parseHeader parses multiboot header as defined in
    86  // https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#OS-image-format
    87  func parseHeader(r io.Reader) (*header, error) {
    88  	mandatorySize := binary.Size(mandatory{})
    89  	optionalSize := binary.Size(optional{})
    90  	sizeofHeader := mandatorySize + optionalSize
    91  	var hdr header
    92  	// The multiboot header must be contained completely within the
    93  	// first 8192 bytes of the OS image.
    94  	buf := make([]byte, 8192)
    95  	n, err := io.ReadAtLeast(r, buf, mandatorySize)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	buf = buf[:n]
   100  
   101  	// Append zero bytes to the end of buffer to be able to read hdr
   102  	// in a single binary.Read() when the mandatory
   103  	// part of the header starts near the 8192 boundary.
   104  	buf = append(buf, make([]byte, optionalSize)...)
   105  	br := new(bytes.Reader)
   106  	for len(buf) >= sizeofHeader {
   107  		br.Reset(buf)
   108  		if err := binary.Read(br, ubinary.NativeEndian, &hdr); err != nil {
   109  			return nil, err
   110  		}
   111  		if hdr.Magic == headerMagic && (hdr.Magic+uint32(hdr.Flags)+hdr.Checksum) == 0 {
   112  			if hdr.Flags&flagHeaderUnsupported != 0 {
   113  				return nil, ErrFlagsNotSupported
   114  			}
   115  			if hdr.Flags&flagHeaderMultibootVideoMode != 0 {
   116  				log.Print("VideoMode flag is not supproted yet, trying to load anyway")
   117  			}
   118  			return &hdr, nil
   119  		}
   120  		// The Multiboot header must be 32-bit aligned.
   121  		buf = buf[4:]
   122  	}
   123  	return nil, ErrHeaderNotFound
   124  }