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