github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/pkg/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 headerMagic = 0x1BADB002
    28  
    29  type headerFlag uint32
    30  
    31  const (
    32  	flagHeaderPageAlign          headerFlag = 0x00000001
    33  	flagHeaderMemoryInfo         headerFlag = 0x00000002
    34  	flagHeaderMultibootVideoMode headerFlag = 0x00000004
    35  	flagHeaderUnsupported        headerFlag = 0x0000FFF8
    36  )
    37  
    38  // mandatory is a mandatory part of Multiboot v1 header.
    39  type mandatory struct {
    40  	Magic    uint32
    41  	Flags    headerFlag
    42  	Checksum uint32
    43  }
    44  
    45  // optional is an optional part of Multiboot v1 header.
    46  type optional struct {
    47  	HeaderAddr  uint32
    48  	LoadAddr    uint32
    49  	LoadEndAddr uint32
    50  	BSSEndAddr  uint32
    51  	EntryAddr   uint32
    52  
    53  	ModeType uint32
    54  	Width    uint32
    55  	Height   uint32
    56  	Depth    uint32
    57  }
    58  
    59  // header represents a Multiboot v1 header loaded from the file.
    60  type header struct {
    61  	mandatory
    62  	optional
    63  }
    64  
    65  // parseHeader parses multiboot header as defined in
    66  // https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#OS-image-format
    67  func parseHeader(r io.Reader) (header, error) {
    68  	mandatorySize := binary.Size(mandatory{})
    69  	optionalSize := binary.Size(optional{})
    70  	sizeofHeader := mandatorySize + optionalSize
    71  	var hdr header
    72  	// The multiboot header must be contained completely within the
    73  	// first 8192 bytes of the OS image.
    74  	buf := make([]byte, 8192)
    75  	n, err := io.ReadAtLeast(r, buf, mandatorySize)
    76  	if err != nil {
    77  		return hdr, err
    78  	}
    79  	buf = buf[:n]
    80  
    81  	// Append zero bytes to the end of buffer to be able to read hdr
    82  	// in a single binary.Read() when the mandatory
    83  	// part of the header starts near the 8192 boundary.
    84  	buf = append(buf, make([]byte, optionalSize)...)
    85  	br := new(bytes.Reader)
    86  	for len(buf) >= sizeofHeader {
    87  		br.Reset(buf)
    88  		if err := binary.Read(br, ubinary.NativeEndian, &hdr); err != nil {
    89  			return hdr, err
    90  		}
    91  		if hdr.Magic == headerMagic && (hdr.Magic+uint32(hdr.Flags)+hdr.Checksum) == 0 {
    92  			if hdr.Flags&flagHeaderUnsupported != 0 {
    93  				return hdr, ErrFlagsNotSupported
    94  			}
    95  			if hdr.Flags&flagHeaderMultibootVideoMode != 0 {
    96  				log.Print("VideoMode flag is not supproted yet, trying to load anyway")
    97  			}
    98  			return hdr, nil
    99  		}
   100  		// The Multiboot header must be 32-bit aligned.
   101  		buf = buf[4:]
   102  	}
   103  	return hdr, ErrHeaderNotFound
   104  }