#!/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_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 ] -c -o [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]