1#!/usr/bin/env python3 2# coding=utf-8 3# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16""" 17* Description: NV binary create. 18* Create: 2021-11-30 19""" 20 21import os 22import re 23import sys 24import stat 25import json 26import hashlib 27import struct 28import shutil 29import zlib 30import binascii 31 32g_root = os.path.realpath(__file__) 33g_root = os.path.dirname(g_root) 34g_root = os.path.realpath(os.path.join(g_root, "..", "..", "..")) 35sys.path.append(os.path.join(g_root, 'build')) 36sys.path.append(os.path.join(g_root, 'build', 'script')) 37# print(g_root) 38 39from conf_parser import BuildConfParser, ParserError 40from build_utils import fn_str_to_int 41from generate_data_stream import generate_data_stream 42 43from ctypes import c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, Structure, sizeof 44 45TD_CHAR = c_char 46TD_S8 = c_byte 47TD_U8 = c_ubyte 48TD_S16 = c_short 49TD_U16 = c_ushort 50TD_S32 = c_int 51TD_U32 = c_uint 52g_u8_max = 0xFF 53g_u16_max = 0xFFFF 54class KeyHead(Structure): 55 _fields_ = [ 56 ("magic", TD_U8), # Magic number to indicate the start of the item 57 ("valid", TD_U8), # flag to indicate whether the value is valid 58 ("length", TD_U16), # Length of the key_data field in bytes 59 ("type", TD_U8), # Normal (0xFF) or permanent (0x00) or keep (0x04 ) 60 ("upgrade", TD_U8), 61 62 ("key_id", TD_U16), # The Key ID 63 ("enc_key", TD_U16), # Allows some customisation of the data AES key used, 0x0 - key_data is plaintext, Others - key_data is encrypted 64 ("version", TD_U16), # Version of the key 65 ("rnd", TD_U32) # Key header crc calculated from length 66 ] 67 68class NvPageHead(Structure): 69 _fields_ = [ 70 ("id", TD_U16), 71 ("reserved", TD_U8), 72 ("num_pages", TD_U8), 73 ("inverted_details_word", TD_U32), 74 ("last_write", TD_U32), # last_write 75 ("unused", TD_U32), # We want this header to be 4 words long - this allows us to alias anything after it 76 ] 77 78# 1.根据指定的alias,合并所有配置文件 79# 1.1 解析alias中所有type=Nv的配置。 80 81# 2.如果需要,从合并的配置文件中提取NV项ID,生成ID枚举头文件提供给源码使用(构建过程不允许修改源码,因此该头文件只有需要的时候调用脚本生成) 82# 3.预编译所有nv结构 83# 4.解析配置文件中各个nv项的数据内容,与结构结合,生成bin 84 85 86 87class BuildNv: 88 def __init__(self, alias, root=None, targets=None, backup=False, use_crc16=False): 89 self.alias = alias 90 self.root = root if root is not None else g_root 91 self.targets = targets 92 self.is_backup = backup 93 self.use_crc16 = use_crc16 94 self.tmp_path = os.path.join(self.root, json_conf["BUILD_TEMP_PATH"]) 95 self.nv_relative_path = os.path.join(self.root, json_conf["NV_RELATIVE_PATH"]) 96 self.nv_root = os.path.join(self.root, json_conf["NV_DEFAULT_CFG_DIR"]) 97 self.nv_output_dir = os.path.join(self.root, json_conf["OUT_BIN_DIR"]) 98 if not backup: 99 self.nv_output_name = json_conf["OUT_BIN_NAME"] 100 else: 101 self.nv_output_name = json_conf["OUT_BACKUP_BIN_NAME"] 102 self.nv_ver_src_dict = dict() 103 self.nv_ver_dict = dict() 104 self.nv_flash_cfg = None 105 self.nv_cores_ver_bin = dict() 106 self.nv_chip_ver_bin = dict() 107 self.nv_flash_page_index = dict() 108 109 def set_nv_output_dir(self, path): 110 self.nv_output_dir = path 111 112 def start_work(self): 113 self._merge_cfgs() 114 self._load_nv_flash_cfg() 115 self._parse_etypes() 116 self._gen_binary() 117 self._create_header() 118 119 120 def _merge_cfgs(self): 121 ''' 122 Merge config sources in self.nv_ver_src_dict. 123 This will build the self.nv_ver_dict like the following tree: 124 |--- ver1 : { 125 | "merged_cfg" : json file after merge all nv configuration with the same product type. 126 | "prod_type" : "XXXX" } 127 | 128 chip|---target1---|--- ver2 : 129 | | 130 | |--- ver3 : 131 | | 132 | |--- core : "Each target corresponds to one core." 133 |---targetN... 134 ''' 135 for target in self.alias: 136 if self._nv_ver_prepare(target) is False: 137 continue 138 # print('nv_ver_src_dict: ', self.nv_ver_src_dict) 139 140 for chip in self.nv_ver_src_dict: 141 src_chip_dict = self.nv_ver_src_dict[chip] 142 # print("src_chip_dict =",src_chip_dict) 143 self.nv_ver_dict[chip] = {} 144 chip_dict = self.nv_ver_dict[chip] 145 for target in src_chip_dict: 146 if chip_dict.get(target) is None: 147 chip_dict[target] = {'core':src_chip_dict[target]['core']} 148 nv_tmp_dir = os.path.join(self.nv_relative_path) 149 for ver_name in src_chip_dict[target]: 150 if ver_name == 'core': 151 continue 152 cfg_file_prefix = os.path.join(nv_tmp_dir, 'cfg', '%s_nv' % (target)) # 生成中间文件路径 153 # print("cfg_file_prefix = ", cfg_file_prefix) 154 chip_dict[target][ver_name] = self._merge_ver_cfg(cfg_file_prefix, src_chip_dict[target][ver_name]) 155 156 def _parse_etypes(self): 157 for chip in self.nv_ver_dict: 158 chip_dict = self.nv_ver_dict[chip] 159 for target in chip_dict: 160 # scons in chip dir or nv_config dir? etypes path depends on scons path 161 nv_tmp_dir = os.path.join(self.tmp_path, target) 162 etypes_path = os.path.join(nv_tmp_dir, "%s.etypes" % target) # 中间文件xxx.etypes路径 163 if os.path.exists(etypes_path) is not True: # 判断中间文件是否存在,如果不在说明该模块没有被编译,需要加入到编译链接中 164 etypes_path = os.path.join(self.tmp_path, "etypes", "%s.etypes" % target) 165 if os.path.exists(etypes_path) is not True: 166 msg = "[error] [%s] need add nv_config module in alias! %s" % (target, etypes_path) 167 raise ParserError(msg) 168 stream_gen = generate_data_stream() 169 stream_gen.phase_etypes(etypes_path) 170 chip_dict[target]["stream_gen"] = stream_gen 171 dtabase_txt = os.path.join(self.root, json_conf['DATABASE_TXT_FILE']) 172 shutil.copy(etypes_path, dtabase_txt) 173 174 175 def _gen_binary(self): 176 ''' 177 |--- ver1 : binary file of ver1. 178 | (version name : product_type + version name) 179 chip|---core1---|--- ver2 : 180 | | 181 | |--- ver3 : 182 |---coreN... 183 ''' 184 self._gen_binary_prepare() 185 self._gen_target_version_binary() 186 self._gen_chip_nv_binary() 187 188 def _gen_target_version_binary(self): 189 for chip in self.nv_cores_ver_bin: 190 cores = self.nv_cores_ver_bin[chip] 191 # print("cores =", cores) 192 for core in cores: 193 cores[core] = self._gen_version_binary(self.nv_ver_dict[chip], chip, core) 194 195 def _gen_version_binary(self, chip_ver_dict, chip, core): 196 ver_binary_dict = dict() 197 # print("chip_ver_dict = ", chip_ver_dict) # 字典信息包含核名字,配置文件路径 198 if chip_ver_dict is None: 199 return ver_binary_dict 200 for target in chip_ver_dict: 201 if chip_ver_dict[target].get('core') != core: # 判断字典里面的target读出来的core是否和core相同 202 print("chip_ver_dict[target].get('core') = ", chip_ver_dict[target].get('core')) 203 continue 204 stream_gen = chip_ver_dict[target].get('stream_gen') 205 for ver in chip_ver_dict[target]: 206 # print("ver =", ver) 207 if ver == 'core' or ver == 'stream_gen': 208 continue 209 stream_gen = chip_ver_dict[target].get('stream_gen') 210 cfg_file = chip_ver_dict[target][ver]["merged_cfg"] 211 # print("cfg_file =",cfg_file) 212 stream = self._gen_nv_stream(cfg_file, stream_gen, chip, core) 213 nv_ver_bin = \ 214 os.path.join(self.nv_relative_path, 'bin', '%s_nv.bin' % (core)) 215 # print("nv_ver_bin = ", nv_ver_bin) # 生成nvbin文件的路径 216 prod_type = chip_ver_dict[target][ver]["prod_type"] 217 prod_type = "all" if prod_type is None else prod_type 218 ver_binary_dict["%s_%s" % (chip, prod_type)] = self._write_binary_to_file(nv_ver_bin, stream) 219 return ver_binary_dict 220 221 def _write_binary_to_file(self, file_path, stream): 222 if os.path.exists(os.path.dirname(file_path)) is False: 223 os.makedirs(os.path.dirname(file_path)) 224 if os.path.exists(file_path) is True: 225 os.remove(file_path) 226 flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL 227 modes = stat.S_IWUSR | stat.S_IRUSR 228 with os.fdopen(os.open(file_path, flags, modes), 'wb') as fout: 229 fout.write(stream) 230 return file_path 231 232 def _gen_binary_prepare(self): 233 for chip in self.nv_ver_dict: 234 self.nv_chip_ver_bin[chip] = dict() 235 self.nv_cores_ver_bin[chip] = dict() 236 self.nv_flash_page_index[chip] = dict() 237 nv_flash_chip_cfg = self.nv_flash_cfg[chip] 238 cores = nv_flash_chip_cfg["cores"].keys() 239 chip_nv_ver = self.nv_ver_dict[chip] 240 for target in chip_nv_ver: 241 core = chip_nv_ver[target].get('core') 242 for core in cores: 243 if core not in cores: 244 msg = "[error] [%s] [%s] not a core cfg in nv_storage_cfg.json!" % (target, core) 245 raise ParserError(msg) 246 if self.nv_cores_ver_bin[chip].get(core) is None: 247 self.nv_cores_ver_bin[chip][core] = dict() 248 page_size = fn_str_to_int(nv_flash_chip_cfg["size"]["page_size"]) 249 total_size = 0 250 for core in cores: 251 core_page_nums = nv_flash_chip_cfg['cores'][core]['page_nums'] 252 total_size += core_page_nums * page_size 253 self.nv_flash_page_index[chip][core] = [(sizeof(NvPageHead) + num * page_size, (num + 1) * page_size) \ 254 for num in range(0, core_page_nums)] 255 if total_size > fn_str_to_int(nv_flash_chip_cfg["size"]['flash_size']): 256 msg = "[error] cores size: %s, over total flash size: %s!" % \ 257 (total_size, nv_flash_chip_cfg["size"]['flash_size']) 258 raise ParserError(msg) 259 260 def _gen_nv_stream(self, cfg_file, stream_gen, chip, core): 261 core_nv_bin = self._init_nv_page_head(chip, core) 262 263 cfg_data = BuildConfParser(cfg_file).get_conf_data() 264 key_id_list = [] 265 last_key_item_start_addr = 0 266 for module in cfg_data: 267 for key_item in cfg_data[module]: 268 if key_item == 'module_id': 269 continue 270 key_struct_name = cfg_data[module][key_item].get("structure_type") 271 key_value = cfg_data[module][key_item].get("value") 272 key_attr = cfg_data[module][key_item].get("attributions") 273 key_id = cfg_data[module][key_item].get("key_id") 274 key_id = fn_str_to_int(key_id) if type(key_id) is not int else key_id 275 if key_struct_name is None or key_value is None or key_attr is None or key_value == []: 276 msg = "[error] 'structure_type' 'value' 'attributions' must be configured!" 277 raise ParserError(msg) 278 279 if key_id in key_id_list: 280 msg = "[error] key id:%d repeated, please check!" % key_id 281 raise ParserError(msg) 282 key_id_list.append(key_id) 283 284 key_data, key_data_len = stream_gen.generate(key_struct_name, key_value) 285 page_index, key_item_start_addr = self._find_usable_addr(chip, core, key_data, key_data_len) 286 core_nv_bin, key_item_start_addr = \ 287 self._init_key_head(core_nv_bin, key_item_start_addr, key_data_len, key_id, key_attr) 288 289 core_nv_bin, key_item_start_addr = \ 290 self._set_key_data(core_nv_bin, key_item_start_addr, key_data, key_data_len) 291 core_nv_bin, key_item_start_addr = \ 292 self._set_key_hash(core_nv_bin, key_item_start_addr, key_data_len) 293 self._update_core_index(chip, core, page_index, key_item_start_addr) 294 last_key_item_start_addr = max(last_key_item_start_addr, key_item_start_addr) 295 core_nv_bin = self._set_unused_page(chip, core_nv_bin, last_key_item_start_addr) 296 self._reset_core_index(chip, core) 297 return core_nv_bin 298 299 def _set_unused_page(self, chip, core_nv_bin, key_item_start_addr): 300 page_size = fn_str_to_int(self.nv_flash_cfg[chip]['size']['page_size']) 301 core_nv_end_addr = (key_item_start_addr + (page_size - 1)) & ~(page_size - 1) 302 for i in range(key_item_start_addr, core_nv_end_addr): 303 core_nv_bin[i] = 0xFF 304 return core_nv_bin[0 : core_nv_end_addr] 305 306 def _gen_chip_nv_binary(self): 307 for chip in self.nv_cores_ver_bin: 308 chip_bins = self.nv_cores_ver_bin[chip] 309 ver_list = [] 310 for core in chip_bins: 311 ver_list.extend(chip_bins[core].keys()) 312 313 ver_list = set(ver_list) 314 for ver in ver_list: 315 self.nv_chip_ver_bin[chip][ver] = self._assemble_ver_bins(chip, ver) 316 317 def _assemble_ver_bins(self, chip, ver): 318 flash_bin = bytearray(fn_str_to_int(self.nv_flash_cfg[chip]['size']['flash_size'])) 319 for i in range(0, len(flash_bin)): 320 flash_bin[i] = 0xFF 321 322 start_addr = 0 323 chip_bins = self.nv_cores_ver_bin[chip] 324 cores = self.nv_cores_ver_bin[chip] 325 for core in chip_bins: 326 ver_bin = chip_bins[core].get(ver) 327 flash_bin, start_addr = self._append_file_to_stream(flash_bin, start_addr, chip, core, ver_bin) 328 chip_ver_bin_file = os.path.join(self.nv_output_dir, self.nv_output_name) 329 # 目前只考虑单核场景去除 NV bin 末尾的无用 FF 330 return self._write_binary_to_file(chip_ver_bin_file, flash_bin[0 : start_addr]) 331 332 def _append_file_to_stream(self, flash_bin, start_addr, chip, core, ver_bin): 333 core_bin_size = fn_str_to_int(self.nv_flash_cfg[chip]['size']["page_size"]) * \ 334 self.nv_flash_cfg[chip]["cores"][core]['page_nums'] 335 core_nv_bin = b'' 336 if ver_bin is None: 337 core_nv_bin = self._init_nv_page_head(chip, core) 338 else: 339 with open(ver_bin, 'rb') as f: 340 core_nv_bin = f.read() 341 #print('core_nv_bin = ', core_nv_bin) 342 tail_addr = start_addr + len(core_nv_bin) 343 flash_bin[start_addr : tail_addr] = core_nv_bin 344 345 return flash_bin, tail_addr 346 347 def _reset_core_index(self, chip, core): 348 nv_flash_chip_cfg = self.nv_flash_cfg[chip] 349 page_size = fn_str_to_int(nv_flash_chip_cfg['size']["page_size"]) 350 core_page_nums = nv_flash_chip_cfg['cores'][core]['page_nums'] 351 self.nv_flash_page_index[chip][core] = [(sizeof(NvPageHead) + num * page_size, (num + 1) * page_size) \ 352 for num in range(0, core_page_nums)] 353 354 def _update_core_index(self, chip, core, index, addr): 355 (start_addr, page_max_addr) = self.nv_flash_page_index[chip][core][index] 356 if start_addr >= addr or addr > page_max_addr: 357 msg = "[error] addr %s invalid!" % addr 358 raise ParserError(msg) 359 self.nv_flash_page_index[chip][core][index] = (addr, page_max_addr) 360 #print("update page index: \n", self.nv_flash_page_index) 361 362 def _find_usable_addr(self, chip, core, key_data, key_data_len): 363 page_size = fn_str_to_int(self.nv_flash_cfg[chip]['size'].get('page_size')) 364 key_item_total_len = self._get_key_item_len(key_data_len) 365 if key_item_total_len > page_size - sizeof(NvPageHead): 366 msg = "[error] key over page size !" % key_id 367 raise ParserError(msg) 368 369 index = 0 370 for (start_addr, page_max_addr) in self.nv_flash_page_index[chip][core]: 371 if start_addr + key_item_total_len > page_max_addr: 372 index += 1 373 continue 374 return index, start_addr 375 msg = "[error] no more enough space for [%s]!" % core 376 raise ParserError(msg) 377 378 def _get_key_type_from_attr(self, key_id, attr): 379 if (attr & 1) and (not (attr & ~1)): 380 return 0xFF 381 elif (attr & 2) and (not (attr & ~2)): 382 return 0x00 383 elif (attr & 4) and (not (attr & ~4)): 384 return 0xFF 385 else: 386 msg = "[error] attribution config err: [id-%s] [attr-%s] !" % (key_id, attr) 387 raise ParserError(msg) 388 389 def _get_key_upgrade_from_attr(self, key_id, attr): 390 if (attr & 1) and (not (attr & ~1)): 391 return 0xFF 392 elif (attr & 2) and (not (attr & ~2)): 393 return 0xFF 394 elif (attr & 4) and (not (attr & ~4)): 395 return 0x00 396 else: 397 msg = "[error] attribution config err: [id-%s] [attr-%s] !" % (key_id, attr) 398 raise ParserError(msg) 399 400 def _get_key_item_len(self, key_data_len): 401 if key_data_len % 4 != 0: 402 key_data_len += 4 - key_data_len % 4 403 return sizeof(KeyHead) + 4 + key_data_len 404 405 def _set_key_hash(self, nv_bin, key_item_start_addr, key_data_len): 406 if key_data_len % 4 != 0: 407 key_data_len += 4 - key_data_len % 4 408 hash_start_addr = key_item_start_addr - key_data_len - sizeof(KeyHead) 409 hash_end_addr = hash_start_addr + key_data_len + sizeof(KeyHead) 410 if not self.use_crc16: 411 crc32num = zlib.crc32(nv_bin[hash_start_addr : hash_end_addr]) 412 else: 413 crc32num = binascii.crc_hqx(nv_bin[hash_start_addr : hash_end_addr], 0) 414 crc32ret = '{:0>8X}'.format(crc32num) 415 crc32ret = re.sub(r"(?<=\w)(?=(?:\w\w)+$)", " 0x", crc32ret) 416 crc32ret = '0x' + crc32ret 417 crc32list = [int(x,16) for x in crc32ret.split(" ")] 418 sha256bytearray = bytes(crc32list) 419 tail_addr = key_item_start_addr + len(sha256bytearray) 420 nv_bin[key_item_start_addr : tail_addr] = sha256bytearray 421 return nv_bin, tail_addr 422 423 def _set_key_data(self, nv_bin, key_item_start_addr, key_data, key_data_len): 424 if key_data_len % 4 != 0: 425 for i in range(0, 4 - key_data_len % 4) : 426 key_data += b'\x00' 427 key_data_len += 4 - key_data_len % 4 428 tail_addr = key_item_start_addr + key_data_len 429 nv_bin[key_item_start_addr : tail_addr] = key_data 430 return nv_bin, tail_addr 431 432 def _init_key_head(self, nv_bin, key_item_start_addr, key_data_len, key_id, key_attr): 433 nv_key_st = KeyHead.from_buffer(nv_bin[key_item_start_addr:]) 434 435 nv_key_st.magic = 0xA9 436 nv_key_st.length = key_data_len 437 nv_key_st.type = self._get_key_type_from_attr(key_id, key_attr) 438 nv_key_st.upgrade = self._get_key_upgrade_from_attr(key_id, key_attr) 439 nv_key_st.key_id = key_id 440 441 nv_key_st.version = 65535 442 nv_key_st.enc_key = 0 # 目前不支持加密,且nv加密部分不由nv脚本做,可能放到初始化? 443 tail_addr = key_item_start_addr + sizeof(KeyHead) 444 nv_bin[key_item_start_addr : tail_addr] = nv_key_st 445 return nv_bin, tail_addr 446 447 def _init_nv_page_head(self, chip, core): 448 nv_flash_chip_cfg = self.nv_flash_cfg[chip] 449 default_page_nums = nv_flash_chip_cfg.get('default_page_nums') 450 page_size = fn_str_to_int(nv_flash_chip_cfg['size']['page_size']) 451 page_nums = nv_flash_chip_cfg['cores'][core]['page_nums'] 452 if not self.is_backup: 453 page_id_start = nv_flash_chip_cfg['cores'][core]['page_id_start'] 454 else: 455 page_id_start = '0x34B2' 456 core_nv_size = page_nums * page_size 457 core_nv_bin = bytearray(core_nv_size) 458 459 for i in range(0, core_nv_size): 460 core_nv_bin[i] = 0xFF 461 462 for i in range(0, page_nums): 463 start_addr = i * page_size 464 nv_page_head = NvPageHead.from_buffer(core_nv_bin[start_addr:]) 465 nv_page_head.id = fn_str_to_int(page_id_start) 466 nv_page_head.reserved = 1 467 nv_page_head.num_pages = i 468 nv_page_head.inverted_details_word = ~int.from_bytes(struct.pack('HBB', \ 469 nv_page_head.id, nv_page_head.reserved, nv_page_head.num_pages), 'little') 470 nv_page_head.last_write = 0 471 nv_page_head.unused = ~nv_page_head.last_write 472 core_nv_bin[start_addr : start_addr + sizeof(NvPageHead)] = nv_page_head 473 return core_nv_bin 474 475 def _load_nv_flash_cfg(self): 476 self.nv_flash_cfg = dict() 477 for chip in self.nv_ver_dict: 478 cfg_file = os.path.join(self.root, json_conf["NV_TARGET_JSON_PATH"]) 479 self.nv_flash_cfg[chip] = BuildConfParser(cfg_file).get_conf_data() 480 481 def _add_nv_ver(self, chip, target, core, ver, common_cfg, ver_cfg, prod_type=None): 482 ''' 483 Add version config into self.nv_ver_src_dict. 484 There are three configuration scenarios.One target may correspond to multiple NV versions. 485 486 |--- ver1: { srcs:[default, common, cfg1], prod_type: } 487 | 488 chip|---target1---|--- ver2: { srcs:[default, cfg2], prod_type: } 489 | | 490 | |--- ver3: { srcs:[default, common], prod_type: } 491 | | 492 | |--- core : "Each target corresponds to one core." 493 |---targetN... 494 ''' 495 496 ver_cfgs = [] 497 if os.path.exists(common_cfg) is True: 498 ver_cfgs.append(common_cfg) 499 if ver_cfg is not None and os.path.exists(ver_cfg): 500 ver_cfgs.append(ver_cfg) 501 502 if self.nv_ver_src_dict.get(chip) is None: 503 self.nv_ver_src_dict[chip] = dict() 504 505 chip_dict = self.nv_ver_src_dict[chip] 506 if chip_dict.get(target) is not None and chip_dict[target].get(ver) is not None: 507 msg = "[error] Ver config Repeate!" 508 raise ParserError(msg) 509 510 if chip_dict.get(target) is None: 511 chip_dict[target] = {ver:{"srcs":ver_cfgs, 'prod_type': prod_type}} 512 else: 513 chip_dict[target].update({ver:{"srcs":ver_cfgs, 'prod_type': prod_type}}) 514 515 if chip_dict[target].get('core') is None: 516 chip_dict[target]['core'] = core 517 elif chip_dict[target].get('core') != core: 518 msg = "[error] [%s] core not match!" % target 519 raise ParserError(msg) 520 521 def _nv_ver_prepare(self, target): 522 ''' 523 1. Check nv configurations. 524 2. Add all correct config into self.nv_ver_src_dict.. 525 ''' 526 if type(self.alias[target]) is list: 527 return False 528 target_type = self.alias[target].get("TYPE") 529 if target_type is None or target_type != 'nv': 530 return False 531 532 core = self.alias[target].get("CORE") 533 if core is None: 534 msg = "[error] core name not exist!" 535 raise ParserError(msg) 536 chip = self.alias[target].get("CHIP") 537 #default_cfg = os.path.join(self.nv_root, '%s_default.json' % core) 538 ''' 539 if chip is None or os.path.exists(default_cfg) is False: 540 msg = "[error] chip name OR %s not exist!" % default_cfg 541 raise ParserError(msg) 542 ''' 543 kernel_name = self.alias[target].get("KERNEL_BIN") 544 if kernel_name is None: 545 msg = "[error] KERNEL is null!" 546 raise ParserError(msg) 547 if self.targets is not None and kernel_name not in self.targets: 548 return False 549 cfgs = self.alias[target].get("COMPONENT") 550 if cfgs is None: 551 msg = "[error] COMPONENT is null!" 552 raise ParserError(msg) 553 554 prod_type = self.alias[target].get("PRODUCT_TYPE") 555 if prod_type == "": 556 prod_type = None 557 if prod_type is not None and type(prod_type) is not str: 558 msg = "[error] PRODUCT_TYPE must be a string type, one kernel only suuport one product type!" 559 raise ParserError(msg) 560 561 cfg_dir = os.path.join(self.nv_root, kernel_name) 562 common_cfg = os.path.join(cfg_dir, 'common.json') 563 564 for cfg in cfgs: 565 cfg_file = os.path.join(cfg_dir, '%s.json' % cfg) if cfg != 'common' else None 566 self._add_nv_ver(chip, kernel_name, core, cfg, common_cfg, cfg_file, prod_type) 567 568 def _prod_type_filter(self, srcs, prod_type = None): 569 combination = dict() 570 module_dict = dict() 571 for src in srcs: 572 # print("[INFO] nv config src file: ", src) 573 src_conf = BuildConfParser(src).get_conf_data() 574 for module in src_conf: 575 module_id = src_conf.get(module).get('module_id') 576 if module_id is None: 577 msg = "[error][file:%s][%s] module_id is null!" % (src, module) 578 raise ParserError(msg) 579 module_id = fn_str_to_int(module_id) if type(module_id) is not int else module_id 580 if module_id > g_u8_max : 581 msg = "[error][file:%s][%s] module_id is more than 0xFF!" % (src, module) 582 raise ParserError(msg) 583 584 # diffrent module must config with diffrent module_id 585 if module_id in module_dict: 586 if module_dict[module_id] != module: 587 msg = "[error][file:%s][%s] module_id is the same to [%s]!" % (src, module, module_dict[module_id]) 588 raise ParserError(msg) 589 else: 590 module_dict[module_id] = module 591 592 if module not in combination: 593 combination[module] = {'module_id': module_id} 594 elif combination.get(module).get('module_id') != module_id: 595 msg = "[error][%s][%s] module_id is not same as other file!" % (src, module) 596 raise ParserError(msg) 597 598 for item in src_conf.get(module): 599 key_cfg = src_conf.get(module).get(item) 600 if item == 'module_id': 601 continue 602 603 key_id = key_cfg.get('key_id') 604 key_id = None if key_id is None else (fn_str_to_int(key_id) if type(key_id) is not int else key_id) 605 # print("key id: %d, module id: %d, key>>8: %d"%( key_id, module_id, key_id>>8)) 606 if key_id is None or key_id > g_u16_max : 607 msg = "[error][file:%s][%s][%s] key_id is null or more than unsighed 16 or not match with module_id!" % (src, module, item) 608 raise ParserError(msg) 609 610 item_prod_type = key_cfg.get('product_type') 611 key_status = key_cfg.get('key_status') 612 #print('prodtype: %s, key prod: %s'%(prod_type, item_prod_type)) 613 if (prod_type == item_prod_type or (item_prod_type is not None and prod_type in item_prod_type)) \ 614 and key_status == 'alive': 615 combination[module].update({item:key_cfg}) 616 return combination 617 618 def _nv_cfg_writer(self, dst_file, combination): 619 if os.path.exists(os.path.dirname(dst_file)) is False: 620 os.makedirs(os.path.dirname(dst_file)) 621 if os.path.exists(dst_file): 622 os.remove(dst_file) 623 flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL 624 modes = stat.S_IWUSR | stat.S_IRUSR 625 with os.fdopen(os.open(dst_file, flags, modes), 'w') as fout: 626 fout.write(json.dumps(combination, indent=4)) 627 628 def _merge_ver_cfg(self, file_prefix, ver_cfg): 629 srcs = ver_cfg.get('srcs') 630 if srcs is None: 631 msg = "[error] ver cfg file is null!" 632 raise ParserError(msg) 633 634 prod_type = ver_cfg.get('prod_type') 635 combination = self._prod_type_filter(srcs, prod_type) 636 dst_file = '%s.json' % file_prefix 637 self._nv_cfg_writer(dst_file, combination) 638 return { "merged_cfg" : dst_file, "prod_type" : prod_type} 639 640 def _create_header(self): 641 pass 642 643# 检查配置文件中是否有必须配置项 644def check_key(json_conf): 645 check_item = ['OUT_BIN_DIR', 'BUILD_TEMP_PATH', 'NV_TARGET_JSON_PATH', \ 646 'NV_RELATIVE_PATH', 'NV_DEFAULT_CFG_DIR', 'DATABASE_TXT_FILE'] 647 keys = dict.keys(json_conf) 648 for check_key in check_item: 649 if check_key not in keys: 650 msg = "[error] [nv_binary] need add ConfigMap (%s) in json_conf!" % (check_key) 651 raise ParserError(msg) 652 653def test(targets, flag, backup, use_crc16): 654 root = g_root 655 nv_target_json_path = os.path.join(root, json_conf["NV_TARGET_JSON_PATH"]) 656 alias_conf = BuildConfParser(nv_target_json_path).get_conf_data() 657 worker = BuildNv(alias_conf, root, targets, backup, use_crc16) 658 if flag: 659 worker.set_nv_output_dir(os.path.join(root, json_conf["OUT_BIN_DIR"])) 660 worker.start_work() 661 662def nv_begin(in_path, targets, flag, gen_backup=False, use_crc16=False): 663 global json_conf 664 with open(in_path, 'r') as i: 665 json_conf = json.load(i) 666 667 check_key(json_conf) 668 test(targets, flag, False, use_crc16) 669 if gen_backup: 670 test(targets, flag, True, use_crc16) 671 print("build nv bin success!!") 672 673if __name__ == "__main__": 674 in_path = sys.argv[2] 675 targets = sys.argv[3].split() 676 flag = len(sys.argv) == 3 677 678 nv_begin(in_path, targets, flag) 679