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