1#!/usr/bin/env python3 2# 3# Copyright (c) 2020 Nuvoton Technology Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6 7# This file contains general functions for ECST application 8 9import sys 10import argparse 11import colorama 12from colorama import Fore 13 14INVALID_INPUT = -1 15EXIT_FAILURE_STATUS = 1 16 17# Header common fields 18FW_HDR_CRC_DISABLE = 0x00 19FW_HDR_CRC_ENABLE = 0x02 20FW_CRC_DISABLE = 0x00 21FW_CRC_ENABLE = 0x02 22 23SPI_CLOCK_RATIO_1 = 0x00 24SPI_CLOCK_RATIO_2 = 0x08 25 26SPI_UNLIMITED_BURST_DISABLE = 0x00 27SPI_UNLIMITED_BURST_ENABLE = 0x08 28 29# Verbose related values 30NO_VERBOSE = 0 31REG_VERBOSE = 1 32SUPER_VERBOSE = 1 33 34# argument default values. 35DEFAULT_MODE = "bt" 36SPI_MAX_CLOCK_DEFAULT = "20" 37FLASH_SIZE_DEFAULT = "16" 38SPI_CLOCK_RATIO_DEFAULT = 1 39PASTE_FIRMWARE_HEADER_DEFAULT = 0x00000000 40DEFAULT_VERBOSE = NO_VERBOSE 41SPI_MODE_VAL_DEFAULT = 'normal' 42SPI_UNLIMITED_BURST_DEFAULT = SPI_UNLIMITED_BURST_DISABLE 43FW_HDR_CRC_DEFAULT = FW_HDR_CRC_ENABLE 44FW_CRC_DEFAULT = FW_CRC_ENABLE 45FW_CRC_START_OFFSET_DEFAULT = 0x0 46POINTER_OFFSET_DEFAULT = 0x0 47 48# Chips: convert from name to index. 49CHIPS_INFO = { 50 'npcx7m5': {'ram_address': 0x100a8000, 'ram_size': 0x20000}, 51 'npcx7m6': {'ram_address': 0x10090000, 'ram_size': 0x40000}, 52 'npcx7m7': {'ram_address': 0x10070000, 'ram_size': 0x60000}, 53 'npcx9m3': {'ram_address': 0x10080000, 'ram_size': 0x50000}, 54 'npcx9m6': {'ram_address': 0x10090000, 'ram_size': 0x40000}, 55 'npcx9m7': {'ram_address': 0x10070000, 'ram_size': 0x60000}, 56} 57DEFAULT_CHIP = 'npcx7m6' 58 59# RAM related values 60RAM_ADDR = 0x00 61RAM_SIZE = 0x01 62 63class EcstArgs: 64 """creates an arguments object for the ECST, 65 the arguments are taken from the command line and/or 66 argument file 67 """ 68 error_args = None 69 70 mode = DEFAULT_MODE 71 help = False 72 verbose = DEFAULT_VERBOSE 73 super_verbose = False 74 input = None 75 output = None 76 args_file = None 77 chip_name = DEFAULT_CHIP 78 chip_ram_address = CHIPS_INFO[DEFAULT_CHIP]['ram_address'] 79 chip_ram_size = CHIPS_INFO[DEFAULT_CHIP]['ram_address'] 80 firmware_header_crc = FW_HDR_CRC_DEFAULT 81 firmware_crc = FW_CRC_DEFAULT 82 spi_flash_maximum_clock = SPI_MAX_CLOCK_DEFAULT 83 spi_flash_clock_ratio = SPI_CLOCK_RATIO_DEFAULT 84 unlimited_burst_mode = SPI_UNLIMITED_BURST_DEFAULT 85 spi_flash_read_mode = SPI_MODE_VAL_DEFAULT 86 firmware_load_address = None 87 firmware_entry_point = None 88 use_arm_reset = True 89 firmware_crc_start = FW_CRC_START_OFFSET_DEFAULT 90 firmware_crc_size = None 91 firmware_length = None 92 flash_size = FLASH_SIZE_DEFAULT 93 paste_firmware_header = PASTE_FIRMWARE_HEADER_DEFAULT 94 pointer = POINTER_OFFSET_DEFAULT 95 bh_offset = None 96 97 def __init__(self): 98 99 arguments = _create_parser("") 100 valid_arguments = arguments[0] 101 invalid_arguments = arguments[1] 102 self.error_args = invalid_arguments 103 104 _populate_args(self, valid_arguments) 105 _populate_chip_fields(self) 106 107def _populate_chip_fields(self): 108 """populate the chip related fields for the ecst""" 109 self.chip_name = self.chip_name 110 chip = str(self.chip_name).lower() 111 112 if chip not in CHIPS_INFO: 113 self.chip_name = INVALID_INPUT 114 return 115 116 self.chip_ram_address = CHIPS_INFO[chip]['ram_address'] 117 self.chip_ram_size = CHIPS_INFO[chip]['ram_size'] 118 if self.firmware_load_address is None: 119 self.firmware_load_address = self.chip_ram_address 120 121def _populate_args(self, argument_list): 122 """populate the ecst arguments according to the command line/ args file""" 123 for arg in vars(argument_list): 124 if (arg == "input") & (argument_list.input is not None): 125 self.input = argument_list.input 126 127 elif (arg == "output") & (argument_list.output is not None): 128 self.output = argument_list.output 129 130 elif (arg == "chip") & (argument_list.chip is not None): 131 self.chip_name = argument_list.chip 132 _populate_chip_fields(self) 133 134 elif (arg == "verbose") & argument_list.verbose: 135 self.verbose = REG_VERBOSE 136 137 elif (arg == "super_verbose") & argument_list.super_verbose: 138 self.verbose = SUPER_VERBOSE 139 140 elif (arg == "spi_flash_maximum_clock") & \ 141 (argument_list.spi_flash_maximum_clock is not None): 142 self.spi_flash_maximum_clock =\ 143 argument_list.spi_flash_maximum_clock 144 145 elif (arg == "spi_flash_clock_ratio") & \ 146 (argument_list.spi_flash_clock_ratio is not None): 147 if argument_list.spi_flash_clock_ratio.isdigit(): 148 self.spi_flash_clock_ratio =\ 149 int(argument_list.spi_flash_clock_ratio) 150 else: 151 self.spi_flash_clock_ratio = INVALID_INPUT 152 153 elif (arg == "firmware_header_crc") &\ 154 argument_list.firmware_header_crc: 155 self.firmware_header_crc = FW_HDR_CRC_DISABLE 156 157 elif (arg == "firmware_crc") & argument_list.firmware_crc: 158 self.firmware_crc = FW_CRC_DISABLE 159 160 elif (arg == "spi_read_mode") &\ 161 (argument_list.spi_read_mode is not None): 162 163 self.spi_flash_read_mode = argument_list.spi_read_mode 164 165 elif (arg == "flash_size") & (argument_list.flash_size is not None): 166 self.flash_size = argument_list.flash_size 167 168 elif (arg == "paste_firmware_header") & \ 169 (argument_list.paste_firmware_header is not None): 170 if _is_hex(argument_list.paste_firmware_header): 171 self.paste_firmware_header =\ 172 int(argument_list.paste_firmware_header, 16) 173 else: 174 self.paste_firmware_header = INVALID_INPUT 175 176def _create_parser(arg_list): 177 """create argument parser according to pre-defined arguments 178 179 :param arg_list: when empty, parses command line arguments, 180 else parses the given string 181 """ 182 183 parser = argparse.ArgumentParser(conflict_handler='resolve', allow_abbrev=False) 184 parser.add_argument("-i", nargs='?', dest="input") 185 parser.add_argument("-o", nargs='?', dest="output") 186 parser.add_argument("-chip", dest="chip") 187 parser.add_argument("-v", action="store_true", dest="verbose") 188 parser.add_argument("-vv", action="store_true", dest="super_verbose") 189 parser.add_argument("-nohcrc", action="store_true", 190 dest="firmware_header_crc") 191 parser.add_argument("-nofcrc", action="store_true", dest="firmware_crc") 192 parser.add_argument("-spimaxclk", nargs='?', 193 dest="spi_flash_maximum_clock") 194 parser.add_argument("-spiclkratio", nargs='?', 195 dest="spi_flash_clock_ratio") 196 parser.add_argument("-spireadmode", nargs='?', dest="spi_read_mode") 197 parser.add_argument("-flashsize", nargs='?', dest="flash_size") 198 parser.add_argument("-ph", nargs='?', dest="paste_firmware_header") 199 200 args = parser.parse_known_args(arg_list.split()) 201 202 if arg_list == "": 203 args = parser.parse_known_args() 204 205 return args 206 207def _file_to_line(arg_file): 208 """helper to convert a text file to one line string 209 used to parse the arguments in a given argfile 210 211 :param arg_file: the file to manipulate 212 """ 213 with open(arg_file, "r") as arg_file_to_read: 214 data = arg_file_to_read.read().strip() 215 arg_file_to_read.close() 216 217 return data 218 219def _is_hex(val): 220 """helper to determine whether an input is a hex 221 formatted number 222 223 :param val: input to be checked 224 """ 225 if val.startswith("0x") or val.startswith("0X"): 226 val = val[2:] 227 hex_digits = set("0123456789abcdefABCDEF") 228 for char in val: 229 if char not in hex_digits: 230 return False 231 return True 232 233def exit_with_failure(message): 234 """formatted failure message printer, prints the 235 relevant error message and exits the application. 236 237 :param message: the error message to be printed 238 """ 239 240 message = '\n' + message 241 message += '\n' 242 message += '******************************\n' 243 message += '*** FAILED ***\n' 244 message += '******************************\n' 245 print(Fore.RED + message) 246 247 sys.exit(EXIT_FAILURE_STATUS) 248 249colorama.init() 250