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