import os import subprocess EON = os.path.isfile('/EON') TICI = os.path.isfile('/TICI') PC = not (EON or TICI) PREFIX = "arm-none-eabi-" BUILDER = "DEV" if os.getenv("PEDAL"): PROJECT = "pedal" STARTUP_FILE = "startup_stm32f205xx.s" MAIN = "pedal/main.c" PROJECT_FLAGS = [ "-mcpu=cortex-m3", "-msoft-float", "-DSTM32F2", "-DSTM32F205xx", "-O2", "-DPEDAL", ] if os.getenv("GATEWAY"): PROJECT = "panda" STARTUP_FILE = "startup_stm32f413xx.s" if os.getenv("IBST"): MAIN = "ibst/main.c" elif os.getenv("SDSU"): MAIN = "smart_dsu/main.c" elif os.getenv("EPS_GW"): MAIN = "eps_gw/main.c" PROJECT_FLAGS = [ "-mcpu=cortex-m4", "-mhard-float", "-DSTM32F4", "-DSTM32F413xx", "-mfpu=fpv4-sp-d16", "-fsingle-precision-constant", "-Os", "-g", "-DGATEWAY", ] else: PROJECT = "panda" STARTUP_FILE = "startup_stm32f413xx.s" MAIN = "main.c" PROJECT_FLAGS = [ "-mcpu=cortex-m4", "-mhard-float", "-DSTM32F4", "-DSTM32F413xx", "-mfpu=fpv4-sp-d16", "-fsingle-precision-constant", "-Os", "-g", ] if not PC: PROJECT_FLAGS += ["-DEON"] BUILDER = "EON" def get_version(builder, build_type): version_file = File('../VERSION').srcnode().abspath version = open(version_file).read() try: git = subprocess.check_output(["git", "rev-parse", "--short=8", "HEAD"], encoding='utf8').strip() except subprocess.CalledProcessError: git = "unknown" return f"{version}-{builder}-{git}-{build_type}" def to_c_uint32(x): nums = [] for _ in range(0x20): nums.append(x % (2**32)) x //= (2**32) return "{" + 'U,'.join(map(str, nums)) + "U}" def get_key_header(name): from Crypto.PublicKey import RSA public_fn = File(f'../certs/{name}.pub').srcnode().abspath rsa = RSA.importKey(open(public_fn).read()) assert(rsa.size_in_bits() == 1024) rr = pow(2**1024, 2, rsa.n) n0inv = 2**32 - pow(rsa.n, -1, 2**32) r = [ f"RSAPublicKey {name}_rsa_key = {{", f" .len = 0x20,", f" .n0inv = {n0inv}U,", f" .n = {to_c_uint32(rsa.n)},", f" .rr = {to_c_uint32(rr)},", f" .exponent = {rsa.e},", f"}};", ] return r def objcopy(source, target, env, for_signature): return '$OBJCOPY -O binary %s %s' % (source[0], target[0]) linkerscript_fn = File("stm32_flash.ld").srcnode().abspath flags = [ "-Wall", "-Wextra", "-Wstrict-prototypes", "-Werror", "-mlittle-endian", "-mthumb", "-nostdlib", "-fno-builtin", f"-T{linkerscript_fn}", "-std=gnu11", ] + PROJECT_FLAGS if os.getenv("RELEASE"): BUILD_TYPE = "RELEASE" cert_fn = os.getenv("CERT") assert cert_fn is not None, 'No certificate file specified. Please set CERT env variable' assert os.path.exists(cert_fn), 'Certificate file not found. Please specify absolute path' else: BUILD_TYPE = "DEBUG" cert_fn = File("../certs/debug").srcnode().abspath flags += ["-DALLOW_DEBUG"] includes = [ "inc", "..", ".", ] panda_env = Environment( ENV=os.environ, CC=PREFIX + 'gcc', AS=PREFIX + 'gcc', OBJCOPY=PREFIX + 'objcopy', OBJDUMP=PREFIX + 'objdump', ASCOM="$AS $ASFLAGS -o $TARGET -c $SOURCES", CFLAGS=flags, ASFLAGS=flags, LINKFLAGS=flags, CPPPATH=includes, BUILDERS={ 'Objcopy': Builder(generator=objcopy, suffix='.bin', src_suffix='.elf') } ) # Common autogenerated includes version = f'const uint8_t gitversion[] = "{get_version(BUILDER, BUILD_TYPE)}";' gitversion = panda_env.Textfile("obj/gitversion.h", [version, ""]) Ignore('bootstub.o', gitversion) Requires('bootstub.o', gitversion) Ignore('main.o', gitversion) Requires('main.o', gitversion) certs = [get_key_header(n) for n in ["debug", "release"]] certheader = panda_env.Textfile("obj/cert.h", certs + [""]) startup = panda_env.Object(STARTUP_FILE) # Bootstub crypto = ["../crypto/rsa.c", "../crypto/sha.c"] bootstub_elf = panda_env.Program(f"obj/bootstub.{PROJECT}.elf", [startup] + crypto + ["bootstub.c"]) bootstub_bin = panda_env.Objcopy(f"obj/bootstub.{PROJECT}.bin", bootstub_elf) # Build main main_elf = panda_env.Program(f"obj/{PROJECT}.elf", [startup, MAIN], LINKFLAGS=["-Wl,--section-start,.isr_vector=0x8004000"] + flags) main_bin = panda_env.Objcopy(f"obj/{PROJECT}.bin", main_elf) # Sign main sign_py = File("../crypto/sign.py").srcnode().abspath panda_bin_signed = panda_env.Command(f"obj/{PROJECT}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}")