Path: blob/master/Tools/scripts/build_bootloaders.py
9515 views
#!/usr/bin/env python312# flake8: noqa34"""5script to build all of our bootloaders using AP_Bootloader and put the resulting binaries in Tools/bootloaders6"""78import os9import shutil10import subprocess11import sys12import fnmatch13import re1415# get command line arguments16from argparse import ArgumentParser17parser = ArgumentParser(description='This Program is used to build ArduPilot bootloaders for boards.')18parser.add_argument("--signing-key", type=str, action='append', help="signing key for secure bootloader (can be used multiple times)")19parser.add_argument("--omit-ardupilot-keys", action='store_true', default=False, help="omit ArduPilot signing keys")20parser.add_argument("--debug", action='store_true', default=False, help="build with debug symbols")21parser.add_argument("--periph-only", action='store_true', default=False, help="only build AP_Periph boards")22parser.add_argument("pattern", type=str, default='*', help="board wildcard pattern", nargs='?')23args = parser.parse_args()2425os.environ['PYTHONUNBUFFERED'] = '1'2627failed_boards = set()2829def has_hwdef_bl(board):30"""Return True if libraries/AP_HAL_ChibiOS/hwdef/<board>/hwdef-bl.dat exists"""31hwdef = os.path.join('libraries', 'AP_HAL_ChibiOS', 'hwdef', board, 'hwdef-bl.dat')32return os.path.exists(hwdef)333435def read_hwdef(filepath):36'''read a hwdef file recursively'''37fh = open(filepath)38ret = []39text = fh.readlines()40for line in text:41m = re.match(r"^\s*include\s+(.+)\s*$", line)42if m is not None:43ret += read_hwdef(os.path.join(os.path.dirname(filepath), m.group(1)))44else:45ret += [line]46return ret4748def is_ap_periph(hwdef):49'''return True if a hwdef is for a AP_Periph board'''50lines = read_hwdef(hwdef)51for line in lines:52if line.find('AP_PERIPH') != -1:53return True54return False5556def get_board_list():57'''add boards based on existence of hwdef-bl.dat in subdirectories for ChibiOS'''58board_list = []59dirname, dirlist, filenames = next(os.walk('libraries/AP_HAL_ChibiOS/hwdef'))60for d in dirlist:61hwdef = os.path.join(dirname, d, 'hwdef-bl.dat')62if os.path.exists(hwdef):63if args.periph_only and not is_ap_periph(hwdef):64continue65board_list.append(d)66return board_list6768def validate_signing_keys(keys):69"""Validate that all signing key files exist and are not private keys"""70missing_keys = []71private_keys = []7273for key in keys:74if not os.path.isfile(key):75missing_keys.append(key)76elif os.path.basename(key).lower().find("private") != -1:77private_keys.append(key)7879if missing_keys:80print("Error: The following files were not found:")81for key in missing_keys:82print(f" {key}")83sys.exit(1)8485if private_keys:86print("Error: You must use the public key in the bootloader. Check the following files:")87for key in private_keys:88print(f" {key}")89sys.exit(1)9091if args.signing_key is not None:92validate_signing_keys(args.signing_key)9394def run_program(cmd_list):95print("Running (%s)" % " ".join(cmd_list))96retcode = subprocess.call(cmd_list)97if retcode != 0:98print("Build failed: %s" % ' '.join(cmd_list))99return False100return True101102103def build_board(board):104# do not attempt to build a bootloader for boards without hwdef-bl.dat105if not has_hwdef_bl(board):106print(f"Skipping {board}: no hwdef-bl.dat (no bootloader for this board)")107return True # treat as success, since there is nothing to build108109configure_args = "--board %s --bootloader --no-submodule-update --Werror" % board110configure_args = configure_args.split()111if args.signing_key is not None:112print("Building secure bootloader")113configure_args.append("--signed-fw")114if args.debug:115print("Building with debug symbols")116configure_args.append("--debug")117if not run_program(["./waf", "configure"] + configure_args):118return False119if not run_program(["./waf", "clean"]):120return False121if not run_program(["./waf", "bootloader"]):122return False123return True124125board_list = get_board_list()126def get_all_board_dirs():127dirname, dirlist, filenames = next(os.walk('libraries/AP_HAL_ChibiOS/hwdef'))128return dirlist129130all_board_dirs = get_all_board_dirs()131132# Determine pattern matches against *all* directories and against buildable boards133matches_all = [b for b in all_board_dirs if fnmatch.fnmatch(b, args.pattern)]134matches_buildable = [b for b in board_list if fnmatch.fnmatch(b, args.pattern)]135136# If nothing matches any directory name at all, warn once137if args.pattern != '*' and not matches_all:138print(f"Warning: no board matches pattern '{args.pattern}'. Continuing.")139140# For directories that match the pattern but *aren't* buildable (no hwdef-bl.dat),141# print the explicit skip message now so users see why their requested board didn't build.142for b in matches_all:143if b not in board_list:144print(f"Skipping {b}: no hwdef-bl.dat (no bootloader for this board)")145146additional_args = []147if args.omit_ardupilot_keys:148# If the user has requested to omit ardupilot keys, ensure it is forwarded to the make_secure_bl program149additional_args.append("--omit-ardupilot-keys")150151# check that the user-supplied board pattern matches something; if not, warn and exit152for board in board_list:153if not fnmatch.fnmatch(board, args.pattern):154continue155if not has_hwdef_bl(board):156print(f"Skipping {board}: no hwdef-bl.dat (no bootloader for this board)")157continue158print("Building for %s" % board)159if not build_board(board):160failed_boards.add(board)161continue162bl_file = 'Tools/bootloaders/%s_bl.bin' % board163hex_file = 'Tools/bootloaders/%s_bl.hex' % board164elf_file = 'Tools/bootloaders/%s_bl.elf' % board165shutil.copy('build/%s/bin/AP_Bootloader.bin' % board, bl_file)166print("Created %s" % bl_file)167shutil.copy('build/%s/bootloader/AP_Bootloader' % board, elf_file)168print("Created %s" % elf_file)169if args.signing_key is not None:170print("Signing bootloader with %s" % ", ".join(args.signing_key))171if not run_program(["./Tools/scripts/signing/make_secure_bl.py", *additional_args, bl_file] + args.signing_key):172print("Failed to sign bootloader for %s" % board)173sys.exit(1)174if not run_program(["./Tools/scripts/signing/make_secure_bl.py", *additional_args, elf_file] + args.signing_key):175print("Failed to sign ELF bootloader for %s" % board)176sys.exit(1)177if not run_program([sys.executable, "Tools/scripts/bin2hex.py", "--offset", "0x08000000", bl_file, hex_file]):178failed_boards.add(board)179continue180print("Created %s" % hex_file)181182if len(failed_boards):183print("Failed boards: %s" % list(failed_boards))184185186