1#!/usr/bin/env python3 2# Copyright 2023 The ChromiumOS Authors 3# SPDX-License-Identifier: Apache-2.0 4import struct 5import sys 6 7import elftools.elf.elffile 8import elftools.elf.sections 9 10# Converts a zephyr.elf file into an extremely simple "image format" 11# for device loading. Really we should just load the ELF file 12# directly, but the python ChromeOS test image lacks elftools. Longer 13# term we should probably just use rimage, but that's significantly 14# harder to parse. 15# 16# Format: 17# 18# 1. Three LE 32 bit words: MagicNumber, SRAM len, BootAddress 19# 2. Two byte arrays: SRAM (length specified), and DRAM (remainder of file) 20# 21# No padding or uninterpreted bytes. 22 23FILE_MAGIC = 0xE463BE95 24 25elf_file = sys.argv[1] 26out_file = sys.argv[2] 27 28sram = bytearray() 29dram = bytearray() 30 31# Returns the offset of a segment within the sram region, or -1 if it 32# doesn't appear to be SRAM. SRAM is mapped differently for different 33# SOCs, but it's always a <=1M region in 0x4xxxxxxx. Just use what we 34# get, but validate that it fits. 35sram_block = 0 36 37 38def sram_off(addr): 39 global sram_block 40 if addr < 0x40000000 or addr >= 0x50000000: 41 return -1 42 block = addr & ~0xFFFFF 43 assert sram_block in (0, block) 44 45 sram_block = block 46 off = addr - sram_block 47 assert off < 0x100000 48 return off 49 50 51# Similar heuristics: current platforms put DRAM either at 0x60000000 52# or 0x90000000 with no more than 16M of range 53def dram_off(addr): 54 if (addr >> 28 not in [6, 9]) or (addr & 0x0F000000 != 0): 55 return -1 56 return addr & 0xFFFFFF 57 58 59def read_elf(efile): 60 ef = elftools.elf.elffile.ELFFile(efile) 61 62 for seg in ef.iter_segments(): 63 h = seg.header 64 if h.p_type == "PT_LOAD": 65 soff = sram_off(h.p_paddr) 66 doff = dram_off(h.p_paddr) 67 if soff >= 0: 68 buf = sram 69 off = soff 70 elif doff >= 0: 71 buf = dram 72 off = doff 73 else: 74 print(f"Invalid PT_LOAD address {h.p_paddr:x}") 75 sys.exit(1) 76 77 dat = seg.data() 78 end = off + len(dat) 79 if end > len(buf): 80 buf.extend(b'\x00' * (end - len(buf))) 81 82 # pylint: disable=consider-using-enumerate 83 for i in range(len(dat)): 84 buf[i + off] = dat[i] 85 86 for sec in ef.iter_sections(): 87 if isinstance(sec, elftools.elf.sections.SymbolTableSection): 88 for sym in sec.iter_symbols(): 89 if sym.name == "mtk_adsp_boot_entry": 90 boot_vector = sym.entry['st_value'] 91 92 with open(out_file, "wb") as of: 93 of.write(struct.pack("<III", FILE_MAGIC, len(sram), boot_vector)) 94 of.write(sram) 95 of.write(dram) 96 97 98with open(elf_file, "rb") as f: 99 read_elf(f) 100