github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+incompatible/pkg/multiboot/module.go (about) 1 // Copyright 2018-2019 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 // Module defines modules to be loaded along with the kernel. 6 // https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format. 7 8 package multiboot 9 10 import ( 11 "bytes" 12 "encoding/binary" 13 "fmt" 14 "log" 15 "os" 16 "strings" 17 18 "github.com/u-root/u-root/pkg/ubinary" 19 ) 20 21 // A Module represents a module to be loaded along with the kernel. 22 type Module struct { 23 // Start is the inclusive start of the Module memory location 24 Start uint32 25 // End is the exclusive end of the Module memory location. 26 End uint32 27 28 // CmdLine is a pointer to a null-terminated ASCII string. 29 CmdLine uint32 30 31 // Reserved is always zero. 32 Reserved uint32 33 } 34 35 type modules []Module 36 37 func (m *Multiboot) addModules() (uintptr, error) { 38 loaded, data, err := loadModules(m.modules) 39 if err != nil { 40 return 0, err 41 } 42 43 addr, err := m.mem.AddKexecSegment(data) 44 if err != nil { 45 return 0, err 46 } 47 48 loaded.fix(uint32(addr)) 49 50 m.loadedModules = loaded 51 52 b, err := loaded.marshal() 53 if err != nil { 54 return 0, err 55 } 56 return m.mem.AddKexecSegment(b) 57 } 58 59 // loadModules loads module files. 60 // Returns loaded modules description and buffer storing loaded modules. 61 // Memory layout of the loaded modules is following: 62 // cmdLine_1 63 // cmdLine_2 64 // ... 65 // cmdLine_n 66 // <padding> 67 // modules_1 68 // <padding> 69 // modules_2 70 // ... 71 // <padding> 72 // modules_n 73 // 74 // <padding> aligns the start of each module to a page beginning. 75 func loadModules(cmds []string) (loaded modules, data []byte, err error) { 76 loaded = make(modules, len(cmds)) 77 buf := bytes.Buffer{} 78 79 for i, cmd := range cmds { 80 if err := loaded[i].setCmdLine(&buf, cmd); err != nil { 81 return nil, nil, err 82 } 83 } 84 85 for i, cmd := range cmds { 86 name := strings.Fields(cmd)[0] 87 if err := loaded[i].loadModule(&buf, name); err != nil { 88 return nil, nil, fmt.Errorf("error adding module %v: %v", name, err) 89 } 90 } 91 92 return loaded, buf.Bytes(), nil 93 } 94 95 // alignUp pads buf to a page boundary. 96 func alignUp(buf *bytes.Buffer) error { 97 mask := (os.Getpagesize() - 1) 98 size := (buf.Len() + mask) &^ mask 99 _, err := buf.Write(bytes.Repeat([]byte{0}, size-buf.Len())) 100 return err 101 } 102 103 func (m *Module) loadModule(buf *bytes.Buffer, name string) error { 104 log.Printf("Adding module %v", name) 105 106 b, err := readFile(name) 107 if err != nil { 108 return err 109 } 110 111 // place start of each module to a beginning of a page. 112 if err := alignUp(buf); err != nil { 113 return err 114 } 115 116 m.Start = uint32(buf.Len()) 117 if _, err := buf.Write(b); err != nil { 118 return err 119 } 120 m.End = uint32(buf.Len()) 121 122 return nil 123 } 124 125 func (m *Module) setCmdLine(buf *bytes.Buffer, cmdLine string) error { 126 m.CmdLine = uint32(buf.Len()) 127 if _, err := buf.WriteString(cmdLine); err != nil { 128 return err 129 } 130 return buf.WriteByte(0) 131 } 132 133 // fix fixes pointers converting relative values to absolute values. 134 func (m modules) fix(base uint32) { 135 for i := range m { 136 m[i].Start += base 137 m[i].End += base 138 m[i].CmdLine += base 139 } 140 } 141 142 // marshal writes out the exact bytes of modules to be loaded 143 // along with the kernel. 144 func (m modules) marshal() ([]byte, error) { 145 buf := bytes.Buffer{} 146 err := binary.Write(&buf, ubinary.NativeEndian, m) 147 return buf.Bytes(), err 148 }