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 }