Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
tools/flash_algo.py@0:01f31e923fe2, 2020-04-07 (annotated)
- Committer:
- Pawel Zarembski
- Date:
- Tue Apr 07 12:55:42 2020 +0200
- Revision:
- 0:01f31e923fe2
hani: DAPLink with reset workaround
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Pawel Zarembski |
0:01f31e923fe2 | 1 | #!/usr/bin/env python |
Pawel Zarembski |
0:01f31e923fe2 | 2 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 3 | mbed |
Pawel Zarembski |
0:01f31e923fe2 | 4 | Copyright (c) 2017-2019 ARM Limited |
Pawel Zarembski |
0:01f31e923fe2 | 5 | |
Pawel Zarembski |
0:01f31e923fe2 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); |
Pawel Zarembski |
0:01f31e923fe2 | 7 | you may not use this file except in compliance with the License. |
Pawel Zarembski |
0:01f31e923fe2 | 8 | You may obtain a copy of the License at |
Pawel Zarembski |
0:01f31e923fe2 | 9 | |
Pawel Zarembski |
0:01f31e923fe2 | 10 | http://www.apache.org/licenses/LICENSE-2.0 |
Pawel Zarembski |
0:01f31e923fe2 | 11 | |
Pawel Zarembski |
0:01f31e923fe2 | 12 | Unless required by applicable law or agreed to in writing, software |
Pawel Zarembski |
0:01f31e923fe2 | 13 | distributed under the License is distributed on an "AS IS" BASIS, |
Pawel Zarembski |
0:01f31e923fe2 | 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Pawel Zarembski |
0:01f31e923fe2 | 15 | See the License for the specific language governing permissions and |
Pawel Zarembski |
0:01f31e923fe2 | 16 | limitations under the License. |
Pawel Zarembski |
0:01f31e923fe2 | 17 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 18 | |
Pawel Zarembski |
0:01f31e923fe2 | 19 | from __future__ import print_function |
Pawel Zarembski |
0:01f31e923fe2 | 20 | import os |
Pawel Zarembski |
0:01f31e923fe2 | 21 | import struct |
Pawel Zarembski |
0:01f31e923fe2 | 22 | import binascii |
Pawel Zarembski |
0:01f31e923fe2 | 23 | import argparse |
Pawel Zarembski |
0:01f31e923fe2 | 24 | import logging |
Pawel Zarembski |
0:01f31e923fe2 | 25 | from six.moves import StringIO |
Pawel Zarembski |
0:01f31e923fe2 | 26 | import jinja2 |
Pawel Zarembski |
0:01f31e923fe2 | 27 | from collections import namedtuple |
Pawel Zarembski |
0:01f31e923fe2 | 28 | from itertools import count |
Pawel Zarembski |
0:01f31e923fe2 | 29 | |
Pawel Zarembski |
0:01f31e923fe2 | 30 | from elftools.common.py3compat import bytes2str |
Pawel Zarembski |
0:01f31e923fe2 | 31 | from elftools.elf.elffile import ELFFile |
Pawel Zarembski |
0:01f31e923fe2 | 32 | from elftools.elf.sections import SymbolTableSection |
Pawel Zarembski |
0:01f31e923fe2 | 33 | |
Pawel Zarembski |
0:01f31e923fe2 | 34 | logger = logging.getLogger(__name__) |
Pawel Zarembski |
0:01f31e923fe2 | 35 | logger.addHandler(logging.NullHandler()) |
Pawel Zarembski |
0:01f31e923fe2 | 36 | |
Pawel Zarembski |
0:01f31e923fe2 | 37 | |
Pawel Zarembski |
0:01f31e923fe2 | 38 | def main(): |
Pawel Zarembski |
0:01f31e923fe2 | 39 | parser = argparse.ArgumentParser(description="Algo Extracter") |
Pawel Zarembski |
0:01f31e923fe2 | 40 | parser.add_argument("input", help="File to extract flash algo from") |
Pawel Zarembski |
0:01f31e923fe2 | 41 | parser.add_argument("template", default="py_blob.tmpl", |
Pawel Zarembski |
0:01f31e923fe2 | 42 | help="Template to use") |
Pawel Zarembski |
0:01f31e923fe2 | 43 | parser.add_argument("output", help="Output file") |
Pawel Zarembski |
0:01f31e923fe2 | 44 | args = parser.parse_args() |
Pawel Zarembski |
0:01f31e923fe2 | 45 | |
Pawel Zarembski |
0:01f31e923fe2 | 46 | with open(args.input, "rb") as file_handle: |
Pawel Zarembski |
0:01f31e923fe2 | 47 | data = file_handle.read() |
Pawel Zarembski |
0:01f31e923fe2 | 48 | algo = PackFlashAlgo(data) |
Pawel Zarembski |
0:01f31e923fe2 | 49 | algo.process_template(args.template, args.output) |
Pawel Zarembski |
0:01f31e923fe2 | 50 | |
Pawel Zarembski |
0:01f31e923fe2 | 51 | |
Pawel Zarembski |
0:01f31e923fe2 | 52 | class PackFlashAlgo(object): |
Pawel Zarembski |
0:01f31e923fe2 | 53 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 54 | Class to wrap a flash algo |
Pawel Zarembski |
0:01f31e923fe2 | 55 | |
Pawel Zarembski |
0:01f31e923fe2 | 56 | This class is intended to provide easy access to the information |
Pawel Zarembski |
0:01f31e923fe2 | 57 | provided by a flash algorithm, such as symbols and the flash |
Pawel Zarembski |
0:01f31e923fe2 | 58 | algorithm itself. |
Pawel Zarembski |
0:01f31e923fe2 | 59 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 60 | |
Pawel Zarembski |
0:01f31e923fe2 | 61 | REQUIRED_SYMBOLS = set([ |
Pawel Zarembski |
0:01f31e923fe2 | 62 | "Init", |
Pawel Zarembski |
0:01f31e923fe2 | 63 | "UnInit", |
Pawel Zarembski |
0:01f31e923fe2 | 64 | "EraseSector", |
Pawel Zarembski |
0:01f31e923fe2 | 65 | "ProgramPage", |
Pawel Zarembski |
0:01f31e923fe2 | 66 | ]) |
Pawel Zarembski |
0:01f31e923fe2 | 67 | |
Pawel Zarembski |
0:01f31e923fe2 | 68 | EXTRA_SYMBOLS = set([ |
Pawel Zarembski |
0:01f31e923fe2 | 69 | "BlankCheck", |
Pawel Zarembski |
0:01f31e923fe2 | 70 | "EraseChip", |
Pawel Zarembski |
0:01f31e923fe2 | 71 | "Verify", |
Pawel Zarembski |
0:01f31e923fe2 | 72 | ]) |
Pawel Zarembski |
0:01f31e923fe2 | 73 | |
Pawel Zarembski |
0:01f31e923fe2 | 74 | def __init__(self, data): |
Pawel Zarembski |
0:01f31e923fe2 | 75 | """Construct a PackFlashAlgorithm from an ElfFileSimple""" |
Pawel Zarembski |
0:01f31e923fe2 | 76 | self.elf = ElfFileSimple(data) |
Pawel Zarembski |
0:01f31e923fe2 | 77 | self.flash_info = PackFlashInfo(self.elf) |
Pawel Zarembski |
0:01f31e923fe2 | 78 | |
Pawel Zarembski |
0:01f31e923fe2 | 79 | self.flash_start = self.flash_info.start |
Pawel Zarembski |
0:01f31e923fe2 | 80 | self.flash_size = self.flash_info.size |
Pawel Zarembski |
0:01f31e923fe2 | 81 | self.page_size = self.flash_info.page_size |
Pawel Zarembski |
0:01f31e923fe2 | 82 | self.sector_sizes = self.flash_info.sector_info_list |
Pawel Zarembski |
0:01f31e923fe2 | 83 | |
Pawel Zarembski |
0:01f31e923fe2 | 84 | symbols = {} |
Pawel Zarembski |
0:01f31e923fe2 | 85 | symbols.update(_extract_symbols(self.elf, self.REQUIRED_SYMBOLS)) |
Pawel Zarembski |
0:01f31e923fe2 | 86 | symbols.update(_extract_symbols(self.elf, self.EXTRA_SYMBOLS, |
Pawel Zarembski |
0:01f31e923fe2 | 87 | default=0xFFFFFFFF)) |
Pawel Zarembski |
0:01f31e923fe2 | 88 | self.symbols = symbols |
Pawel Zarembski |
0:01f31e923fe2 | 89 | |
Pawel Zarembski |
0:01f31e923fe2 | 90 | sections_to_find = ( |
Pawel Zarembski |
0:01f31e923fe2 | 91 | ("PrgCode", "SHT_PROGBITS"), |
Pawel Zarembski |
0:01f31e923fe2 | 92 | ("PrgData", "SHT_PROGBITS"), |
Pawel Zarembski |
0:01f31e923fe2 | 93 | ("PrgData", "SHT_NOBITS"), |
Pawel Zarembski |
0:01f31e923fe2 | 94 | ) |
Pawel Zarembski |
0:01f31e923fe2 | 95 | |
Pawel Zarembski |
0:01f31e923fe2 | 96 | ro_rw_zi = _find_sections(self.elf, sections_to_find) |
Pawel Zarembski |
0:01f31e923fe2 | 97 | ro_rw_zi = _algo_fill_zi_if_missing(ro_rw_zi) |
Pawel Zarembski |
0:01f31e923fe2 | 98 | error_msg = _algo_check_for_section_problems(ro_rw_zi) |
Pawel Zarembski |
0:01f31e923fe2 | 99 | if error_msg is not None: |
Pawel Zarembski |
0:01f31e923fe2 | 100 | raise Exception(error_msg) |
Pawel Zarembski |
0:01f31e923fe2 | 101 | |
Pawel Zarembski |
0:01f31e923fe2 | 102 | sect_ro, sect_rw, sect_zi = ro_rw_zi |
Pawel Zarembski |
0:01f31e923fe2 | 103 | self.ro_start = sect_ro["sh_addr"] |
Pawel Zarembski |
0:01f31e923fe2 | 104 | self.ro_size = sect_ro["sh_size"] |
Pawel Zarembski |
0:01f31e923fe2 | 105 | self.rw_start = sect_rw["sh_addr"] |
Pawel Zarembski |
0:01f31e923fe2 | 106 | self.rw_size = sect_rw["sh_size"] |
Pawel Zarembski |
0:01f31e923fe2 | 107 | self.zi_start = sect_zi["sh_addr"] |
Pawel Zarembski |
0:01f31e923fe2 | 108 | self.zi_size = sect_zi["sh_size"] |
Pawel Zarembski |
0:01f31e923fe2 | 109 | |
Pawel Zarembski |
0:01f31e923fe2 | 110 | self.algo_data = _create_algo_bin(ro_rw_zi) |
Pawel Zarembski |
0:01f31e923fe2 | 111 | |
Pawel Zarembski |
0:01f31e923fe2 | 112 | def format_algo_data(self, spaces, group_size, fmt): |
Pawel Zarembski |
0:01f31e923fe2 | 113 | """" |
Pawel Zarembski |
0:01f31e923fe2 | 114 | Return a string representing algo_data suitable for use in a template |
Pawel Zarembski |
0:01f31e923fe2 | 115 | |
Pawel Zarembski |
0:01f31e923fe2 | 116 | The string is intended for use in a template. |
Pawel Zarembski |
0:01f31e923fe2 | 117 | |
Pawel Zarembski |
0:01f31e923fe2 | 118 | :param spaces: The number of leading spaces for each line |
Pawel Zarembski |
0:01f31e923fe2 | 119 | :param group_size: number of elements per line (element type |
Pawel Zarembski |
0:01f31e923fe2 | 120 | depends of format) |
Pawel Zarembski |
0:01f31e923fe2 | 121 | :param fmt: - format to create - can be either "hex" or "c" |
Pawel Zarembski |
0:01f31e923fe2 | 122 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 123 | padding = " " * spaces |
Pawel Zarembski |
0:01f31e923fe2 | 124 | if fmt == "hex": |
Pawel Zarembski |
0:01f31e923fe2 | 125 | blob = binascii.b2a_hex(self.algo_data) |
Pawel Zarembski |
0:01f31e923fe2 | 126 | line_list = [] |
Pawel Zarembski |
0:01f31e923fe2 | 127 | for i in xrange(0, len(blob), group_size): |
Pawel Zarembski |
0:01f31e923fe2 | 128 | line_list.append('"' + blob[i:i + group_size] + '"') |
Pawel Zarembski |
0:01f31e923fe2 | 129 | return ("\n" + padding).join(line_list) |
Pawel Zarembski |
0:01f31e923fe2 | 130 | elif fmt == "c": |
Pawel Zarembski |
0:01f31e923fe2 | 131 | blob = self.algo_data[:] |
Pawel Zarembski |
0:01f31e923fe2 | 132 | pad_size = 0 if len(blob) % 4 == 0 else 4 - len(blob) % 4 |
Pawel Zarembski |
0:01f31e923fe2 | 133 | blob = blob + "\x00" * pad_size |
Pawel Zarembski |
0:01f31e923fe2 | 134 | integer_list = struct.unpack("<" + "L" * (len(blob) / 4), blob) |
Pawel Zarembski |
0:01f31e923fe2 | 135 | line_list = [] |
Pawel Zarembski |
0:01f31e923fe2 | 136 | for pos in range(0, len(integer_list), group_size): |
Pawel Zarembski |
0:01f31e923fe2 | 137 | group = ["0x%08x" % value for value in |
Pawel Zarembski |
0:01f31e923fe2 | 138 | integer_list[pos:pos + group_size]] |
Pawel Zarembski |
0:01f31e923fe2 | 139 | line_list.append(", ".join(group)) |
Pawel Zarembski |
0:01f31e923fe2 | 140 | return (",\n" + padding).join(line_list) |
Pawel Zarembski |
0:01f31e923fe2 | 141 | else: |
Pawel Zarembski |
0:01f31e923fe2 | 142 | raise Exception("Unsupported format %s" % fmt) |
Pawel Zarembski |
0:01f31e923fe2 | 143 | |
Pawel Zarembski |
0:01f31e923fe2 | 144 | def process_template(self, template_path, output_path, data_dict=None): |
Pawel Zarembski |
0:01f31e923fe2 | 145 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 146 | Generate output from the supplied template |
Pawel Zarembski |
0:01f31e923fe2 | 147 | |
Pawel Zarembski |
0:01f31e923fe2 | 148 | All the public methods and fields of this class can be accessed from |
Pawel Zarembski |
0:01f31e923fe2 | 149 | the template via "algo". |
Pawel Zarembski |
0:01f31e923fe2 | 150 | |
Pawel Zarembski |
0:01f31e923fe2 | 151 | :param template_path: Relative or absolute file path to the template |
Pawel Zarembski |
0:01f31e923fe2 | 152 | :param output_path: Relative or absolute file path to create |
Pawel Zarembski |
0:01f31e923fe2 | 153 | :param data_dict: Additional data to use when generating |
Pawel Zarembski |
0:01f31e923fe2 | 154 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 155 | if data_dict is None: |
Pawel Zarembski |
0:01f31e923fe2 | 156 | data_dict = {} |
Pawel Zarembski |
0:01f31e923fe2 | 157 | else: |
Pawel Zarembski |
0:01f31e923fe2 | 158 | assert isinstance(data_dict, dict) |
Pawel Zarembski |
0:01f31e923fe2 | 159 | data_dict = dict(data_dict) |
Pawel Zarembski |
0:01f31e923fe2 | 160 | assert "algo" not in data_dict, "algo already set by user data" |
Pawel Zarembski |
0:01f31e923fe2 | 161 | data_dict["algo"] = self |
Pawel Zarembski |
0:01f31e923fe2 | 162 | |
Pawel Zarembski |
0:01f31e923fe2 | 163 | with open(template_path) as file_handle: |
Pawel Zarembski |
0:01f31e923fe2 | 164 | template_text = file_handle.read() |
Pawel Zarembski |
0:01f31e923fe2 | 165 | |
Pawel Zarembski |
0:01f31e923fe2 | 166 | template = jinja2.Template(template_text) |
Pawel Zarembski |
0:01f31e923fe2 | 167 | target_text = template.render(data_dict) |
Pawel Zarembski |
0:01f31e923fe2 | 168 | |
Pawel Zarembski |
0:01f31e923fe2 | 169 | with open(output_path, "wb") as file_handle: |
Pawel Zarembski |
0:01f31e923fe2 | 170 | file_handle.write(target_text) |
Pawel Zarembski |
0:01f31e923fe2 | 171 | |
Pawel Zarembski |
0:01f31e923fe2 | 172 | |
Pawel Zarembski |
0:01f31e923fe2 | 173 | def _extract_symbols(simple_elf, symbols, default=None): |
Pawel Zarembski |
0:01f31e923fe2 | 174 | """Fill 'symbols' field with required flash algo symbols""" |
Pawel Zarembski |
0:01f31e923fe2 | 175 | to_ret = {} |
Pawel Zarembski |
0:01f31e923fe2 | 176 | for symbol in symbols: |
Pawel Zarembski |
0:01f31e923fe2 | 177 | if symbol not in simple_elf.symbols: |
Pawel Zarembski |
0:01f31e923fe2 | 178 | if default is not None: |
Pawel Zarembski |
0:01f31e923fe2 | 179 | to_ret[symbol] = default |
Pawel Zarembski |
0:01f31e923fe2 | 180 | continue |
Pawel Zarembski |
0:01f31e923fe2 | 181 | raise Exception("Missing symbol %s" % symbol) |
Pawel Zarembski |
0:01f31e923fe2 | 182 | to_ret[symbol] = simple_elf.symbols[symbol].value |
Pawel Zarembski |
0:01f31e923fe2 | 183 | return to_ret |
Pawel Zarembski |
0:01f31e923fe2 | 184 | |
Pawel Zarembski |
0:01f31e923fe2 | 185 | |
Pawel Zarembski |
0:01f31e923fe2 | 186 | def _find_sections(elf, name_type_pairs): |
Pawel Zarembski |
0:01f31e923fe2 | 187 | """Return a list of sections the same length and order of the input list""" |
Pawel Zarembski |
0:01f31e923fe2 | 188 | sections = [None] * len(name_type_pairs) |
Pawel Zarembski |
0:01f31e923fe2 | 189 | for section in elf.iter_sections(): |
Pawel Zarembski |
0:01f31e923fe2 | 190 | section_name = bytes2str(section.name) |
Pawel Zarembski |
0:01f31e923fe2 | 191 | section_type = section["sh_type"] |
Pawel Zarembski |
0:01f31e923fe2 | 192 | for i, name_and_type in enumerate(name_type_pairs): |
Pawel Zarembski |
0:01f31e923fe2 | 193 | if name_and_type != (section_name, section_type): |
Pawel Zarembski |
0:01f31e923fe2 | 194 | continue |
Pawel Zarembski |
0:01f31e923fe2 | 195 | if sections[i] is not None: |
Pawel Zarembski |
0:01f31e923fe2 | 196 | raise Exception("Elf contains duplicate section %s attr %s" % |
Pawel Zarembski |
0:01f31e923fe2 | 197 | (section_name, section_type)) |
Pawel Zarembski |
0:01f31e923fe2 | 198 | sections[i] = section |
Pawel Zarembski |
0:01f31e923fe2 | 199 | return sections |
Pawel Zarembski |
0:01f31e923fe2 | 200 | |
Pawel Zarembski |
0:01f31e923fe2 | 201 | |
Pawel Zarembski |
0:01f31e923fe2 | 202 | def _algo_fill_zi_if_missing(ro_rw_zi): |
Pawel Zarembski |
0:01f31e923fe2 | 203 | """Create an empty zi section if it is missing""" |
Pawel Zarembski |
0:01f31e923fe2 | 204 | s_ro, s_rw, s_zi = ro_rw_zi |
Pawel Zarembski |
0:01f31e923fe2 | 205 | if s_rw is None: |
Pawel Zarembski |
0:01f31e923fe2 | 206 | return ro_rw_zi |
Pawel Zarembski |
0:01f31e923fe2 | 207 | if s_zi is not None: |
Pawel Zarembski |
0:01f31e923fe2 | 208 | return ro_rw_zi |
Pawel Zarembski |
0:01f31e923fe2 | 209 | s_zi = { |
Pawel Zarembski |
0:01f31e923fe2 | 210 | "sh_addr": s_rw["sh_addr"] + s_rw["sh_size"], |
Pawel Zarembski |
0:01f31e923fe2 | 211 | "sh_size": 0 |
Pawel Zarembski |
0:01f31e923fe2 | 212 | } |
Pawel Zarembski |
0:01f31e923fe2 | 213 | return s_ro, s_rw, s_zi |
Pawel Zarembski |
0:01f31e923fe2 | 214 | |
Pawel Zarembski |
0:01f31e923fe2 | 215 | |
Pawel Zarembski |
0:01f31e923fe2 | 216 | def _algo_check_for_section_problems(ro_rw_zi): |
Pawel Zarembski |
0:01f31e923fe2 | 217 | """Return a string describing any errors with the layout or None if good""" |
Pawel Zarembski |
0:01f31e923fe2 | 218 | s_ro, s_rw, s_zi = ro_rw_zi |
Pawel Zarembski |
0:01f31e923fe2 | 219 | if s_ro is None: |
Pawel Zarembski |
0:01f31e923fe2 | 220 | return "RO section is missing" |
Pawel Zarembski |
0:01f31e923fe2 | 221 | if s_rw is None: |
Pawel Zarembski |
0:01f31e923fe2 | 222 | return "RW section is missing" |
Pawel Zarembski |
0:01f31e923fe2 | 223 | if s_zi is None: |
Pawel Zarembski |
0:01f31e923fe2 | 224 | return "ZI section is missing" |
Pawel Zarembski |
0:01f31e923fe2 | 225 | if s_ro["sh_addr"] != 0: |
Pawel Zarembski |
0:01f31e923fe2 | 226 | return "RO section does not start at address 0" |
Pawel Zarembski |
0:01f31e923fe2 | 227 | if s_ro["sh_addr"] + s_ro["sh_size"] != s_rw["sh_addr"]: |
Pawel Zarembski |
0:01f31e923fe2 | 228 | return "RW section does not follow RO section" |
Pawel Zarembski |
0:01f31e923fe2 | 229 | if s_rw["sh_addr"] + s_rw["sh_size"] != s_zi["sh_addr"]: |
Pawel Zarembski |
0:01f31e923fe2 | 230 | return "ZI section does not follow RW section" |
Pawel Zarembski |
0:01f31e923fe2 | 231 | return None |
Pawel Zarembski |
0:01f31e923fe2 | 232 | |
Pawel Zarembski |
0:01f31e923fe2 | 233 | |
Pawel Zarembski |
0:01f31e923fe2 | 234 | def _create_algo_bin(ro_rw_zi): |
Pawel Zarembski |
0:01f31e923fe2 | 235 | """Create a binary blob of the flash algo which can execute from ram""" |
Pawel Zarembski |
0:01f31e923fe2 | 236 | sect_ro, sect_rw, sect_zi = ro_rw_zi |
Pawel Zarembski |
0:01f31e923fe2 | 237 | algo_size = sect_ro["sh_size"] + sect_rw["sh_size"] + sect_zi["sh_size"] |
Pawel Zarembski |
0:01f31e923fe2 | 238 | algo_data = bytearray(algo_size) |
Pawel Zarembski |
0:01f31e923fe2 | 239 | for section in (sect_ro, sect_rw): |
Pawel Zarembski |
0:01f31e923fe2 | 240 | start = section["sh_addr"] |
Pawel Zarembski |
0:01f31e923fe2 | 241 | size = section["sh_size"] |
Pawel Zarembski |
0:01f31e923fe2 | 242 | data = section.data() |
Pawel Zarembski |
0:01f31e923fe2 | 243 | assert len(data) == size |
Pawel Zarembski |
0:01f31e923fe2 | 244 | algo_data[start:start + size] = data |
Pawel Zarembski |
0:01f31e923fe2 | 245 | return algo_data |
Pawel Zarembski |
0:01f31e923fe2 | 246 | |
Pawel Zarembski |
0:01f31e923fe2 | 247 | |
Pawel Zarembski |
0:01f31e923fe2 | 248 | class PackFlashInfo(object): |
Pawel Zarembski |
0:01f31e923fe2 | 249 | """Wrapper class for the non-executable information in an FLM file""" |
Pawel Zarembski |
0:01f31e923fe2 | 250 | |
Pawel Zarembski |
0:01f31e923fe2 | 251 | FLASH_DEVICE_STRUCT = "<H128sHLLLLBxxxLL" |
Pawel Zarembski |
0:01f31e923fe2 | 252 | FLASH_SECTORS_STRUCT = "<LL" |
Pawel Zarembski |
0:01f31e923fe2 | 253 | FLASH_SECTORS_STRUCT_SIZE = struct.calcsize(FLASH_SECTORS_STRUCT) |
Pawel Zarembski |
0:01f31e923fe2 | 254 | SECTOR_END = 0xFFFFFFFF |
Pawel Zarembski |
0:01f31e923fe2 | 255 | |
Pawel Zarembski |
0:01f31e923fe2 | 256 | def __init__(self, elf_simple): |
Pawel Zarembski |
0:01f31e923fe2 | 257 | dev_info = elf_simple.symbols["FlashDevice"] |
Pawel Zarembski |
0:01f31e923fe2 | 258 | info_start = dev_info.value |
Pawel Zarembski |
0:01f31e923fe2 | 259 | info_size = struct.calcsize(self.FLASH_DEVICE_STRUCT) |
Pawel Zarembski |
0:01f31e923fe2 | 260 | data = elf_simple.read(info_start, info_size) |
Pawel Zarembski |
0:01f31e923fe2 | 261 | values = struct.unpack(self.FLASH_DEVICE_STRUCT, data) |
Pawel Zarembski |
0:01f31e923fe2 | 262 | |
Pawel Zarembski |
0:01f31e923fe2 | 263 | self.version = values[0] |
Pawel Zarembski |
0:01f31e923fe2 | 264 | self.name = values[1].strip("\x00") |
Pawel Zarembski |
0:01f31e923fe2 | 265 | self.type = values[2] |
Pawel Zarembski |
0:01f31e923fe2 | 266 | self.start = values[3] |
Pawel Zarembski |
0:01f31e923fe2 | 267 | self.size = values[4] |
Pawel Zarembski |
0:01f31e923fe2 | 268 | self.page_size = values[5] |
Pawel Zarembski |
0:01f31e923fe2 | 269 | self.value_empty = values[7] |
Pawel Zarembski |
0:01f31e923fe2 | 270 | self.prog_timeout_ms = values[8] |
Pawel Zarembski |
0:01f31e923fe2 | 271 | self.erase_timeout_ms = values[9] |
Pawel Zarembski |
0:01f31e923fe2 | 272 | |
Pawel Zarembski |
0:01f31e923fe2 | 273 | sector_gen = self._sector_and_sz_itr(elf_simple, |
Pawel Zarembski |
0:01f31e923fe2 | 274 | info_start + info_size) |
Pawel Zarembski |
0:01f31e923fe2 | 275 | self.sector_info_list = list(sector_gen) |
Pawel Zarembski |
0:01f31e923fe2 | 276 | |
Pawel Zarembski |
0:01f31e923fe2 | 277 | def __str__(self): |
Pawel Zarembski |
0:01f31e923fe2 | 278 | desc = "" |
Pawel Zarembski |
0:01f31e923fe2 | 279 | desc += "Flash Device:" + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 280 | desc += " name=%s" % self.name + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 281 | desc += " version=0x%x" % self.version + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 282 | desc += " type=%i" % self.type + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 283 | desc += " start=0x%x" % self.start + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 284 | desc += " size=0x%x" % self.size + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 285 | desc += " page_size=0x%x" % self.page_size + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 286 | desc += " value_empty=0x%x" % self.value_empty + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 287 | desc += " prog_timeout_ms=%i" % self.prog_timeout_ms + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 288 | desc += " erase_timeout_ms=%i" % self.erase_timeout_ms + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 289 | desc += " sectors:" + os.linesep |
Pawel Zarembski |
0:01f31e923fe2 | 290 | for sector_start, sector_size in self.sector_info_list: |
Pawel Zarembski |
0:01f31e923fe2 | 291 | desc += (" start=0x%x, size=0x%x" % |
Pawel Zarembski |
0:01f31e923fe2 | 292 | (sector_start, sector_size) + os.linesep) |
Pawel Zarembski |
0:01f31e923fe2 | 293 | return desc |
Pawel Zarembski |
0:01f31e923fe2 | 294 | |
Pawel Zarembski |
0:01f31e923fe2 | 295 | def _sector_and_sz_itr(self, elf_simple, data_start): |
Pawel Zarembski |
0:01f31e923fe2 | 296 | """Iterator which returns starting address and sector size""" |
Pawel Zarembski |
0:01f31e923fe2 | 297 | for entry_start in count(data_start, self.FLASH_SECTORS_STRUCT_SIZE): |
Pawel Zarembski |
0:01f31e923fe2 | 298 | data = elf_simple.read(entry_start, self.FLASH_SECTORS_STRUCT_SIZE) |
Pawel Zarembski |
0:01f31e923fe2 | 299 | size, start = struct.unpack(self.FLASH_SECTORS_STRUCT, data) |
Pawel Zarembski |
0:01f31e923fe2 | 300 | start_and_size = start, size |
Pawel Zarembski |
0:01f31e923fe2 | 301 | if start_and_size == (self.SECTOR_END, self.SECTOR_END): |
Pawel Zarembski |
0:01f31e923fe2 | 302 | return |
Pawel Zarembski |
0:01f31e923fe2 | 303 | yield start_and_size |
Pawel Zarembski |
0:01f31e923fe2 | 304 | |
Pawel Zarembski |
0:01f31e923fe2 | 305 | |
Pawel Zarembski |
0:01f31e923fe2 | 306 | SymbolSimple = namedtuple("SymbolSimple", "name, value, size") |
Pawel Zarembski |
0:01f31e923fe2 | 307 | |
Pawel Zarembski |
0:01f31e923fe2 | 308 | |
Pawel Zarembski |
0:01f31e923fe2 | 309 | class ElfFileSimple(ELFFile): |
Pawel Zarembski |
0:01f31e923fe2 | 310 | """Wrapper for elf object which allows easy access to symbols and rom""" |
Pawel Zarembski |
0:01f31e923fe2 | 311 | |
Pawel Zarembski |
0:01f31e923fe2 | 312 | def __init__(self, data): |
Pawel Zarembski |
0:01f31e923fe2 | 313 | """Construct a ElfFileSimple from bytes or a bytearray""" |
Pawel Zarembski |
0:01f31e923fe2 | 314 | super(ElfFileSimple, self).__init__(StringIO.StringIO(data)) |
Pawel Zarembski |
0:01f31e923fe2 | 315 | self.symbols = self._read_symbol_table() |
Pawel Zarembski |
0:01f31e923fe2 | 316 | |
Pawel Zarembski |
0:01f31e923fe2 | 317 | def _read_symbol_table(self): |
Pawel Zarembski |
0:01f31e923fe2 | 318 | """Read the symbol table into the field "symbols" for easy use""" |
Pawel Zarembski |
0:01f31e923fe2 | 319 | section = self.get_section_by_name(b".symtab") |
Pawel Zarembski |
0:01f31e923fe2 | 320 | if not section: |
Pawel Zarembski |
0:01f31e923fe2 | 321 | raise Exception("Missing symbol table") |
Pawel Zarembski |
0:01f31e923fe2 | 322 | |
Pawel Zarembski |
0:01f31e923fe2 | 323 | if not isinstance(section, SymbolTableSection): |
Pawel Zarembski |
0:01f31e923fe2 | 324 | raise Exception("Invalid symbol table section") |
Pawel Zarembski |
0:01f31e923fe2 | 325 | |
Pawel Zarembski |
0:01f31e923fe2 | 326 | symbols = {} |
Pawel Zarembski |
0:01f31e923fe2 | 327 | for symbol in section.iter_symbols(): |
Pawel Zarembski |
0:01f31e923fe2 | 328 | name_str = bytes2str(symbol.name) |
Pawel Zarembski |
0:01f31e923fe2 | 329 | if name_str in symbols: |
Pawel Zarembski |
0:01f31e923fe2 | 330 | logging.debug("Duplicate symbol %s", name_str) |
Pawel Zarembski |
0:01f31e923fe2 | 331 | symbols[name_str] = SymbolSimple(name_str, symbol["st_value"], |
Pawel Zarembski |
0:01f31e923fe2 | 332 | symbol["st_size"]) |
Pawel Zarembski |
0:01f31e923fe2 | 333 | return symbols |
Pawel Zarembski |
0:01f31e923fe2 | 334 | |
Pawel Zarembski |
0:01f31e923fe2 | 335 | def read(self, addr, size): |
Pawel Zarembski |
0:01f31e923fe2 | 336 | """Read program data from the elf file |
Pawel Zarembski |
0:01f31e923fe2 | 337 | |
Pawel Zarembski |
0:01f31e923fe2 | 338 | :param addr: physical address (load address) to read from |
Pawel Zarembski |
0:01f31e923fe2 | 339 | :param size: number of bytes to read |
Pawel Zarembski |
0:01f31e923fe2 | 340 | :return: Requested data or None if address is unmapped |
Pawel Zarembski |
0:01f31e923fe2 | 341 | """ |
Pawel Zarembski |
0:01f31e923fe2 | 342 | for segment in self.iter_segments(): |
Pawel Zarembski |
0:01f31e923fe2 | 343 | seg_addr = segment["p_paddr"] |
Pawel Zarembski |
0:01f31e923fe2 | 344 | seg_size = min(segment["p_memsz"], segment["p_filesz"]) |
Pawel Zarembski |
0:01f31e923fe2 | 345 | if addr >= seg_addr + seg_size: |
Pawel Zarembski |
0:01f31e923fe2 | 346 | continue |
Pawel Zarembski |
0:01f31e923fe2 | 347 | if addr + size <= seg_addr: |
Pawel Zarembski |
0:01f31e923fe2 | 348 | continue |
Pawel Zarembski |
0:01f31e923fe2 | 349 | # There is at least some overlap |
Pawel Zarembski |
0:01f31e923fe2 | 350 | |
Pawel Zarembski |
0:01f31e923fe2 | 351 | if addr >= seg_addr and addr + size <= seg_addr + seg_size: |
Pawel Zarembski |
0:01f31e923fe2 | 352 | # Region is fully contained |
Pawel Zarembski |
0:01f31e923fe2 | 353 | data = segment.data() |
Pawel Zarembski |
0:01f31e923fe2 | 354 | start = addr - seg_addr |
Pawel Zarembski |
0:01f31e923fe2 | 355 | return data[start:start + size] |
Pawel Zarembski |
0:01f31e923fe2 | 356 | |
Pawel Zarembski |
0:01f31e923fe2 | 357 | |
Pawel Zarembski |
0:01f31e923fe2 | 358 | if __name__ == '__main__': |
Pawel Zarembski |
0:01f31e923fe2 | 359 | main() |