From a4e66bf11771fdd3434e6317934e5277fa3d30c1 Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Tue, 30 Aug 2022 14:30:42 +0200 Subject: [PATCH] Unify bundle generation scripts Pay a long due technical debt by unifying the bundle generation scripts, and fixing the way in which the padding is generated. Fixes #1 Signed-off-by: Sergio Lopez --- Image_to_bundle.py | 48 ------------ Makefile | 10 +-- bin2cbundle.py | 173 +++++++++++++++++++++++++++++++++++++++++++ initrd_to_bundle.py | 42 ----------- qboot_to_bundle.py | 42 ----------- vmlinux_to_bundle.py | 68 ----------------- 6 files changed, 178 insertions(+), 205 deletions(-) delete mode 100644 Image_to_bundle.py create mode 100644 bin2cbundle.py delete mode 100644 initrd_to_bundle.py delete mode 100644 qboot_to_bundle.py delete mode 100644 vmlinux_to_bundle.py diff --git a/Image_to_bundle.py b/Image_to_bundle.py deleted file mode 100644 index 1da7493..0000000 --- a/Image_to_bundle.py +++ /dev/null @@ -1,48 +0,0 @@ -import sys - -footer = """ -char * krunfw_get_kernel(size_t *load_addr, size_t *size) -{ - *load_addr = KERNEL_LOAD_ADDR; - *size = (((KERNEL_SIZE - 1) / 16384) + 1) * 16384; - return &KERNEL_BUNDLE[0]; -} - -int krunfw_get_version() -{ - return ABI_VERSION; -} -""" - -load_segments = [ ] - -if len(sys.argv) != 2: - print('Invalid arguments') - print('Usage: %s VMLINUX_BINARY' % sys.argv[0]) - sys.exit(-1) - -kelf = open(sys.argv[1], 'rb') - -kc = open('kernel.c', 'w') -kc.write('#include \n') -kc.write('__attribute__ ((aligned (4096))) char KERNEL_BUNDLE[] = \n"') - -entry = 0x80000000; -col = 0 -pos = 0 -prev_paddr = None -byte = kelf.read(1) -while byte != b"": - kc.write('\\x' + byte.hex()) - if col == 20: - kc.write('"\n"') - col = 0 - else: - col = col + 1 - byte = kelf.read(1) - pos = pos + 1 - -kc.write('";\n') -kc.write('size_t KERNEL_SIZE = 0x%s;\n' % format(pos, 'x')) -kc.write('size_t KERNEL_LOAD_ADDR = 0x%s;\n' % format(entry, 'x')) -kc.write(footer) diff --git a/Makefile b/Makefile index 2237dab..8a8e69b 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,8 @@ endif ARCH = $(shell uname -m) OS = $(shell uname -s) -BUNDLE_SCRIPT_x86_64 = vmlinux_to_bundle.py -BUNDLE_SCRIPT_aarch64 = Image_to_bundle.py +KBUNDLE_TYPE_x86_64 = vmlinux +KBUNDLE_TYPE_aarch64 = Image KERNEL_BINARY_x86_64 = $(KERNEL_SOURCES)/vmlinux KERNEL_BINARY_aarch64 = $(KERNEL_SOURCES)/arch/arm64/boot/Image @@ -70,16 +70,16 @@ $(KERNEL_BINARY_$(ARCH)): $(KERNEL_SOURCES) $(KERNEL_C_BUNDLE): $(KERNEL_BINARY_$(ARCH)) @echo "Generating $(KERNEL_C_BUNDLE) from $(KERNEL_BINARY_$(ARCH))..." - @python3 $(BUNDLE_SCRIPT_$(ARCH)) $(KERNEL_BINARY_$(ARCH)) + @python3 bin2cbundle.py -t $(KBUNDLE_TYPE_$(ARCH)) $(KERNEL_BINARY_$(ARCH)) kernel.c ifeq ($(SEV),1) $(QBOOT_C_BUNDLE): $(QBOOT_BINARY) @echo "Generating $(QBOOT_C_BUNDLE) from $(QBOOT_BINARY)..." - @python3 qboot_to_bundle.py $(QBOOT_BINARY) + @python3 bin2cbundle.py -t qboot $(QBOOT_BINARY) qboot.c $(INITRD_C_BUNDLE): $(INITRD_BINARY) @echo "Generating $(INITRD_C_BUNDLE) from $(INITRD_BINARY)..." - @python3 initrd_to_bundle.py $(INITRD_BINARY) + @python3 bin2cbundle.py -t initrd $(INITRD_BINARY) initrd.c endif $(KRUNFW_BINARY_$(OS)): $(KERNEL_C_BUNDLE) $(QBOOT_C_BUNDLE) $(INITRD_C_BUNDLE) diff --git a/bin2cbundle.py b/bin2cbundle.py new file mode 100644 index 0000000..3e7db98 --- /dev/null +++ b/bin2cbundle.py @@ -0,0 +1,173 @@ +try: + from elftools.elf.elffile import ELFFile +except: + pass +import argparse +import sys + +# Use Apple Silicon's page size for rounding. +PAGE_SIZE = 16384 +AARCH64_LOAD_ADDR = '0x80000000' + +def write_header(ofile, bundle_name): + ofile.write('#include \n') + ofile.write('__attribute__ ((aligned (4096))) char {}_BUNDLE[] = \n"'.format(bundle_name)) + + +def write_padding(ofile, padding, col): + while padding > 0: + ofile.write('\\x0') + + if col == 15: + ofile.write('"\n"') + col = 0 + else: + col = col + 1 + + padding = padding - 1 + + +def write_elf_cbundle(ifile, ofile) -> int: + elffile = ELFFile(ifile) + entry = elffile['e_entry'] + + load_segments = [ ] + for segment in elffile.iter_segments(): + if segment['p_type'] == 'PT_LOAD': + load_segments.append(segment) + + col = 0 + total_size = 0 + prev_paddr = None + load_addr = elffile['e_entry'] + + for segment in load_segments: + if prev_paddr != None: + padding = segment['p_paddr'] - prev_paddr - prev_filesz + write_padding(ofile, padding, col) + total_size = total_size + padding + + assert((segment['p_paddr'] - load_addr) == total_size) + + for byte in segment.data(): + ofile.write('\\x{:x}'.format(byte)) + + if col == 15: + ofile.write('"\n"') + col = 0 + else: + col = col + 1 + + prev_paddr = segment['p_paddr'] + prev_filesz = segment['p_filesz'] + total_size = total_size + prev_filesz + + rounded_size = int((total_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE + padding = rounded_size - total_size + write_padding(ofile, padding, col) + + return load_addr + + +def write_raw_cbundle(ifile, ofile) -> int: + col = 0 + total_size = 0 + byte = ifile.read(1) + while byte: + ofile.write('\\x{:x}'.format(byte[0])) + + if col == 15: + ofile.write('"\n"') + col = 0 + else: + col = col + 1 + + total_size = total_size + 1 + byte = ifile.read(1) + + rounded_size = int((total_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE + padding = rounded_size - total_size + write_padding(ofile, padding, col) + + +def write_footer_generic(ofile, bundle_name): + footer = """ +char * krunfw_get_{}(size_t *size) +{{ + *size = sizeof({}_BUNDLE) - 1; + return &{}_BUNDLE[0]; +}} +""" + ofile.write('";\n') + ofile.write(footer.format(bundle_name.lower(), bundle_name, bundle_name)) + + +def write_footer_kernel(ofile, load_addr): + footer = """ +char * krunfw_get_kernel(size_t *load_addr, size_t *size) +{{ + *load_addr = {}; + *size = sizeof(KERNEL_BUNDLE) - 1; + return &KERNEL_BUNDLE[0]; +}} + +int krunfw_get_version() +{{ + return ABI_VERSION; +}} +""" + ofile.write('";\n') + ofile.write(footer.format(load_addr)) + + +def main() -> int: + parser = argparse.ArgumentParser(description='Generate C blob from a binary') + + parser.add_argument('input_file', type=str, + help='Input file') + parser.add_argument('output_file', type=str, + help='Output file') + parser.add_argument('-t', type=str, help='Bundle type (vmlinux, Image, qboot, initrd)') + + args = parser.parse_args() + + bundle_name = None + ifmt = None + if args.t == 'vmlinux': + bundle_name = 'KERNEL' + ifmt = 'elf' + elif args.t == 'Image': + bundle_name = 'KERNEL' + ifmt = 'raw' + elif args.t == 'qboot': + bundle_name = 'QBOOT' + ifmt = 'raw' + elif args.t == 'initrd': + bundle_name = 'INITRD' + ifmt = 'raw' + else: + print('Invalid bundle type') + return -1 + + ifile = open(args.input_file, 'rb') + ofile = open(args.output_file, 'w') + + write_header(ofile, bundle_name) + + if ifmt == 'elf': + load_addr = write_elf_cbundle(ifile, ofile) + elif ifmt == 'raw': + write_raw_cbundle(ifile, ofile) + + if bundle_name == 'KERNEL': + if ifmt == 'raw': + load_addr = AARCH64_LOAD_ADDR; + write_footer_kernel(ofile, load_addr) + else: + write_footer_generic(ofile, bundle_name) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/initrd_to_bundle.py b/initrd_to_bundle.py deleted file mode 100644 index e805e51..0000000 --- a/initrd_to_bundle.py +++ /dev/null @@ -1,42 +0,0 @@ -from elftools.elf.elffile import ELFFile -import sys - -footer = """ -char * krunfw_get_initrd(size_t *size) -{ - *size = INITRD_SIZE; - return &INITRD_BUNDLE[0]; -} -""" - -load_segments = [ ] - -if len(sys.argv) != 2: - print('Invalid arguments') - print('Usage: %s INITRD_BINARY' % sys.argv[0]) - sys.exit(-1) - -initrd = open(sys.argv[1], 'rb') - -qc = open('initrd.c', 'w') -qc.write('#include \n') -qc.write('__attribute__ ((aligned (4096))) char INITRD_BUNDLE[] = \n"') - -col = 0 -pos = 0 -prev_paddr = None -byte = initrd.read(1) -while byte: - qc.write('\\x' + format(byte[0], 'x')) - if col == 20: - qc.write('"\n"') - col = 0 - else: - col = col + 1 - - pos = pos + 1 - byte = initrd.read(1) - -qc.write('";\n') -qc.write('size_t INITRD_SIZE = 0x%s;\n' % format(pos, 'x')) -qc.write(footer) diff --git a/qboot_to_bundle.py b/qboot_to_bundle.py deleted file mode 100644 index f40e410..0000000 --- a/qboot_to_bundle.py +++ /dev/null @@ -1,42 +0,0 @@ -from elftools.elf.elffile import ELFFile -import sys - -footer = """ -char * krunfw_get_qboot(size_t *size) -{ - *size = QBOOT_SIZE; - return &QBOOT_BUNDLE[0]; -} -""" - -load_segments = [ ] - -if len(sys.argv) != 2: - print('Invalid arguments') - print('Usage: %s QBOOT_BINARY' % sys.argv[0]) - sys.exit(-1) - -qboot = open(sys.argv[1], 'rb') - -qc = open('qboot.c', 'w') -qc.write('#include \n') -qc.write('__attribute__ ((aligned (4096))) char QBOOT_BUNDLE[] = \n"') - -col = 0 -pos = 0 -prev_paddr = None -byte = qboot.read(1) -while byte: - qc.write('\\x' + format(byte[0], 'x')) - if col == 20: - qc.write('"\n"') - col = 0 - else: - col = col + 1 - - pos = pos + 1 - byte = qboot.read(1) - -qc.write('";\n') -qc.write('size_t QBOOT_SIZE = 0x%s;\n' % format(pos, 'x')) -qc.write(footer) diff --git a/vmlinux_to_bundle.py b/vmlinux_to_bundle.py deleted file mode 100644 index 8e5914f..0000000 --- a/vmlinux_to_bundle.py +++ /dev/null @@ -1,68 +0,0 @@ -from elftools.elf.elffile import ELFFile -import sys - -footer = """ -char * krunfw_get_kernel(size_t *load_addr, size_t *size) -{ - *load_addr = KERNEL_LOAD_ADDR; - *size = KERNEL_SIZE; - return &KERNEL_BUNDLE[0]; -} - -int krunfw_get_version() -{ - return ABI_VERSION; -} -""" - -load_segments = [ ] - -if len(sys.argv) != 2: - print('Invalid arguments') - print('Usage: %s VMLINUX_BINARY' % sys.argv[0]) - sys.exit(-1) - -kelf = open(sys.argv[1], 'rb') -elffile = ELFFile(kelf) -entry = elffile['e_entry'] - -for segment in elffile.iter_segments(): - if segment['p_type'] == 'PT_LOAD': - load_segments.append(segment) - -kc = open('kernel.c', 'w') -kc.write('#include \n') -kc.write('__attribute__ ((aligned (4096))) char KERNEL_BUNDLE[] = \n"') - -col = 0 -pos = 0 -prev_paddr = None -for segment in load_segments: - if prev_paddr == None: - prev_paddr = segment['p_paddr'] - else: - offset = segment['p_paddr'] - prev_paddr - prev_addr = segment['p_paddr'] - for i in range(offset - pos): - kc.write('\\x0') - if col == 20: - kc.write('"\n"') - col = 0 - else: - col = col + 1 - pos = offset - - for byte in segment.data(): - kc.write('\\x' + format(byte, 'x')) - if col == 20: - kc.write('"\n"') - col = 0 - else: - col = col + 1 - - pos = pos + segment['p_filesz'] - -kc.write('";\n') -kc.write('size_t KERNEL_SIZE = 0x%s;\n' % format(pos, 'x')) -kc.write('size_t KERNEL_LOAD_ADDR = 0x%s;\n' % format(entry, 'x')) -kc.write(footer)