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 }