Exemple #1
0
def getTrailer(signature, sigTypeDescrip, descripFixedSize, sigFixedSize):
    """
    create a trailer which has the following format
    [a + b + c], where

    a = signature type description
    (Use fixed size to store it. Use zero to fill up the rest if description size is smaller than fixed size)

    b = size of signature
    (converted into hexadecimal representation in 32 bits in little endian format)

    c = signature
    (Used fixed size to store it. Use zero to fill up the rest if signature size is smaller than fixed size)

    :param signature:
    :param sigTypeDescrip: signature type description
    :param descripFixedSize: fixed size in bytes for storing signature type description
    :param sigFixedSize: fixed size in bytes for storing signature
    :return:
    """
    trailer = bytearray()

    # append signature type description  to fixed
    sigTypeDescrip = bytearray(source=sigTypeDescrip, encoding="utf-8")
    typeDescripSize = len(sigTypeDescrip)
    if typeDescripSize > descripFixedSize:
        raise Exception(
            "Signature type description exceeded allowed size! Description size: "
            + sigTypeDescrip + ". Allowed maximum size: " + descripFixedSize +
            ". Description given: " + sigTypeDescrip)

    padSize = descripFixedSize - typeDescripSize
    pad = bytearray(padSize)
    trailer.extend(sigTypeDescrip)
    trailer.extend(pad)

    # append signature size as a 4-byte filed in little endian format
    sigSize = len(signature)
    sigSizeFiled = hex(sigSize)
    sigSizeFiled = format32BitHexStr(sigSizeFiled)
    sigSizeFiled = toLitteEndianByte(sigSizeFiled)
    trailer.extend(sigSizeFiled)

    # append signature
    if len(signature) > sigFixedSize:
        raise Exception(
            "Signature size  exceeded allowed size! signature size: " +
            sigSize + ". Allowed maximum size: " + sigFixedSize)
    padSize = sigFixedSize - sigSize
    pad = bytearray(padSize)
    trailer.extend(signature)
    trailer.extend(pad)

    return trailer
Exemple #2
0
def printOTADescriptorImageStruct(processedImagePath, imageLines, offset):
    """
    output the OTA descriptor of processed image along with some of its contents
    for additionalLines

    :param processedImagePath:
    :param imageLines:  number of lines to output when printing the image content
    :param offset: number of bytes to skip from the beginning
    :return:
    """
    cuttingLine = "--------"

    f = open(processedImagePath, "rb")
    f.seek(offset)
    try:
        print(cuttingLine + "Generated OTA descriptor" + cuttingLine)
        byte = f.read(4)
        print(format32BitHexStr(hex(int.from_bytes(byte, "little"))),
              " -> sequence number")

        byte = f.read(4)
        print(format32BitHexStr(hex(int.from_bytes(byte, "little"))),
              " -> start address")

        byte = f.read(4)
        print(format32BitHexStr(hex(int.from_bytes(byte, "little"))),
              " -> end address")

        byte = f.read(4)
        print(format32BitHexStr(hex(int.from_bytes(byte, "little"))),
              " -> execution address")

        byte = f.read(4)
        print(format32BitHexStr(hex(int.from_bytes(byte, "little"))),
              " -> hardware ID")

        byte = f.read(4)
        print(format32BitHexStr(hex(int.from_bytes(byte, "little"))),
              " -> reserved bytes")

        print(cuttingLine + "Image Content" + cuttingLine)
        time = imageLines
        while time > 0:
            byte = f.read(4)  # Every time print 32 bits
            time -= 1
            print(format32BitHexStr(hex(int.from_bytes(byte, "little"))))
        print("...")
        print("...")
    finally:
        f.close()
Exemple #3
0
def printFactoryImageStruct(processedImagePath, trailerSize,
                            numLinesImageContent, descripFixedSize):
    """
    print structure of factory image

    :param processedImagePath: path of processed image
    :param trailerSize: size of trailer in bytes
    :param numLinesImageContent: number of lines of image content to output
    :param descripFixedSize: fixed size in bytes for storing signature type description
    :return:
    """

    cuttingLine = "--------"
    subCuttingLine = "-----"

    # print magic code
    with open(processedImagePath, "rb") as f:
        print(cuttingLine + subCuttingLine + "Magic Code" + subCuttingLine +
              cuttingLine)
        byte = f.read(8)
        print(byte)

    # print [ota_descriptor + image content]
    printOTADescriptorImageStruct(processedImagePath, numLinesImageContent, 8)

    # print trailer
    fSize = getFileSize(processedImagePath)
    f = open(processedImagePath, "rb")
    f.seek(fSize - trailerSize)

    print(cuttingLine + cuttingLine + "Trailer" + cuttingLine + cuttingLine)

    try:
        print(subCuttingLine + " signature type " + subCuttingLine)
        byte = f.read(descripFixedSize)
        print(byte)

        print(subCuttingLine + " signature size " + subCuttingLine)
        byte = f.read(4)
        print(format32BitHexStr(hex(struct.unpack('<I', byte)[0])))

        byte = f.read()
        print(subCuttingLine + " signature " + subCuttingLine)
        print(byte)

    finally:
        f.close()
Exemple #4
0
def getOTADescriptor(userConfigFilePath, inputImagePath, ruleFolderPath, hardwarePlatform):
    """
    parse and validate the parameters defined by user.
    calculate the end address

    If all parameters are valid, return them as ota descriptor.

    Otherwise, raise exeception.

    :param userConfigFilePath: path of the user config file
    :param inputImagePath: path of the input image, which will be used to calculate the end address
    :param ruleFolderPath: path of the folder which contains the validation rule file for the user config
    :param hardwarePlatform: hardware platform name
    :return: parameters to be used to generate the OTA descriptor.
             Each parameter will be formatted as a 10-character string to represent a 32-bit hexadecimal number,
             where the first two character is a prefix "0x".
    """

    parsedParams = parseConfigFile(userConfigFilePath)
    # 1. validate the hardware platform is valid and corresponding rule file can be found
    validHardwarePlatforms = os.listdir(ruleFolderPath)
    if hardwarePlatform not in validHardwarePlatforms:
        raise Exception(
            "Invalid hardware platform! \nExpected hardware platforms: " + str(
                validHardwarePlatforms) + ". \nFound: " + hardwarePlatform)

    # 2. Make sure the rule file and the parameters defined in it are valid
    validationFileLocation = os.path.join(ruleFolderPath, hardwarePlatform)
    validateFilePath(validationFileLocation)
    ruleParams = parseConfigFile(validationFileLocation)
    if len(ruleParams.keys()) != 2:
        raise Exception("Invalid validation rule file : " + validationFileLocation +
                        "\nExpected 2 parameters in this file. " + "\nFound: " + str(len(ruleParams.keys())))

    if "MIN_ADDRESS" not in ruleParams:
        raise Exception("Error! parameter \"MIN_ADDRESS\" is not defined in " + validationFileLocation)
    minAddrHardwarePlatform = ruleParams["MIN_ADDRESS"]
    validate32BitHexParam(minAddrHardwarePlatform, "MIN_ADDRESS", validationFileLocation)
    minAddrHardwarePlatform = format32BitHexStr(minAddrHardwarePlatform)

    if "MAX_ADDRESS" not in ruleParams:
        raise Exception("Error! parameter \"MAX_ADDRESS\" is not defined in " + validationFileLocation)
    maxAddrHardwarePlatform = ruleParams["MAX_ADDRESS"]
    validate32BitHexParam(maxAddrHardwarePlatform, "MAX_ADDRESS", validationFileLocation)
    maxAddrHardwarePlatform = format32BitHexStr(maxAddrHardwarePlatform)

    if (int(maxAddrHardwarePlatform, 16) <= int(minAddrHardwarePlatform, 16)):
        raise Exception(
            "MAX_ADDRESS must be greater than the MIN_ADDRESS !" + " File location " + validationFileLocation)

    # 3. validate sequence number
    if "SEQUENCE_NUMBER" not in parsedParams:
        raise Exception("Error! parameter \"SEQUENCE_NUMBER\" is not defined in " + userConfigFilePath)
    sequenceNumber = parsedParams["SEQUENCE_NUMBER"]
    validate32BitUIntParam(sequenceNumber, "SEQUENCE_NUMBER", userConfigFilePath)
    # convert from string of 32-bit unsigned integer to string of 32-bit hexadecimal
    sequenceNumber = hex(int(sequenceNumber, 10))
    sequenceNumber = format32BitHexStr(sequenceNumber)

    # 4. validate hardware id
    if "HARDWARE_ID" not in parsedParams:
        raise Exception("Error! parameter \"HARDWARE_ID\" is not defined in " + userConfigFilePath)
    hardwareID = parsedParams["HARDWARE_ID"]

    hardwareID = formatHardwareID(hardwareID, userConfigFilePath)
    hardwareID = format32BitHexStr(hardwareID)

    # 5. validate reserved bytes
    if "RESERVED_BYTES" not in parsedParams:
        raise Exception("Error! parameter \"RESERVED_BYTES\" is not defined in " + userConfigFilePath)
    reserves = parsedParams["RESERVED_BYTES"]
    validate32BitHexParam(reserves, "RESERVED_BYTES", userConfigFilePath)
    reserves = format32BitHexStr(reserves)

    # 6. validate start address
    if "START_ADDRESS" not in parsedParams:
        raise Exception("Error! parameter \"START_ADDRESS\" is not defined in " + userConfigFilePath)
    startAddress = parsedParams["START_ADDRESS"]
    validate32BitHexParam(startAddress, "START_ADDRESS", userConfigFilePath)
    startAddress = format32BitHexStr(startAddress)
    # make sure minAddrHardwarePlatform <= startAddress < maxAddressHardwarePlatform
    startMin = minAddrHardwarePlatform
    startMax = format32BitHexStr(hex(int(maxAddrHardwarePlatform, 16) - 1))
    validate32BitHexParamRange(startAddress, "START_ADDRESS", startMin, startMax, userConfigFilePath)

    # 7. calculate and validate the end address
    fileSize = getFileSize(inputImagePath)
    endAddress = getEndAddress(fileSize, int(startAddress, 16))  # get end address in decimal format
    endAddress = hex(endAddress).upper()  # convert to hexadecimal format

    # make sure minAddrHardwarePlatform < endAddress <= maxAddressHardwarePlatform
    endMin = format32BitHexStr(hex(int(minAddrHardwarePlatform, 16) + 1))
    endMax = maxAddrHardwarePlatform
    if int(endAddress, 16) < int(endMin, 16) or int(endAddress, 16) > int(endMax, 16):
        raise Exception(
            "Invalid value of \"END_ADDRESS\"! Expected range : [" + endMin + "," + endMax + "]. Calculated Result : " + endAddress
            + "\nPossible reasons: START_ADDRESS is too large or image size is too large (END_ADDRESS = START_ADDRESS + 24 bytes + size of input image)"
            + "\n\nDebug Info: "
            + "\nImage size: " + str(fileSize)
            + "\nSTART_ADDRESS: " + startAddress + ". Config file location" + userConfigFilePath)
    endAddress = format32BitHexStr(endAddress)

    # 8. validate the execution address
    if "EXECUTION_ADDRESS" not in parsedParams:
        raise Exception("Error! parameter \"EXECUTION_ADDRESS\" is not defined in " + userConfigFilePath)
    executionAddress = parsedParams["EXECUTION_ADDRESS"]
    validate32BitHexParam(executionAddress, "EXECUTION_ADDRESS", userConfigFilePath)
    # make sure startAddress <= executionAddress <= endAddress
    execMin = startAddress
    execMax = endAddress
    validate32BitHexParamRange(executionAddress, "EXECUTION_ADDRESS", execMin, execMax, userConfigFilePath)
    executionAddress = format32BitHexStr(executionAddress)

    return OTADescriptor(sequenceNumber, startAddress, endAddress, executionAddress, hardwareID, reserves)
Exemple #5
0
def formatHardwareID(hardwareIdStr, fileLocation):
    """
    format the hardware id into hexadecimal representation
    
    raise exception if the given  hardwareIdStr is not valid.

    :param hardwareIdStr: a string representing hardware id
    :param fileLocation: location where the hardware Id is defined
    :return:
        formatted hexadecimal string of hardware id

    exmaples:

        hardwarID = "0.0.0"
        return "0x00000000"

        hardwarID = "255.255.65535"
        return "0xFFFFFFFF"

        hardwarID = "171.205.61355"
        return "0xABCDEFAB"

        hardwarID ="1.2.772"
        return "0x01020304"

        hardwarID = "000001.000000000002.00000000000772"
        return "0x01020304"

        hardwarID = "1.1.1"
        return "0x01010001"

        hardwarID = "1.1.00000000"
        return "0x01010000"

        hardwarID = "0.0.1"
        return "0x00000001"
    """
    formatErrorMsg = "Invalid Hardware ID format. Expected format: \"a.b.c\" ,where a,b is 8-bit unsigned integer with range [0,255], c is 16-bit unsigned integer with range range[0,65535]" \
                     + "\nFound: \"" + hardwareIdStr + "\"." \
                     + "\nFile location: " + fileLocation
    fields = hardwareIdStr.split(".")
    if len(fields) != 3:
        raise Exception(formatErrorMsg)

    a, b, c = fields

    try:
        a = int(a, 10)
        b = int(b, 10)
        c = int(c, 10)
    except Exception:
        raise Exception(formatErrorMsg)

    rangeErrorMsg = "Value of hardware ID is not within expected range. \n" \
                    + "Expected range for \"a.b.c\" is a->[0,255], b->[0,255], c->[0,65535]. Found: " + hardwareIdStr + "\n" \
                    + "File location: " + fileLocation
    if a < 0 or a > 255 or b < 0 or b > 255 or c < 0 or c > 65535:
        raise Exception(rangeErrorMsg)

    # convert hardware ID into hex representation
    # remove prefix if there's any
    a = hex(a).replace("0x", "").replace("0X", "")
    b = hex(b).replace("0x", "").replace("0X", "")
    c = hex(c).replace("0x", "").replace("0X", "")

    # fill zeroes to get the desired fixed length since we are going to concatenate those hex strings
    a = a.zfill(2)
    b = b.zfill(2)
    c = c.zfill(4)

    hexStr = a + b + c

    return format32BitHexStr(hexStr)