コード例 #1
0
 def check_wr_protection_area(self, num_blk, wr_data):
     # checks fields which have the write protection bit.
     # if the write protection bit is set, we need to protect that area from changes.
     write_disable_bit = self.read_field("WR_DIS", bitstring=False)
     mask_wr_data = BitString(len(wr_data))
     mask_wr_data.set(0)
     blk = self.Blocks.get(self.Blocks.BLOCKS[num_blk])
     if blk.write_disable_bit is not None and write_disable_bit & (
         1 << blk.write_disable_bit
     ):
         mask_wr_data.set(1)
     else:
         for e in self.Fields.EFUSES:
             field = self.Fields.get(e)
             if blk.id == field.block and field.block == num_blk:
                 if field.write_disable_bit is not None and write_disable_bit & (
                     1 << field.write_disable_bit
                 ):
                     data = self.read_field(field.name)
                     data.set(1)
                     mask_wr_data.pos = mask_wr_data.length - (
                         field.word * 32 + field.pos + data.len
                     )
                     mask_wr_data.overwrite(data)
     mask_wr_data.invert()
     return wr_data & mask_wr_data
コード例 #2
0
ファイル: config.py プロジェクト: luken/pcitweak
    def write(self, value, offset, length, bit_offset=None, bit_length=None):
        """
        If a whole register, writes value to the whole register
        If a bit field, reads the register and mods only the specified bit then writes that new value back
        """
        if bit_offset is None:
            data = BitString(uint=value, length=length)
        else:
            orig = self.read(offset, length)
            #print "orig int 0x%x" % (orig)
            orig = BitString(uint=orig, length=length)
            #print "orig bs %s" % (orig.bin)
            new = BitString(uint=value, length=bit_length)
            #print "new bs %s going in at offset %d" % (new.bin, bit_offset)
            # Slice addresses are in reverse order
            orig.overwrite(new, length - (bit_offset + bit_length))
            #orig.overwrite(new, bit_offset)
            data = orig

        #print "%s %s" % (data.hex, data.bin)
        data = self.swap_le_be(data)
        self.config.seek(offset)
        self.config.write(data.bytes)
コード例 #3
0
ファイル: base_fields.py プロジェクト: FranckCCC/gullivigne
class EfuseFieldBase(EfuseProtectBase):
    def __init__(self, parent, param):
        self.category = param.category
        self.parent = parent
        self.block = param.block
        self.word = param.word
        self.pos = param.pos
        self.write_disable_bit = param.write_disable_bit
        self.read_disable_bit = param.read_disable_bit
        self.name = param.name
        self.efuse_class = param.class_type
        self.efuse_type = param.type
        self.description = param.description
        self.dict_value = param.dictionary
        if self.efuse_type.startswith("bool"):
            field_len = 1
        else:
            field_len = int(re.search(r'\d+', self.efuse_type).group())
            if self.efuse_type.startswith("bytes"):
                field_len *= 8
        self.bitarray = BitString(field_len)
        self.bit_len = field_len
        self.bitarray.set(0)
        self.update(self.parent.blocks[self.block].bitarray)

    def check_format(self, new_value_str):
        if new_value_str is None:
            return new_value_str
        else:
            if self.efuse_type.startswith("bytes"):
                if new_value_str.startswith("0x"):
                    # cmd line: 0x0102030405060708 .... 112233ff      (hex)
                    # regs: 112233ff ... 05060708 01020304
                    # BLK: ff 33 22 11 ... 08 07 06 05 04 03 02 01
                    return binascii.unhexlify(new_value_str[2:])[::-1]
                else:
                    # cmd line: 0102030405060708 .... 112233ff        (string)
                    # regs: 04030201 08070605 ... ff332211
                    # BLK: 01 02 03 04 05 06 07 08 ... 11 22 33 ff
                    return binascii.unhexlify(new_value_str)
            else:
                return new_value_str

    def convert_to_bitstring(self, new_value):
        if isinstance(new_value, BitArray):
            return new_value
        else:
            if self.efuse_type.startswith("bytes"):
                # new_value (bytes) = [0][1][2] ... [N]             (original data)
                # in string format  = [0] [1] [2] ... [N]           (util.hexify(data, " "))
                # in hex format     = 0x[N]....[2][1][0]            (from bitstring print(data))
                # in reg format     = [3][2][1][0] ... [N][][][]    (as it will be in the device)
                # in bitstring      = [N] ... [2][1][0]             (to get a correct bitstring need to reverse new_value)
                # *[x] - means a byte.
                return BitArray(bytes=new_value[::-1],
                                length=len(new_value) * 8)
            else:
                return BitArray(self.efuse_type + "={}".format(new_value))

    def check_new_value(self, bitarray_new_value):
        bitarray_old_value = self.get_bitstring()
        if bitarray_new_value.len != bitarray_old_value.len:
            raise esptool.FatalError(
                "For {} efuse, the length of the new value is wrong, expected {} bits, was {} bits."
                .format(self.name, bitarray_old_value.len,
                        bitarray_new_value.len))
        if bitarray_new_value == bitarray_old_value:
            error_msg = "\tThe same value for {} is already burned. Do not change the efuse.".format(
                self.name)
            print(error_msg)
            bitarray_new_value.set(0)
        else:
            if self.name not in ["WR_DIS", "RD_DIS"]:
                # WR_DIS, RD_DIS fields can have already set bits.
                # Do not neeed to check below condition for them.
                if bitarray_new_value | bitarray_old_value != bitarray_new_value:
                    error_msg = "\tNew value contains some bits that cannot be cleared (value will be {})".format(
                        bitarray_old_value | bitarray_new_value)
                    self.parent.print_error_msg(error_msg)
            self.check_wr_rd_protect()

    def save_to_block(self, bitarray_field):
        block = self.parent.blocks[self.block]
        wr_bitarray_temp = block.wr_bitarray.copy()
        position = wr_bitarray_temp.length - (self.word * 32 + self.pos +
                                              bitarray_field.len)
        wr_bitarray_temp.overwrite(bitarray_field, pos=position)
        block.wr_bitarray |= wr_bitarray_temp

    def save(self, new_value):
        bitarray_field = self.convert_to_bitstring(new_value)
        self.check_new_value(bitarray_field)
        self.save_to_block(bitarray_field)

    def update(self, bit_array_block):
        field_len = self.bitarray.len
        bit_array_block.pos = bit_array_block.length - (self.word * 32 +
                                                        self.pos + field_len)
        self.bitarray.overwrite(bit_array_block.read(field_len), pos=0)

    def get_raw(self, from_read=True):
        """ Return the raw (unformatted) numeric value of the efuse bits

        Returns a simple integer or (for some subclasses) a bitstring.
        type: int or bool -> int
        type: bytes -> bytearray
        """
        return self.get_bitstring(from_read).read(self.efuse_type)

    def get(self, from_read=True):
        """ Get a formatted version of the efuse value, suitable for display
        type: int or bool -> int
        type: bytes -> string  "01 02 03 04 05 06 07 08 ... ". Byte order [0] ... [N]. dump regs: 0x04030201 0x08070605 ...
        """
        if self.efuse_type.startswith("bytes"):
            return util.hexify(self.get_bitstring(from_read).bytes[::-1], " ")
        else:
            return self.get_raw(from_read)

    def get_meaning(self, from_read=True):
        """ Get the meaning of efuse from dict if possible, suitable for display """
        if self.dict_value:
            try:
                return self.dict_value[self.get_raw(from_read)]
            except KeyError:
                pass
        return self.get(from_read)

    def get_bitstring(self, from_read=True):
        if from_read:
            self.bitarray.pos = 0
            return self.bitarray
        else:
            field_len = self.bitarray.len
            block = self.parent.blocks[self.block]
            block.wr_bitarray.pos = block.wr_bitarray.length - (
                self.word * 32 + self.pos + field_len)
            return block.wr_bitarray.read(self.bitarray.len)

    def burn(self, new_value):
        # Burn a efuse. Added for compatibility reason.
        self.save(new_value)
        self.parent.burn_all()
コード例 #4
0
ファイル: base_fields.py プロジェクト: FranckCCC/gullivigne
class EfuseBlockBase(EfuseProtectBase):
    def __init__(self, parent, param, skip_read=False):
        self.parent = parent
        self.name = param.name
        self.alias = param.alias
        self.id = param.id
        self.rd_addr = param.rd_addr
        self.wr_addr = param.wr_addr
        self.write_disable_bit = param.write_disable_bit
        self.read_disable_bit = param.read_disable_bit
        self.len = param.len
        self.key_purpose_name = param.key_purpose
        bit_block_len = self.get_block_len() * 8
        self.bitarray = BitString(bit_block_len)
        self.bitarray.set(0)
        self.wr_bitarray = BitString(bit_block_len)
        self.wr_bitarray.set(0)
        if not skip_read:
            self.read()

    def get_block_len(self):
        coding_scheme = self.get_coding_scheme()
        if coding_scheme == self.parent.REGS.CODING_SCHEME_NONE:
            return self.len * 4
        elif coding_scheme == self.parent.REGS.CODING_SCHEME_34:
            return (self.len * 3 // 4) * 4
        elif coding_scheme == self.parent.REGS.CODING_SCHEME_RS:
            return self.len * 4
        else:
            raise esptool.FatalError("Coding scheme (%d) not supported" %
                                     (coding_scheme))

    def get_coding_scheme(self):
        if self.id == 0:
            return self.parent.REGS.CODING_SCHEME_NONE
        else:
            return self.parent.coding_scheme

    def get_raw(self, from_read=True):
        if from_read:
            return self.bitarray.bytes
        else:
            return self.wr_bitarray.bytes

    def get(self, from_read=True):
        self.get_bitstring(from_read=from_read)

    def get_bitstring(self, from_read=True):
        if from_read:
            return self.bitarray
        else:
            return self.wr_bitarray

    def convert_to_bitstring(self, new_data):
        if isinstance(new_data, BitArray):
            return new_data
        else:
            return BitArray(bytes=new_data, length=len(new_data) * 8)

    def get_words(self):
        def get_offsets(self):
            return [
                x + self.rd_addr for x in range(0, self.get_block_len(), 4)
            ]

        return [self.parent.read_reg(offs) for offs in get_offsets(self)]

    def read(self):
        words = self.get_words()
        data = BitArray()
        for word in reversed(words):
            data.append("uint:32=%d" % word)
        self.bitarray.overwrite(data, pos=0)
        self.print_block(self.bitarray, "read_regs")

    def print_block(self, bit_string, comment, debug=False):
        if self.parent.debug or debug:
            bit_string.pos = 0
            print(
                "%-15s (%-16s) [%-2d] %s:" %
                (self.name, " ".join(self.alias)[:16], self.id, comment),
                " ".join([
                    "%08x" % word
                    for word in bit_string.readlist('%d*uint:32' %
                                                    (bit_string.len /
                                                     32))[::-1]
                ]))

    def check_wr_data(self):
        wr_data = self.wr_bitarray
        if wr_data.all(False):
            # nothing to burn
            if self.parent.debug:
                print("[{:02}] {:20} nothing to burn".format(
                    self.id, self.name))
            return False
        if len(wr_data.bytes) != len(self.bitarray.bytes):
            raise esptool.FatalError(
                "Data does not fit: the block%d size is %d bytes, data is %d bytes"
                % (self.id, len(self.bitarray.bytes), len(wr_data.bytes)))
        self.check_wr_rd_protect()

        if self.get_bitstring().all(False):
            print("[{:02}] {:20} is empty, will burn the new value".format(
                self.id, self.name))
        else:
            # the written block in chip is not empty
            if self.get_bitstring() == wr_data:
                print(
                    "[{:02}] {:20} is already written the same value, continue with EMPTY_BLOCK"
                    .format(self.id, self.name))
                wr_data.set(0)
            else:
                print("[{:02}] {:20} is not empty".format(self.id, self.name))
                print("\t(written ):", self.get_bitstring())
                print("\t(to write):", wr_data)
                mask = self.get_bitstring() & wr_data
                if mask == wr_data:
                    print(
                        "\tAll wr_data bits are set in the written block, continue with EMPTY_BLOCK."
                    )
                    wr_data.set(0)
                else:
                    coding_scheme = self.get_coding_scheme()
                    if coding_scheme == self.parent.REGS.CODING_SCHEME_NONE:
                        print("\t(coding scheme = NONE)")
                    elif coding_scheme == self.parent.REGS.CODING_SCHEME_RS:
                        print("\t(coding scheme = RS)")
                        error_msg = "\tBurn into %s is forbidden (RS coding scheme does not allow this)." % (
                            self.name)
                        self.parent.print_error_msg(error_msg)
                    elif coding_scheme == self.parent.REGS.CODING_SCHEME_34:
                        print("\t(coding scheme = 3/4)")
                        data_can_not_be_burn = False
                        for i in range(0, self.get_bitstring().len, 6 * 8):
                            rd_chunk = self.get_bitstring()[i:i + 6 * 8:]
                            wr_chunk = wr_data[i:i + 6 * 8:]
                            if rd_chunk.any(True):
                                if wr_chunk.any(True):
                                    print(
                                        "\twritten chunk [%d] and wr_chunk are not empty. "
                                        % (i // (6 * 8)),
                                        end="")
                                    if rd_chunk == wr_chunk:
                                        print(
                                            "wr_chunk == rd_chunk. Countinue with empty chunk."
                                        )
                                        wr_data[i:i + 6 * 8:].set(0)
                                    else:
                                        print(
                                            "wr_chunk != rd_chunk. Can not burn."
                                        )
                                        print("\twritten ", rd_chunk)
                                        print("\tto write", wr_chunk)
                                        data_can_not_be_burn = True
                        if data_can_not_be_burn:
                            error_msg = "\tBurn into %s is forbidden (3/4 coding scheme does not allow this)." % (
                                self.name)
                            self.parent.print_error_msg(error_msg)
                    else:
                        raise esptool.FatalError(
                            "The coding scheme ({}) is not supported".format(
                                coding_scheme))

    def save(self, new_data):
        # new_data will be checked by check_wr_data() during burn_all()
        # new_data (bytes)  = [0][1][2] ... [N]             (original data)
        # in string format  = [0] [1] [2] ... [N]           (util.hexify(data, " "))
        # in hex format     = 0x[N]....[2][1][0]            (from bitstring print(data))
        # in reg format     = [3][2][1][0] ... [N][][][]    (as it will be in the device)
        # in bitstring      = [N] ... [2][1][0]             (to get a correct bitstring need to reverse new_data)
        # *[x] - means a byte.
        data = BitString(bytes=new_data[::-1], length=len(new_data) * 8)
        if self.parent.debug:
            print("\twritten : {} ->\n\tto write: {}".format(
                self.get_bitstring(), data))
        self.wr_bitarray.overwrite(data, pos=0)

    def burn_words(self, words):
        self.parent.efuse_controller_setup()
        if self.parent.debug:
            print("Write data to BLOCK%d" % (self.id))
        write_reg_addr = self.wr_addr
        for word in words:
            # for ep32s2: using EFUSE_PGM_DATA[0..7]_REG for writing data
            #   32 bytes to EFUSE_PGM_DATA[0..7]_REG
            #   12 bytes to EFUSE_CHECK_VALUE[0..2]_REG. These regs are next after EFUSE_PGM_DATA_REG
            # for esp32:
            #   each block has the special regs EFUSE_BLK[0..3]_WDATA[0..7]_REG for writing data
            if self.parent.debug:
                print("Addr 0x%08x, data=0x%08x" % (write_reg_addr, word))
            self.parent.write_reg(write_reg_addr, word)
            write_reg_addr += 4
        warnings_before = self.parent.get_coding_scheme_warnings()
        warnings_after = self.parent.write_efuses(self.id)
        if warnings_after & ~warnings_before != 0:
            print(
                "WARNING: Burning efuse block added coding scheme warnings 0x%x -> 0x%x. Encoding bug?"
                % (warnings_before, warnings_after))

    def burn(self):
        if self.wr_bitarray.all(False):
            # nothing to burn
            return
        before_burn_bitarray = self.bitarray[:]
        assert before_burn_bitarray is not self.bitarray
        self.print_block(self.wr_bitarray, "to_write")
        words = self.apply_coding_scheme()
        self.burn_words(words)
        self.read()
        if not self.is_readable():
            print(
                "{} ({}) is read-protected. Read back the burn value is not possible."
                .format(self.name, self.alias))
            if self.bitarray.all(False):
                print("Read all '0'")
            else:
                # Should never be happened
                raise esptool.FatalError(
                    "The {} is read-protected but not all '0' ({})".format(
                        self.name, self.bitarray.hex))
        else:
            if self.wr_bitarray == self.bitarray:
                print("BURN BLOCK%-2d - OK (write block == read block)" %
                      self.id)
            elif self.wr_bitarray & self.bitarray == self.wr_bitarray and self.bitarray & before_burn_bitarray == before_burn_bitarray:
                print("BURN BLOCK%-2d - OK (all write block bits are set)" %
                      self.id)
            else:
                self.print_block(self.wr_bitarray, "Expected")
                self.print_block(self.bitarray, "Real    ")
                raise esptool.FatalError(
                    "Burn {} ({}) was not successful".format(
                        self.name, self.alias))
        self.wr_bitarray.set(0)
コード例 #5
0
class EmulateEfuseControllerBase(object):
    """ The class for virtual efuse operations. Using for HOST_TEST.
    """

    CHIP_NAME = ""
    mem = None
    debug = False
    Blocks = None
    Fields = None
    REGS = None

    def __init__(self, efuse_file=None, debug=False):
        self.debug = debug
        self.efuse_file = efuse_file
        if self.efuse_file:
            try:
                self.mem = BitString(open(self.efuse_file, 'a+b'),
                                     length=(self.REGS.EFUSE_MEM_SIZE
                                             & self.REGS.EFUSE_ADDR_MASK) * 8)
            except ValueError:
                # the file is empty or does not fit the length.
                self.mem = BitString(length=(self.REGS.EFUSE_MEM_SIZE
                                             & self.REGS.EFUSE_ADDR_MASK) * 8)
                self.mem.set(0)
                self.mem.tofile(open(self.efuse_file, 'a+b'))
        else:
            # efuse_file is not provided it means we do not want to keep the result of efuse operations
            self.mem = BitString(
                (self.REGS.EFUSE_MEM_SIZE & self.REGS.EFUSE_ADDR_MASK) * 8)
            self.mem.set(0)

    """ esptool method start >> """

    def read_efuse(self, n, block=0):
        """ Read the nth word of the ESP3x EFUSE region. """
        blk = self.Blocks.get(self.Blocks.BLOCKS[block])
        return self.read_reg(blk.rd_addr + (4 * n))

    def read_reg(self, addr):
        self.mem.pos = self.mem.length - (
            (addr & self.REGS.EFUSE_ADDR_MASK) * 8 + 32)
        return self.mem.read("uint:32")

    def write_reg(self,
                  addr,
                  value,
                  mask=0xFFFFFFFF,
                  delay_us=0,
                  delay_after_us=0):
        self.mem.pos = self.mem.length - (
            (addr & self.REGS.EFUSE_ADDR_MASK) * 8 + 32)
        self.mem.overwrite("uint:32={}".format(value & mask))
        self.handle_writing_event(addr, value)

    def update_reg(self, addr, mask, new_val):
        position = self.mem.length - (
            (addr & self.REGS.EFUSE_ADDR_MASK) * 8 + 32)
        self.mem.pos = position
        cur_val = self.mem.read("uint:32")
        self.mem.pos = position
        self.mem.overwrite("uint:32={}".format(cur_val | (new_val & mask)))

    def write_efuse(self, n, value, block=0):
        """ Write the nth word of the ESP3x EFUSE region. """
        blk = self.Blocks.get(self.Blocks.BLOCKS[block])
        self.write_reg(blk.wr_addr + (4 * n), value)

    """ << esptool method end """

    def handle_writing_event(self, addr, value):
        self.save_to_file()

    def save_to_file(self):
        if self.efuse_file:
            with open(self.efuse_file, 'wb') as f:
                self.mem.tofile(f)

    def handle_coding_scheme(self, blk, data):
        return data

    def copy_blocks_wr_regs_to_rd_regs(self, updated_block=None):
        for b in reversed(self.Blocks.BLOCKS):
            blk = self.Blocks.get(b)
            if updated_block is not None:
                if blk.id != updated_block:
                    continue
            data = self.read_block(blk.id, wr_regs=True)
            if self.debug:
                print(blk.name, data.hex)
            plain_data = self.handle_coding_scheme(blk, data)
            plain_data = self.check_wr_protection_area(blk.id, plain_data)
            self.update_block(blk, plain_data)

    def clean_blocks_wr_regs(self):
        for b in self.Blocks.BLOCKS:
            blk = self.Blocks.get(b)
            for offset in range(0, blk.len * 4, 4):
                wr_addr = blk.wr_addr + offset
                self.write_reg(wr_addr, 0)

    def read_field(self, name, bitstring=True):
        for e in self.Fields.EFUSES:
            field = self.Fields.get(e)
            if field.name == name:
                self.read_block(field.block)
                block = self.read_block(field.block)
                if field.type.startswith("bool"):
                    field_len = 1
                else:
                    field_len = int(re.search(r'\d+', field.type).group())
                    if field.type.startswith("bytes"):
                        field_len *= 8
                block.pos = block.length - (field.word * 32 + field.pos +
                                            field_len)
                if bitstring:
                    return block.read(field_len)
                else:
                    return block.read(field.type)
        return None

    def get_bitlen_of_block(self, blk, wr=False):
        return 32 * blk.len

    def read_block(self, idx, wr_regs=False):
        block = None
        for b in self.Blocks.BLOCKS:
            blk = self.Blocks.get(b)
            if blk.id == idx:
                blk_len_bits = self.get_bitlen_of_block(blk, wr=wr_regs)
                addr = blk.wr_addr if wr_regs else blk.rd_addr
                self.mem.pos = self.mem.length - (
                    (addr & self.REGS.EFUSE_ADDR_MASK) * 8 + blk_len_bits)
                block = self.mem.read(blk_len_bits)
                break
        return block

    def update_block(self, blk, wr_data):
        wr_data = self.read_block(blk.id) | wr_data
        self.overwrite_mem_from_block(blk, wr_data)

    def overwrite_mem_from_block(self, blk, wr_data):
        self.mem.pos = self.mem.length - (
            (blk.rd_addr & self.REGS.EFUSE_ADDR_MASK) * 8 + wr_data.len)
        self.mem.overwrite(wr_data)

    def check_wr_protection_area(self, num_blk, wr_data):
        # checks fields which have the write protection bit.
        # if the write protection bit is set then we need to protect that area from changes.
        write_disable_bit = self.read_field("WR_DIS", bitstring=False)
        mask_wr_data = BitString(len(wr_data))
        mask_wr_data.set(0)
        blk = self.Blocks.get(self.Blocks.BLOCKS[num_blk])
        if blk.write_disable_bit is not None and write_disable_bit & (
                1 << blk.write_disable_bit):
            mask_wr_data.set(1)
        else:
            for e in self.Fields.EFUSES:
                field = self.Fields.get(e)
                if blk.id == field.block and field.block == num_blk:
                    if field.write_disable_bit is not None and write_disable_bit & (
                            1 << field.write_disable_bit):
                        data = self.read_field(field.name)
                        data.set(1)
                        mask_wr_data.pos = mask_wr_data.length - (
                            field.word * 32 + field.pos + data.len)
                        mask_wr_data.overwrite(data)
        mask_wr_data.invert()
        return wr_data & mask_wr_data

    def check_rd_protection_area(self):
        # checks fields which have the read protection bits.
        # if the read protection bit is set then we need to reset this field to 0.
        read_disable_bit = self.read_field("RD_DIS", bitstring=False)
        for b in self.Blocks.BLOCKS:
            blk = self.Blocks.get(b)
            block = self.read_block(blk.id)
            if blk.read_disable_bit is not None and read_disable_bit & (
                    1 << blk.read_disable_bit):
                block.set(0)
            else:
                for e in self.Fields.EFUSES:
                    field = self.Fields.get(e)
                    if blk.id == field.block and field.read_disable_bit is not None and read_disable_bit & (
                            1 << field.read_disable_bit):
                        raw_data = self.read_field(field.name)
                        raw_data.set(0)
                        block.pos = block.length - (
                            field.word * 32 + field.pos + raw_data.length)
                        block.overwrite(BitString(raw_data.length))
            self.overwrite_mem_from_block(blk, block)

    def clean_mem(self):
        self.mem.set(0)
        if self.efuse_file:
            with open(self.efuse_file, 'wb') as f:
                self.mem.tofile(f)