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 }