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 'npcx9mfp': {'ram_address': 0x10058000, 'ram_size': 0x80000}, 57 'npcx4m3': {'ram_address': 0x10088000, 'ram_size': 0x50000}, 58 'npcx4m8': {'ram_address': 0x10060000, 'ram_size': 0x7c800}, 59} 60DEFAULT_CHIP = 'npcx7m6' 61 62# RAM related values 63RAM_ADDR = 0x00 64RAM_SIZE = 0x01 65 66class EcstArgs: 67 """creates an arguments object for the ECST, 68 the arguments are taken from the command line and/or 69 argument file 70 """ 71 error_args = None 72 73 mode = DEFAULT_MODE 74 help = False 75 verbose = DEFAULT_VERBOSE 76 super_verbose = False 77 input = None 78 output = None 79 args_file = None 80 chip_name = DEFAULT_CHIP 81 chip_ram_address = CHIPS_INFO[DEFAULT_CHIP]['ram_address'] 82 chip_ram_size = CHIPS_INFO[DEFAULT_CHIP]['ram_address'] 83 firmware_header_crc = FW_HDR_CRC_DEFAULT 84 firmware_crc = FW_CRC_DEFAULT 85 spi_flash_maximum_clock = SPI_MAX_CLOCK_DEFAULT 86 spi_flash_clock_ratio = SPI_CLOCK_RATIO_DEFAULT 87 unlimited_burst_mode = SPI_UNLIMITED_BURST_DEFAULT 88 spi_flash_read_mode = SPI_MODE_VAL_DEFAULT 89 firmware_load_address = None 90 firmware_entry_point = None 91 use_arm_reset = True 92 firmware_crc_start = FW_CRC_START_OFFSET_DEFAULT 93 firmware_crc_size = None 94 firmware_length = None 95 flash_size = FLASH_SIZE_DEFAULT 96 paste_firmware_header = PASTE_FIRMWARE_HEADER_DEFAULT 97 pointer = POINTER_OFFSET_DEFAULT 98 bh_offset = None 99 100 def __init__(self): 101 102 arguments = _create_parser("") 103 valid_arguments = arguments[0] 104 invalid_arguments = arguments[1] 105 self.error_args = invalid_arguments 106 107 _populate_args(self, valid_arguments) 108 _populate_chip_fields(self) 109 110def _populate_chip_fields(self): 111 """populate the chip related fields for the ecst""" 112 self.chip_name = self.chip_name 113 chip = str(self.chip_name).lower() 114 115 if chip not in CHIPS_INFO: 116 self.chip_name = INVALID_INPUT 117 return 118 119 self.chip_ram_address = CHIPS_INFO[chip]['ram_address'] 120 self.chip_ram_size = CHIPS_INFO[chip]['ram_size'] 121 if self.firmware_load_address is None: 122 self.firmware_load_address = self.chip_ram_address 123 124def _populate_args(self, argument_list): 125 """populate the ecst arguments according to the command line/ args file""" 126 for arg in vars(argument_list): 127 if (arg == "input") & (argument_list.input is not None): 128 self.input = argument_list.input 129 130 elif (arg == "output") & (argument_list.output is not None): 131 self.output = argument_list.output 132 133 elif (arg == "chip") & (argument_list.chip is not None): 134 self.chip_name = argument_list.chip 135 _populate_chip_fields(self) 136 137 elif (arg == "verbose") & argument_list.verbose: 138 self.verbose = REG_VERBOSE 139 140 elif (arg == "super_verbose") & argument_list.super_verbose: 141 self.verbose = SUPER_VERBOSE 142 143 elif (arg == "spi_flash_maximum_clock") & \ 144 (argument_list.spi_flash_maximum_clock is not None): 145 self.spi_flash_maximum_clock =\ 146 argument_list.spi_flash_maximum_clock 147 148 elif (arg == "spi_flash_clock_ratio") & \ 149 (argument_list.spi_flash_clock_ratio is not None): 150 if argument_list.spi_flash_clock_ratio.isdigit(): 151 self.spi_flash_clock_ratio =\ 152 int(argument_list.spi_flash_clock_ratio) 153 else: 154 self.spi_flash_clock_ratio = INVALID_INPUT 155 156 elif (arg == "firmware_header_crc") &\ 157 argument_list.firmware_header_crc: 158 self.firmware_header_crc = FW_HDR_CRC_DISABLE 159 160 elif (arg == "firmware_crc") & argument_list.firmware_crc: 161 self.firmware_crc = FW_CRC_DISABLE 162 163 elif (arg == "spi_read_mode") &\ 164 (argument_list.spi_read_mode is not None): 165 166 self.spi_flash_read_mode = argument_list.spi_read_mode 167 168 elif (arg == "flash_size") & (argument_list.flash_size is not None): 169 self.flash_size = argument_list.flash_size 170 171 elif (arg == "paste_firmware_header") & \ 172 (argument_list.paste_firmware_header is not None): 173 if _is_hex(argument_list.paste_firmware_header): 174 self.paste_firmware_header =\ 175 int(argument_list.paste_firmware_header, 16) 176 else: 177 self.paste_firmware_header = INVALID_INPUT 178 179def _create_parser(arg_list): 180 """create argument parser according to pre-defined arguments 181 182 :param arg_list: when empty, parses command line arguments, 183 else parses the given string 184 """ 185 186 parser = argparse.ArgumentParser(conflict_handler='resolve', allow_abbrev=False) 187 parser.add_argument("-i", nargs='?', dest="input") 188 parser.add_argument("-o", nargs='?', dest="output") 189 parser.add_argument("-chip", dest="chip") 190 parser.add_argument("-v", action="store_true", dest="verbose") 191 parser.add_argument("-vv", action="store_true", dest="super_verbose") 192 parser.add_argument("-nohcrc", action="store_true", 193 dest="firmware_header_crc") 194 parser.add_argument("-nofcrc", action="store_true", dest="firmware_crc") 195 parser.add_argument("-spimaxclk", nargs='?', 196 dest="spi_flash_maximum_clock") 197 parser.add_argument("-spiclkratio", nargs='?', 198 dest="spi_flash_clock_ratio") 199 parser.add_argument("-spireadmode", nargs='?', dest="spi_read_mode") 200 parser.add_argument("-flashsize", nargs='?', dest="flash_size") 201 parser.add_argument("-ph", nargs='?', dest="paste_firmware_header") 202 203 args = parser.parse_known_args(arg_list.split()) 204 205 if arg_list == "": 206 args = parser.parse_known_args() 207 208 return args 209 210def _file_to_line(arg_file): 211 """helper to convert a text file to one line string 212 used to parse the arguments in a given argfile 213 214 :param arg_file: the file to manipulate 215 """ 216 with open(arg_file, "r") as arg_file_to_read: 217 data = arg_file_to_read.read().strip() 218 arg_file_to_read.close() 219 220 return data 221 222def _is_hex(val): 223 """helper to determine whether an input is a hex 224 formatted number 225 226 :param val: input to be checked 227 """ 228 if val.startswith("0x") or val.startswith("0X"): 229 val = val[2:] 230 hex_digits = set("0123456789abcdefABCDEF") 231 for char in val: 232 if char not in hex_digits: 233 return False 234 return True 235 236def exit_with_failure(message): 237 """formatted failure message printer, prints the 238 relevant error message and exits the application. 239 240 :param message: the error message to be printed 241 """ 242 243 message = '\n' + message 244 message += '\n' 245 message += '******************************\n' 246 message += '*** FAILED ***\n' 247 message += '******************************\n' 248 print(Fore.RED + message) 249 250 sys.exit(EXIT_FAILURE_STATUS) 251 252colorama.init() 253