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