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