util: bsp-tool: extract bootstrap exec constants and store them in the bsp image
This commit is contained in:
@@ -3,7 +3,9 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tarfile
|
import tarfile
|
||||||
|
import struct
|
||||||
from lib.manifest import Manifest, Component
|
from lib.manifest import Manifest, Component
|
||||||
|
from lib.elf import ELF64Image
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
@@ -59,12 +61,13 @@ def add_binary():
|
|||||||
|
|
||||||
|
|
||||||
def build_bsp():
|
def build_bsp():
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 4:
|
||||||
print("USAGE: {} build-bsp <manifest-path> <dest-path>".format(sys.argv[0]))
|
print("USAGE: {} build-bsp <manifest-path> <bootstrap-program-path> <dest-path>".format(sys.argv[0]))
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
manifest_path = sys.argv[2]
|
manifest_path = sys.argv[2]
|
||||||
bsp_path = sys.argv[3]
|
bootstrap_path = sys.argv[3]
|
||||||
|
bsp_path = sys.argv[4]
|
||||||
|
|
||||||
if os.path.exists(bsp_path):
|
if os.path.exists(bsp_path):
|
||||||
os.remove(bsp_path)
|
os.remove(bsp_path)
|
||||||
@@ -82,9 +85,6 @@ def build_bsp():
|
|||||||
header_dest = header_dest[1:]
|
header_dest = header_dest[1:]
|
||||||
|
|
||||||
for f in os.listdir(header_src):
|
for f in os.listdir(header_src):
|
||||||
print('ADD {} -> {}'.format(
|
|
||||||
os.path.join(header_src, f),
|
|
||||||
os.path.join(header_dest, f)))
|
|
||||||
bsp_file.add(
|
bsp_file.add(
|
||||||
os.path.join(header_src, f),
|
os.path.join(header_src, f),
|
||||||
arcname=os.path.join(header_dest, f))
|
arcname=os.path.join(header_dest, f))
|
||||||
@@ -94,10 +94,54 @@ def build_bsp():
|
|||||||
binary_dest = b['dest']
|
binary_dest = b['dest']
|
||||||
while binary_dest.startswith('/'):
|
while binary_dest.startswith('/'):
|
||||||
binary_dest = binary_dest[1:]
|
binary_dest = binary_dest[1:]
|
||||||
|
binary_dest = os.path.join(binary_dest, os.path.basename(binary_src))
|
||||||
|
|
||||||
bsp_file.add(binary_src, arcname=binary_dest)
|
bsp_file.add(binary_src, arcname=binary_dest)
|
||||||
|
|
||||||
bsp_file.close()
|
bsp_file.close()
|
||||||
|
bootstrap_offset = os.path.getsize(bsp_path)
|
||||||
|
|
||||||
|
bsp = open(bsp_path, mode='ab')
|
||||||
|
prog = open(bootstrap_path, mode='rb')
|
||||||
|
|
||||||
|
padding = bootstrap_offset % 0x1000
|
||||||
|
bsp.write(b'\0' * padding)
|
||||||
|
bootstrap_offset += padding
|
||||||
|
prog_len = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
data = prog.read(1024)
|
||||||
|
bsp.write(data)
|
||||||
|
prog_len += len(data)
|
||||||
|
|
||||||
|
if len(data) < 1024:
|
||||||
|
break
|
||||||
|
|
||||||
|
prog.close
|
||||||
|
|
||||||
|
prog_elf = ELF64Image()
|
||||||
|
if prog_elf.load(bootstrap_path) != 0:
|
||||||
|
print('failed to parse bootstrap program')
|
||||||
|
|
||||||
|
for ph in prog_elf.ph_list:
|
||||||
|
print('{}: {}/{} ({}/{} bytes) {}'.format(
|
||||||
|
ph.type,
|
||||||
|
ph.offset, ph.vaddr,
|
||||||
|
ph.filesz, ph.memsz, ph.flags))
|
||||||
|
|
||||||
|
trailer = struct.pack('>IQIQIQQQQQQQ',
|
||||||
|
0xcafebabe,
|
||||||
|
0, bootstrap_offset,
|
||||||
|
bootstrap_offset, prog_len,
|
||||||
|
prog_elf.text.offset, prog_elf.text.vaddr, prog_elf.text.memsz,
|
||||||
|
prog_elf.data.offset, prog_elf.data.vaddr, prog_elf.data.memsz,
|
||||||
|
prog_elf.entry)
|
||||||
|
|
||||||
|
bsp.write(trailer)
|
||||||
|
|
||||||
|
bsp.close()
|
||||||
|
prog.close()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1
util/lib/__init__.py
Normal file
1
util/lib/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import *
|
||||||
102
util/lib/elf.py
Normal file
102
util/lib/elf.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
from enum import Enum, Flag
|
||||||
|
import struct
|
||||||
|
|
||||||
|
class ELFPType(Enum):
|
||||||
|
NULL = 0
|
||||||
|
LOAD = 1
|
||||||
|
DYNAMIC = 2
|
||||||
|
INTERP = 3
|
||||||
|
NOTE = 4
|
||||||
|
SHLIB = 5
|
||||||
|
PHDR = 6
|
||||||
|
TLS = 7
|
||||||
|
|
||||||
|
|
||||||
|
class ELFPFlag(Flag):
|
||||||
|
NONE = 0
|
||||||
|
EXEC = 1
|
||||||
|
WRITE = 2
|
||||||
|
READ = 4
|
||||||
|
|
||||||
|
|
||||||
|
class ELFEndian(Enum):
|
||||||
|
LITTLE = 1
|
||||||
|
BIG = 2
|
||||||
|
|
||||||
|
|
||||||
|
class ELF64Phdr:
|
||||||
|
def __init__(self):
|
||||||
|
self.type = ELFPType.NULL
|
||||||
|
self.flags = 0
|
||||||
|
self.offset = 0
|
||||||
|
self.vaddr = 0
|
||||||
|
self.paddr = 0
|
||||||
|
self.filesz = 0
|
||||||
|
self.memsz = 0
|
||||||
|
self.align = 0
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def parse(self, buf, endian):
|
||||||
|
endian_marker = '>' if endian == ELFEndian.BIG else '<'
|
||||||
|
entry = struct.unpack('{}IIQQQQQQ'.format(endian_marker), buf)
|
||||||
|
|
||||||
|
self.type = ELFPType(entry[0])
|
||||||
|
self.flags = ELFPFlag.NONE
|
||||||
|
self.offset = entry[2]
|
||||||
|
self.vaddr = entry[3]
|
||||||
|
self.paddr = entry[4]
|
||||||
|
self.filesz = entry[5]
|
||||||
|
self.memsz = entry[6]
|
||||||
|
self.align = entry[7]
|
||||||
|
|
||||||
|
if entry[1] & ELFPFlag.READ.value: self.flags |= ELFPFlag.READ
|
||||||
|
if entry[1] & ELFPFlag.WRITE.value: self.flags |= ELFPFlag.WRITE
|
||||||
|
if entry[1] & ELFPFlag.EXEC.value: self.flags |= ELFPFlag.EXEC
|
||||||
|
|
||||||
|
|
||||||
|
class ELF64Image:
|
||||||
|
def __init__(self):
|
||||||
|
self.ph_list = []
|
||||||
|
self.text = None
|
||||||
|
self.data = None
|
||||||
|
self.entry = None
|
||||||
|
|
||||||
|
def load(self, path):
|
||||||
|
f = open(path, mode='rb')
|
||||||
|
ident_bytes = f.read(16)
|
||||||
|
|
||||||
|
ident = struct.unpack('BBBBBBBBBBBBBBBB', ident_bytes)
|
||||||
|
|
||||||
|
if ident[0] != 0x7F or ident[1] != ord('E') or ident[2] != ord('L') or ident[3] != ord('F'):
|
||||||
|
f.close()
|
||||||
|
return -1
|
||||||
|
|
||||||
|
endian = ELFEndian(ident[5])
|
||||||
|
endian_marker = '>' if endian == ELFEndian.BIG else '<'
|
||||||
|
|
||||||
|
hdr_bytes = f.read(48)
|
||||||
|
hdr = struct.unpack('{}HHIQQQIHHHHHH'.format(endian_marker), hdr_bytes)
|
||||||
|
|
||||||
|
self.entry = hdr[3]
|
||||||
|
phoff = hdr[4]
|
||||||
|
phnum = hdr[9]
|
||||||
|
phentsize = hdr[8]
|
||||||
|
|
||||||
|
for i in range(0, phnum):
|
||||||
|
f.seek(phoff + (i * phentsize))
|
||||||
|
phdr_bytes = f.read(phentsize)
|
||||||
|
|
||||||
|
phdr = ELF64Phdr()
|
||||||
|
phdr.parse(phdr_bytes, endian)
|
||||||
|
|
||||||
|
if phdr.flags == ELFPFlag.READ | ELFPFlag.EXEC:
|
||||||
|
self.text = phdr
|
||||||
|
if phdr.flags == ELFPFlag.READ | ELFPFlag.WRITE:
|
||||||
|
self.data = phdr
|
||||||
|
|
||||||
|
self.ph_list.append(phdr)
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
return 0
|
||||||
|
|
||||||
101
util/lib/manifest.py
Normal file
101
util/lib/manifest.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class Component:
|
||||||
|
def __init__(self):
|
||||||
|
self.headers = []
|
||||||
|
self.binaries = []
|
||||||
|
return
|
||||||
|
|
||||||
|
def add_headers(self, src, dest):
|
||||||
|
for h in self.headers:
|
||||||
|
if h['src'] == src and h['dest'] == dest:
|
||||||
|
return
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
headers['src'] = src
|
||||||
|
headers['dest'] = dest
|
||||||
|
self.headers.append(headers)
|
||||||
|
|
||||||
|
|
||||||
|
def add_binary(self, src, dest):
|
||||||
|
for b in self.binaries:
|
||||||
|
if b['src'] == src and b['dest'] == dest:
|
||||||
|
return
|
||||||
|
|
||||||
|
binary = {}
|
||||||
|
binary['src'] = src
|
||||||
|
binary['dest'] = dest
|
||||||
|
self.binaries.append(binary)
|
||||||
|
|
||||||
|
|
||||||
|
def serialise(self):
|
||||||
|
data = {}
|
||||||
|
if len(self.headers) > 0:
|
||||||
|
data['headers'] = self.headers
|
||||||
|
|
||||||
|
if len(self.binaries) > 0:
|
||||||
|
data['binaries'] = self.binaries
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def deserialise(self, data):
|
||||||
|
if 'headers' in data:
|
||||||
|
self.headers = data['headers']
|
||||||
|
if 'binaries' in data:
|
||||||
|
self.binaries = data['binaries']
|
||||||
|
|
||||||
|
|
||||||
|
def get_headers(self):
|
||||||
|
return self.headers
|
||||||
|
|
||||||
|
|
||||||
|
def get_binaries(self):
|
||||||
|
return self.binaries
|
||||||
|
|
||||||
|
|
||||||
|
class Manifest:
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
self.components = {}
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
with open(self.path, 'r') as f:
|
||||||
|
self.data = json.load(f)
|
||||||
|
|
||||||
|
if 'components' not in self.data:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
for n, t in self.data['components'].items():
|
||||||
|
component = Component()
|
||||||
|
component.deserialise(t)
|
||||||
|
self.components[n] = component
|
||||||
|
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
component_data = {}
|
||||||
|
for n, t in self.components.items():
|
||||||
|
d = t.serialise()
|
||||||
|
component_data[n] = d
|
||||||
|
|
||||||
|
self.data['components'] = component_data
|
||||||
|
|
||||||
|
with open(self.path, 'w') as f:
|
||||||
|
json.dump(self.data, f, indent=4)
|
||||||
|
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.data = {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_component(self, name):
|
||||||
|
if name in self.components:
|
||||||
|
return self.components[name]
|
||||||
|
|
||||||
|
component = Component()
|
||||||
|
self.components[name] = component
|
||||||
|
return component
|
||||||
|
|
||||||
|
def get_all_components(self):
|
||||||
|
return self.components
|
||||||
Reference in New Issue
Block a user