Загрузка данных


#!/usr/bin/env python3
import sys
import subprocess
import os
import re
import struct

def patch_boot_data_length(bin_path, final_length):
    if not os.path.exists(bin_path):
        return
    try:
        with open(bin_path, "r+b") as f:
            f.seek(0x24) # Смещение поля Boot Data Length для i.MX RT
            f.write(struct.pack("<I", final_length))
        print(f"[LMA Filter] BootROM Patch: Updated Boot Data Length to {final_length} bytes ({hex(final_length)})")
    except Exception as e:
        print(f"[LMA Filter] BootROM Patch Error: {e}")

def main():
    if len(sys.argv) < 2:
        print("[LMA Filter] Error: No real objcopy path provided.")
        sys.exit(1)

    real_objcopy = sys.argv[1]
    args = sys.argv[2:]
    elf_path = "zephyr.elf"
    
    for arg in args:
        if arg.endswith("zephyr.elf"):
            elf_path = arg
            break

    is_elf_to_elf_adjust = any("--change-section-lma" in arg for arg in args) and ("zephyr.elf" in elf_path) and not any(fmt in " ".join(args) for fmt in ["ihex", "binary"])
    if is_elf_to_elf_adjust:
        sys.exit(0)

    is_hex_or_bin_generation = any("--output-target=" in arg for arg in args) or any(fmt in " ".join(args) for fmt in ["ihex", "binary"])

    if is_hex_or_bin_generation and os.path.exists(elf_path):
        sdk_bin_dir = os.path.dirname(real_objcopy)
        readelf_bin = os.path.join(sdk_bin_dir, "arm-zephyr-eabi-readelf")
        if not os.path.exists(readelf_bin):
            for file in os.listdir(sdk_bin_dir):
                if file.endswith("readelf"):
                    readelf_bin = os.path.join(sdk_bin_dir, file)
                    break

        dynamic_offsets = []
        
        if os.path.exists(readelf_bin):
            res = subprocess.run([readelf_bin, "-SW", elf_path], capture_output=True, text=True, env={"LC_ALL": "C"})
            if res.returncode == 0:
                # Регулярное выражение для поиска индекса секции, имени, типа, VMA, смещения и размера
                section_regex = re.compile(r'^\s*\[\s*(\d+)\]\s+([\.\w\-_]+)\s+(\w+)\s+([0-9a-fA-F]{8,16})\s+([0-9a-fA-F]{6,8})\s+([0-9a-fA-F]{6,8}).*?([AXMSILG01-9\s]+)$')
                
                parsed_sections = []
                max_code_vma_end = 0x80000000

                for line in res.stdout.splitlines():
                    match = section_regex.match(line)
                    if match:
                        idx_str, sec_name, sec_type, vma_str, offset_str, size_str, flags_str = match.groups()
                        idx_val = int(idx_str)
                        vma_val = int(vma_str, 16)
                        size_val = int(size_str, 16)
                        
                        is_alloc = 'A' in flags_str
                        has_contents = (sec_type != "NOBITS") and (size_val > 0)
                        is_in_sdram = (0x80000000 <= vma_val < 0x82000000)
                        
                        if is_alloc and has_contents and is_in_sdram:
                            parsed_sections.append((idx_val, vma_val, size_val, sec_name))
                            # Ищем реальный физический конец непрерывного кода во главе с rodata
                            if vma_val < 0x80400000:
                                end_pos = vma_val + size_val
                                if end_pos > max_code_vma_end:
                                    max_code_vma_end = end_pos

                # Сортируем секции строго по их физическому индексу в ELF (idx_val), чтобы ублажить objcopy!
                parsed_sections.sort(key=lambda x: x[0])

                # Вычисляем LMA-стык для упаковки данных сразу за кодом во Flash
                code_end_lma = max_code_vma_end - 0x20000000
                flash_data_start_lma = (code_end_lma + 0x3FFF) & ~0x3FFF # Выравнивание 16KB под MPU
                
                print(f"[LMA Filter] Corrected MPU Packing:")
                print(f"  -> Real code ends at Flash LMA: {hex(code_end_lma)}")
                print(f"  -> Data payload will start at Flash LMA: {hex(flash_data_start_lma)}")

                current_data_lma = flash_data_start_lma
                for idx_val, vma_val, size_val, sec_name in parsed_sections:
                    if vma_val >= 0x80400000:
                        # Секции данных (упаковываем последовательно)
                        dynamic_offsets += ["--change-section-lma", f"{sec_name}={hex(current_data_lma)}"]
                        current_data_lma += (size_val + 3) & ~3
                    else:
                        # Секции кода (прямое смещение 0x80000000 -> 0x60000000)
                        standard_lma = vma_val - 0x20000000
                        dynamic_offsets += ["--change-section-lma", f"{sec_name}={hex(standard_lma)}"]
                
                final_payload_end_lma = current_data_lma

        # 1. Запуск objcopy для генерации финального HEX/BIN с правильными адресами 0x60xxxxxx
        final_cmd = [real_objcopy] + dynamic_offsets + args
        subprocess.run(final_cmd, check=True)

        # 2. Безопасное создание патченного ELF для GDB отладчика (без перезаписи оригинала)
        if dynamic_offsets and ("--output-target=ihex" in " ".join(args)):
            gdb_elf_path = elf_path.replace("zephyr.elf", "zephyr_gdb.elf")
            print(f"[LMA Filter] GDB Patching: Generating non-corrupted {gdb_elf_path}...")
            elf_patch_cmd = [real_objcopy] + dynamic_offsets + [elf_path, gdb_elf_path]
            try:
                subprocess.run(elf_patch_cmd, check=True)
            except Exception as e:
                print(f"[LMA Filter] GDB Patch Error (skipped): {e}")

        # 3. Корректировка заголовка bin-файла для корректной работы бутлоадера платы
        calculated_image_size = (final_payload_end_lma - 0x60000000)
        elf_dir = os.path.dirname(elf_path)
        potential_bin = os.path.join(elf_dir, "zephyr.bin")
        if not os.path.exists(potential_bin):
            potential_bin = os.path.join(os.getcwd(), "zephyr", "zephyr.bin")

        if os.path.exists(potential_bin):
            patch_boot_data_length(potential_bin, calculated_image_size)

if __name__ == "__main__":
    main()