mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
203 lines
5.6 KiB
Python
Executable File
203 lines
5.6 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
import os, re, getopt, sys
|
|
from stat import ST_SIZE
|
|
from subprocess import PIPE, Popen
|
|
|
|
verbose = 0
|
|
|
|
|
|
# return address of 4K page following the spefified address
|
|
def round_page(addr):
|
|
page_size = 0x1000
|
|
return (addr + page_size) & ~(page_size - 1)
|
|
|
|
|
|
def first_free_addr_after_program(elf, cross_prefix = ""):
|
|
try:
|
|
objdump = cross_prefix + "objdump"
|
|
objdump_output = Popen([objdump, "-p", elf],
|
|
stdout=PIPE).communicate()[0]
|
|
except OSError:
|
|
print "Error: execution of " + objdump + " failed, invalid cross-tool prefix?"
|
|
exit(3)
|
|
|
|
#
|
|
# The output of 'objdump -p' contains the list of program segments. Each
|
|
# segment has two lines of text, the first containing the 'vaddr' value and
|
|
# the latter containing the 'memsz' value. For each line, we match for both
|
|
# 'vaddr' and 'memsz' fields. When observing a line with a 'memsz' field,
|
|
# we know that the previous line contained the corresponding 'vaddr' and
|
|
# that the end address of the segment is the sum of the current 'vaddr'
|
|
# and 'memsz' values.
|
|
#
|
|
max_end_addr = 0
|
|
for line in objdump_output.splitlines():
|
|
match_vaddr = re.compile(".*vaddr (0x[0-9a-f]*).*").match(line)
|
|
match_memsz = re.compile(".*memsz (0x[0-9a-f]*).*").match(line)
|
|
if (match_vaddr):
|
|
vaddr = int(match_vaddr.group(1), 0)
|
|
if (match_memsz):
|
|
memsz = int(match_memsz.group(1), 0)
|
|
max_end_addr = max(max_end_addr, vaddr + memsz)
|
|
|
|
# align the first free address at the next page boundary
|
|
return round_page(max_end_addr)
|
|
|
|
|
|
def generate_modules_asm(modules):
|
|
"""
|
|
Generate assembly code aggregating boot-module data from specified files.
|
|
The generated assembly code looks as follows:
|
|
|
|
/*
|
|
* The ELF image consists only of a data section. At file offset 0, there
|
|
* is a magic cookie that core validates when accessing the ROM fs. It is
|
|
* followed by the end address of the meta data.
|
|
*/
|
|
.section .data
|
|
.string "GROM" /* magic cookie used by core to identify a ROM fs image*/
|
|
.long header_end /* end of ROM fs meta data */
|
|
|
|
/*
|
|
* Each module is represented by a struct of 3 long values. The first
|
|
* value is pointer to the module name. A null-pointer marks the end of
|
|
* the module list.
|
|
*/
|
|
.long mod1_name /* pointer to the null-terminated module name */
|
|
.long mod1_start /* pointer to the module data */
|
|
.long mod1_end - mod1_start /* size of the module data */
|
|
|
|
.long 0
|
|
|
|
/*
|
|
* For each module, there exists a null-terminated string labeled with
|
|
* 'mod<index>_name' referenced by the module list above.
|
|
*/
|
|
mod1_name:
|
|
.string "name of data module"
|
|
.byte 0
|
|
|
|
header_end:
|
|
|
|
/*
|
|
* The data of each module must be aligned at a page boundary to enable
|
|
* the mapping of individual modules to different address spaces.
|
|
*/
|
|
.align 4096
|
|
mod1_start: .incbin "data"
|
|
mod1_end:
|
|
"""
|
|
|
|
asm_src = ""
|
|
|
|
# header
|
|
asm_src += ".section .data\nmodule_list:\n"
|
|
asm_src += ".ascii \"GROM\"\n"
|
|
asm_src += ".long header_end\n"
|
|
|
|
# module list
|
|
i = 1
|
|
for module in modules:
|
|
asm_src += ".long mod" + str(i) + "_name\n"
|
|
asm_src += ".long mod" + str(i) + "_start\n"
|
|
asm_src += ".long mod" + str(i) + "_end - mod" + str(i) + "_start\n"
|
|
i = i + 1
|
|
asm_src += ".long 0\n"
|
|
|
|
# module names
|
|
i = 1
|
|
for module in modules:
|
|
asm_src += "mod" + str(i) + "_name: .string \"" + os.path.split(module)[1] + "\"; .byte 0\n"
|
|
i = i + 1
|
|
|
|
asm_src += "header_end:\n"
|
|
|
|
# module data
|
|
i = 1
|
|
for module in modules:
|
|
asm_src += ".p2align 12,0\n"
|
|
asm_src += "mod" + str(i) + "_start: .incbin \"" + module + "\"; "
|
|
asm_src += "mod" + str(i) + "_end:\n"
|
|
i = i + 1
|
|
|
|
return asm_src
|
|
|
|
instructions = """
|
|
usage: gen_romfs [-v] [-p <cross-prefix>] -c <core-elf> -o <output> [modules ...]
|
|
|
|
Generates Genode ROM file system as ELF file loadable into a Codezero container
|
|
|
|
-c|--core ELF binary of Genode's core
|
|
-o|--output name of ELF image to generate
|
|
-p|--prefix cross toolchain prefix
|
|
-v|--verbose print details about generated ROM file systemn
|
|
"""
|
|
|
|
def usage():
|
|
print instructions
|
|
|
|
def user_error(message):
|
|
print "Error: " + message
|
|
usage
|
|
sys.exit(2)
|
|
|
|
# default values for command-line arguments
|
|
cross_prefix = ""
|
|
core_elf = ""
|
|
dst_elf = ""
|
|
|
|
# parse command line arguments
|
|
try:
|
|
opts, modules = getopt.getopt(sys.argv[1:],
|
|
"c:o:p:v",
|
|
["core=", "output=", "prefix=", "verbose"])
|
|
except getopt.GetoptError:
|
|
usage()
|
|
sys.exit(2)
|
|
for opt, arg in opts:
|
|
if opt in ("-c", "--core"):
|
|
core_elf = arg
|
|
elif opt in ("-o", "--output"):
|
|
dst_elf = arg
|
|
elif opt in ("-p", "--prefix"):
|
|
cross_prefix = arg
|
|
elif opt in ("-v", "--verbose"):
|
|
verbose = 1
|
|
else:
|
|
user_error("invalid argument \"" + arg + "\"")
|
|
|
|
# validate arguments
|
|
if (core_elf == ""): user_error("no core binary specified")
|
|
if (len(modules) == 0): user_error("no modules specified")
|
|
if (dst_elf == ""): user_error("no output file spefied")
|
|
|
|
# determine destination address of the modules ELF image
|
|
modules_start_addr = first_free_addr_after_program(core_elf, cross_prefix)
|
|
|
|
if (verbose):
|
|
print "module address: " + hex(modules_start_addr)
|
|
|
|
# generate assembly code aggregating the module data
|
|
asm_src = generate_modules_asm(modules)
|
|
|
|
if (verbose):
|
|
print "generated assember code:"
|
|
for line in asm_src.splitlines():
|
|
print " " + line
|
|
|
|
# invoke assembler and linker through the gcc front end
|
|
gcc_cmd = [cross_prefix + "gcc",
|
|
"-nostdlib",
|
|
"-x", "assembler",
|
|
"-Wl,--entry=0",
|
|
"-Wl,--section-start=.data=" + hex(modules_start_addr),
|
|
"-o", dst_elf,
|
|
"-"]
|
|
|
|
if (verbose):
|
|
print "gcc command line:"
|
|
print " " + ' '.join(gcc_cmd)
|
|
|
|
Popen(gcc_cmd, stdin=PIPE).communicate(asm_src)[0]
|