github.com/usbarmory/armory-boot@v0.0.0-20240307133412-208c66a380b9/exec/elf.go (about)

     1  // https://github.com/usbarmory/armory-boot
     2  //
     3  // Copyright (c) WithSecure Corporation
     4  // https://foundry.withsecure.com
     5  //
     6  // Use of this source code is governed by the license
     7  // that can be found in the LICENSE file.
     8  
     9  package exec
    10  
    11  import (
    12  	"bytes"
    13  	"debug/elf"
    14  	"errors"
    15  	"fmt"
    16  
    17  	"github.com/usbarmory/tamago/dma"
    18  )
    19  
    20  // ELFImage represents a bootable bare-metal ELF image.
    21  type ELFImage struct {
    22  	// Region is the memory area for image loading.
    23  	Region *dma.Region
    24  	// ELF is a bootable bare-metal ELF image.
    25  	ELF []byte
    26  
    27  	entry  uint
    28  	loaded bool
    29  }
    30  
    31  // Load loads a bare-metal ELF image in memory.
    32  //
    33  // The ELF loader is _very_ simple, suitable for loading unikernels like those
    34  // produced by TamaGo.
    35  func (image *ELFImage) Load() (err error) {
    36  	if image.Region == nil {
    37  		return errors.New("image memory Region must be assigned")
    38  	}
    39  
    40  	f, err := elf.NewFile(bytes.NewReader(image.ELF))
    41  
    42  	if err != nil {
    43  		return
    44  	}
    45  
    46  	for idx, prg := range f.Progs {
    47  		if prg.Type != elf.PT_LOAD {
    48  			continue
    49  		}
    50  
    51  		b := make([]byte, prg.Memsz)
    52  
    53  		if _, err := prg.ReadAt(b[0:prg.Filesz], 0); err != nil {
    54  			return fmt.Errorf("failed to read LOAD section at idx %d, %q", idx, err)
    55  		}
    56  
    57  		if uint(prg.Paddr) < image.Region.Start() {
    58  			return fmt.Errorf("incompatible memory layout (paddr:%x)", prg.Paddr)
    59  		}
    60  
    61  		off := uint(prg.Paddr) - image.Region.Start()
    62  
    63  		if off > image.Region.Size() {
    64  			return fmt.Errorf("incompatible memory layout (paddr:%x off:%x)", prg.Paddr, off)
    65  		}
    66  
    67  		image.Region.Write(image.Region.Start(), int(off), b)
    68  	}
    69  
    70  	image.entry = uint(f.Entry)
    71  	image.loaded = true
    72  
    73  	return
    74  }
    75  
    76  // Entry returns the image entry address.
    77  func (image *ELFImage) Entry() uint {
    78  	return image.entry
    79  }
    80  
    81  // Boot calls a loaded bare-metal ELF image.
    82  func (image *ELFImage) Boot(cleanup func()) (err error) {
    83  	if !image.loaded {
    84  		return errors.New("Load() kernel before Boot()")
    85  	}
    86  
    87  	return boot(image.entry, 0, cleanup, true)
    88  }