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  }