示例#1
0
 def verify_data(self):
     from stm32_crc import crc32
     data_crc = crc32(self.resource_data[self.data_offset:])
     assert data_crc == self.manifest['crc']
     for entry in self.table:
         chunk_crc = crc32(self.get_chunk(entry['file_id']))
         assert chunk_crc == entry['crc']
示例#2
0
    def deserialize(cls, f_in):
        # Parse manifest:
        manifest = f_in.read(cls.MANIFEST_SIZE_BYTES)
        fmt = cls.MANIFEST_FMT
        (num_files, crc, timestamp) = struct.unpack(fmt, manifest)

        resource_pack = cls()

        # Parse table entries:
        resource_pack.table_entries = []
        for n in xrange(num_files):
            table_entry = f_in.read(cls.TABLE_ENTRY_SIZE_BYTES)
            fmt = cls.TABLE_ENTRY_FMT
            file_id, offset, length, crc = struct.unpack(fmt, table_entry)
            if file_id == 0:
                break
            if file_id != n + 1:
                raise Exception("File ID is expected to be %u, but was %u" % (n + 1, file_id))
            resource_pack.table_entries.append((offset, length, crc))
        if len(resource_pack.table_entries) != num_files:
            raise Exception("Number of files in manifest is %u, but actual" "number is %u" % (num_files, n))

        # Fetch the contents:
        for entry in resource_pack.table_entries:
            offset, length, crc = entry
            f_in.seek(offset + cls.CONTENT_START_OFFSET)
            content = f_in.read(length)
            calculated_crc = stm32_crc.crc32(content)
            if calculated_crc != crc:
                raise Exception("Entry %s does not match CRC of content (0x%x)" % (entry, calculated_crc))
            resource_pack.contents.append(content)

        resource_pack.num_files = num_files
        resource_pack.timestamp = timestamp
        return resource_pack
示例#3
0
文件: pebble.py 项目: Elleo/rockwatch
	def commit(self):
		if self._crc:
			crc = self._crc
		else:
			crc = stm32_crc.crc32(self._buffer)
		data = pack("!bII", 3, self._token & 0xFFFFFFFF, crc)
		self._pebble._send_message("PUTBYTES", data)
示例#4
0
def cmd_resource_header(args):
    if (len(args.resource_pair_list) % 2) != 0:
        raise Exception(
            "resource_pair_list list must have an even number of entries")
    with open(args.output_header, 'w') as output_file:
        output_file.write("""
#pragma once

//
// AUTOGENERATED BY tools/generate_resource_code.py
// DO NOT MODIFY
//

#include <stdint.h>
#include "{resource_header}"
typedef enum {{
  INVALID_RESOURCE = 0,
  DEFAULT_MENU_ICON = 0, // Friendly synonym for use in `PBL_APP_INFO()` calls
""".format(resource_header=args.resource_include))
        for i in range(1, len(args.resource_pair_list), 2):
            output_file.write("  RESOURCE_ID_" + args.resource_pair_list[i] +
                              ",\n")

        output_file.write("""
} ResourceId;
""")

        if args.version_def_name:
            with open(args.data_file, 'rb') as f:
                crc = stm32_crc.crc32(f.read())

            output_file.write("""
static const ResBankVersion {} = {{
  .crc = {},
  .timestamp = {}
}};
""".format(args.version_def_name, crc, args.timestamp))

        output_file.write("""
static const uint32_t resource_crc_table[] = {
""")

        for i in range(0, len(args.resource_pair_list), 2):
            with open(args.resource_pair_list[i], 'rb') as f:
                output_file.write("  " + str(stm32_crc.crc32(f.read())) +
                                  ",\n")
        output_file.write('};\n\n')
示例#5
0
def save_pbpack(fname, rsrcs):
    """
    Outputs a handful of resources to a file.

    |rsrcs| is a list of resources, with the first mapping to resource index
    "1".  Although the PebbleOS resource structure permits a sparse mapping
    -- i.e., one in which one must read the whole resource table to find the
    index that one desires -- the RebbleOS resource loader simply ignores
    the ID number in each table entry, and indexes directly in to find what
    it wants.  (And, further, every Pebble pbpack that I can find only has
    them in order.)  So we, in keeping, will only generate things like that.

    """

    # First, turn the resource table into a list of entries, including
    # index, offset, size, and CRC.
    def mk_ent(data):
        assert (len(data) > 0)
        ent = {
            "idx": mk_ent.idx,
            "offset": mk_ent.offset,
            "size": len(data),
            "crc": crc32(data),
            "data": data
        }
        mk_ent.offset += len(data)
        mk_ent.idx += 1
        return ent

    mk_ent.offset = 0
    mk_ent.idx = 1
    rsrc_ents = [mk_ent(data) for data in rsrcs]

    with open(fname, 'wb+') as f:
        f.write(struct.pack('I', len(rsrc_ents)))  # Number of resources.
        # We'll come back to the big CRC later.

        # Write out the table.
        f.seek(TAB_OFS)
        for ent in rsrc_ents:
            f.write(
                struct.pack('iiiI', ent["idx"], ent["offset"], ent["size"],
                            ent["crc"]))

        # Write out the resources themselves.
        for ent in rsrc_ents:
            f.seek(RES_OFS + ent["offset"])
            f.write(ent["data"])

        # Now compute the CRC of the whole show.
        f.seek(RES_OFS)
        alldata = f.read()

        totlen = f.tell()

        f.seek(4)
        f.write(struct.pack('I', crc32(alldata)))

    return totlen
示例#6
0
 def serialize_manifest(self, crc=None, timestamp=None):
     if crc is None:
         all_contents = b"".join(self.contents)
         crc = stm32_crc.crc32(all_contents)
     if timestamp is None:
         timestamp = self.timestamp
     fmt = self.MANIFEST_FMT
     return struct.pack(fmt, len(self.table), crc, timestamp)
示例#7
0
def populate(manifest, what, filename):
  with open(filename, "rb") as f:
    stat = os.fstat(f.fileno())
    data = f.read()
  manifest[what]["crc"] = crc32(data)
  manifest[what]["size"] = len(data)
  manifest[what]["timestamp"] = int(stat.st_mtime)
  return data
示例#8
0
 def serialize(self, f_out):
     all_contents = b"".join(self.contents)
     crc = stm32_crc.crc32(all_contents)
     table = self.serialize_table()
     manifest = self.serialize_manifest(crc)
     f_out.write(manifest)
     f_out.write(table)
     f_out.write(all_contents)
     return crc
def cmd_resource_header(args):
    if (len(args.resource_pair_list) % 2) != 0:
        raise Exception("resource_pair_list list must have an even number of entries")
    with open(args.output_header, 'w') as output_file:
        output_file.write("""
#pragma once

//
// AUTOGENERATED BY tools/generate_resource_code.py
// DO NOT MODIFY
//

#include <stdint.h>
#include "{resource_header}"
typedef enum {{
  INVALID_RESOURCE = 0,
  DEFAULT_MENU_ICON = 0, // Friendly synonym for use in `PBL_APP_INFO()` calls
""".format(resource_header=args.resource_include))
        for i in range(1, len(args.resource_pair_list), 2):
            output_file.write("  RESOURCE_ID_" + args.resource_pair_list[i] + ",\n")

        output_file.write("""
} ResourceId;
""")

        if args.version_def_name:
            with open(args.data_file, 'rb') as f:
                crc = stm32_crc.crc32(f.read())

            output_file.write("""
static const ResBankVersion {} = {{
  .crc = {},
  .timestamp = {}
}};
""".format(args.version_def_name, crc, args.timestamp))

        output_file.write("""
static const uint32_t resource_crc_table[] = {
""")

        for i in range(0, len(args.resource_pair_list), 2):
            with open(args.resource_pair_list[i], 'rb') as f:
                output_file.write("  " + str(stm32_crc.crc32(f.read())) + ",\n")
        output_file.write('};\n\n')
示例#10
0
 def mk_ent(data):
     ent = {
         "idx": mk_ent.idx,
         "offset": mk_ent.offset,
         "size": len(data),
         "crc": crc32(data),
         "data": data
     }
     mk_ent.offset += len(data)
     mk_ent.idx += 1
     return ent
示例#11
0
文件: pebble.py 项目: Elleo/rockwatch
	def install_firmware(self, pbz_path, recovery=False):

		"""Install a firmware bundle to the target watch."""

		resources = None
		pbz = zipfile.ZipFile(pbz_path)
		binary = pbz.read("tintin_fw.bin")

		# Calculate CRC in advance to avoid timeout on slow hardware
		bincrc = stm32_crc.crc32(binary)

		if not recovery:
			resources = pbz.read("system_resources.pbpack")
			if resources:
				rescrc = stm32_crc.crc32(resources)

		self.system_message("FIRMWARE_START")
		time.sleep(2)

		if resources:
			client = PutBytesClient(self, 0, "SYS_RESOURCES", resources, rescrc)
			self.register_endpoint("PUTBYTES", client.handle_message)
			client.init()
			while not client._done and not client._error:
				time.sleep(0.2)
			if client._error:
				raise PebbleError(self.id, "Failed to send firmware resources %s/system_resources.pbpack" % pbz_path)


		client = PutBytesClient(self, 0, "RECOVERY" if recovery else "FIRMWARE", binary, bincrc)
		self.register_endpoint("PUTBYTES", client.handle_message)
		client.init()
		while not client._done and not client._error:
			time.sleep(0.2)
		if client._error:
			raise PebbleError(self.id, "Failed to send firmware binary %s/tintin_fw.bin" % pbz_path)

		self.system_message("FIRMWARE_COMPLETE")
示例#12
0
	def commit(self):
		data = pack("!bII", 3, self._token & 0xFFFFFFFF, stm32_crc.crc32(self._buffer))
		self._pebble._send_message("PUTBYTES", data)
示例#13
0
 def commit(self):
     data = pack("!bII", 3, self._token & 0xFFFFFFFF,
                 stm32_crc.crc32(self._buffer))
     self._pebble._send_message("PUTBYTES", data)
示例#14
0
def inject_metadata(target_binary):

    if target_binary[-4:] != '.bin':
        raise InvalidBinaryError

    def get_symbol_addr(elf_file, symbol):
        global cached_nm_output

        if not cached_nm_output:
            nm_process = Popen(['arm-none-eabi-nm', elf_file], stdout=PIPE)
            # Popen.communicate returns a tuple of (stdout, stderr)
            nm_output = nm_process.communicate()[0]

            if not nm_output:
                raise InvalidBinaryError()

            cached_nm_output = nm_output
        else:
            nm_output = cached_nm_output

        for sym in nm_output.split('\n'):
            if symbol in sym:
                return int(sym.split()[0], 16)

        raise InvalidBinaryError()

    def get_relocate_entries(elf_file):
        """ returns a list of all the locations requiring an offset"""
        # TODO: insert link to the wiki page I'm about to write about PIC and relocatable values
        entries = []

        # get the .data locations
        readelf_relocs_process = Popen(['arm-none-eabi-readelf', '-r', elf_file], stdout=PIPE)
        readelf_relocs_output = readelf_relocs_process.communicate()[0]
        lines = readelf_relocs_output.split('\n')

        i = 0
        reading_section = False
        while i < len(lines):
            if not reading_section:
                # look for the next section
                if lines[i].find("Relocation section '.rel.data") == 0:
                    reading_section = True
                    i += 1 # skip the column title section
            else:
                if len(lines[i]) == 0:
                    # end of the section
                    reading_section = False
                else:
                    entries.append(int(lines[i].split(' ')[0], 16))
            i += 1

        # get any Global Offset Table (.got) entries
        readelf_relocs_process = Popen(['arm-none-eabi-readelf', '--sections', elf_file], stdout=PIPE)
        readelf_relocs_output = readelf_relocs_process.communicate()[0]
        lines = readelf_relocs_output.split('\n')
        for line in lines:
            # We shouldn't need to do anything with the Procedure Linkage Table since we don't actually export functions
            if '.got' in line and '.got.plt' not in line:
                words = line.split(' ')
                while '' in words:
                    words.remove('')
                section_label_idx = words.index('.got')
                addr = int(words[section_label_idx + 2], 16)
                length = int(words[section_label_idx + 4], 16)
                for i in range(addr, addr + length, 4):
                    entries.append(i)
                break

        return entries

    target_elf = '.'.join([os.path.splitext(target_binary)[0], 'elf'])
    app_entry_address = get_symbol_addr(target_elf, ENTRY_PT_SYMBOL)
    jump_table_address = get_symbol_addr(target_elf, JUMP_TABLE_ADDR_SYMBOL)


    reloc_entries = get_relocate_entries(target_elf)

    statinfo = os.stat(target_binary)
    app_size = statinfo.st_size

    if DEBUG:
        copy2(target_binary, target_binary + ".orig")

    with open(target_binary, 'r+b') as f:
        app_bin = f.read()
        compiled_bin_size = len(app_bin)

        if compiled_bin_size + len(reloc_entries)*4 > MAX_APP_BINARY_SIZE:
            raise "Appending the reloc table will make this app too large"

        app_crc = stm32_crc.crc32(app_bin[STRUCT_SIZE_BYTES:])

        struct_changes = {
            'size' : app_size,
            'entry_point' : "0x%08x" % app_entry_address,
            'symbol_table' : "0x%08x" % jump_table_address,
            'crc' : "0x%08x" % app_crc,
            'reloc_list_start': "0x%08x" % compiled_bin_size,
            'num_reloc_entries': "0x%08x" % len(reloc_entries)
            }


        f.seek(SIZE_ADDR)
        f.write(pack('<HLL', app_size, app_entry_address, app_crc))

        f.seek(JUMP_TABLE_ADDR)
        f.write(pack('<L', jump_table_address))

        f.seek(RELOC_LIST_START_ADDR)
        f.write(pack('<LL', compiled_bin_size, len(reloc_entries)))

        f.seek(compiled_bin_size)
        for entry in reloc_entries:
            f.write(pack('<L', entry))

        f.flush()

    return struct_changes
示例#15
0
 def make_entry(file_id, offset, length, content):
     crc = 0 if content is None else stm32_crc.crc32(content)
     fmt = self.TABLE_ENTRY_FMT
     return struct.pack(fmt, file_id, offset, length, crc)
示例#16
0
def cmd_table(args):
    with open(args.table_file, 'wb') as table_file:

        cur_file_id = 1
        next_free_byte = 0

        for filename in args.pack_file_list:
            with open(filename, 'rb') as data_file:
                content = data_file.read()
                length = len(content)
                table_file.write(struct.pack('<IIII', cur_file_id, next_free_byte, length, stm32_crc.crc32(content)))
                cur_file_id += 1
                next_free_byte += length

        # pad the rest of the file
        for i in range(len(args.pack_file_list), MAX_NUM_FILES):
            table_file.write(struct.pack('<IIII', 0, 0, 0, 0))
示例#17
0
def cmd_manifest(args):
    with open(args.manifest_file, 'wb') as manifest_file:
        with open(args.data_chunk_file, 'rb') as data_file:
            crc = stm32_crc.crc32(data_file.read())
            manifest_file.write(struct.pack('<III', int(args.num_files), crc, int(args.timestamp)))
示例#18
0
def stm32crc(path):
    with open(path, 'r+b') as f:
        binfile = f.read()
        return stm32_crc.crc32(binfile) & 0xFFFFFFFF
示例#19
0
def stm32crc(path):
    with open(path, 'r+b') as f:
        binfile = f.read()
        return stm32_crc.crc32(binfile) & 0xFFFFFFFF