You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.7 KiB
99 lines
2.7 KiB
#!/usr/bin/env python3 |
|
# Copyright 2023 The ChromiumOS Authors |
|
# SPDX-License-Identifier: Apache-2.0 |
|
import struct |
|
import sys |
|
|
|
import elftools.elf.elffile |
|
import elftools.elf.sections |
|
|
|
# Converts a zephyr.elf file into an extremely simple "image format" |
|
# for device loading. Really we should just load the ELF file |
|
# directly, but the python ChromeOS test image lacks elftools. Longer |
|
# term we should probably just use rimage, but that's significantly |
|
# harder to parse. |
|
# |
|
# Format: |
|
# |
|
# 1. Three LE 32 bit words: MagicNumber, SRAM len, BootAddress |
|
# 2. Two byte arrays: SRAM (length specified), and DRAM (remainder of file) |
|
# |
|
# No padding or uninterpreted bytes. |
|
|
|
FILE_MAGIC = 0xE463BE95 |
|
|
|
elf_file = sys.argv[1] |
|
out_file = sys.argv[2] |
|
|
|
sram = bytearray() |
|
dram = bytearray() |
|
|
|
# Returns the offset of a segment within the sram region, or -1 if it |
|
# doesn't appear to be SRAM. SRAM is mapped differently for different |
|
# SOCs, but it's always a <=1M region in 0x4xxxxxxx. Just use what we |
|
# get, but validate that it fits. |
|
sram_block = 0 |
|
|
|
|
|
def sram_off(addr): |
|
global sram_block |
|
if addr < 0x40000000 or addr >= 0x50000000: |
|
return -1 |
|
block = addr & ~0xFFFFF |
|
assert sram_block in (0, block) |
|
|
|
sram_block = block |
|
off = addr - sram_block |
|
assert off < 0x100000 |
|
return off |
|
|
|
|
|
# Similar heuristics: current platforms put DRAM either at 0x60000000 |
|
# or 0x90000000 with no more than 16M of range |
|
def dram_off(addr): |
|
if (addr >> 28 not in [6, 9]) or (addr & 0x0F000000 != 0): |
|
return -1 |
|
return addr & 0xFFFFFF |
|
|
|
|
|
def read_elf(efile): |
|
ef = elftools.elf.elffile.ELFFile(efile) |
|
|
|
for seg in ef.iter_segments(): |
|
h = seg.header |
|
if h.p_type == "PT_LOAD": |
|
soff = sram_off(h.p_paddr) |
|
doff = dram_off(h.p_paddr) |
|
if soff >= 0: |
|
buf = sram |
|
off = soff |
|
elif doff >= 0: |
|
buf = dram |
|
off = doff |
|
else: |
|
print(f"Invalid PT_LOAD address {h.p_paddr:x}") |
|
sys.exit(1) |
|
|
|
dat = seg.data() |
|
end = off + len(dat) |
|
if end > len(buf): |
|
buf.extend(b'\x00' * (end - len(buf))) |
|
|
|
# pylint: disable=consider-using-enumerate |
|
for i in range(len(dat)): |
|
buf[i + off] = dat[i] |
|
|
|
for sec in ef.iter_sections(): |
|
if isinstance(sec, elftools.elf.sections.SymbolTableSection): |
|
for sym in sec.iter_symbols(): |
|
if sym.name == "mtk_adsp_boot_entry": |
|
boot_vector = sym.entry['st_value'] |
|
|
|
with open(out_file, "wb") as of: |
|
of.write(struct.pack("<III", FILE_MAGIC, len(sram), boot_vector)) |
|
of.write(sram) |
|
of.write(dram) |
|
|
|
|
|
with open(elf_file, "rb") as f: |
|
read_elf(f)
|
|
|