├── ectf_tools ├── __init__.py ├── .flake8 ├── build_depl.py ├── utils.py ├── update.py ├── boot_tool.py ├── list_tool.py ├── attestation_tool.py ├── replace_tool.py ├── build_ap.py └── build_comp.py ├── component ├── .clang-format ├── project.mk ├── inc │ ├── simple_i2c_peripheral.h │ └── board_link.h ├── src │ ├── board_link.c │ ├── component.c │ └── simple_i2c_peripheral.c ├── firmware.ld ├── Makefile └── startup_firmware.S ├── application_processor ├── .clang-format ├── src │ ├── host_messaging.c │ ├── board_link.c │ ├── simple_flash.c │ ├── simple_crypto.c │ ├── simple_i2c_controller.c │ └── application_processor.c ├── project.mk ├── inc │ ├── host_messaging.h │ ├── board_link.h │ ├── simple_flash.h │ ├── simple_crypto.h │ └── simple_i2c_controller.h ├── firmware.ld └── Makefile ├── deployment └── Makefile ├── pyproject.toml ├── shell.nix ├── custom_nix_pkgs └── analog_openocd.nix ├── .gitignore ├── LICENSE.txt └── README.md /ectf_tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /component/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | IndentWidth: '4' 3 | UseTab: Never 4 | 5 | ... 6 | -------------------------------------------------------------------------------- /application_processor/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | IndentWidth: '4' 3 | UseTab: Never 4 | 5 | ... 6 | -------------------------------------------------------------------------------- /ectf_tools/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E203 4 | exclude = .git -------------------------------------------------------------------------------- /deployment/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # function to check required arguments 3 | check_defined = \ 4 | $(strip $(foreach 1,$1, \ 5 | $(call __check_defined,$1))) 6 | __check_defined = \ 7 | $(if $(value $1),, \ 8 | $(error Undefined $1)) 9 | 10 | all: 11 | echo "#define SECRET 1234" > global_secrets.h 12 | 13 | clean: 14 | rm -f global_secrets.h 15 | -------------------------------------------------------------------------------- /application_processor/src/host_messaging.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file host_messaging.c 3 | * @author Frederich Stine 4 | * @brief eCTF Host Messaging Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include "host_messaging.h" 15 | 16 | // Print a message through USB UART and then receive a line over USB UART 17 | void recv_input(const char *msg, char *buf) { 18 | print_debug(msg); 19 | fflush(0); 20 | print_ack(); 21 | gets(buf); 22 | puts(""); 23 | } 24 | 25 | // Prints a buffer of bytes as a hex string 26 | void print_hex(uint8_t *buf, size_t len) { 27 | for (int i = 0; i < len; i++) 28 | printf("%02x", buf[i]); 29 | printf("\n"); 30 | } 31 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | include = '\.pyi?$' 3 | exclude = ''' 4 | /( 5 | \.git 6 | | \.hg 7 | | \.mypy_cache 8 | | \.tox 9 | | \.venv 10 | | _build 11 | | buck-out 12 | | build 13 | | dist 14 | )/ 15 | ''' 16 | 17 | [tool.poetry] 18 | name = "ectf_tools" 19 | version = "1.0" 20 | description = "eCTF Tools for the 2024 eCTF" 21 | authors = ["Fritz Stine "] 22 | readme = "README.md" 23 | packages = [{include = "ectf_tools"}] 24 | 25 | [tool.poetry.dependencies] 26 | python = "^3.8" 27 | pyserial = "^3.5" 28 | argparse = "^1.4.0" 29 | loguru = "^0.7.2" 30 | gdbgui = "^0.15.2.0" 31 | tqdm = "^4.66.1" 32 | 33 | [build-system] 34 | requires = ["poetry-core"] 35 | build-backend = "poetry.core.masonry.api" 36 | 37 | [tool.poetry.scripts] 38 | ectf_build_ap = "ectf_tools.build_ap:main" 39 | ectf_build_comp = "ectf_tools.build_comp:main" 40 | ectf_build_depl = "ectf_tools.build_depl:main" 41 | ectf_attestation = "ectf_tools.attestation_tool:main" 42 | ectf_boot = "ectf_tools.boot_tool:main" 43 | ectf_list = "ectf_tools.list_tool:main" 44 | ectf_replace = "ectf_tools.replace_tool:main" 45 | ectf_update = "ectf_tools.update:main" 46 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "shell.nix" 3 | * @author Ben Janis 4 | * @brief Nix shell environment file 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | { pkgs ? import {} 15 | , fetchzip ? pkgs.fetchzip 16 | , fetchgit ? pkgs.fetchgit 17 | , fetchurl ? pkgs.fetchurl 18 | , unzip ? pkgs.unzip 19 | }: 20 | 21 | pkgs.mkShell { 22 | buildInputs = [ 23 | pkgs.gnumake 24 | pkgs.python39 25 | pkgs.gcc-arm-embedded 26 | pkgs.poetry 27 | pkgs.cacert 28 | (pkgs.callPackage custom_nix_pkgs/analog_openocd.nix { }) 29 | pkgs.minicom 30 | ]; 31 | 32 | msdk = builtins.fetchGit { 33 | url = "https://github.com/Analog-Devices-MSDK/msdk.git"; 34 | ref = "refs/tags/v2023_06"; 35 | }; 36 | shellHook = 37 | '' 38 | cp -r $msdk $PWD/msdk 39 | chmod -R u+rwX,go+rX,go-w $PWD/msdk 40 | export MAXIM_PATH=$PWD/msdk 41 | ''; 42 | } 43 | -------------------------------------------------------------------------------- /application_processor/project.mk: -------------------------------------------------------------------------------- 1 | # This file can be used to set build configuration 2 | # variables. These variables are defined in a file called 3 | # "Makefile" that is located next to this one. 4 | 5 | # For instructions on how to use this system, see 6 | # https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system 7 | 8 | #MXC_OPTIMIZE_CFLAGS = -Og 9 | # ^ For example, you can uncomment this line to 10 | # optimize the project for debugging 11 | 12 | # ********************************************************** 13 | 14 | # Add your config here! 15 | 16 | # This example is only compatible with the FTHR board, 17 | # so we override the BOARD value to hard-set it. 18 | override BOARD=FTHR_RevA 19 | MFLOAT_ABI=soft 20 | 21 | IPATH+=../deployment 22 | IPATH+=inc/ 23 | VPATH+=src/ 24 | 25 | # ****************** eCTF Bootloader ******************* 26 | # DO NOT REMOVE 27 | LINKERFILE=firmware.ld 28 | STARTUPFILE=startup_firmware.S 29 | ENTRY=firmware_startup 30 | 31 | # ****************** eCTF Crypto Example ******************* 32 | # Uncomment the commented lines below and comment the disable 33 | # lines to enable the eCTF Crypto Example. 34 | # WolfSSL must be included in this directory as wolfssl/ 35 | # WolfSSL can be downloaded from: https://www.wolfssl.com/download/ 36 | 37 | # Disable Crypto Example 38 | CRYPTO_EXAMPLE=0 39 | 40 | # Enable Crypto Example 41 | #CRYPTO_EXAMPLE=1 42 | -------------------------------------------------------------------------------- /component/project.mk: -------------------------------------------------------------------------------- 1 | # This file can be used to set build configuration 2 | # variables. These variables are defined in a file called 3 | # "Makefile" that is located next to this one. 4 | 5 | # For instructions on how to use this system, see 6 | # https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system 7 | 8 | #MXC_OPTIMIZE_CFLAGS = -Og 9 | # ^ For example, you can uncomment this line to 10 | # optimize the project for debugging 11 | 12 | # ********************************************************** 13 | 14 | # Add your config here! 15 | 16 | # This example is only compatible with the FTHR board, 17 | # so we override the BOARD value to hard-set it. 18 | override BOARD=FTHR_RevA 19 | 20 | IPATH+=../deployment 21 | IPATH+=inc/ 22 | VPATH+=src/ 23 | 24 | # ****************** eCTF Bootloader ******************* 25 | # DO NOT REMOVE 26 | LINKERFILE=firmware.ld 27 | STARTUPFILE=startup_firmware.S 28 | ENTRY=firmware_startup 29 | 30 | # ****************** eCTF Crypto Example ******************* 31 | # Uncomment the commented lines below and comment the disable 32 | # lines to enable the eCTF Crypto Example. 33 | # WolfSSL must be included in this directory as wolfssl/ 34 | # WolfSSL can be downloaded from: https://www.wolfssl.com/download/ 35 | # There is no additional functionality as in the application_processor 36 | # but this will set up compilation and linking for WolfSSL 37 | 38 | # Disable Crypto Example 39 | CRYPTO_EXAMPLE=0 40 | 41 | # Enable Crypto Example 42 | #CRYPTO_EXAMPLE=1 43 | -------------------------------------------------------------------------------- /ectf_tools/build_depl.py: -------------------------------------------------------------------------------- 1 | # @file build_depl.py 2 | # @author Frederich Stine 3 | # @brief Tool for building deployment 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | from loguru import logger 14 | import argparse 15 | import asyncio 16 | from pathlib import Path 17 | import os 18 | 19 | from ectf_tools.utils import run_shell 20 | 21 | 22 | def build_depl( 23 | design: Path 24 | ): 25 | """ 26 | Build a deployment 27 | """ 28 | 29 | logger.info("Running build") 30 | output = asyncio.run(run_shell( 31 | f"cd {design} && " 32 | f"pwd && " 33 | f"nix-shell --command " 34 | f"\"cd deployment && " 35 | f" make clean && " 36 | f" make\"" 37 | )) 38 | 39 | logger.info("Built deployment") 40 | 41 | return output 42 | 43 | 44 | def main(): 45 | parser = argparse.ArgumentParser( 46 | prog="eCTF Build Deployment Tool", 47 | description="Build a deployment using Nix" 48 | ) 49 | 50 | parser.add_argument( 51 | "-d", "--design", required=True, type=Path, 52 | help="Path to the root directory of the included design" 53 | ) 54 | 55 | args = parser.parse_args() 56 | 57 | build_depl( 58 | args.design, 59 | ) 60 | 61 | 62 | if __name__ == '__main__': 63 | main() 64 | 65 | -------------------------------------------------------------------------------- /application_processor/inc/host_messaging.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file host_messaging.h 3 | * @author Frederich Stine 4 | * @brief eCTF Host Messaging Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #ifndef __HOST_MESSAGING__ 15 | #define __HOST_MESSAGING__ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | // Macro definitions to print the specified format for error messages 22 | #define print_error(...) printf("%%error: "); printf(__VA_ARGS__); printf("%%"); fflush(stdout) 23 | #define print_hex_error(...) printf("%%error: "); print_hex(__VA_ARGS__); printf("%%"); fflush(stdout) 24 | 25 | // Macro definitions to print the specified format for success messages 26 | #define print_success(...) printf("%%success: "); printf(__VA_ARGS__); printf("%%"); fflush(stdout) 27 | #define print_hex_success(...) printf("%%success: "); print_hex(__VA_ARGS__); printf("%%"); fflush(stdout) 28 | 29 | // Macro definitions to print the specified format for debug messages 30 | #define print_debug(...) printf("%%debug: "); printf(__VA_ARGS__); printf("%%"); fflush(stdout) 31 | #define print_hex_debug(...) printf("%%debug: "); print_hex(__VA_ARGS__); printf("%%"); fflush(stdout) 32 | 33 | // Macro definitions to print the specified format for info messages 34 | #define print_info(...) printf("%%info: "); printf(__VA_ARGS__); printf("%%"); fflush(stdout) 35 | #define print_hex_info(...) printf("%%info: "); print_hex(__VA_ARGS__); printf("%%"); fflush(stdout) 36 | 37 | // Macro definitions to print the specified format for ack messages 38 | #define print_ack() printf("%%ack%%\n"); fflush(stdout) 39 | 40 | // Print a message through USB UART and then receive a line over USB UART 41 | void recv_input(const char *msg, char *buf); 42 | 43 | // Prints a buffer of bytes as a hex string 44 | void print_hex(uint8_t *buf, size_t len); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /custom_nix_pkgs/analog_openocd.nix: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "analog_openocd.nix" 3 | * @author Frederich Stine 4 | * @brief Nix build for Analog Devices fork of OpenOCD 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | { stdenv 15 | , lib 16 | , pkg-config 17 | , hidapi 18 | , jimtcl 19 | , libjaylink 20 | , libusb1 21 | , libgpiod 22 | , gcc 23 | , gnumake 24 | , coreutils 25 | , autoconf 26 | , automake 27 | , texinfo 28 | , git 29 | , libtool 30 | , which 31 | , libftdi1 32 | }: 33 | 34 | stdenv.mkDerivation { 35 | pname = "openocd-analog"; 36 | version = "0.12.0"; 37 | 38 | src = builtins.fetchGit { 39 | url = "https://github.com/analogdevicesinc/openocd.git"; 40 | ref = "release"; 41 | submodules = true; 42 | }; 43 | 44 | nativeBuiltInputs = [ pkg-config ]; 45 | 46 | buildInputs = [ 47 | hidapi 48 | gcc 49 | gnumake 50 | coreutils 51 | pkg-config 52 | autoconf 53 | automake 54 | texinfo 55 | git 56 | jimtcl 57 | libusb1 58 | libjaylink 59 | libftdi1 60 | libtool 61 | which 62 | ]; 63 | 64 | postPatch = '' 65 | substituteInPlace src/jtag/drivers/libjaylink/autogen.sh --replace "LIBTOOLIZE=glibtoolize" "LIBTOOLIZE=libtoolize" 66 | ''; 67 | 68 | enableParallelBuilding = true; 69 | 70 | hardeningDisable = [ "fortify" ]; 71 | 72 | configurePhase = '' 73 | SKIP_SUBMODULE=1 ./bootstrap 74 | ./configure --prefix=$out --disable-werror 75 | ''; 76 | 77 | meta = with lib; { 78 | description = "OpenOCD fork for Analog Devices microcontrollers"; 79 | longDescription = '' 80 | This is a fork of OpenOCD by ADI, 81 | which brings support to MAXIM MCUs microcontroller. 82 | ''; 83 | homepage = "https://github.com/analogdevicesinc/openocd.git"; 84 | license = licenses.gpl2Plus; 85 | maintainers = with maintainers; [ eCTF ]; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /component/inc/simple_i2c_peripheral.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_i2c_peripheral.h" 3 | * @author Frederich Stine 4 | * @brief Simple Asynchronous I2C Peripheral Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | 15 | #ifndef __I2C_SIMPLE_PERIPHERAL__ 16 | #define __I2C_SIMPLE_PERIPHERAL__ 17 | 18 | #include "i2c_reva_regs.h" 19 | #include "i2c_reva.h" 20 | #include "stdbool.h" 21 | #include "stdint.h" 22 | #include "mxc_errors.h" 23 | #include "board.h" 24 | #include "nvic_table.h" 25 | #include "i2c.h" 26 | 27 | /******************************** MACRO DEFINITIONS ********************************/ 28 | #define I2C_FREQ 100000 29 | #define I2C_INTERFACE MXC_I2C1 30 | #define MAX_REG TRANSMIT_LEN 31 | #define MAX_I2C_MESSAGE_LEN 256 32 | 33 | /******************************** EXTERN DEFINITIONS ********************************/ 34 | // Extern definition to make I2C_REGS and I2C_REGS_LEN 35 | // accessible outside of the implementation 36 | extern volatile uint8_t* I2C_REGS[6]; 37 | extern int I2C_REGS_LEN[6]; 38 | 39 | /******************************** TYPE DEFINITIONS ********************************/ 40 | // Enumeration with registers on the peripheral device 41 | typedef enum { 42 | RECEIVE, 43 | RECEIVE_DONE, 44 | RECEIVE_LEN, 45 | TRANSMIT, 46 | TRANSMIT_DONE, 47 | TRANSMIT_LEN, 48 | } ECTF_I2C_REGS; 49 | 50 | typedef uint8_t i2c_addr_t; 51 | 52 | /******************************** FUNCTION PROTOTYPES ********************************/ 53 | /** 54 | * @brief Initialize the I2C Connection 55 | * 56 | * @param addr: i2c_addr_t, the address of the I2C peripheral 57 | * 58 | * @return int: negative if error, zero if successful 59 | * 60 | * Initialize the I2C by enabling the module, setting the address, 61 | * setting the correct frequency, and enabling the interrupt to our i2c_simple_isr 62 | */ 63 | int i2c_simple_peripheral_init(i2c_addr_t addr); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /application_processor/inc/board_link.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "board_link.h" 3 | * @author Frederich Stine 4 | * @brief High Level API for I2C Controller Communications Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #ifndef __BOARD_LINK__ 15 | #define __BOARD_LINK__ 16 | 17 | #include "simple_i2c_controller.h" 18 | 19 | /******************************** MACRO DEFINITIONS ********************************/ 20 | // Last byte of the component ID is the I2C address 21 | #define COMPONENT_ADDR_MASK 0x000000FF 22 | #define SUCCESS_RETURN 0 23 | #define ERROR_RETURN -1 24 | 25 | /******************************** FUNCTION PROTOTYPES ********************************/ 26 | /** 27 | * @brief Initialize the board link connection 28 | * 29 | * Initiailize the underlying i2c simple interface 30 | */ 31 | void board_link_init(void); 32 | 33 | /** 34 | * @brief Convert 4-byte component ID to I2C address 35 | * 36 | * @param component_id: uint32_t, component_id to convert 37 | * 38 | * @return i2c_addr_t, i2c address 39 | */ 40 | i2c_addr_t component_id_to_i2c_addr(uint32_t component_id); 41 | 42 | /** 43 | * @brief Send an arbitrary packet over I2C 44 | * 45 | * @param address: i2c_addr_t, i2c address 46 | * @param len: uint8_t, length of the packet 47 | * @param packet: uint8_t*, pointer to packet to be sent 48 | * 49 | * @return status: SUCCESS_RETURN if success, ERROR_RETURN if error 50 | * Function sends an arbitrary packet over i2c to a specified component 51 | */ 52 | int send_packet(i2c_addr_t address, uint8_t len, uint8_t* packet); 53 | 54 | /** 55 | * @brief Poll a component and receive a packet 56 | * 57 | * @param address: i2c_addr_t, i2c address 58 | * @param packet: uint8_t*, pointer to a buffer where a packet will be received 59 | * 60 | * @return int: size of data received, ERROR_RETURN if error 61 | */ 62 | int poll_and_receive_packet(i2c_addr_t address, uint8_t* packet); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /component/inc/board_link.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "board_link.h" 3 | * @author Frederich Stine 4 | * @brief High Level API for I2C Controller Communications Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #ifndef __BOARD_LINK__ 15 | #define __BOARD_LINK__ 16 | 17 | #include "simple_i2c_peripheral.h" 18 | 19 | /******************************** MACRO DEFINITIONS ********************************/ 20 | // Last byte of the component ID is the I2C address 21 | #define COMPONENT_ADDR_MASK 0x000000FF 22 | #define SUCCESS_RETURN 0 23 | #define ERROR_RETURN -1 24 | 25 | /******************************** FUNCTION PROTOTYPES ********************************/ 26 | 27 | /** 28 | * @brief Initialize the board link interface 29 | * 30 | * @param addr: i2c_addr_t: address of this i2c device 31 | * 32 | * @return int: negative if error, zero if successful 33 | * 34 | * Initialized the underlying i2c_simple interface 35 | */ 36 | int board_link_init(i2c_addr_t addr); 37 | 38 | /** 39 | * @brief Convert 4-byte component ID to I2C address 40 | * 41 | * @param component_id: uint32_t, component_id to convert 42 | * 43 | * @return i2c_addr_t, i2c address 44 | */ 45 | i2c_addr_t component_id_to_i2c_addr(uint32_t component_id); 46 | 47 | /** 48 | * @brief Send a packet to the AP and wait for ACK 49 | * 50 | * @param message: uint8_t*, message to be sent 51 | * 52 | * This function utilizes the simple_i2c_peripheral library to 53 | * send a packet to the AP and wait for the message to be received 54 | */ 55 | void send_packet_and_ack(uint8_t len, uint8_t* packet); 56 | 57 | /** 58 | * @brief Wait for a new message from AP and process the message 59 | * 60 | * @param packet: uint8_t*, message received 61 | * 62 | * @return uint8_t: length of message received 63 | * 64 | * This function waits for a new message to be available from the AP, 65 | * once the message is available it is returned in the buffer pointer to by packet 66 | */ 67 | uint8_t wait_and_receive_packet(uint8_t* packet); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /component/src/board_link.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "board_link.c" 3 | * @author Frederich Stine 4 | * @brief High Level API for I2C Controller Communications Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include 15 | 16 | #include "board_link.h" 17 | 18 | /** 19 | * @brief Initialize the board link interface 20 | * 21 | * @param addr: i2c_addr_t: address of this i2c device 22 | * 23 | * @return int: negative if error, zero if successful 24 | * 25 | * Initialized the underlying i2c_simple interface 26 | */ 27 | int board_link_init(i2c_addr_t addr) { 28 | return i2c_simple_peripheral_init(addr); 29 | } 30 | 31 | /** 32 | * @brief Convert 4-byte component ID to I2C address 33 | * 34 | * @param component_id: uint32_t, component_id to convert 35 | * 36 | * @return i2c_addr_t, i2c address 37 | */ 38 | i2c_addr_t component_id_to_i2c_addr(uint32_t component_id) { 39 | return (uint8_t) component_id & COMPONENT_ADDR_MASK; 40 | } 41 | 42 | /** 43 | * @brief Send a packet to the AP and wait for ACK 44 | * 45 | * @param message: uint8_t*, message to be sent 46 | * 47 | * This function utilizes the simple_i2c_peripheral library to 48 | * send a packet to the AP and wait for the message to be received 49 | */ 50 | void send_packet_and_ack(uint8_t len, uint8_t* packet) { 51 | I2C_REGS[TRANSMIT_LEN][0] = len; 52 | memcpy((void*)I2C_REGS[TRANSMIT], (void*)packet, len); 53 | I2C_REGS[TRANSMIT_DONE][0] = false; 54 | 55 | // Wait for ack from AP 56 | while(!I2C_REGS[TRANSMIT_DONE][0]); 57 | I2C_REGS[RECEIVE_DONE][0] = false; 58 | } 59 | 60 | /** 61 | * @brief Wait for a new message from AP and process the message 62 | * 63 | * @param packet: uint8_t*, message received 64 | * 65 | * This function waits for a new message to be available from the AP, 66 | * once the message is available it is returned in the buffer pointer to by packet 67 | */ 68 | uint8_t wait_and_receive_packet(uint8_t* packet) { 69 | while(!I2C_REGS[RECEIVE_DONE][0]); 70 | 71 | uint8_t len = I2C_REGS[RECEIVE_LEN][0]; 72 | memcpy(packet, (void*)I2C_REGS[RECEIVE], len); 73 | 74 | return len; 75 | } 76 | -------------------------------------------------------------------------------- /application_processor/inc/simple_flash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_flash.h" 3 | * @author Frederich Stine 4 | * @brief Simple Flash Interface Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #ifndef __SIMPLE_FLASH__ 15 | #define __SIMPLE_FLASH__ 16 | 17 | #include 18 | 19 | /** 20 | * @brief Initialize the Simple Flash Interface 21 | * 22 | * This function registers the interrupt for the flash system, 23 | * enables the interrupt, and disables ICC 24 | */ 25 | void flash_simple_init(void); 26 | /** 27 | * @brief Flash Simple Erase Page 28 | * 29 | * @param address: uint32_t, address of flash page to erase 30 | * 31 | * @return int: return negative if failure, zero if success 32 | * 33 | * This function erases a page of flash such that it can be updated. 34 | * Flash memory can only be erased in a large block size called a page. 35 | * Once erased, memory can only be written one way e.g. 1->0. 36 | * In order to be re-written the entire page must be erased. 37 | */ 38 | int flash_simple_erase_page(uint32_t address); 39 | /** 40 | * @brief Flash Simple Read 41 | * 42 | * @param address: uint32_t, address of flash page to read 43 | * @param buffer: uint32_t*, pointer to buffer for data to be read into 44 | * @param size: uint32_t, number of bytes to read from flash 45 | * 46 | * This function reads data from the specified flash page into the buffer 47 | * with the specified amount of bytes 48 | */ 49 | void flash_simple_read(uint32_t address, uint32_t* buffer, uint32_t size); 50 | /** 51 | * @brief Flash Simple Write 52 | * 53 | * @param address: uint32_t, address of flash page to write 54 | * @param buffer: uint32_t*, pointer to buffer to write data from 55 | * @param size: uint32_t, number of bytes to write from flash 56 | * 57 | * @return int: return negative if failure, zero if success 58 | * 59 | * This function writes data to the specified flash page from the buffer passed 60 | * with the specified amount of bytes. Flash memory can only be written in one 61 | * way e.g. 1->0. To rewrite previously written memory see the 62 | * flash_simple_erase_page documentation. 63 | */ 64 | int flash_simple_write(uint32_t address, uint32_t* buffer, uint32_t size); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /ectf_tools/utils.py: -------------------------------------------------------------------------------- 1 | # @file utils.py 2 | # @author Frederich Stine 3 | # @brief Helper functions 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | import asyncio 14 | import subprocess 15 | from loguru import logger 16 | from typing import Tuple, Callable, Awaitable 17 | import shlex 18 | from time import sleep 19 | import os 20 | from pathlib import Path 21 | 22 | HandlerRet = Tuple[bytes, bytes] 23 | HandlerTy = Callable[..., Awaitable[Tuple[bytes, bytes]]] 24 | 25 | class CmdFailedError(Exception): 26 | pass 27 | 28 | """ 29 | Run shell command 30 | """ 31 | async def run_shell(cmd: str) -> HandlerRet: 32 | logger.debug(f"Running command {repr(cmd)}") 33 | proc = await asyncio.create_subprocess_shell( 34 | cmd, 35 | stdout=asyncio.subprocess.PIPE, 36 | stderr=asyncio.subprocess.PIPE, 37 | ) 38 | 39 | stdout_raw, stderr_raw = await proc.communicate() 40 | stdout = stdout_raw.decode(errors="backslashreplace") 41 | stderr = stderr_raw.decode(errors="backslashreplace") 42 | stdout_msg = f"STDOUT:\n{stdout}" if stdout else "NO STDOUT" 43 | stderr_msg = f"STDERR:\n{stderr}" if stderr else "NO STDERR" 44 | #if proc.returncode: 45 | # logger.error(stdout_msg) 46 | # logger.error(stderr_msg) 47 | # raise CmdFailedError( 48 | # f"Tool build failed with return code {proc.returncode}", stdout, stderr 49 | # ) 50 | logger.info(stdout_msg) 51 | logger.info(stderr_msg) 52 | return stdout_raw, stderr_raw 53 | 54 | 55 | PAGE_SIZE = 8192 56 | 57 | APP_PAGES = 28 58 | TOTAL_SIZE = APP_PAGES * PAGE_SIZE 59 | 60 | """ 61 | Package a device image for use with the bootstrapper 62 | """ 63 | def package_binary(bin_path, image_path): 64 | 65 | # Read input binaries 66 | with open(bin_path, "rb") as fp: 67 | bl_data = fp.read() 68 | 69 | # Pad bootloader to max size 70 | image_bl_pad_len = TOTAL_SIZE - len(bl_data) 71 | image_bl_padding = b"\xff" * image_bl_pad_len 72 | image_bl_data = bl_data + image_bl_padding 73 | 74 | # Write output binary 75 | with open(image_path, "wb") as fp: 76 | fp.write(image_bl_data) 77 | 78 | 79 | 80 | def i2c_address_is_blacklisted(addr): 81 | addr &= 0xFF 82 | if 0 <= addr <= 7: 83 | return True 84 | elif 0x78 <= addr <= 0x7F: 85 | return True 86 | elif addr in (0x18, 0x28, 0x36): 87 | return True 88 | else: 89 | return False -------------------------------------------------------------------------------- /application_processor/inc/simple_crypto.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_crypto.h" 3 | * @author Ben Janis 4 | * @brief Simplified Crypto API Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #if CRYPTO_EXAMPLE 15 | #ifndef ECTF_CRYPTO_H 16 | #define ECTF_CRYPTO_H 17 | 18 | #include "wolfssl/wolfcrypt/aes.h" 19 | #include "wolfssl/wolfcrypt/hash.h" 20 | 21 | /******************************** MACRO DEFINITIONS ********************************/ 22 | #define BLOCK_SIZE AES_BLOCK_SIZE 23 | #define KEY_SIZE 16 24 | #define HASH_SIZE MD5_DIGEST_SIZE 25 | 26 | /******************************** FUNCTION PROTOTYPES ********************************/ 27 | /** @brief Encrypts plaintext using a symmetric cipher 28 | * 29 | * @param plaintext A pointer to a buffer of length len containing the 30 | * plaintext to encrypt 31 | * @param len The length of the plaintext to encrypt. Must be a multiple of 32 | * BLOCK_SIZE (16 bytes) 33 | * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing 34 | * the key to use for encryption 35 | * @param ciphertext A pointer to a buffer of length len where the resulting 36 | * ciphertext will be written to 37 | * 38 | * @return 0 on success, -1 on bad length, other non-zero for other error 39 | */ 40 | int encrypt_sym(uint8_t *plaintext, size_t len, uint8_t *key, uint8_t *ciphertext); 41 | 42 | /** @brief Decrypts ciphertext using a symmetric cipher 43 | * 44 | * @param ciphertext A pointer to a buffer of length len containing the 45 | * ciphertext to decrypt 46 | * @param len The length of the ciphertext to decrypt. Must be a multiple of 47 | * BLOCK_SIZE (16 bytes) 48 | * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing 49 | * the key to use for decryption 50 | * @param plaintext A pointer to a buffer of length len where the resulting 51 | * plaintext will be written to 52 | * 53 | * @return 0 on success, -1 on bad length, other non-zero for other error 54 | */ 55 | int decrypt_sym(uint8_t *ciphertext, size_t len, uint8_t *key, uint8_t *plaintext); 56 | 57 | /** @brief Hashes arbitrary-length data 58 | * 59 | * @param data A pointer to a buffer of length len containing the data 60 | * to be hashed 61 | * @param len The length of the plaintext to encrypt 62 | * @param hash_out A pointer to a buffer of length HASH_SIZE (16 bytes) where the resulting 63 | * hash output will be written to 64 | * 65 | * @return 0 on success, non-zero for other error 66 | */ 67 | int hash(void *data, size_t len, uint8_t *hash_out); 68 | 69 | #endif // CRYPTO_EXAMPLE 70 | #endif // ECTF_CRYPTO_H 71 | -------------------------------------------------------------------------------- /ectf_tools/update.py: -------------------------------------------------------------------------------- 1 | # @file update.py 2 | # @author Jacob Doll 3 | # @brief Tool for installing a new binary onto the eCTF bootloader 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | import argparse 14 | import serial 15 | from pathlib import Path 16 | from tqdm import tqdm 17 | 18 | PAGE_SIZE = 8192 19 | APP_PAGES = 28 20 | TOTAL_SIZE = APP_PAGES * PAGE_SIZE 21 | 22 | success_codes = [1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 16, 18, 19, 20] 23 | error_codes = [6, 9, 12, 14, 15, 17] 24 | 25 | UPDATE_COMMAND = b"\x00" 26 | 27 | 28 | # Wait for expected bootloader repsonse byte 29 | # Exit if response does not match 30 | def verify_resp(ser, print_out=True): 31 | resp = ser.read(1) 32 | while (resp == b"") or (not ord(resp) in (success_codes + error_codes)): 33 | resp = ser.read(1) 34 | if ord(resp) not in success_codes: 35 | print(f"Error. Bootloader responded with: {ord(resp)}") 36 | exit() 37 | if print_out: 38 | print(f"Success. Bootloader responded with code {ord(resp)}") 39 | 40 | return ord(resp) 41 | 42 | 43 | def image_update(in_file, port): 44 | # Open serial port 45 | ser = serial.Serial( 46 | port=port, 47 | baudrate=115200, 48 | parity=serial.PARITY_NONE, 49 | stopbits=serial.STOPBITS_ONE, 50 | bytesize=serial.EIGHTBITS, 51 | timeout=2, 52 | ) 53 | ser.reset_input_buffer() 54 | 55 | print(f"Connected to bootloader on {port}") 56 | 57 | # Open protected image 58 | img_file = Path(in_file) 59 | if not img_file.exists(): 60 | print(f"Image file {img_file} not found. Exiting") 61 | exit() 62 | 63 | with open(img_file, "rb") as image_fp: 64 | # Send update command 65 | print("Requesting update") 66 | ser.write(b"\x00") 67 | 68 | verify_resp(ser) 69 | verify_resp(ser) 70 | 71 | # Send image and verify each block 72 | print("Update started") 73 | print("Sending image data") 74 | 75 | t = tqdm(total=(TOTAL_SIZE)) 76 | 77 | block_bytes = image_fp.read(16) 78 | while block_bytes != b"": 79 | t.update(16) 80 | 81 | ser.write(block_bytes) 82 | verify_resp(ser, print_out=False) 83 | block_bytes = image_fp.read(16) 84 | 85 | t.close() 86 | 87 | print("Listening for installation status...\n") 88 | 89 | # Wait for update finish 90 | resp = -1 91 | while resp != success_codes[-1]: 92 | resp = verify_resp(ser) 93 | 94 | print("\nUpdate Complete!\n") 95 | 96 | ser.close() 97 | 98 | 99 | def main(): 100 | parser = argparse.ArgumentParser() 101 | parser.add_argument( 102 | "--infile", required=True, type=Path, help="Path to the input binary" 103 | ) 104 | parser.add_argument("--port", required=True, help="Serial port") 105 | 106 | args = parser.parse_args() 107 | image_update(args.infile, args.port) 108 | 109 | 110 | if __name__ == "__main__": 111 | main() 112 | -------------------------------------------------------------------------------- /application_processor/src/board_link.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "board_link.c" 3 | * @author Frederich Stine 4 | * @brief High Level API for I2C Controller Communications Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2SUCCESS_RETURN23 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2SUCCESS_RETURN23 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include 15 | 16 | #include "board_link.h" 17 | #include "mxc_delay.h" 18 | 19 | /******************************** FUNCTION DEFINITIONS ********************************/ 20 | /** 21 | * @brief Initialize the board link connection 22 | * 23 | * Initiailize the underlying i2c simple interface 24 | */ 25 | void board_link_init(void) { 26 | i2c_simple_controller_init(); 27 | } 28 | 29 | /** 30 | * @brief Convert 4-byte component ID to I2C address 31 | * 32 | * @param component_id: uint32_t, component_id to convert 33 | * 34 | * @return i2c_addr_t, i2c address 35 | */ 36 | i2c_addr_t component_id_to_i2c_addr(uint32_t component_id) { 37 | return (uint8_t) component_id & COMPONENT_ADDR_MASK; 38 | } 39 | 40 | /** 41 | * @brief Send an arbitrary packet over I2C 42 | * 43 | * @param address: i2c_addr_t, i2c address 44 | * @param len: uint8_t, length of the packet 45 | * @param packet: uint8_t*, pointer to packet to be sent 46 | * 47 | * @return status: SUCCESS_RETURN if success, ERROR_RETURN if error 48 | * 49 | * Function sends an arbitrary packet over i2c to a specified component 50 | */ 51 | int send_packet(i2c_addr_t address, uint8_t len, uint8_t* packet) { 52 | 53 | int result; 54 | result = i2c_simple_write_receive_len(address, len); 55 | if (result < SUCCESS_RETURN) { 56 | return ERROR_RETURN; 57 | } 58 | result = i2c_simple_write_data_generic(address, RECEIVE, len, packet); 59 | if (result < SUCCESS_RETURN) { 60 | return ERROR_RETURN; 61 | } 62 | result = i2c_simple_write_receive_done(address, true); 63 | if (result < SUCCESS_RETURN) { 64 | return ERROR_RETURN; 65 | } 66 | 67 | return SUCCESS_RETURN; 68 | } 69 | 70 | /** 71 | * @brief Poll a component and receive a packet 72 | * 73 | * @param address: i2c_addr_t, i2c address 74 | * @param packet: uint8_t*, pointer to a buffer where a packet will be received 75 | * 76 | * @return int: size of data received, ERROR_RETURN if error 77 | */ 78 | int poll_and_receive_packet(i2c_addr_t address, uint8_t* packet) { 79 | 80 | int result = SUCCESS_RETURN; 81 | while (true) { 82 | result = i2c_simple_read_transmit_done(address); 83 | if (result < SUCCESS_RETURN) { 84 | return ERROR_RETURN; 85 | } 86 | else if (result == SUCCESS_RETURN) { 87 | break; 88 | } 89 | MXC_Delay(50); 90 | } 91 | 92 | int len = i2c_simple_read_transmit_len(address); 93 | if (len < SUCCESS_RETURN) { 94 | return ERROR_RETURN; 95 | } 96 | result = i2c_simple_read_data_generic(address, TRANSMIT, (uint8_t)len, packet); 97 | if (result < SUCCESS_RETURN) { 98 | return ERROR_RETURN; 99 | } 100 | result = i2c_simple_write_transmit_done(address, true); 101 | if (result < SUCCESS_RETURN) { 102 | return ERROR_RETURN; 103 | } 104 | 105 | return len; 106 | } 107 | -------------------------------------------------------------------------------- /application_processor/src/simple_flash.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_flash.c" 3 | * @author Frederich Stine 4 | * @brief Simple Flash Interface Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include "simple_flash.h" 15 | 16 | #include 17 | 18 | #include "flc.h" 19 | #include "icc.h" 20 | #include "nvic_table.h" 21 | 22 | #include 23 | 24 | /** 25 | * @brief ISR for the Flash Controller 26 | * 27 | * This ISR allows for access to the flash through simple_flash to operate 28 | */ 29 | void flash_simple_irq(void) { 30 | uint32_t temp; 31 | temp = MXC_FLC0->intr; 32 | 33 | if (temp & MXC_F_FLC_INTR_DONE) { 34 | MXC_FLC0->intr &= ~MXC_F_FLC_INTR_DONE; 35 | } 36 | 37 | if (temp & MXC_F_FLC_INTR_AF) { 38 | MXC_FLC0->intr &= ~MXC_F_FLC_INTR_AF; 39 | printf(" -> Interrupt! (Flash access failure)\n\n"); 40 | } 41 | } 42 | 43 | /** 44 | * @brief Initialize the Simple Flash Interface 45 | * 46 | * This function registers the interrupt for the flash system, 47 | * enables the interrupt, and disables ICC 48 | */ 49 | void flash_simple_init(void) { 50 | // Setup Flash 51 | MXC_NVIC_SetVector(FLC0_IRQn, flash_simple_irq); 52 | NVIC_EnableIRQ(FLC0_IRQn); 53 | MXC_FLC_EnableInt(MXC_F_FLC_INTR_DONEIE | MXC_F_FLC_INTR_AFIE); 54 | MXC_ICC_Disable(MXC_ICC0); 55 | } 56 | 57 | /** 58 | * @brief Flash Simple Erase Page 59 | * 60 | * @param address: uint32_t, address of flash page to erase 61 | * 62 | * @return int: return negative if failure, zero if success 63 | * 64 | * This function erases a page of flash such that it can be updated. 65 | * Flash memory can only be erased in a large block size called a page. 66 | * Once erased, memory can only be written one way e.g. 1->0. 67 | * In order to be re-written the entire page must be erased. 68 | */ 69 | int flash_simple_erase_page(uint32_t address) { 70 | return MXC_FLC_PageErase(address); 71 | } 72 | 73 | /** 74 | * @brief Flash Simple Read 75 | * 76 | * @param address: uint32_t, address of flash page to read 77 | * @param buffer: uint32_t*, pointer to buffer for data to be read into 78 | * @param size: uint32_t, number of bytes to read from flash 79 | * 80 | * This function reads data from the specified flash page into the buffer 81 | * with the specified amount of bytes 82 | */ 83 | void flash_simple_read(uint32_t address, uint32_t* buffer, uint32_t size) { 84 | MXC_FLC_Read(address, buffer, size); 85 | } 86 | 87 | /** 88 | * @brief Flash Simple Write 89 | * 90 | * @param address: uint32_t, address of flash page to write 91 | * @param buffer: uint32_t*, pointer to buffer to write data from 92 | * @param size: uint32_t, number of bytes to write from flash 93 | * 94 | * @return int: return negative if failure, zero if success 95 | * 96 | * This function writes data to the specified flash page from the buffer passed 97 | * with the specified amount of bytes. Flash memory can only be written in one 98 | * way e.g. 1->0. To rewrite previously written memory see the 99 | * flash_simple_erase_page documentation. 100 | */ 101 | int flash_simple_write(uint32_t address, uint32_t* buffer, uint32_t size) { 102 | return MXC_FLC_Write(address, size, buffer); 103 | } 104 | -------------------------------------------------------------------------------- /ectf_tools/boot_tool.py: -------------------------------------------------------------------------------- 1 | # @file boot_tool.py 2 | # @author Frederich Stine 3 | # @brief Host tool for booting system 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | import argparse 14 | import serial 15 | import re 16 | from loguru import logger 17 | import sys 18 | 19 | # Logger formatting 20 | fmt = ( 21 | "{time:YYYY-MM-DD HH:mm:ss.SSS} | " 22 | "{extra[extra]: <6} | " 23 | "{level: <8} | " 24 | "{message} " 25 | ) 26 | 27 | logger.remove(0) 28 | logger.add(sys.stdout, format=fmt) 29 | 30 | 31 | # Boot function 32 | def boot(args): 33 | ser = serial.Serial( 34 | port=args.application_processor, 35 | baudrate=115200, 36 | parity=serial.PARITY_NONE, 37 | stopbits=serial.STOPBITS_ONE, 38 | bytesize=serial.EIGHTBITS, 39 | ) 40 | 41 | # Send command 42 | ser.write(b"boot\r") 43 | logger.bind(extra="INPUT").debug("boot\r") 44 | output = "" 45 | # Receive messages until done 46 | while True: 47 | byte = ser.read() 48 | char = byte.decode("utf-8") 49 | output += char 50 | output = process_output(output) 51 | 52 | 53 | def process_output(output): 54 | # Find INFO level messages 55 | match = re.search("%info: ((.|\n|\r)*?)%", output) 56 | if match != None: 57 | # Output all of the data and remove from buffer 58 | output = output[:match.start()] + output[match.end():] 59 | for line in match.group(1).strip().split('\n'): 60 | logger.bind(extra="OUTPUT").info(line.strip()) 61 | # Find DEBUG level messages 62 | match = re.search("%debug: ((.|\n|\r)*?)%", output) 63 | if match != None: 64 | # Output all of the data and remove from buffer 65 | output = output[:match.start()] + output[match.end():] 66 | for line in match.group(1).strip().split('\n'): 67 | logger.bind(extra="OUTPUT").debug(line.strip()) 68 | # Find ACK level messages 69 | match = re.search("%ack%", output) 70 | if match != None: 71 | # Ignore 72 | output = output[:match.start()] + output[match.end():] 73 | # Find SUCCESS level messages 74 | match = re.search("%success: ((.|\n|\r)*?)%", output) 75 | if match != None: 76 | # Output all of the data and remove from buffer 77 | output = output[:match.start()] + output[match.end():] 78 | for line in match.group(1).strip().split('\n'): 79 | logger.bind(extra="OUTPUT").success(line.strip()) 80 | exit(0) 81 | # Find ERROR level messages 82 | match = re.search("%error: ((.|\n|\r)*?)%", output) 83 | if match != None: 84 | # Output all of the data and remove from buffer 85 | output = output[:match.start()] + output[match.end():] 86 | for line in match.group(1).strip().split('\n'): 87 | logger.bind(extra="OUTPUT").error(line.strip()) 88 | exit(1) 89 | # Return the spliced output 90 | return output 91 | 92 | 93 | # Main function 94 | def main(): 95 | parser = argparse.ArgumentParser( 96 | prog="eCTF Boot Host Tool", description="Boot the medical device" 97 | ) 98 | 99 | parser.add_argument( 100 | "-a", "--application-processor", required=True, help="Serial device of the AP" 101 | ) 102 | 103 | args = parser.parse_args() 104 | 105 | boot(args) 106 | 107 | 108 | if __name__ == "__main__": 109 | main() 110 | 111 | -------------------------------------------------------------------------------- /ectf_tools/list_tool.py: -------------------------------------------------------------------------------- 1 | # @file list_tool.py 2 | # @author Frederich Stine 3 | # @brief host tool for listing installed components 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | import argparse 14 | import serial 15 | import re 16 | from loguru import logger 17 | import sys 18 | 19 | # Logger formatting 20 | fmt = ( 21 | "{time:YYYY-MM-DD HH:mm:ss.SSS} | " 22 | "{extra[extra]: <6} | " 23 | "{level: <8} | " 24 | "{message} " 25 | ) 26 | 27 | logger.remove(0) 28 | logger.add(sys.stdout, format=fmt) 29 | 30 | 31 | # List function 32 | def list(args): 33 | ser = serial.Serial( 34 | port=args.application_processor, 35 | baudrate=115200, 36 | parity=serial.PARITY_NONE, 37 | stopbits=serial.STOPBITS_ONE, 38 | bytesize=serial.EIGHTBITS, 39 | ) 40 | 41 | # Send command 42 | ser.write(b"list\r") 43 | logger.bind(extra="INPUT").debug("list\r") 44 | output = "" 45 | # Receive messages until done 46 | while True: 47 | byte = ser.read() 48 | char = byte.decode("utf-8") 49 | output += char 50 | output = process_output(output) 51 | 52 | 53 | def process_output(output): 54 | # Find INFO level messages 55 | match = re.search("%info: ((.|\n|\r)*?)%", output) 56 | if match != None: 57 | # Output all of the data and remove from buffer 58 | output = output[:match.start()] + output[match.end():] 59 | for line in match.group(1).strip().split('\n'): 60 | logger.bind(extra="OUTPUT").info(line.strip()) 61 | # Find DEBUG level messages 62 | match = re.search("%debug: ((.|\n|\r)*?)%", output) 63 | if match != None: 64 | # Output all of the data and remove from buffer 65 | output = output[:match.start()] + output[match.end():] 66 | for line in match.group(1).strip().split('\n'): 67 | logger.bind(extra="OUTPUT").debug(line.strip()) 68 | # Find ACK level messages 69 | match = re.search("%ack%", output) 70 | if match != None: 71 | # Ignore 72 | output = output[:match.start()] + output[match.end():] 73 | # Find SUCCESS level messages 74 | match = re.search("%success: ((.|\n|\r)*?)%", output) 75 | if match != None: 76 | # Output all of the data and remove from buffer 77 | output = output[:match.start()] + output[match.end():] 78 | for line in match.group(1).strip().split('\n'): 79 | logger.bind(extra="OUTPUT").success(line.strip()) 80 | exit(0) 81 | # Find ERROR level messages 82 | match = re.search("%error: ((.|\n|\r)*?)%", output) 83 | if match != None: 84 | # Output all of the data and remove from buffer 85 | output = output[:match.start()] + output[match.end():] 86 | for line in match.group(1).strip().split('\n'): 87 | logger.bind(extra="OUTPUT").error(line.strip()) 88 | exit(1) 89 | # Return the spliced output 90 | return output 91 | 92 | 93 | # Main function 94 | def main(): 95 | parser = argparse.ArgumentParser( 96 | prog="eCTF List Host Tool", 97 | description="List the components connected to the medical device", 98 | ) 99 | 100 | parser.add_argument( 101 | "-a", "--application-processor", required=True, help="Serial device of the AP" 102 | ) 103 | 104 | args = parser.parse_args() 105 | 106 | list(args) 107 | 108 | 109 | if __name__ == "__main__": 110 | main() 111 | 112 | -------------------------------------------------------------------------------- /application_processor/src/simple_crypto.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_crypto.c" 3 | * @author Ben Janis 4 | * @brief Simplified Crypto API Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #if CRYPTO_EXAMPLE 15 | 16 | #include "simple_crypto.h" 17 | #include 18 | #include 19 | 20 | /******************************** FUNCTION PROTOTYPES ********************************/ 21 | /** @brief Encrypts plaintext using a symmetric cipher 22 | * 23 | * @param plaintext A pointer to a buffer of length len containing the 24 | * plaintext to encrypt 25 | * @param len The length of the plaintext to encrypt. Must be a multiple of 26 | * BLOCK_SIZE (16 bytes) 27 | * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing 28 | * the key to use for encryption 29 | * @param ciphertext A pointer to a buffer of length len where the resulting 30 | * ciphertext will be written to 31 | * 32 | * @return 0 on success, -1 on bad length, other non-zero for other error 33 | */ 34 | int encrypt_sym(uint8_t *plaintext, size_t len, uint8_t *key, uint8_t *ciphertext) { 35 | Aes ctx; // Context for encryption 36 | int result; // Library result 37 | 38 | // Ensure valid length 39 | if (len <= 0 || len % BLOCK_SIZE) 40 | return -1; 41 | 42 | // Set the key for encryption 43 | result = wc_AesSetKey(&ctx, key, 16, NULL, AES_ENCRYPTION); 44 | if (result != 0) 45 | return result; // Report error 46 | 47 | 48 | // Encrypt each block 49 | for (int i = 0; i < len - 1; i += BLOCK_SIZE) { 50 | result = wc_AesEncryptDirect(&ctx, ciphertext + i, plaintext + i); 51 | if (result != 0) 52 | return result; // Report error 53 | } 54 | return 0; 55 | } 56 | 57 | /** @brief Decrypts ciphertext using a symmetric cipher 58 | * 59 | * @param ciphertext A pointer to a buffer of length len containing the 60 | * ciphertext to decrypt 61 | * @param len The length of the ciphertext to decrypt. Must be a multiple of 62 | * BLOCK_SIZE (16 bytes) 63 | * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing 64 | * the key to use for decryption 65 | * @param plaintext A pointer to a buffer of length len where the resulting 66 | * plaintext will be written to 67 | * 68 | * @return 0 on success, -1 on bad length, other non-zero for other error 69 | */ 70 | int decrypt_sym(uint8_t *ciphertext, size_t len, uint8_t *key, uint8_t *plaintext) { 71 | Aes ctx; // Context for decryption 72 | int result; // Library result 73 | 74 | // Ensure valid length 75 | if (len <= 0 || len % BLOCK_SIZE) 76 | return -1; 77 | 78 | // Set the key for decryption 79 | result = wc_AesSetKey(&ctx, key, 16, NULL, AES_DECRYPTION); 80 | if (result != 0) 81 | return result; // Report error 82 | 83 | // Decrypt each block 84 | for (int i = 0; i < len - 1; i += BLOCK_SIZE) { 85 | result = wc_AesDecryptDirect(&ctx, plaintext + i, ciphertext + i); 86 | if (result != 0) 87 | return result; // Report error 88 | } 89 | return 0; 90 | } 91 | 92 | /** @brief Hashes arbitrary-length data 93 | * 94 | * @param data A pointer to a buffer of length len containing the data 95 | * to be hashed 96 | * @param len The length of the plaintext to encrypt 97 | * @param hash_out A pointer to a buffer of length HASH_SIZE (16 bytes) where the resulting 98 | * hash output will be written to 99 | * 100 | * @return 0 on success, non-zero for other error 101 | */ 102 | int hash(void *data, size_t len, uint8_t *hash_out) { 103 | // Pass values to hash 104 | return wc_Md5Hash((uint8_t *)data, len, hash_out); 105 | } 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /ectf_tools/attestation_tool.py: -------------------------------------------------------------------------------- 1 | # @file attestation_tool.py 2 | # @author Frederich Stine 3 | # @brief Host tool for returning the attestation data from an installed component 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | import argparse 14 | import serial 15 | import time 16 | import re 17 | from loguru import logger 18 | import sys 19 | 20 | # Logger formatting 21 | fmt = ( 22 | "{time:YYYY-MM-DD HH:mm:ss.SSS} | " 23 | "{extra[extra]: <6} | " 24 | "{level: <8} | " 25 | "{message} " 26 | ) 27 | 28 | logger.remove(0) 29 | logger.add(sys.stdout, format=fmt) 30 | 31 | # Attest function 32 | def attest(args): 33 | ser = serial.Serial( 34 | port=args.application_processor, 35 | baudrate=115200, 36 | parity=serial.PARITY_NONE, 37 | stopbits=serial.STOPBITS_ONE, 38 | bytesize=serial.EIGHTBITS, 39 | ) 40 | 41 | # Arguments passed to the AP 42 | input_list = [ 43 | "attest\r", 44 | f"{args.pin}\r", 45 | f"{args.component}\r" 46 | ] 47 | 48 | # Send and receive messages until done 49 | message = input_list.pop(0) 50 | ser.write(message.encode()) 51 | logger.bind(extra="INPUT").debug(message) 52 | output = "" 53 | while True: 54 | byte = ser.read() 55 | char = byte.decode("utf-8") 56 | output += char 57 | output = process_output(output, input_list, ser) 58 | 59 | 60 | def process_output(output, input_list, ser): 61 | # Find INFO level messages 62 | match = re.search("%info: ((.|\n|\r)*?)%", output) 63 | if match != None: 64 | # Output all of the data and remove from buffer 65 | output = output[:match.start()] + output[match.end():] 66 | for line in match.group(1).strip().split('\n'): 67 | logger.bind(extra="OUTPUT").info(line.strip()) 68 | # Find DEBUG level messages 69 | match = re.search("%debug: ((.|\n|\r)*?)%", output) 70 | if match != None: 71 | # Output all of the data and remove from buffer 72 | output = output[:match.start()] + output[match.end():] 73 | for line in match.group(1).strip().split('\n'): 74 | logger.bind(extra="OUTPUT").debug(line.strip()) 75 | # Find ACK level messages 76 | match = re.search("%ack%", output) 77 | if match != None: 78 | # Send next message 79 | output = output[:match.start()] + output[match.end():] 80 | message = input_list.pop(0) 81 | ser.write(message.encode()) 82 | logger.bind(extra="INPUT").debug(message) 83 | # Find SUCCESS level messages 84 | match = re.search("%success: ((.|\n|\r)*?)%", output) 85 | if match != None: 86 | # Output all of the data and remove from buffer 87 | output = output[:match.start()] + output[match.end():] 88 | for line in match.group(1).strip().split('\n'): 89 | logger.bind(extra="OUTPUT").success(line.strip()) 90 | exit(0) 91 | # Find ERROR level messages 92 | match = re.search("%error: ((.|\n|\r)*?)%", output) 93 | if match != None: 94 | # Output all of the data and remove from buffer 95 | output = output[:match.start()] + output[match.end():] 96 | for line in match.group(1).strip().split('\n'): 97 | logger.bind(extra="OUTPUT").error(line.strip()) 98 | exit(1) 99 | # Return the spliced output 100 | return output 101 | 102 | 103 | # Main function 104 | def main(): 105 | # Parse arguments 106 | parser = argparse.ArgumentParser( 107 | prog="eCTF Attestation Host Tool", 108 | description="Return the attestation data from a component", 109 | ) 110 | 111 | parser.add_argument( 112 | "-a", "--application-processor", required=True, help="Serial device of the AP" 113 | ) 114 | parser.add_argument( 115 | "-p", "--pin", required=True, help="PIN for the AP" 116 | ) 117 | parser.add_argument( 118 | "-c", 119 | "--component", 120 | required=True, 121 | help="Component ID of the target component", 122 | ) 123 | 124 | args = parser.parse_args() 125 | 126 | attest(args) 127 | 128 | 129 | if __name__ == "__main__": 130 | main() 131 | -------------------------------------------------------------------------------- /component/firmware.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64kB ROM */ 3 | BOOTLOADER (rx) : ORIGIN = 0x10000000, LENGTH = 0x0000E000 /* Bootloader flash */ 4 | FLASH (rx) : ORIGIN = 0x1000E000, LENGTH = 0x00038000 /* Location of team firmware */ 5 | RESERVED (rw) : ORIGIN = 0x10046000, LENGTH = 0x00038000 /* Reserved */ 6 | ROM_BL_PAGE (rw) : ORIGIN = 0x1007E000, LENGTH = 0x00002000 /* Reserved */ 7 | SRAM (rwx): ORIGIN = 0x20000000, LENGTH = 0x00020000 /* 128kB SRAM */ 8 | } 9 | 10 | SECTIONS { 11 | .rom : 12 | { 13 | KEEP(*(.rom_vector)) 14 | *(.rom_handlers*) 15 | } > ROM 16 | 17 | .text : 18 | { 19 | _text = .; 20 | KEEP(*(.isr_vector)) 21 | KEEP(*(.firmware_startup)) 22 | *(.text*) /* program code */ 23 | *(.rodata*) /* read-only data: "const" */ 24 | 25 | KEEP(*(.init)) 26 | KEEP(*(.fini)) 27 | 28 | /* C++ Exception handling */ 29 | KEEP(*(.eh_frame*)) 30 | _etext = .; 31 | } > FLASH 32 | 33 | /* Binary import */ 34 | .bin_storage : 35 | { 36 | FILL(0xFF) 37 | _bin_start_ = .; 38 | KEEP(*(.bin_storage_img)) 39 | _bin_end_ = .; 40 | . = ALIGN(4); 41 | } > FLASH 42 | 43 | .rom_code : 44 | { 45 | . = ALIGN(16); 46 | _sran_code = .; 47 | *(.rom_code_section) 48 | _esran_code = .; 49 | } > ROM 50 | 51 | .flash_code : 52 | { 53 | . = ALIGN(16); 54 | _sran_code = .; 55 | *(.flash_code_section) 56 | _esran_code = .; 57 | } > FLASH 58 | 59 | .sram_code : 60 | { 61 | . = ALIGN(16); 62 | _sran_code = .; 63 | *(.sram_code_section) 64 | _esran_code = .; 65 | } > SRAM 66 | 67 | /* it's used for C++ exception handling */ 68 | /* we need to keep this to avoid overlapping */ 69 | .ARM.exidx : 70 | { 71 | __exidx_start = .; 72 | *(.ARM.exidx*) 73 | __exidx_end = .; 74 | } > FLASH 75 | 76 | .data : 77 | { 78 | _data = ALIGN(., 4); 79 | *(.data*) /*read-write initialized data: initialized global variable*/ 80 | *(.flashprog*) /* Flash program */ 81 | 82 | /* These array sections are used by __libc_init_array to call static C++ constructors */ 83 | . = ALIGN(4); 84 | /* preinit data */ 85 | PROVIDE_HIDDEN (__preinit_array_start = .); 86 | KEEP(*(.preinit_array)) 87 | PROVIDE_HIDDEN (__preinit_array_end = .); 88 | 89 | . = ALIGN(4); 90 | /* init data */ 91 | PROVIDE_HIDDEN (__init_array_start = .); 92 | KEEP(*(SORT(.init_array.*))) 93 | KEEP(*(.init_array)) 94 | PROVIDE_HIDDEN (__init_array_end = .); 95 | 96 | . = ALIGN(4); 97 | /* finit data */ 98 | PROVIDE_HIDDEN (__fini_array_start = .); 99 | KEEP(*(SORT(.fini_array.*))) 100 | KEEP(*(.fini_array)) 101 | PROVIDE_HIDDEN (__fini_array_end = .); 102 | 103 | _edata = ALIGN(., 4); 104 | } > SRAM AT>FLASH 105 | __load_data = LOADADDR(.data); 106 | 107 | .bss : 108 | { 109 | . = ALIGN(4); 110 | _bss = .; 111 | *(.bss*) /*read-write zero initialized data: uninitialzed global variable*/ 112 | *(COMMON) 113 | _ebss = ALIGN(., 4); 114 | } > SRAM 115 | 116 | .shared : 117 | { 118 | . = ALIGN(4); 119 | _shared = .; 120 | *(.mailbox*) 121 | . = ALIGN(4); 122 | *(.shared*) /*read-write zero initialized data: uninitialzed global variable*/ 123 | _eshared = ALIGN(., 4); 124 | } > SRAM 125 | __shared_data = LOADADDR(.shared); 126 | 127 | /* Set stack top to end of RAM, and stack limit move down by 128 | * size of stack_dummy section */ 129 | __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); 130 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 131 | 132 | /* .stack_dummy section doesn't contains any symbols. It is only 133 | * used for linker to calculate size of stack sections, and assign 134 | * values to stack symbols later */ 135 | .stack_dummy (COPY): 136 | { 137 | *(.stack*) 138 | } > SRAM 139 | 140 | .heap (COPY): 141 | { 142 | . = ALIGN(4); 143 | *(.heap*) 144 | __HeapLimit = ABSOLUTE(__StackLimit); 145 | } > SRAM 146 | 147 | PROVIDE(__stack = __StackTop); 148 | 149 | /* Check if data + heap + stack exceeds RAM limit */ 150 | ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") 151 | } 152 | -------------------------------------------------------------------------------- /application_processor/firmware.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64kB ROM */ 3 | BOOTLOADER (rx) : ORIGIN = 0x10000000, LENGTH = 0x0000E000 /* Bootloader flash */ 4 | FLASH (rx) : ORIGIN = 0x1000E000, LENGTH = 0x00038000 /* Location of team firmware */ 5 | RESERVED (rw) : ORIGIN = 0x10046000, LENGTH = 0x00038000 /* Reserved */ 6 | ROM_BL_PAGE (rw) : ORIGIN = 0x1007E000, LENGTH = 0x00002000 /* Reserved */ 7 | SRAM (rwx): ORIGIN = 0x20000000, LENGTH = 0x00020000 /* 128kB SRAM */ 8 | } 9 | 10 | SECTIONS { 11 | .rom : 12 | { 13 | KEEP(*(.rom_vector)) 14 | *(.rom_handlers*) 15 | } > ROM 16 | 17 | .text : 18 | { 19 | _text = .; 20 | KEEP(*(.isr_vector)) 21 | KEEP(*(.firmware_startup)) 22 | *(.text*) /* program code */ 23 | *(.rodata*) /* read-only data: "const" */ 24 | 25 | KEEP(*(.init)) 26 | KEEP(*(.fini)) 27 | 28 | /* C++ Exception handling */ 29 | KEEP(*(.eh_frame*)) 30 | _etext = .; 31 | } > FLASH 32 | 33 | /* Binary import */ 34 | .bin_storage : 35 | { 36 | FILL(0xFF) 37 | _bin_start_ = .; 38 | KEEP(*(.bin_storage_img)) 39 | _bin_end_ = .; 40 | . = ALIGN(4); 41 | } > FLASH 42 | 43 | .rom_code : 44 | { 45 | . = ALIGN(16); 46 | _sran_code = .; 47 | *(.rom_code_section) 48 | _esran_code = .; 49 | } > ROM 50 | 51 | .flash_code : 52 | { 53 | . = ALIGN(16); 54 | _sran_code = .; 55 | *(.flash_code_section) 56 | _esran_code = .; 57 | } > FLASH 58 | 59 | .sram_code : 60 | { 61 | . = ALIGN(16); 62 | _sran_code = .; 63 | *(.sram_code_section) 64 | _esran_code = .; 65 | } > SRAM 66 | 67 | /* it's used for C++ exception handling */ 68 | /* we need to keep this to avoid overlapping */ 69 | .ARM.exidx : 70 | { 71 | __exidx_start = .; 72 | *(.ARM.exidx*) 73 | __exidx_end = .; 74 | } > FLASH 75 | 76 | .data : 77 | { 78 | _data = ALIGN(., 4); 79 | *(.data*) /*read-write initialized data: initialized global variable*/ 80 | *(.flashprog*) /* Flash program */ 81 | 82 | /* These array sections are used by __libc_init_array to call static C++ constructors */ 83 | . = ALIGN(4); 84 | /* preinit data */ 85 | PROVIDE_HIDDEN (__preinit_array_start = .); 86 | KEEP(*(.preinit_array)) 87 | PROVIDE_HIDDEN (__preinit_array_end = .); 88 | 89 | . = ALIGN(4); 90 | /* init data */ 91 | PROVIDE_HIDDEN (__init_array_start = .); 92 | KEEP(*(SORT(.init_array.*))) 93 | KEEP(*(.init_array)) 94 | PROVIDE_HIDDEN (__init_array_end = .); 95 | 96 | . = ALIGN(4); 97 | /* finit data */ 98 | PROVIDE_HIDDEN (__fini_array_start = .); 99 | KEEP(*(SORT(.fini_array.*))) 100 | KEEP(*(.fini_array)) 101 | PROVIDE_HIDDEN (__fini_array_end = .); 102 | 103 | _edata = ALIGN(., 4); 104 | } > SRAM AT>FLASH 105 | __load_data = LOADADDR(.data); 106 | 107 | .bss : 108 | { 109 | . = ALIGN(4); 110 | _bss = .; 111 | *(.bss*) /*read-write zero initialized data: uninitialzed global variable*/ 112 | *(COMMON) 113 | _ebss = ALIGN(., 4); 114 | } > SRAM 115 | 116 | .shared : 117 | { 118 | . = ALIGN(4); 119 | _shared = .; 120 | *(.mailbox*) 121 | . = ALIGN(4); 122 | *(.shared*) /*read-write zero initialized data: uninitialzed global variable*/ 123 | _eshared = ALIGN(., 4); 124 | } > SRAM 125 | __shared_data = LOADADDR(.shared); 126 | 127 | /* Set stack top to end of RAM, and stack limit move down by 128 | * size of stack_dummy section */ 129 | __StackTop = ORIGIN(SRAM) + LENGTH(SRAM); 130 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 131 | 132 | /* .stack_dummy section doesn't contains any symbols. It is only 133 | * used for linker to calculate size of stack sections, and assign 134 | * values to stack symbols later */ 135 | .stack_dummy (COPY): 136 | { 137 | *(.stack*) 138 | } > SRAM 139 | 140 | .heap (COPY): 141 | { 142 | . = ALIGN(4); 143 | *(.heap*) 144 | __HeapLimit = ABSOLUTE(__StackLimit); 145 | } > SRAM 146 | 147 | PROVIDE(__stack = __StackTop); 148 | 149 | /* Check if data + heap + stack exceeds RAM limit */ 150 | ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack") 151 | } 152 | -------------------------------------------------------------------------------- /ectf_tools/replace_tool.py: -------------------------------------------------------------------------------- 1 | # @file replace_tool.py 2 | # @author Frederich Stine 3 | # @brief host tool for replacing a component on the system 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | import argparse 14 | import serial 15 | import time 16 | import re 17 | from loguru import logger 18 | import sys 19 | 20 | # Logger formatting 21 | fmt = ( 22 | "{time:YYYY-MM-DD HH:mm:ss.SSS} | " 23 | "{extra[extra]: <6} | " 24 | "{level: <8} | " 25 | "{message} " 26 | ) 27 | 28 | logger.remove(0) 29 | logger.add(sys.stdout, format=fmt) 30 | 31 | 32 | # Replace function 33 | def replace(args): 34 | ser = serial.Serial( 35 | port=args.application_processor, 36 | baudrate=115200, 37 | parity=serial.PARITY_NONE, 38 | stopbits=serial.STOPBITS_ONE, 39 | bytesize=serial.EIGHTBITS, 40 | ) 41 | 42 | # Arguments passed to the AP 43 | input_list = [ 44 | "replace\r", 45 | f"{args.token}\r", 46 | f"{args.component_in}\r", 47 | f"{args.component_out}\r" 48 | ] 49 | 50 | # Send and receive messages until done 51 | message = input_list.pop(0) 52 | ser.write(message.encode()) 53 | logger.bind(extra="INPUT").debug(message) 54 | output = "" 55 | while True: 56 | byte = ser.read() 57 | char = byte.decode("utf-8") 58 | output += char 59 | output = process_output(output, input_list, ser) 60 | 61 | 62 | def process_output(output, input_list, ser): 63 | # Find INFO level messages 64 | match = re.search("%info: ((.|\n|\r)*?)%", output) 65 | if match != None: 66 | # Output all of the data and remove from buffer 67 | output = output[:match.start()] + output[match.end():] 68 | for line in match.group(1).strip().split('\n'): 69 | logger.bind(extra="OUTPUT").info(line.strip()) 70 | # Find DEBUG level messages 71 | match = re.search("%debug: ((.|\n|\r)*?)%", output) 72 | if match != None: 73 | # Output all of the data and remove from buffer 74 | output = output[:match.start()] + output[match.end():] 75 | for line in match.group(1).strip().split('\n'): 76 | logger.bind(extra="OUTPUT").debug(line.strip()) 77 | # Find ACK level messages 78 | match = re.search("%ack%", output) 79 | if match != None: 80 | # Send next message 81 | output = output[:match.start()] + output[match.end():] 82 | message = input_list.pop(0) 83 | ser.write(message.encode()) 84 | logger.bind(extra="INPUT").debug(message) 85 | # Find SUCCESS level messages 86 | match = re.search("%success: ((.|\n|\r)*?)%", output) 87 | if match != None: 88 | # Output all of the data and remove from buffer 89 | output = output[:match.start()] + output[match.end():] 90 | for line in match.group(1).strip().split('\n'): 91 | logger.bind(extra="OUTPUT").success(line.strip()) 92 | exit(0) 93 | # Find ERROR level messages 94 | match = re.search("%error: ((.|\n|\r)*?)%", output) 95 | if match != None: 96 | # Output all of the data and remove from buffer 97 | output = output[:match.start()] + output[match.end():] 98 | for line in match.group(1).strip().split('\n'): 99 | logger.bind(extra="OUTPUT").error(line.strip()) 100 | exit(1) 101 | # Return the spliced output 102 | return output 103 | 104 | 105 | # Main function 106 | def main(): 107 | # Parse arguments 108 | parser = argparse.ArgumentParser( 109 | prog="eCTF Replace Host Tool", 110 | description="Replace a component on the medical device", 111 | ) 112 | 113 | parser.add_argument( 114 | "-a", "--application-processor", required=True, help="Serial device of the AP" 115 | ) 116 | parser.add_argument( 117 | "-t", "--token", required=True, help="Replacement token for the AP" 118 | ) 119 | parser.add_argument( 120 | "-i", "--component-in", required=True, help="Component ID of the new component" 121 | ) 122 | parser.add_argument( 123 | "-o", 124 | "--component-out", 125 | required=True, 126 | help="Component ID of the component being replaced", 127 | ) 128 | 129 | args = parser.parse_args() 130 | 131 | replace(args) 132 | 133 | 134 | if __name__ == "__main__": 135 | 136 | main() 137 | -------------------------------------------------------------------------------- /ectf_tools/build_ap.py: -------------------------------------------------------------------------------- 1 | # @file build_ap.py 2 | # @author Frederich Stine 3 | # @brief Tool for building application processor firmware 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | from loguru import logger 14 | import argparse 15 | import asyncio 16 | from pathlib import Path 17 | import os 18 | 19 | from ectf_tools.utils import run_shell, package_binary, i2c_address_is_blacklisted 20 | 21 | 22 | def build_ap( 23 | design: Path, 24 | output_name, 25 | output_dir: Path, 26 | pin, 27 | token, 28 | component_cnt, 29 | component_ids, 30 | boot_message 31 | ): 32 | """ 33 | Build an application processor. 34 | """ 35 | 36 | try: 37 | for component_id in component_ids.split(","): 38 | component_id = int(component_id.strip(), 0) 39 | if i2c_address_is_blacklisted(component_id): 40 | logger.error(f"Invalid component ID {component_id:x}") 41 | logger.error(f"IDs ending in 0x00-0x07, 0x78-0x7F, and 0x18, 0x28, or 0x36 are reserved due to I2C conflicts") 42 | exit(1) 43 | except ValueError: 44 | logger.warning("Cannot parse component IDs to enforce I2C blacklist") 45 | 46 | try: 47 | os.makedirs(output_dir, exist_ok=True) 48 | except Exception as e: 49 | print(e) 50 | raise 51 | 52 | logger.info("Creating parameters for build") 53 | fh = open(design / Path("application_processor/inc/ectf_params.h"), "w") 54 | fh.write("#ifndef __ECTF_PARAMS__\n") 55 | fh.write("#define __ECTF_PARAMS__\n") 56 | fh.write(f"#define AP_PIN \"{pin}\"\n") 57 | fh.write(f"#define AP_TOKEN \"{token}\"\n") 58 | fh.write(f"#define COMPONENT_IDS {component_ids}\n") 59 | fh.write(f"#define COMPONENT_CNT {component_cnt}\n") 60 | fh.write(f"#define AP_BOOT_MSG \"{boot_message}\"\n") 61 | fh.write("#endif\n") 62 | fh.close() 63 | 64 | output_dir = os.path.abspath(output_dir) 65 | output_elf = f"{output_dir}/{output_name}.elf" 66 | output_bin = f"{output_dir}/{output_name}.bin" 67 | output_img = f"{output_dir}/{output_name}.img" 68 | 69 | logger.info("Checking output paths") 70 | if os.path.exists(output_elf): 71 | logger.info("Removing old .elf output") 72 | os.remove(output_elf) 73 | if os.path.exists(output_bin): 74 | logger.info("Removing old .bin output") 75 | os.remove(output_bin) 76 | if os.path.exists(output_img): 77 | logger.info("Removing old .img output") 78 | os.remove(output_img) 79 | 80 | logger.info("Running build") 81 | output = asyncio.run(run_shell( 82 | f"cd {design} && " 83 | f"pwd && " 84 | f"nix-shell --command " 85 | f"\"cd application_processor && " 86 | f" make clean && " 87 | f" make && make release && " 88 | f" cp build/max78000.elf {output_elf} && " 89 | f" cp build/max78000.bin {output_bin}\"" 90 | )) 91 | 92 | if not os.path.exists(output_bin): 93 | logger.error("Error: tool did not build properly") 94 | exit(1) 95 | 96 | logger.info("Built application processor") 97 | 98 | logger.info("Packaging binary") 99 | package_binary(output_bin, output_img) 100 | logger.info("Binary packaged") 101 | 102 | return output 103 | 104 | 105 | def main(): 106 | parser = argparse.ArgumentParser( 107 | prog="eCTF Build Application Processor Tool", 108 | description="Build an Application Processor using Nix" 109 | ) 110 | 111 | parser.add_argument( 112 | "-d", "--design", required=True, type=Path, 113 | help="Path to the root directory of the included design" 114 | ) 115 | 116 | parser.add_argument( 117 | "-on", "--output-name", required=True, 118 | help=("Output prefix of the built application processor binary \n" 119 | "Example 'ap' -> ap.bin, ap.elf, ap.img" 120 | ) 121 | ) 122 | 123 | parser.add_argument( 124 | "-od", "--output-dir", required=False, type=Path, 125 | default=Path('.'), help=f"Output name of the directory to store the result: default: %(default)s" 126 | ) 127 | 128 | parser.add_argument( 129 | "-p", "--pin", required=True, 130 | help="PIN for built application processor" 131 | ) 132 | 133 | parser.add_argument( 134 | "-t", "--token", required=True, 135 | help="Token for built application processor" 136 | ) 137 | 138 | parser.add_argument( 139 | "-c", "--component-cnt", required=True, 140 | help="Number of components to provision Application Processor for" 141 | ) 142 | 143 | parser.add_argument( 144 | "-ids", "--component-ids", required=True, 145 | help="Component IDs to provision the Application Processor for" 146 | ) 147 | 148 | parser.add_argument( 149 | "-b", "--boot-message", required=True, 150 | help="Application Processor boot message" 151 | ) 152 | 153 | args = parser.parse_args() 154 | 155 | build_ap( 156 | args.design, 157 | args.output_name, 158 | args.output_dir, 159 | args.pin, 160 | args.token, 161 | args.component_cnt, 162 | args.component_ids, 163 | args.boot_message 164 | ) 165 | 166 | 167 | if __name__ == '__main__': 168 | main() 169 | 170 | -------------------------------------------------------------------------------- /ectf_tools/build_comp.py: -------------------------------------------------------------------------------- 1 | # @file build_comp.py 2 | # @author Frederich Stine 3 | # @brief Tool for building component firmware 4 | # @date 2024 5 | # 6 | # This source file is part of an example system for MITRE's 2024 Embedded CTF (eCTF). 7 | # This code is being provided only for educational purposes for the 2024 MITRE eCTF 8 | # competition, and may not meet MITRE standards for quality. Use this code at your 9 | # own risk! 10 | # 11 | # @copyright Copyright (c) 2024 The MITRE Corporation 12 | 13 | from loguru import logger 14 | import argparse 15 | import asyncio 16 | from pathlib import Path 17 | import os 18 | 19 | from ectf_tools.utils import run_shell, package_binary, i2c_address_is_blacklisted 20 | 21 | 22 | def build_component( 23 | design: Path, 24 | output_name, 25 | output_dir: Path, 26 | component_id, 27 | boot_message, 28 | attestation_location, 29 | attestation_date, 30 | attestation_customer 31 | ): 32 | """ 33 | Build a component. 34 | """ 35 | 36 | try: 37 | component_id = int(component_id, 0) 38 | i2c_address = component_id & 0x7F 39 | if i2c_address_is_blacklisted(component_id): 40 | logger.error(f"Invalid component ID {component_id:x}") 41 | logger.error(f"IDs ending in 0x00-0x07, 0x78-0x7F, and 0x18, 0x28, or 0x36 are reserved due to I2C conflicts") 42 | exit(1) 43 | except ValueError: 44 | logger.warning("Cannot parse component ID to enforce I2C blacklist") 45 | 46 | 47 | try: 48 | os.makedirs(output_dir, exist_ok=True) 49 | except Exception as e: 50 | print(e) 51 | raise 52 | 53 | logger.info("Creating parameters for build") 54 | fh = open(design / Path("component/inc/ectf_params.h"), "w") 55 | fh.write("#ifndef __ECTF_PARAMS__\n") 56 | fh.write("#define __ECTF_PARAMS__\n") 57 | fh.write(f"#define COMPONENT_ID {component_id}\n") 58 | fh.write(f"#define COMPONENT_BOOT_MSG \"{boot_message}\"\n") 59 | fh.write(f"#define ATTESTATION_LOC \"{attestation_location}\"\n") 60 | fh.write(f"#define ATTESTATION_DATE \"{attestation_date}\"\n") 61 | fh.write(f"#define ATTESTATION_CUSTOMER \"{attestation_customer}\"\n") 62 | fh.write("#endif\n") 63 | fh.close() 64 | 65 | output_dir = os.path.abspath(output_dir) 66 | output_elf = f"{output_dir}/{output_name}.elf" 67 | output_bin = f"{output_dir}/{output_name}.bin" 68 | output_img = f"{output_dir}/{output_name}.img" 69 | 70 | logger.info("Checking output paths") 71 | if os.path.exists(output_elf): 72 | logger.info("Removing old .elf output") 73 | os.remove(output_elf) 74 | if os.path.exists(output_bin): 75 | logger.info("Removing old .bin output") 76 | os.remove(output_bin) 77 | if os.path.exists(output_img): 78 | logger.info("Removing old .img output") 79 | os.remove(output_img) 80 | 81 | logger.info("Running build") 82 | output = asyncio.run(run_shell( 83 | f"cd {design} && " 84 | f"pwd && " 85 | f"nix-shell --command " 86 | f"\"cd component && " 87 | f" make clean && " 88 | f" make && make release && " 89 | f" cp build/max78000.elf {output_elf} && " 90 | f" cp build/max78000.bin {output_bin}\"" 91 | )) 92 | 93 | if not os.path.exists(output_bin): 94 | logger.error("Error: tool did not build properly") 95 | exit(1) 96 | 97 | logger.info("Built application processor") 98 | 99 | logger.info("Packaging binary") 100 | package_binary(output_bin, output_img) 101 | logger.info("Binary packaged") 102 | 103 | return output 104 | 105 | 106 | def main(): 107 | parser = argparse.ArgumentParser( 108 | prog="eCTF Build Application Processor Tool", 109 | description="Build an Application Processor using Nix" 110 | ) 111 | 112 | parser.add_argument( 113 | "-d", "--design", required=True, type=Path, 114 | help="Path to the root directory of the included design" 115 | ) 116 | 117 | parser.add_argument( 118 | "-on", "--output-name", required=True, 119 | help=("Output prefix of the built application processor binary \n" 120 | "Example 'ap' -> ap.bin, ap.elf, ap.img" 121 | ) 122 | ) 123 | 124 | parser.add_argument( 125 | "-od", "--output-dir", required=False, type=Path, 126 | default=Path('.'), help=f"Output name of the directory to store the result: default: %(default)s" 127 | ) 128 | 129 | parser.add_argument( 130 | "-id", "--component-id", required=True, 131 | help="Component ID for the provisioned component" 132 | ) 133 | 134 | parser.add_argument( 135 | "-b", "--boot-message", required=True, 136 | help="Component boot message" 137 | ) 138 | 139 | parser.add_argument( 140 | "-al", "--attestation-location", required=True, 141 | help="Attestation data location field" 142 | ) 143 | 144 | parser.add_argument( 145 | "-ad", "--attestation-date", required=True, 146 | help="Attestation data date field" 147 | ) 148 | 149 | parser.add_argument( 150 | "-ac", "--attestation-customer", required=True, 151 | help="Attestation data customer field" 152 | ) 153 | 154 | args = parser.parse_args() 155 | 156 | build_component( 157 | args.design, 158 | args.output_name, 159 | args.output_dir, 160 | args.component_id, 161 | args.boot_message, 162 | args.attestation_location, 163 | args.attestation_date, 164 | args.attestation_customer 165 | ) 166 | 167 | 168 | if __name__ == '__main__': 169 | main() 170 | 171 | -------------------------------------------------------------------------------- /application_processor/inc/simple_i2c_controller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_i2c_controller.h" 3 | * @author Frederich Stine 4 | * @brief Simple Synchronous I2C Controller Header 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #ifndef __I2C_SIMPLE_CONTROLLER__ 15 | #define __I2C_SIMPLE_CONTROLLER__ 16 | 17 | #include "stdbool.h" 18 | #include "stdint.h" 19 | #include "mxc_errors.h" 20 | #include "board.h" 21 | #include "nvic_table.h" 22 | #include "i2c.h" 23 | #include "string.h" 24 | 25 | /******************************** MACRO DEFINITIONS ********************************/ 26 | // I2C frequency in HZ 27 | #define I2C_FREQ 100000 28 | // Physical I2C interface 29 | #define I2C_INTERFACE MXC_I2C1 30 | // Last register for out-of-bounds checking 31 | #define MAX_REG TRANSMIT_LEN 32 | // Maximum length of an I2C register 33 | #define MAX_I2C_MESSAGE_LEN 256 34 | 35 | /******************************** TYPE DEFINITIONS ********************************/ 36 | /* ECTF_I2C_REGS 37 | * Emulated hardware registers for sending and receiving I2C messages 38 | */ 39 | typedef enum { 40 | RECEIVE, 41 | RECEIVE_DONE, 42 | RECEIVE_LEN, 43 | TRANSMIT, 44 | TRANSMIT_DONE, 45 | TRANSMIT_LEN, 46 | } ECTF_I2C_REGS; 47 | 48 | typedef uint8_t i2c_addr_t; 49 | 50 | /******************************** FUNCTION PROTOTYPES ********************************/ 51 | /** 52 | * @brief Initialize the I2C Connection 53 | * 54 | * Initialize the I2C by enabling the module, setting the correct 55 | * frequency, and enabling the interrupt to our I2C_Handler 56 | */ 57 | int i2c_simple_controller_init(void); 58 | 59 | /** 60 | * @brief Read RECEIVE_DONE reg 61 | * 62 | * @param addr: i2c_addr_t, address of I2C device 63 | * 64 | * @return int: RECEIVE_DONE value, negative if error 65 | * 66 | * Read the RECEIVE_DONE for an I2C peripheral 67 | * and return the value 68 | */ 69 | int i2c_simple_read_receive_done(i2c_addr_t addr); 70 | /** 71 | * @brief Read RECEIVE_LEN reg 72 | * 73 | * @param addr: i2c_addr_t, address of I2C device 74 | * 75 | * @return int: RECEIVE_LEN value, negative if error 76 | * 77 | * Read the RECEIVE_LEN for an I2C peripheral 78 | * and return the value 79 | */ 80 | int i2c_simple_read_receive_len(i2c_addr_t addr); 81 | /** 82 | * @brief Read TRANSMIT_DONE reg 83 | * 84 | * @param addr: i2c_addr_t, address of I2C device 85 | * 86 | * @return int: TRANSMIT_DONE value, negative if error 87 | * 88 | * Read the TRANSMIT_DONE for an I2C peripheral 89 | * and return the value 90 | */ 91 | int i2c_simple_read_transmit_done(i2c_addr_t addr); 92 | /** 93 | * @brief Read TRANSMIT_LEN reg 94 | * 95 | * @param addr: i2c_addr_t, address of I2C device 96 | * 97 | * @return int: TRANSMIT_LEN value, negative if error 98 | * 99 | * Read the TRANSMIT_LEN for an I2C peripheral 100 | * and return the value 101 | */ 102 | int i2c_simple_read_transmit_len(i2c_addr_t addr); 103 | 104 | /** 105 | * @brief Write RECEIVE_DONE reg 106 | * 107 | * @param addr: i2c_addr_t, address of I2C device 108 | * @param done: uint8_t, RECEIVE_DONE value 109 | * 110 | * @return int: negative if error, 0 if success 111 | * 112 | * Write the RECEIVE_DONE reg for an I2C peripheral to the 113 | * specified value 114 | */ 115 | int i2c_simple_write_receive_done(i2c_addr_t addr, bool done); 116 | /** 117 | * @brief Write RECEIVE_LEN reg 118 | * 119 | * @param addr: i2c_addr_t, address of I2C device 120 | * @param len: uint8_t, RECEIVE_LEN value 121 | * 122 | * @return int: negative if error, 0 if success 123 | * 124 | * Write the RECEIVE_LEN reg for an I2C peripheral to the 125 | * specified value 126 | */ 127 | int i2c_simple_write_receive_len(i2c_addr_t addr, uint8_t len); 128 | /** 129 | * @brief Write TRANSMIT_DONE reg 130 | * 131 | * @param addr: i2c_addr_t, address of I2C device 132 | * @param done: bool, TRANSMIT_DONE value 133 | * 134 | * @return int: negative if error, 0 if success 135 | * 136 | * Write the TRANSMIT_DONE reg for an I2C peripheral to the 137 | * specified value 138 | */ 139 | int i2c_simple_write_transmit_done(i2c_addr_t addr, bool done); 140 | /** 141 | * @brief Write TRANSMIT_LEN reg 142 | * 143 | * @param addr: i2c_addr_t, address of I2C device 144 | * @param len: uint8_t, TRANSMIT_LEN value 145 | * 146 | * @return int: negative if error, 0 if success 147 | * 148 | * Write the TRANSMIT_LEN reg for an I2C peripheral to the 149 | * specified value 150 | */ 151 | int i2c_simple_write_transmit_len(i2c_addr_t addr, uint8_t len); 152 | 153 | /** 154 | * @brief Read generic data reg 155 | * 156 | * @param addr: i2c_addr_t, address of I2C device 157 | * @param reg: ECTF_I2C_REGS, register to read from 158 | * @param len: uint8_t, length of data to read 159 | * @param buf: uint8_t*, buffer to read data into 160 | * 161 | * @return int: negative if error, 0 if success 162 | * 163 | * Read any register larger than 1B in size 164 | * Can be used to read the PARAMS or RESULT register 165 | */ 166 | int i2c_simple_read_data_generic(i2c_addr_t addr, ECTF_I2C_REGS reg, uint8_t len, uint8_t* buf); 167 | /** 168 | * @brief Write generic data reg 169 | * 170 | * @param addr: i2c_addr_t, address of I2C device 171 | * @param reg: ECTF_I2C_REGS, register to write to 172 | * @param len: uint8_t, length of data to write 173 | * @param buf: uint8_t*, buffer to write data from 174 | * 175 | * @return int: negative if error, 0 if success 176 | * 177 | * Write any register larger than 1B in size 178 | * Can be used to write the PARAMS or RESULT register 179 | */ 180 | int i2c_simple_write_data_generic(i2c_addr_t addr, ECTF_I2C_REGS reg, uint8_t len, uint8_t* buf); 181 | /** 182 | * @brief Read generic status reg 183 | * 184 | * @param addr: i2c_addr_t, address of I2C device 185 | * @param reg: ECTF_I2C_REGS, register to read to 186 | * 187 | * @return int: value returned from device, negative if error 188 | * 189 | * Read any register that is 1B in size 190 | */ 191 | int i2c_simple_read_status_generic(i2c_addr_t addr, ECTF_I2C_REGS reg); 192 | /** 193 | * @brief Write generic status reg 194 | * 195 | * @param addr: i2c_addr_t, address of I2C device 196 | * @param reg: ECTF_I2C_REGS, register to write to 197 | * @param value: uint8_t, value to write to register 198 | * 199 | * @return int: negative if error, 0 if success 200 | * 201 | * Write any register that is 1B in size 202 | */ 203 | int i2c_simple_write_status_generic(i2c_addr_t addr, ECTF_I2C_REGS reg, uint8_t value); 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /component/src/component.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file component.c 3 | * @author Jacob Doll 4 | * @brief eCTF Component Example Design Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include "board.h" 15 | #include "i2c.h" 16 | #include "led.h" 17 | #include "mxc_delay.h" 18 | #include "mxc_errors.h" 19 | #include "nvic_table.h" 20 | #include 21 | #include 22 | #include 23 | 24 | #include "simple_i2c_peripheral.h" 25 | #include "board_link.h" 26 | 27 | // Includes from containerized build 28 | #include "ectf_params.h" 29 | #include "global_secrets.h" 30 | 31 | #ifdef POST_BOOT 32 | #include "led.h" 33 | #include 34 | #include 35 | #include 36 | #endif 37 | 38 | /********************************* CONSTANTS **********************************/ 39 | 40 | // Passed in through ectf-params.h 41 | // Example of format of ectf-params.h shown here 42 | /* 43 | #define COMPONENT_ID 0x11111124 44 | #define COMPONENT_BOOT_MSG "Component boot" 45 | #define ATTESTATION_LOC "McLean" 46 | #define ATTESTATION_DATE "08/08/08" 47 | #define ATTESTATION_CUSTOMER "Fritz" 48 | */ 49 | 50 | /******************************** TYPE DEFINITIONS ********************************/ 51 | // Commands received by Component using 32 bit integer 52 | typedef enum { 53 | COMPONENT_CMD_NONE, 54 | COMPONENT_CMD_SCAN, 55 | COMPONENT_CMD_VALIDATE, 56 | COMPONENT_CMD_BOOT, 57 | COMPONENT_CMD_ATTEST 58 | } component_cmd_t; 59 | 60 | /******************************** TYPE DEFINITIONS ********************************/ 61 | // Data structure for receiving messages from the AP 62 | typedef struct { 63 | uint8_t opcode; 64 | uint8_t params[MAX_I2C_MESSAGE_LEN-1]; 65 | } command_message; 66 | 67 | typedef struct { 68 | uint32_t component_id; 69 | } validate_message; 70 | 71 | typedef struct { 72 | uint32_t component_id; 73 | } scan_message; 74 | 75 | /********************************* FUNCTION DECLARATIONS **********************************/ 76 | // Core function definitions 77 | void component_process_cmd(void); 78 | void process_boot(void); 79 | void process_scan(void); 80 | void process_validate(void); 81 | void process_attest(void); 82 | 83 | /********************************* GLOBAL VARIABLES **********************************/ 84 | // Global varaibles 85 | uint8_t receive_buffer[MAX_I2C_MESSAGE_LEN]; 86 | uint8_t transmit_buffer[MAX_I2C_MESSAGE_LEN]; 87 | 88 | /******************************* POST BOOT FUNCTIONALITY *********************************/ 89 | /** 90 | * @brief Secure Send 91 | * 92 | * @param buffer: uint8_t*, pointer to data to be send 93 | * @param len: uint8_t, size of data to be sent 94 | * 95 | * Securely send data over I2C. This function is utilized in POST_BOOT functionality. 96 | * This function must be implemented by your team to align with the security requirements. 97 | */ 98 | void secure_send(uint8_t* buffer, uint8_t len) { 99 | send_packet_and_ack(len, buffer); 100 | } 101 | 102 | /** 103 | * @brief Secure Receive 104 | * 105 | * @param buffer: uint8_t*, pointer to buffer to receive data to 106 | * 107 | * @return int: number of bytes received, negative if error 108 | * 109 | * Securely receive data over I2C. This function is utilized in POST_BOOT functionality. 110 | * This function must be implemented by your team to align with the security requirements. 111 | */ 112 | int secure_receive(uint8_t* buffer) { 113 | return wait_and_receive_packet(buffer); 114 | } 115 | 116 | /******************************* FUNCTION DEFINITIONS *********************************/ 117 | 118 | // Example boot sequence 119 | // Your design does not need to change this 120 | void boot() { 121 | 122 | // POST BOOT FUNCTIONALITY 123 | // DO NOT REMOVE IN YOUR DESIGN 124 | #ifdef POST_BOOT 125 | POST_BOOT 126 | #else 127 | // Anything after this macro can be changed by your design 128 | // but will not be run on provisioned systems 129 | LED_Off(LED1); 130 | LED_Off(LED2); 131 | LED_Off(LED3); 132 | // LED loop to show that boot occurred 133 | while (1) { 134 | LED_On(LED1); 135 | MXC_Delay(500000); 136 | LED_On(LED2); 137 | MXC_Delay(500000); 138 | LED_On(LED3); 139 | MXC_Delay(500000); 140 | LED_Off(LED1); 141 | MXC_Delay(500000); 142 | LED_Off(LED2); 143 | MXC_Delay(500000); 144 | LED_Off(LED3); 145 | MXC_Delay(500000); 146 | } 147 | #endif 148 | } 149 | 150 | // Handle a transaction from the AP 151 | void component_process_cmd() { 152 | command_message* command = (command_message*) receive_buffer; 153 | 154 | // Output to application processor dependent on command received 155 | switch (command->opcode) { 156 | case COMPONENT_CMD_BOOT: 157 | process_boot(); 158 | break; 159 | case COMPONENT_CMD_SCAN: 160 | process_scan(); 161 | break; 162 | case COMPONENT_CMD_VALIDATE: 163 | process_validate(); 164 | break; 165 | case COMPONENT_CMD_ATTEST: 166 | process_attest(); 167 | break; 168 | default: 169 | printf("Error: Unrecognized command received %d\n", command->opcode); 170 | break; 171 | } 172 | } 173 | 174 | void process_boot() { 175 | // The AP requested a boot. Set `component_boot` for the main loop and 176 | // respond with the boot message 177 | uint8_t len = strlen(COMPONENT_BOOT_MSG) + 1; 178 | memcpy((void*)transmit_buffer, COMPONENT_BOOT_MSG, len); 179 | send_packet_and_ack(len, transmit_buffer); 180 | // Call the boot function 181 | boot(); 182 | } 183 | 184 | void process_scan() { 185 | // The AP requested a scan. Respond with the Component ID 186 | scan_message* packet = (scan_message*) transmit_buffer; 187 | packet->component_id = COMPONENT_ID; 188 | send_packet_and_ack(sizeof(scan_message), transmit_buffer); 189 | } 190 | 191 | void process_validate() { 192 | // The AP requested a validation. Respond with the Component ID 193 | validate_message* packet = (validate_message*) transmit_buffer; 194 | packet->component_id = COMPONENT_ID; 195 | send_packet_and_ack(sizeof(validate_message), transmit_buffer); 196 | } 197 | 198 | void process_attest() { 199 | // The AP requested attestation. Respond with the attestation data 200 | uint8_t len = sprintf((char*)transmit_buffer, "LOC>%s\nDATE>%s\nCUST>%s\n", 201 | ATTESTATION_LOC, ATTESTATION_DATE, ATTESTATION_CUSTOMER) + 1; 202 | send_packet_and_ack(len, transmit_buffer); 203 | } 204 | 205 | /*********************************** MAIN *************************************/ 206 | 207 | int main(void) { 208 | printf("Component Started\n"); 209 | 210 | // Enable Global Interrupts 211 | __enable_irq(); 212 | 213 | // Initialize Component 214 | i2c_addr_t addr = component_id_to_i2c_addr(COMPONENT_ID); 215 | board_link_init(addr); 216 | 217 | LED_On(LED2); 218 | 219 | while (1) { 220 | wait_and_receive_packet(receive_buffer); 221 | 222 | component_process_cmd(); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Project .gitignore ## 2 | 3 | .DS_Store 4 | .vscode/ 5 | **/gcc 6 | 7 | !device/lib 8 | 9 | ## Begin Generic .gitignore ## 10 | 11 | # Created by https://www.toptal.com/developers/gitignore/api/python,c,c++,git,pycharm 12 | # Edit at https://www.toptal.com/developers/gitignore?templates=python,c,c++,git,pycharm 13 | 14 | ### C ### 15 | # Prerequisites 16 | *.d 17 | 18 | # Object files 19 | *.o 20 | *.ko 21 | *.obj 22 | *.elf 23 | 24 | # Linker output 25 | *.ilk 26 | *.map 27 | *.exp 28 | 29 | # Precompiled Headers 30 | *.gch 31 | *.pch 32 | 33 | # Libraries 34 | *.lib 35 | *.a 36 | *.la 37 | *.lo 38 | 39 | # Shared objects (inc. Windows DLLs) 40 | *.dll 41 | *.so 42 | *.so.* 43 | *.dylib 44 | 45 | # Executables 46 | *.exe 47 | *.out 48 | *.app 49 | *.i*86 50 | *.x86_64 51 | *.hex 52 | 53 | # Debug files 54 | *.dSYM/ 55 | *.su 56 | *.idb 57 | *.pdb 58 | 59 | # Kernel Module Compile Results 60 | *.mod* 61 | *.cmd 62 | .tmp_versions/ 63 | modules.order 64 | Module.symvers 65 | Mkfile.old 66 | dkms.conf 67 | 68 | ### C++ ### 69 | # Prerequisites 70 | 71 | # Compiled Object files 72 | *.slo 73 | 74 | # Precompiled Headers 75 | 76 | # Compiled Dynamic libraries 77 | 78 | # Fortran module files 79 | *.mod 80 | *.smod 81 | 82 | # Compiled Static libraries 83 | *.lai 84 | 85 | # Executables 86 | 87 | ### Git ### 88 | # Created by git for backups. To disable backups in Git: 89 | # $ git config --global mergetool.keepBackup false 90 | *.orig 91 | 92 | # Created by git when using merge tools for conflicts 93 | *.BACKUP.* 94 | *.BASE.* 95 | *.LOCAL.* 96 | *.REMOTE.* 97 | *_BACKUP_*.txt 98 | *_BASE_*.txt 99 | *_LOCAL_*.txt 100 | *_REMOTE_*.txt 101 | 102 | ### PyCharm ### 103 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 104 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 105 | 106 | # User-specific stuff 107 | .idea/**/workspace.xml 108 | .idea/**/tasks.xml 109 | .idea/**/usage.statistics.xml 110 | .idea/**/dictionaries 111 | .idea/**/shelf 112 | 113 | # AWS User-specific 114 | .idea/**/aws.xml 115 | 116 | # Generated files 117 | .idea/**/contentModel.xml 118 | 119 | # Sensitive or high-churn files 120 | .idea/**/dataSources/ 121 | .idea/**/dataSources.ids 122 | .idea/**/dataSources.local.xml 123 | .idea/**/sqlDataSources.xml 124 | .idea/**/dynamic.xml 125 | .idea/**/uiDesigner.xml 126 | .idea/**/dbnavigator.xml 127 | 128 | # Gradle 129 | .idea/**/gradle.xml 130 | .idea/**/libraries 131 | 132 | # Gradle and Maven with auto-import 133 | # When using Gradle or Maven with auto-import, you should exclude module files, 134 | # since they will be recreated, and may cause churn. Uncomment if using 135 | # auto-import. 136 | # .idea/artifacts 137 | # .idea/compiler.xml 138 | # .idea/jarRepositories.xml 139 | # .idea/modules.xml 140 | # .idea/*.iml 141 | # .idea/modules 142 | # *.iml 143 | # *.ipr 144 | 145 | # CMake 146 | cmake-build-*/ 147 | 148 | # Mongo Explorer plugin 149 | .idea/**/mongoSettings.xml 150 | 151 | # File-based project format 152 | *.iws 153 | 154 | # IntelliJ 155 | out/ 156 | 157 | # mpeltonen/sbt-idea plugin 158 | .idea_modules/ 159 | 160 | # JIRA plugin 161 | atlassian-ide-plugin.xml 162 | 163 | # Cursive Clojure plugin 164 | .idea/replstate.xml 165 | 166 | # SonarLint plugin 167 | .idea/sonarlint/ 168 | 169 | # Crashlytics plugin (for Android Studio and IntelliJ) 170 | com_crashlytics_export_strings.xml 171 | crashlytics.properties 172 | crashlytics-build.properties 173 | fabric.properties 174 | 175 | # Editor-based Rest Client 176 | .idea/httpRequests 177 | 178 | # Android studio 3.1+ serialized cache file 179 | .idea/caches/build_file_checksums.ser 180 | 181 | ### PyCharm Patch ### 182 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 183 | 184 | # *.iml 185 | # modules.xml 186 | # .idea/misc.xml 187 | # *.ipr 188 | 189 | # Sonarlint plugin 190 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 191 | .idea/**/sonarlint/ 192 | 193 | # SonarQube Plugin 194 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 195 | .idea/**/sonarIssues.xml 196 | 197 | # Markdown Navigator plugin 198 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 199 | .idea/**/markdown-navigator.xml 200 | .idea/**/markdown-navigator-enh.xml 201 | .idea/**/markdown-navigator/ 202 | 203 | # Cache file creation bug 204 | # See https://youtrack.jetbrains.com/issue/JBR-2257 205 | .idea/$CACHE_FILE$ 206 | 207 | # CodeStream plugin 208 | # https://plugins.jetbrains.com/plugin/12206-codestream 209 | .idea/codestream.xml 210 | 211 | ### Python ### 212 | # Byte-compiled / optimized / DLL files 213 | __pycache__/ 214 | *.py[cod] 215 | *$py.class 216 | 217 | # C extensions 218 | 219 | # Distribution / packaging 220 | .Python 221 | build/ 222 | develop-eggs/ 223 | dist/ 224 | downloads/ 225 | eggs/ 226 | .eggs/ 227 | lib/ 228 | lib64/ 229 | parts/ 230 | sdist/ 231 | var/ 232 | wheels/ 233 | share/python-wheels/ 234 | *.egg-info/ 235 | .installed.cfg 236 | *.egg 237 | MANIFEST 238 | 239 | # PyInstaller 240 | # Usually these files are written by a python script from a template 241 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 242 | *.manifest 243 | *.spec 244 | 245 | # Installer logs 246 | pip-log.txt 247 | pip-delete-this-directory.txt 248 | 249 | # Unit test / coverage reports 250 | htmlcov/ 251 | .tox/ 252 | .nox/ 253 | .coverage 254 | .coverage.* 255 | .cache 256 | nosetests.xml 257 | coverage.xml 258 | *.cover 259 | *.py,cover 260 | .hypothesis/ 261 | .pytest_cache/ 262 | cover/ 263 | 264 | # Translations 265 | *.mo 266 | *.pot 267 | 268 | # Django stuff: 269 | *.log 270 | local_settings.py 271 | db.sqlite3 272 | db.sqlite3-journal 273 | 274 | # Flask stuff: 275 | instance/ 276 | .webassets-cache 277 | 278 | # Scrapy stuff: 279 | .scrapy 280 | 281 | # Sphinx documentation 282 | docs/_build/ 283 | 284 | # PyBuilder 285 | .pybuilder/ 286 | target/ 287 | 288 | # Jupyter Notebook 289 | .ipynb_checkpoints 290 | 291 | # IPython 292 | profile_default/ 293 | ipython_config.py 294 | 295 | # pyenv 296 | # For a library or package, you might want to ignore these files since the code is 297 | # intended to run in multiple environments; otherwise, check them in: 298 | # .python-version 299 | 300 | # pipenv 301 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 302 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 303 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 304 | # install all needed dependencies. 305 | #Pipfile.lock 306 | 307 | # poetry 308 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 309 | # This is especially recommended for binary packages to ensure reproducibility, and is more 310 | # commonly ignored for libraries. 311 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 312 | #poetry.lock 313 | 314 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 315 | __pypackages__/ 316 | 317 | # Celery stuff 318 | celerybeat-schedule 319 | celerybeat.pid 320 | 321 | # SageMath parsed files 322 | *.sage.py 323 | 324 | # Environments 325 | .env 326 | .venv 327 | env/ 328 | venv/ 329 | ENV/ 330 | env.bak/ 331 | venv.bak/ 332 | 333 | # Spyder project settings 334 | .spyderproject 335 | .spyproject 336 | 337 | # Rope project settings 338 | .ropeproject 339 | 340 | # mkdocs documentation 341 | /site 342 | 343 | # mypy 344 | .mypy_cache/ 345 | .dmypy.json 346 | dmypy.json 347 | 348 | # Pyre type checker 349 | .pyre/ 350 | 351 | # pytype static type analyzer 352 | .pytype/ 353 | 354 | # Cython debug symbols 355 | cython_debug/ 356 | 357 | # PyCharm 358 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 359 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 360 | # and can be added to the global gitignore or merged into this file. For a more nuclear 361 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 362 | #.idea/ 363 | 364 | # End of https://www.toptal.com/developers/gitignore/api/python,c,c++,git,pycharm 365 | 366 | ## Project Post-.gitignore ## 367 | 368 | !device/lib 369 | msdk/ -------------------------------------------------------------------------------- /application_processor/src/simple_i2c_controller.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_i2c_controller.c" 3 | * @author Frederich Stine 4 | * @brief Simple Synchronous I2C Controller Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | 15 | #include "simple_i2c_controller.h" 16 | 17 | /******************************** FUNCTION PROTOTYPES ********************************/ 18 | /** 19 | * @brief Built-In I2C Interrupt Handler 20 | * 21 | * Utilize the built-in I2C interrupt handler to allow for the use 22 | * of MXC_I2C_Master_Transaction() function calls 23 | */ 24 | static void I2C_Handler(void) { MXC_I2C_AsyncHandler(I2C_INTERFACE); } 25 | 26 | /******************************** FUNCTION DEFINITIONS ********************************/ 27 | /** 28 | * @brief Initialize the I2C Connection 29 | * 30 | * Initialize the I2C by enabling the module, setting the correct 31 | * frequency, and enabling the interrupt to our I2C_Handler 32 | */ 33 | int i2c_simple_controller_init(void) { 34 | int error; 35 | 36 | // Initialize the I2C Interface 37 | error = MXC_I2C_Init(I2C_INTERFACE, true, 0); 38 | if (error != E_NO_ERROR) { 39 | printf("Failed to initialize I2C.\n"); 40 | return error; 41 | } 42 | // Set frequency to frequency macro 43 | MXC_I2C_SetFrequency(I2C_INTERFACE, I2C_FREQ); 44 | 45 | // Set up interrupt 46 | MXC_NVIC_SetVector(MXC_I2C_GET_IRQ(MXC_I2C_GET_IDX(I2C_INTERFACE)), I2C_Handler); 47 | NVIC_EnableIRQ(MXC_I2C_GET_IRQ(MXC_I2C_GET_IDX(I2C_INTERFACE))); 48 | 49 | return E_NO_ERROR; 50 | } 51 | 52 | /** 53 | * @brief Read RECEIVE_DONE reg 54 | * 55 | * @param addr: i2c_addr_t, address of I2C device 56 | * 57 | * @return int: RECEIVE_DONE value, negative if error 58 | * 59 | * Read the RECEIVE_DONE for an I2C peripheral 60 | * and return the value 61 | */ 62 | int i2c_simple_read_receive_done(i2c_addr_t addr) { 63 | return i2c_simple_read_status_generic(addr, RECEIVE_DONE); 64 | } 65 | 66 | /** 67 | * @brief Read RECEIVE_LEN reg 68 | * 69 | * @param addr: i2c_addr_t, address of I2C device 70 | * 71 | * @return uint8_t: RECEIVE_LEN value, negative if error 72 | * 73 | * Read the RECEIVE_LEN for an I2C peripheral 74 | * and return the value 75 | */ 76 | int i2c_simple_read_receive_len(i2c_addr_t addr) { 77 | return i2c_simple_read_status_generic(addr, RECEIVE_LEN); 78 | } 79 | 80 | /** 81 | * @brief Read TRANSMIT_DONE reg 82 | * 83 | * @param addr: i2c_addr_t, address of I2C device 84 | * 85 | * @return int: TRANSMIT_DONE value, negative if error 86 | * 87 | * Read the TRANSMIT_DONE for an I2C peripheral 88 | * and return the value 89 | */ 90 | int i2c_simple_read_transmit_done(i2c_addr_t addr) { 91 | return i2c_simple_read_status_generic(addr, TRANSMIT_DONE); 92 | } 93 | 94 | /** 95 | * @brief Read TRANSMIT_LEN reg 96 | * 97 | * @param addr: i2c_addr_t, address of I2C device 98 | * 99 | * @return int: TRANSMIT_LEN value, negative if error 100 | * 101 | * Read the TRANSMIT_LEN for an I2C peripheral 102 | * and return the value 103 | */ 104 | int i2c_simple_read_transmit_len(i2c_addr_t addr) { 105 | return i2c_simple_read_status_generic(addr, TRANSMIT_LEN); 106 | } 107 | 108 | /** 109 | * @brief Write RECEIVE_DONE reg 110 | * 111 | * @param addr: i2c_addr_t, address of I2C device 112 | * @param done: uint8_t, RECEIVE_DONE value 113 | * 114 | * @return int: negative if error, 0 if success 115 | * 116 | * Write the RECEIVE_DONE reg for an I2C peripheral to the 117 | * specified value 118 | */ 119 | int i2c_simple_write_receive_done(i2c_addr_t addr, bool done) { 120 | return i2c_simple_write_status_generic(addr, RECEIVE_DONE, done); 121 | } 122 | 123 | /** 124 | * @brief Write RECEIVE_LEN reg 125 | * 126 | * @param addr: i2c_addr_t, address of I2C device 127 | * @param len: uint8_t, RECEIVE_LEN value 128 | * 129 | * @return int: negative if error, 0 if success 130 | * 131 | * Write the RECEIVE_LEN reg for an I2C peripheral to the 132 | * specified value 133 | */ 134 | int i2c_simple_write_receive_len(i2c_addr_t addr, uint8_t len) { 135 | return i2c_simple_write_status_generic(addr, RECEIVE_LEN, len); 136 | } 137 | 138 | /** 139 | * @brief Write TRANSMIT_DONE reg 140 | * 141 | * @param addr: i2c_addr_t, address of I2C device 142 | * @param done: bool, TRANSMIT_DONE value 143 | * 144 | * @return int: negative if error, 0 if success 145 | * 146 | * Write the TRANSMIT_DONE reg for an I2C peripheral to the 147 | * specified value 148 | */ 149 | int i2c_simple_write_transmit_done(i2c_addr_t addr, bool done) { 150 | return i2c_simple_write_status_generic(addr, TRANSMIT_DONE, done); 151 | } 152 | 153 | /** 154 | * @brief Write TRANSMIT_LEN reg 155 | * 156 | * @param addr: i2c_addr_t, address of I2C device 157 | * @param len: uint8_t, TRANSMIT_LEN value 158 | * 159 | * @return int: negative if error, 0 if success 160 | * 161 | * Write the TRANSMIT_LEN reg for an I2C peripheral to the 162 | * specified value 163 | */ 164 | int i2c_simple_write_transmit_len(i2c_addr_t addr, uint8_t len) { 165 | return i2c_simple_write_status_generic(addr, TRANSMIT_LEN, len); 166 | } 167 | 168 | /** 169 | * @brief Read generic data reg 170 | * 171 | * @param addr: i2c_addr_t, address of I2C device 172 | * @param reg: ECTF_I2C_REGS, register to read from 173 | * @param len: uint8_t, length of data to read 174 | * @param buf: uint8_t*, buffer to read data into 175 | * 176 | * @return int: negative if error, 0 if success 177 | * 178 | * Read any register larger than 1B in size 179 | * Can be used to read the PARAMS or RESULT register 180 | */ 181 | int i2c_simple_read_data_generic(i2c_addr_t addr, ECTF_I2C_REGS reg, uint8_t len, uint8_t* buf) 182 | { 183 | mxc_i2c_req_t request; 184 | request.i2c = I2C_INTERFACE; 185 | request.addr = addr; 186 | request.tx_len = 1; 187 | request.tx_buf = (uint8_t*)® 188 | request.rx_len = (unsigned int) len; 189 | request.rx_buf = buf; 190 | request.restart = 0; 191 | request.callback = NULL; 192 | 193 | return MXC_I2C_MasterTransaction(&request); 194 | } 195 | 196 | /** 197 | * @brief Write generic data reg 198 | * 199 | * @param addr: i2c_addr_t, address of I2C device 200 | * @param reg: ECTF_I2C_REGS, register to write to 201 | * @param len: uint8_t, length of data to write 202 | * @param buf: uint8_t*, buffer to write data from 203 | * 204 | * @return int: negative if error, 0 if success 205 | * 206 | * Write any register larger than 1B in size 207 | * Can be used to write the PARAMS or RESULT register 208 | */ 209 | int i2c_simple_write_data_generic(i2c_addr_t addr, ECTF_I2C_REGS reg, uint8_t len, uint8_t* buf) { 210 | uint8_t packet[257]; 211 | packet[0] = reg; 212 | memcpy(&packet[1], buf, len); 213 | 214 | mxc_i2c_req_t request; 215 | request.i2c = I2C_INTERFACE; 216 | request.addr = addr; 217 | request.tx_len = len+1; 218 | request.tx_buf = packet; 219 | request.rx_len = 0; 220 | request.rx_buf = 0; 221 | request.restart = 0; 222 | request.callback = NULL; 223 | 224 | return MXC_I2C_MasterTransaction(&request); 225 | } 226 | 227 | /** 228 | * @brief Read generic status reg 229 | * 230 | * @param addr: i2c_addr_t, address of I2C device 231 | * @param reg: ECTF_I2C_REGS, register to read to 232 | * 233 | * @return int: value returned from device, negative if error 234 | * 235 | * Read any register that is 1B in size 236 | */ 237 | int i2c_simple_read_status_generic(i2c_addr_t addr, ECTF_I2C_REGS reg) { 238 | uint8_t value = 0; 239 | 240 | mxc_i2c_req_t request; 241 | request.i2c = I2C_INTERFACE; 242 | request.addr = addr; 243 | request.tx_len = 1; 244 | request.tx_buf = (uint8_t*)® 245 | request.rx_len = 1; 246 | request.rx_buf = (uint8_t*)&value; 247 | request.restart = 0; 248 | request.callback = NULL; 249 | 250 | int result = MXC_I2C_MasterTransaction(&request); 251 | if (result < 0) { 252 | return result; 253 | } 254 | return value; 255 | } 256 | 257 | /** 258 | * @brief Write generic status reg 259 | * 260 | * @param addr: i2c_addr_t, address of I2C device 261 | * @param reg: ECTF_I2C_REGS, register to write to 262 | * @param value: uint8_t, value to write to register 263 | * 264 | * @return int: negative if error, 0 if success 265 | * 266 | * Write any register that is 1B in size 267 | */ 268 | int i2c_simple_write_status_generic(i2c_addr_t addr, ECTF_I2C_REGS reg, uint8_t value) { 269 | uint8_t packet[2]; 270 | packet[0] = (uint8_t) reg; 271 | packet[1] = value; 272 | 273 | mxc_i2c_req_t request; 274 | request.i2c = I2C_INTERFACE; 275 | request.addr = addr; 276 | request.tx_len = 2; 277 | request.tx_buf = packet; 278 | request.rx_len = 0; 279 | request.rx_buf = 0; 280 | request.restart = 0; 281 | request.callback = NULL; 282 | 283 | return MXC_I2C_MasterTransaction(&request); 284 | } 285 | -------------------------------------------------------------------------------- /component/src/simple_i2c_peripheral.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file "simple_i2c_peripheral.c" 3 | * @author Frederich Stine 4 | * @brief Simple Asynchronous I2C Peripheral Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include "simple_i2c_peripheral.h" 15 | 16 | /******************************** GLOBAL DEFINITIONS ********************************/ 17 | // Data for all of the I2C registers 18 | volatile uint8_t RECEIVE_REG[MAX_I2C_MESSAGE_LEN]; 19 | volatile uint8_t RECEIVE_DONE_REG[1]; 20 | volatile uint8_t RECEIVE_LEN_REG[1]; 21 | volatile uint8_t TRANSMIT_REG[MAX_I2C_MESSAGE_LEN]; 22 | volatile uint8_t TRANSMIT_DONE_REG[1]; 23 | volatile uint8_t TRANSMIT_LEN_REG[1]; 24 | 25 | // Data structure to allow easy reference of I2C registers 26 | volatile uint8_t* I2C_REGS[6] = { 27 | [RECEIVE] = RECEIVE_REG, 28 | [RECEIVE_DONE] = RECEIVE_DONE_REG, 29 | [RECEIVE_LEN] = RECEIVE_LEN_REG, 30 | [TRANSMIT] = TRANSMIT_REG, 31 | [TRANSMIT_DONE] = TRANSMIT_DONE_REG, 32 | [TRANSMIT_LEN] = TRANSMIT_LEN_REG, 33 | }; 34 | 35 | // Data structure to allow easy reference to I2C register length 36 | int I2C_REGS_LEN[6] = { 37 | [RECEIVE] = MAX_I2C_MESSAGE_LEN, 38 | [RECEIVE_DONE] = 1, 39 | [RECEIVE_LEN] = 1, 40 | [TRANSMIT] = MAX_I2C_MESSAGE_LEN, 41 | [TRANSMIT_DONE] = 1, 42 | [TRANSMIT_LEN] = 1, 43 | }; 44 | 45 | /******************************** FUNCTION PROTOTYPES ********************************/ 46 | static void i2c_simple_isr(void); 47 | 48 | /******************************** FUNCTION DEFINITIONS ********************************/ 49 | /** 50 | * @brief Initialize the I2C Connection 51 | * 52 | * @param addr: uint8_t, the address of the I2C peripheral 53 | * 54 | * @return int: negative if error, zero if successful 55 | * 56 | * Initialize the I2C by enabling the module, setting the address, 57 | * setting the correct frequency, and enabling the interrupt to our i2c_simple_isr 58 | */ 59 | int i2c_simple_peripheral_init(uint8_t addr) { 60 | int error; 61 | // Initialize the I2C Interface 62 | error = MXC_I2C_Init(I2C_INTERFACE, false, addr); 63 | if (error != E_NO_ERROR) { 64 | printf("Failed to initialize I2C.\n"); 65 | return error; 66 | } 67 | 68 | // Set frequency and clear FIFO 69 | MXC_I2C_SetFrequency(I2C_INTERFACE, I2C_FREQ); 70 | MXC_I2C_ClearRXFIFO(I2C_INTERFACE); 71 | 72 | // Enable interrupts and link ISR 73 | MXC_I2C_EnableInt(I2C_INTERFACE, MXC_F_I2C_INTFL0_RD_ADDR_MATCH, 0); 74 | MXC_I2C_EnableInt(I2C_INTERFACE, MXC_F_I2C_INTFL0_WR_ADDR_MATCH, 0); 75 | MXC_I2C_EnableInt(I2C_INTERFACE, MXC_F_I2C_INTFL0_STOP, 0); 76 | MXC_NVIC_SetVector(MXC_I2C_GET_IRQ(MXC_I2C_GET_IDX(I2C_INTERFACE)), i2c_simple_isr); 77 | NVIC_EnableIRQ(MXC_I2C_GET_IRQ(MXC_I2C_GET_IDX(I2C_INTERFACE))); 78 | MXC_I2C_ClearFlags(I2C_INTERFACE, 0xFFFFFFFF, 0xFFFFFFFF); 79 | 80 | // Prefix READY values for registers 81 | I2C_REGS[RECEIVE_DONE][0] = false; 82 | I2C_REGS[TRANSMIT_DONE][0] = true; 83 | 84 | return E_NO_ERROR; 85 | } 86 | 87 | /** 88 | * @brief ISR for the I2C Peripheral 89 | * 90 | * This ISR allows for a fully asynchronous interface between controller and peripheral 91 | * Transactions are able to begin immediately after a transaction ends 92 | */ 93 | void i2c_simple_isr (void) { 94 | // Variables for state of ISR 95 | static bool WRITE_START = false; 96 | static int READ_INDEX = 0; 97 | static int WRITE_INDEX = 0; 98 | static ECTF_I2C_REGS ACTIVE_REG = RECEIVE; 99 | 100 | // Read interrupt flags 101 | uint32_t Flags = I2C_INTERFACE->intfl0; 102 | 103 | // Transaction over interrupt 104 | if (Flags & MXC_F_I2C_INTFL0_STOP) { 105 | 106 | // Ready any remaining data 107 | if (WRITE_START == true) { 108 | MXC_I2C_ReadRXFIFO(I2C_INTERFACE, (volatile unsigned char*) &ACTIVE_REG, 1); 109 | WRITE_START = false; 110 | } 111 | if (ACTIVE_REG <= MAX_REG) { 112 | int available = MXC_I2C_GetRXFIFOAvailable(I2C_INTERFACE); 113 | if (available < (I2C_REGS_LEN[ACTIVE_REG]-WRITE_INDEX)) { 114 | WRITE_INDEX += MXC_I2C_ReadRXFIFO(I2C_INTERFACE, 115 | &I2C_REGS[ACTIVE_REG][WRITE_INDEX], 116 | MXC_I2C_GetRXFIFOAvailable(I2C_INTERFACE)); 117 | } 118 | else { 119 | WRITE_INDEX += MXC_I2C_ReadRXFIFO(I2C_INTERFACE, 120 | &I2C_REGS[ACTIVE_REG][WRITE_INDEX], 121 | I2C_REGS_LEN[ACTIVE_REG]-WRITE_INDEX); 122 | } 123 | } else { 124 | MXC_I2C_ClearRXFIFO(I2C_INTERFACE); 125 | } 126 | 127 | // Disable bulk send/receive interrupts 128 | MXC_I2C_DisableInt(I2C_INTERFACE, MXC_F_I2C_INTEN0_RX_THD, 0); 129 | MXC_I2C_DisableInt(I2C_INTERFACE, MXC_F_I2C_INTEN0_TX_THD, 0); 130 | 131 | // Clear FIFOs if full 132 | if (MXC_I2C_GetRXFIFOAvailable(I2C_INTERFACE) != 0) { 133 | MXC_I2C_ClearRXFIFO(I2C_INTERFACE); 134 | } 135 | if (MXC_I2C_GetTXFIFOAvailable(I2C_INTERFACE) != 8) { 136 | MXC_I2C_ClearTXFIFO(I2C_INTERFACE); 137 | } 138 | 139 | // Reset state 140 | READ_INDEX = 0; 141 | WRITE_INDEX = 0; 142 | WRITE_START = false; 143 | 144 | // Clear ISR flag 145 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_STOP, 0); 146 | } 147 | 148 | // TX Fifo Threshold Met on Read 149 | if (Flags & MXC_F_I2C_INTEN0_TX_THD && (I2C_INTERFACE->inten0 & MXC_F_I2C_INTEN0_TX_THD)) { 150 | 151 | if (Flags & MXC_F_I2C_INTFL0_TX_LOCKOUT) { 152 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_TX_LOCKOUT, 0); 153 | } 154 | // 2 bytes in TX fifo triggers threshold by default 155 | // 8 byte FIFO length by default 156 | // More data is needed within the FIFO 157 | if (ACTIVE_REG <= MAX_REG) { 158 | READ_INDEX += MXC_I2C_WriteTXFIFO(I2C_INTERFACE, 159 | (volatile unsigned char*)&I2C_REGS[ACTIVE_REG][READ_INDEX], 160 | I2C_REGS_LEN[ACTIVE_REG]-READ_INDEX); 161 | if (I2C_REGS_LEN[ACTIVE_REG]-1 == READ_INDEX) { 162 | MXC_I2C_DisableInt(I2C_INTERFACE, MXC_F_I2C_INTEN0_TX_THD, 0); 163 | } 164 | } 165 | 166 | // Clear ISR flag 167 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_TX_THD, 0); 168 | } 169 | 170 | // Read from Peripheral from Controller Match 171 | if (Flags & MXC_F_I2C_INTFL0_WR_ADDR_MATCH) { 172 | // Clear ISR flag 173 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_WR_ADDR_MATCH, 0); 174 | 175 | // TX_LOCKOUT Triggers at the start of a just-in-time read 176 | if (Flags & MXC_F_I2C_INTFL0_TX_LOCKOUT) { 177 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_TX_LOCKOUT, 0); 178 | 179 | // Select active register 180 | MXC_I2C_ReadRXFIFO(I2C_INTERFACE, (volatile unsigned char*) &ACTIVE_REG, 1); 181 | 182 | // Write data to TX Buf 183 | if (ACTIVE_REG <= MAX_REG) { 184 | READ_INDEX += MXC_I2C_WriteTXFIFO(I2C_INTERFACE, (volatile unsigned char*)I2C_REGS[ACTIVE_REG], I2C_REGS_LEN[ACTIVE_REG]); 185 | if (READ_INDEX < I2C_REGS_LEN[ACTIVE_REG]) { 186 | MXC_I2C_EnableInt(I2C_INTERFACE, MXC_F_I2C_INTEN0_TX_THD, 0); 187 | } 188 | } 189 | } 190 | } 191 | 192 | // Write to Peripheral from Controller Match 193 | if (Flags & MXC_F_I2C_INTFL0_RD_ADDR_MATCH) { 194 | // Set write start variable 195 | WRITE_START = true; 196 | 197 | // Enable bulk receive interrupt 198 | MXC_I2C_EnableInt(I2C_INTERFACE, MXC_F_I2C_INTEN0_RX_THD, 0); 199 | 200 | // Clear flag 201 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_RD_ADDR_MATCH, 0); 202 | } 203 | 204 | // RX Fifo Threshold Met on Write 205 | if (Flags & MXC_F_I2C_INTEN0_RX_THD) { 206 | // We always write a register before writing data so select register 207 | if (WRITE_START == true) { 208 | MXC_I2C_ReadRXFIFO(I2C_INTERFACE, (volatile unsigned char*) &ACTIVE_REG, 1); 209 | WRITE_START = false; 210 | } 211 | // Read remaining data 212 | if (ACTIVE_REG <= MAX_REG) { 213 | int available = MXC_I2C_GetRXFIFOAvailable(I2C_INTERFACE); 214 | if (available < (I2C_REGS_LEN[ACTIVE_REG]-WRITE_INDEX)) { 215 | WRITE_INDEX += MXC_I2C_ReadRXFIFO(I2C_INTERFACE, 216 | &I2C_REGS[ACTIVE_REG][WRITE_INDEX], 217 | MXC_I2C_GetRXFIFOAvailable(I2C_INTERFACE)); 218 | } 219 | else { 220 | WRITE_INDEX += MXC_I2C_ReadRXFIFO(I2C_INTERFACE, 221 | &I2C_REGS[ACTIVE_REG][WRITE_INDEX], 222 | I2C_REGS_LEN[ACTIVE_REG]-WRITE_INDEX); 223 | } 224 | // Clear out FIFO if invalid register specified 225 | } else { 226 | MXC_I2C_ClearRXFIFO(I2C_INTERFACE); 227 | } 228 | 229 | // Clear ISR flag 230 | MXC_I2C_ClearFlags(I2C_INTERFACE, MXC_F_I2C_INTFL0_RX_THD, 0); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2024 The MITRE Corporation. All rights reserved 190 | Approved for Public Release; Distribution Unlimited. Case Number 23-03630-3R 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eCTF Insecure Example 2 | This repository holds the insecure example design for an eCTF MISC system. 3 | 4 | 5 | ## Layout 6 | 7 | - `application_processor` - Code for the application processor 8 | - `project.mk` - This file defines project specific variables included in the Makefile 9 | - `Makefile` - This makefile is invoked by the eCTF tools when creating a application processor 10 | - `inc` - Directory with c header files 11 | - `src` - Directory with c source files 12 | - `wolfssl` - Location to place wolfssl library for included Crypto Example 13 | - `deployment` - Code for deployment secret generation 14 | - `Makefile` - This makefile is invoked by the eCTF tools when creating a deployment 15 | - You may put other scripts here to invoke from the Makefile 16 | - `ectf_tools` - Host tools and build tools - DO NOT MODIFY ANYTHING IN THIS DIRECTORY 17 | - `attestation_tool.py` - Runs attestation command on application processor 18 | - `boot_tool.py` - Boots the application processor and sensors 19 | - `list_tool.py` - Lists what sensors are currently online 20 | - `replace_tool.py` - Replaces a sensor id on the application processor 21 | - `build tools` - Tools to build 22 | - `component` - Code for the components 23 | - `project.mk` - This file defines project specific variables included in the Makefile 24 | - `Makefile` - This makefile is invoked by the eCTF tools when creating a component 25 | - `inc` - Directory with c header files 26 | - `src` - Directory with c source files 27 | - `wolfssl` - Location to place wolfssl library for included Crypto Example 28 | - `shell.nix` - Nix configuration file for Nix environment 29 | - `custom_nix_pkgs` - Custom derived nix packages 30 | - `analog-openocd.nix` - Custom nix package to build Analog Devices fork of OpenOCD 31 | 32 | 33 | ## Usage and Requirements 34 | 35 | This repository contains two main elements: firmware source code and tooling. 36 | 37 | Firmware is built through the included eCTF Tools. These tools invoke the Makefiles 38 | in specific ways in the provided Nix environment. Firmware compiling should be executed 39 | through these included tools. 40 | 41 | Source code and tooling is provided that runs directly on the host. All of these tools are 42 | created in Python. The tools can be easily installed with the use of Poetry. Once inside 43 | of the activated Nix environment, run `poetry install` to initialize the Poetry environment. 44 | These tools can be invoked either through `poetry run {toolname}` or by activating the poetry environment 45 | with `poetry shell` and then running as standard python programs. 46 | 47 | ### Environment Build 48 | 49 | The environment is built with a Nix, which should install all packages 50 | necessary for running the design in a reproducible fashion. The environment is automatically 51 | built when an eCTF Build Tool is run. If building `analog_openocd.nix` this step may 52 | take some time to complete. 53 | 54 | Development can be prototyped by launching into the Nix environment through `nix-shell`. 55 | 56 | ### Host Tools 57 | 58 | Host Tools for the 2024 competition do not need to be modified by teams at any point. Your design 59 | should work with the standardized interface between host and MISC system. The host tools will 60 | pass any required arguments to the MISC system and receive all relevant output. 61 | 62 | ### Deployment 63 | 64 | When creating a deployment, the Makefile within the `deployment` folder of the design 65 | repo will be executed. This is the only stage in which information can be shared between 66 | separate portions of the build (e.g. components and application processors). A clean 67 | target should be implemented in this Makefile to allow for elimination of all generated secrets. 68 | 69 | ### Application Processor and Component 70 | 71 | When building the application processor and components, the `Makefile` with the 72 | respective directories will be invoked. The eCTF Tools will populate parameters into 73 | a C header file `ectf_params.h` within the design directory. Examples of these header 74 | files can be found in the respective main source files for the application processor 75 | and component. 76 | 77 | ## Using the eCTF Tools 78 | ### Building the deployment 79 | This will run the `Makefile` found in the deployment folder using the following inputs: 80 | 81 | ``` 82 | ectf_build_depl --help 83 | usage: eCTF Build Deployment Tool [-h] -d DESIGN 84 | 85 | Build a deployment using Nix 86 | 87 | options: 88 | -h, --help show this help message and exit 89 | -d DESIGN, --design DESIGN 90 | Path to the root directory of the included design 91 | ``` 92 | 93 | **Example Utilization** 94 | ```bash 95 | ectf_build_depl -d ../ectf-2024-example 96 | ``` 97 | ### Building the Application Processor 98 | This will run the `Makefile` found in the application processor folder using the following inputs: 99 | 100 | ``` 101 | ectf_build_ap --help 102 | usage: eCTF Build Application Processor Tool [-h] -d DESIGN -on OUTPUT_NAME [-od OUTPUT_DIR] -p P 103 | -b BOOT_MESSAGE 104 | 105 | Build an Application Processor using Nix 106 | 107 | options: 108 | -h, --help show this help message and exit 109 | -d DESIGN, --design DESIGN 110 | Path to the root directory of the included design 111 | -on OUTPUT_NAME, --output-name OUTPUT_NAME 112 | Output prefix of the built application processor binary Example 'ap' -> a 113 | -od OUTPUT_DIR, --output-dir OUTPUT_DIR 114 | Output name of the directory to store the result: default: . 115 | -p PIN, --pin PIN PIN for built application processor 116 | -t TOKEN, --token TOKEN 117 | Token for built application processor 118 | -c COMPONENT_CNT, --component-cnt COMPONENT_CNT 119 | Number of components to provision Application Processor for 120 | -ids COMPONENT_IDS, --component-ids COMPONENT_IDS 121 | Component IDs to provision the Application Processor for 122 | -b BOOT_MESSAGE, --boot-message BOOT_MESSAGE 123 | Application Processor boot message 124 | ``` 125 | 126 | **Example Utilization** 127 | ```bash 128 | ectf_build_ap -d ../ectf-2024-example -on ap --p 123456 -c 2 -ids "0x11111124, 0x11111125" -b "Test boot message" -t 0123456789abcdef -od build 129 | ``` 130 | 131 | ### Building the Component 132 | ``` 133 | ectf_build_comp --help 134 | usage: eCTF Build Application Processor Tool [-h] -d DESIGN -on OUTPUT_NAME [-od OUTPUT_DIR] -id COMPONENT_ID -b BOOT_MESSAGE -al 135 | ATTESTATION_LOCATION -ad ATTESTATION_DATE -ac ATTESTATION_CUSTOMER 136 | 137 | Build an Application Processor using Nix 138 | 139 | options: 140 | -h, --help show this help message and exit 141 | -d DESIGN, --design DESIGN 142 | Path to the root directory of the included design 143 | -on OUTPUT_NAME, --output-name OUTPUT_NAME 144 | Output prefix of the built application processor binary Example 'ap' -> ap.bin, ap.elf, ap.img 145 | -od OUTPUT_DIR, --output-dir OUTPUT_DIR 146 | Output name of the directory to store the result: default: . 147 | -id COMPONENT_ID, --component-id COMPONENT_ID 148 | Component ID for the provisioned component 149 | -b BOOT_MESSAGE, --boot-message BOOT_MESSAGE 150 | Component boot message 151 | -al ATTESTATION_LOCATION, --attestation-location ATTESTATION_LOCATION 152 | Attestation data location field 153 | -ad ATTESTATION_DATE, --attestation-date ATTESTATION_DATE 154 | Attestation data date field 155 | -ac ATTESTATION_CUSTOMER, --attestation-customer ATTESTATION_CUSTOMER 156 | Attestation data customer field 157 | ``` 158 | 159 | **Example Utilization** 160 | ```bash 161 | ectf_build_comp -d ../ectf-2024-example -on comp -od build -id 0x11111125 -b "Component boot" -al "McLean" -ad "08/08/08" -ac "Fritz" 162 | ``` 163 | 164 | ## Flashing 165 | Flashing the MAX78000 is done through the eCTF Bootloader. You will need to initially flash the eCTF Bootloader onto the provided hardware. 166 | This can be done easily by dragging and dropping the [provided bootloader](https://ectfmitre.gitlab.io/ectf-website/2024/components/bootloader.html) (for design phase:`insecure.bin`) to the DAPLink interface. DAPLink will show up as an external drive when connected to your system. Succesfull installation would make a blue LED flash on the board. 167 | 168 | To flash a specific bootloader image on the board (AP or Components), use `ectf_update`. 169 | ``` 170 | ectf_update [-h] --infile INFILE --port PORT 171 | 172 | optional arguments: 173 | -h, --help show this help message and exit 174 | --infile INFILE Path to the input binary 175 | --port PORT Serial port 176 | ``` 177 | 178 | **Example Utilization** 179 | ```bash 180 | ectf_update --infile example_fw/build/firmware.img --port /dev/ttyUSB0 181 | ``` 182 | 183 | ## Host Tools 184 | ### List Tool 185 | The list tool applies the required list components functionality from the MISC system. This is availble on the 186 | PATH within the Poetry environment as `ectf_list`. 187 | 188 | ``` 189 | ectf_list -h 190 | usage: eCTF List Host Tool [-h] -a APPLICATION_PROCESSOR 191 | 192 | List the components connected to the medical device 193 | 194 | options: 195 | -h, --help show this help message and exit 196 | -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR 197 | Serial device of the AP 198 | ``` 199 | 200 | **Example Utilization** 201 | ``` bash 202 | ectf_list -a /dev/ttyUSB0 203 | ``` 204 | 205 | ### Boot Tool 206 | The boot tool boots the full system. This is available on the PATH within the Poetry environment as `ectf_boot` 207 | 208 | ``` 209 | ectf_boot --help 210 | usage: eCTF Boot Host Tool [-h] -a APPLICATION_PROCESSOR 211 | 212 | Boot the medical device 213 | 214 | options: 215 | -h, --help show this help message and exit 216 | -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR 217 | Serial device of the AP 218 | ``` 219 | 220 | **Example Utilization** 221 | ``` bash 222 | ectf_boot -a /dev/ttyUSB0 223 | ``` 224 | 225 | ### Replace Tool 226 | The replace tool replaces a provisioned component on the system with a new component. 227 | This is available on the PATH within the Poetry environment as `ectf_replace`. 228 | 229 | ``` 230 | ectf_replace --help 231 | usage: eCTF Replace Host Tool [-h] -a APPLICATION_PROCESSOR -t TOKEN -i COMPONENT_IN -o COMPONENT_OUT 232 | 233 | Replace a component on the medical device 234 | 235 | options: 236 | -h, --help show this help message and exit 237 | -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR 238 | Serial device of the AP 239 | -t TOKEN, --token TOKEN 240 | Replacement token for the AP 241 | -i COMPONENT_IN, --component-in COMPONENT_IN 242 | Component ID of the new component 243 | -o COMPONENT_OUT, --component-out COMPONENT_OUT 244 | Component ID of the component being replaced 245 | ``` 246 | 247 | **Example Utilization** 248 | ``` bash 249 | ectf_replace -a /dev/ttyUSB0 -t 0123456789abcdef -i 0x11111126 -o 0x11111125 250 | ``` 251 | 252 | ### Attestation Tool 253 | The attestation tool returns the confidential attestation data provisioned on a component. 254 | This is available on the PATH within the Poetry environment as `ectf_attestation`. 255 | 256 | ``` 257 | ectf_attestation --help 258 | usage: eCTF Attestation Host Tool [-h] -a APPLICATION_PROCESSOR -p PIN -c COMPONENT 259 | 260 | Return the attestation data from a component 261 | 262 | options: 263 | -h, --help show this help message and exit 264 | -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR 265 | Serial device of the AP 266 | -p PIN, --pin PIN PIN for the AP 267 | -c COMPONENT, --component COMPONENT 268 | Component ID of the target component 269 | ``` 270 | 271 | **Example Utilization** 272 | ``` 273 | ectf_attestation -a /dev/ttyUSB0 -p 123456 -c 0x11111124 274 | ``` 275 | -------------------------------------------------------------------------------- /application_processor/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation 7 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | # and/or sell copies of the Software, and to permit persons to whom the 9 | # Software is furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included 12 | # in all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | # IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 18 | # OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | # OTHER DEALINGS IN THE SOFTWARE. 21 | # 22 | # Except as contained in this notice, the name of Maxim Integrated 23 | # Products, Inc. shall not be used except as stated in the Maxim Integrated 24 | # Products, Inc. Branding Policy. 25 | # 26 | # The mere transfer of this software does not imply any licenses 27 | # of trade secrets, proprietary technology, copyrights, patents, 28 | # trademarks, maskwork rights, or any other form of intellectual 29 | # property whatsoever. Maxim Integrated Products, Inc. retains all 30 | # ownership rights. 31 | # 32 | ############################################################################### 33 | 34 | # ** Readme! ** 35 | # Don't edit this file! This is the core Makefile for a MaximSDK 36 | # project. The available configuration options can be overridden 37 | # in "project.mk", on the command-line, or with system environment 38 | # variables. 39 | 40 | # See https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system 41 | # for more detailed instructions on how to use this system. 42 | 43 | # The detailed instructions mentioned above are easier to read than 44 | # this file, but the comments found in this file also outline the 45 | # available configuration variables. This file is organized into 46 | # sub-sections, some of which expose config variables. 47 | 48 | 49 | # ******************************************************************************* 50 | # Set the target microcontroller and board to compile for. 51 | 52 | # Every TARGET microcontroller has some Board Support Packages (BSPs) that are 53 | # available for it under the MaximSDK/Libraries/Boards/TARGET folder. The BSP 54 | # that gets selected is MaximSDK/Libraries/Boards/TARGET/BOARD. 55 | 56 | # Configuration Variables: 57 | # - TARGET : Override the default target microcontroller. Ex: TARGET=MAX78000 58 | # - BOARD : Override the default BSP (case sensitive). Ex: BOARD=EvKit_V1, BOARD=FTHR_RevA 59 | 60 | 61 | ifeq "$(TARGET)" "" 62 | # Default target microcontroller 63 | TARGET := MAX78000 64 | TARGET_UC := MAX78000 65 | TARGET_LC := max78000 66 | else 67 | # "TARGET" has been overridden in the environment or on the command-line. 68 | # We need to calculate an upper and lowercase version of the part number, 69 | # because paths on Linux and MacOS are case-sensitive. 70 | TARGET_UC := $(subst m,M,$(subst a,A,$(subst x,X,$(TARGET)))) 71 | TARGET_LC := $(subst M,m,$(subst A,a,$(subst X,x,$(TARGET)))) 72 | endif 73 | 74 | # Default board. 75 | BOARD ?= EvKit_V1 76 | 77 | # ******************************************************************************* 78 | # Locate the MaximSDK 79 | 80 | # This Makefile needs to know where to find the MaximSDK, and the MAXIM_PATH variable 81 | # should point to the root directory of the MaximSDK installation. Setting this manually 82 | # is usually only required if you're working on the command-line. 83 | 84 | # If MAXIM_PATH is not specified, we assume the project still lives inside of the MaximSDK 85 | # and move up from this project's original location. 86 | 87 | # Configuration Variables: 88 | # - MAXIM_PATH : Tell this Makefile where to find the MaximSDK. Ex: MAXIM_PATH=C:/MaximSDK 89 | 90 | 91 | ifneq "$(MAXIM_PATH)" "" 92 | # Sanitize MAXIM_PATH for backslashes 93 | MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) 94 | # Locate some other useful paths... 95 | LIBS_DIR := $(abspath $(MAXIM_PATH)/Libraries) 96 | CMSIS_ROOT := $(LIBS_DIR)/CMSIS 97 | endif 98 | 99 | # ******************************************************************************* 100 | # Include project Makefile. We do this after formulating TARGET, BOARD, and MAXIM_PATH 101 | # in case project.mk needs to reference those values. However, we also include 102 | # this as early as possible in the Makefile so that it can append to or override 103 | # the variables below. 104 | 105 | 106 | PROJECTMK ?= $(abspath ./project.mk) 107 | include $(PROJECTMK) 108 | $(info Loaded project.mk) 109 | # PROJECTMK is also used by implicit rules and other libraries to add project.mk as a watch file 110 | 111 | # ******************************************************************************* 112 | # Final path sanitization and re-calculation. No options here. 113 | 114 | ifeq "$(MAXIM_PATH)" "" 115 | # MAXIM_PATH is still not defined... 116 | DEPTH := ../../../ 117 | MAXIM_PATH := $(abspath $(DEPTH)) 118 | $(warning Warning: MAXIM_PATH is not set! Set MAXIM_PATH in your environment or in project.mk to clear this warning.) 119 | $(warning Warning: Attempting to use $(MAXIM_PATH) calculated from relative path) 120 | else 121 | # Sanitize MAXIM_PATH for backslashes 122 | MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) 123 | endif 124 | 125 | # Final recalculation of LIBS_DIR/CMSIS_ROOT 126 | LIBS_DIR := $(abspath $(MAXIM_PATH)/Libraries) 127 | CMSIS_ROOT := $(LIBS_DIR)/CMSIS 128 | 129 | # One final UC/LC check in case user set TARGET in project.mk 130 | TARGET_UC := $(subst m,M,$(subst a,A,$(subst x,X,$(TARGET)))) 131 | TARGET_LC := $(subst M,m,$(subst A,a,$(subst X,x,$(TARGET)))) 132 | 133 | export TARGET 134 | export TARGET_UC 135 | export TARGET_LC 136 | export CMSIS_ROOT 137 | # TODO: Remove dependency on exports for these variables. 138 | 139 | # ******************************************************************************* 140 | # Set up search paths, and auto-detect all source code on those paths. 141 | 142 | # The following paths are searched by default, where "./" is the project directory. 143 | # ./ 144 | # |- *.h 145 | # |- *.c 146 | # |-include (optional) 147 | # |- *.h 148 | # |-src (optional) 149 | # |- *.c 150 | 151 | # Configuration Variables: 152 | # - VPATH : Tell this Makefile to search additional locations for source (.c) files. 153 | # You should use the "+=" operator with this option. 154 | # Ex: VPATH += your/new/path 155 | # - IPATH : Tell this Makefile to search additional locations for header (.h) files. 156 | # You should use the "+=" operator with this option. 157 | # Ex: VPATH += your/new/path 158 | # - SRCS : Tell this Makefile to explicitly add a source (.c) file to the build. 159 | # This is really only useful if you want to add a source file that isn't 160 | # on any VPATH, in which case you can add the full path to the file here. 161 | # You should use the "+=" operator with this option. 162 | # Ex: SRCS += your/specific/source/file.c 163 | # - AUTOSEARCH : Set whether this Makefile should automatically detect .c files on 164 | # VPATH and add them to the build. This is enabled by default. Set 165 | # to 0 to disable. If autosearch is disabled, source files must be 166 | # manually added to SRCS. 167 | # Ex: AUTOSEARCH = 0 168 | 169 | 170 | # Where to find source files for this project. 171 | VPATH += . 172 | VPATH += src 173 | 174 | # eCTF Crypto Example 175 | ifeq ($(CRYPTO_EXAMPLE), 1) 176 | VPATH += wolfssl/wolfcrypt/src 177 | endif 178 | 179 | VPATH := $(VPATH) 180 | 181 | # Where to find header files for this project 182 | IPATH += . 183 | IPATH += include 184 | # eCTF Crypto Example 185 | ifeq ($(CRYPTO_EXAMPLE), 1) 186 | IPATH += wolfssl 187 | endif 188 | IPATH := $(IPATH) 189 | 190 | AUTOSEARCH ?= 1 191 | ifeq ($(AUTOSEARCH), 1) 192 | # Auto-detect all C source files on VPATH 193 | SRCS += $(wildcard $(addsuffix /*.c, $(VPATH))) 194 | endif 195 | 196 | # Collapse SRCS before passing them on to the next stage 197 | SRCS := $(SRCS) 198 | 199 | # ******************************************************************************* 200 | # Set the output filename 201 | 202 | # Configuration Variables: 203 | # - PROJECT : Override the default output filename. Ex: PROJECT=MyProject 204 | 205 | 206 | # The default value creates a file named after the target micro. Ex: MAX78000.elf 207 | PROJECT ?= $(TARGET_LC) 208 | 209 | # ******************************************************************************* 210 | # Compiler options 211 | 212 | # Configuration Variables: 213 | # - DEBUG : Set DEBUG=1 to build explicitly for debugging. This adds some additional 214 | # symbols and sets -Og as the default optimization level. 215 | # - MXC_OPTIMIZE_CFLAGS : Override the default compiler optimization level. 216 | # Ex: MXC_OPTIMIZE_CFLAGS = -O2 217 | # - PROJ_CFLAGS : Add additional compiler flags to the build. 218 | # You should use the "+=" operator with this option. 219 | # Ex: PROJ_CFLAGS += -Wextra 220 | # - MFLOAT_ABI : Set the floating point acceleration level. 221 | # The only options are "hard", "soft", or "softfp". 222 | # Ex: MFLOAT_ABI = hard 223 | # - LINKERFILE : Override the default linkerfile. 224 | # Ex: LINKERFILE = customlinkerfile.ld 225 | # - LINKERPATH : Override the default search location for $(LINKERFILE) 226 | # The default search location is $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/GCC 227 | # If $(LINKERFILE) cannot be found at this path, then the root project 228 | # directory will be used as a fallback. 229 | 230 | # Select 'GCC' or 'IAR' compiler 231 | ifeq "$(COMPILER)" "" 232 | COMPILER := GCC 233 | endif 234 | 235 | # Set default compiler optimization levels 236 | ifeq "$(MAKECMDGOALS)" "release" 237 | # Default optimization level for "release" builds (make release) 238 | MXC_OPTIMIZE_CFLAGS ?= -O2 239 | DEBUG = 0 240 | endif 241 | 242 | ifeq ($(DEBUG),1) 243 | # Optimizes for debugging as recommended 244 | # by GNU for code-edit-debug cycles 245 | # https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options 246 | MXC_OPTIMIZE_CFLAGS := -Og 247 | endif 248 | 249 | # Default level if not building for release or explicitly for debug 250 | MXC_OPTIMIZE_CFLAGS ?= -O2 251 | 252 | # Set compiler flags 253 | PROJ_CFLAGS += -Wall # Enable warnings 254 | ifeq ($(CRYPTO_EXAMPLE), 1) 255 | PROJ_CFLAGS += -DMXC_ASSERT_ENABLE 256 | # eCTF Crypto Example - WolfSSL Flags 257 | PROJ_CFLAGS += -DNO_WOLFSSL_DIR 258 | PROJ_CFLAGS += -DWOLFSSL_AES_DIRECT 259 | PROJ_CFLAGS += -DCRYPTO_EXAMPLE=1 260 | # From https://www.wolfssl.com/documentation/manuals/wolfssl/chapter02.html#building-with-gcc-arm 261 | PROJ_CFLAGS += -DHAVE_PK_CALLBACKS 262 | PROJ_CFLAGS += -DWOLFSSL_USER_IO 263 | PROJ_CFLAGS += -DNO_WRITEV -DTIME_T_NOT_64BIT 264 | endif 265 | 266 | ifeq ($(POST_BOOT_ENABLED), 1) 267 | PROJ_CFLAGS += -DPOST_BOOT=$(POST_BOOT_CODE) 268 | endif 269 | 270 | # Set hardware floating point acceleration. 271 | # Options are: 272 | # - hard 273 | # - soft 274 | # - softfp (default if MFLOAT_ABI is not set) 275 | MFLOAT_ABI ?= softfp 276 | # MFLOAT_ABI must be exported to other Makefiles 277 | export MFLOAT_ABI 278 | 279 | ifeq "$(RISCV_CORE)" "" 280 | # Default linkerfile is only specified for standard Arm-core projects. 281 | # Otherwise, gcc_riscv.mk sets the appropriate riscv linkerfile. 282 | LINKERFILE ?= $(TARGET_LC).ld 283 | LINKERPATH ?= $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/GCC 284 | 285 | # Check if linkerfile exists 286 | ifeq ("$(wildcard $(LINKERPATH)/$(LINKERFILE))","") 287 | # Doesn't exists, attempt to use root project folder. 288 | LINKERPATH:=. 289 | endif 290 | 291 | # Form full path to linkerfile. Works around MSYS2 edge case from (see MSDK-903). 292 | LINKERFILE:=$(LINKERPATH)/$(LINKERFILE) 293 | endif 294 | 295 | # This path contains system-level intialization files for the target micro. Add to the build. 296 | VPATH += $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source 297 | 298 | # ******************************************************************************* 299 | # Secure Boot Tools (SBT) 300 | 301 | # This section integrates the Secure Boot Tools. It's intended for use with 302 | # microcontrollers that have a secure bootloader. 303 | 304 | # Enabling SBT integration will add some special rules, such as "make sla", "make scpa", etc. 305 | 306 | # Configuration variables: 307 | # SBT : Toggle SBT integration. Set to 1 to enable, or 0 308 | # to disable 309 | # MAXIM_SBT_DIR : Specify the location of the SBT tool binaries. This defaults to 310 | # Tools/SBT in the MaximSDK. The standalone SBT installer will override 311 | # this via an environment variable. 312 | # TARGET_SEC : Specify the part number to be passed into the SBT. This should match 313 | # the secure variant part #. The default value will depend on TARGET. 314 | # For example, TARGET=MAX32650 will result in TARGET_SEC=MAX32651, and 315 | # the default selection happens in Tools/SBT/SBT-config. 316 | # However, if there are multiple secure part #s for the target 317 | # microcontroller this variable may need to be changed. 318 | 319 | SBT ?= 0 320 | ifeq ($(SBT), 1) 321 | MAXIM_SBT_DIR ?= $(MAXIM_PATH)/Tools/SBT 322 | MAXIM_SBT_DIR := $(subst \,/,$(MAXIM_SBT_DIR)) 323 | # ^ Must sanitize path for \ on Windows, since this may come from an environment 324 | # variable. 325 | 326 | export MAXIM_SBT_DIR # SBTs must have this environment variable defined to work 327 | 328 | # SBT-config.mk and SBT-rules.mk are included further down this Makefile. 329 | 330 | endif # SBT 331 | 332 | # ******************************************************************************* 333 | # Default goal selection. This section allows you to override the default goal 334 | # that will run if no targets are specified on the command-line. 335 | # (ie. just running 'make' instead of 'make all') 336 | 337 | # Configuration variables: 338 | # .DEFAULT_GOAL : Set the default goal if no targets were specified on the 339 | # command-line 340 | # ** "override" must be used with this variable. ** 341 | # Ex: "override .DEFAULT_GOAL = mygoal" 342 | 343 | ifeq "$(.DEFAULT_GOAL)" "" 344 | ifeq ($(SBT),1) 345 | override .DEFAULT_GOAL := sla 346 | else 347 | override .DEFAULT_GOAL := all 348 | endif 349 | endif 350 | 351 | # Developer note: 'override' is used above for legacy Makefile compatibility. 352 | # gcc.mk/gcc_riscv.mk need to hard-set 'all' internally, so this new system 353 | # uses 'override' to come in over the top without breaking old projects. 354 | 355 | # It's also necessary to explicitly set MAKECMDGOALS... 356 | ifeq "$(MAKECMDGOALS)" "" 357 | MAKECMDGOALS:=$(.DEFAULT_GOAL) 358 | endif 359 | 360 | # Enable colors when --sync-output is used. 361 | # See https://www.gnu.org/software/make/manual/make.html#Terminal-Output (section 13.2) 362 | ifneq ($(MAKE_TERMOUT),) 363 | PROJ_CFLAGS += -fdiagnostics-color=always 364 | endif 365 | 366 | ifneq ($(FORCE_COLOR),) 367 | PROJ_CFLAGS += -fdiagnostics-color=always 368 | endif 369 | 370 | # ******************************************************************************* 371 | # Include SBT config. We need to do this here because it needs to know 372 | # the current MAKECMDGOAL. 373 | ifeq ($(SBT),1) 374 | include $(MAXIM_PATH)/Tools/SBT/SBT-config.mk 375 | endif 376 | 377 | # ******************************************************************************* 378 | # Libraries 379 | 380 | # This section offers "toggle switches" to include or exclude the libraries that 381 | # are available in the MaximSDK. Set a configuration variable to 1 to include the 382 | # library in the build, or 0 to exclude. 383 | 384 | # Each library may also have its own library specific configuration variables. See 385 | # Libraries/libs.mk for more details. 386 | 387 | # Configuration variables: 388 | # - LIB_BOARD : Include the Board-Support Package (BSP) library. (Enabled by default) 389 | # - LIB_PERIPHDRIVERS : Include the peripheral driver library. (Enabled by default) 390 | # - LIB_CMSIS_DSP : Include the CMSIS-DSP library. 391 | # - LIB_CORDIO : Include the Cordio BLE library 392 | # - LIB_FCL : Include the Free Cryptographic Library (FCL) 393 | # - LIB_FREERTOS : Include the FreeRTOS and FreeRTOS-Plus-CLI libraries 394 | # - LIB_LC3 : Include the Low Complexity Communication Codec (LC3) library 395 | # - LIB_LITTLEFS : Include the "little file system" (littleFS) library 396 | # - LIB_LWIP : Include the lwIP library 397 | # - LIB_MAXUSB : Include the MAXUSB library 398 | # - LIB_SDHC : Include the SDHC library 399 | 400 | include $(LIBS_DIR)/libs.mk 401 | 402 | 403 | # ******************************************************************************* 404 | # Rules 405 | 406 | # Include the rules for building for this target. All other makefiles should be 407 | # included before this one. 408 | include $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/$(COMPILER)/$(TARGET_LC).mk 409 | 410 | # Include the rules that integrate the SBTs. SBTs are a special case that must be 411 | # include after the core gcc rules to extend them. 412 | ifeq ($(SBT), 1) 413 | include $(MAXIM_PATH)/Tools/SBT/SBT-rules.mk 414 | endif 415 | 416 | 417 | # Get .DEFAULT_GOAL working. 418 | ifeq "$(MAKECMDGOALS)" "" 419 | MAKECMDGOALS:=$(.DEFAULT_GOAL) 420 | endif 421 | 422 | 423 | all: 424 | # Extend the functionality of the "all" recipe here 425 | arm-none-eabi-size --format=berkeley $(BUILD_DIR)/$(PROJECT).elf 426 | 427 | libclean: 428 | $(MAKE) -f ${PERIPH_DRIVER_DIR}/periphdriver.mk clean.periph 429 | 430 | clean: 431 | # Extend the functionality of the "clean" recipe here 432 | 433 | # The rule to clean out all the build products. 434 | distclean: clean libclean 435 | -------------------------------------------------------------------------------- /component/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation 7 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | # and/or sell copies of the Software, and to permit persons to whom the 9 | # Software is furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included 12 | # in all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | # IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 18 | # OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | # OTHER DEALINGS IN THE SOFTWARE. 21 | # 22 | # Except as contained in this notice, the name of Maxim Integrated 23 | # Products, Inc. shall not be used except as stated in the Maxim Integrated 24 | # Products, Inc. Branding Policy. 25 | # 26 | # The mere transfer of this software does not imply any licenses 27 | # of trade secrets, proprietary technology, copyrights, patents, 28 | # trademarks, maskwork rights, or any other form of intellectual 29 | # property whatsoever. Maxim Integrated Products, Inc. retains all 30 | # ownership rights. 31 | # 32 | ############################################################################### 33 | 34 | # ** Readme! ** 35 | # Don't edit this file! This is the core Makefile for a MaximSDK 36 | # project. The available configuration options can be overridden 37 | # in "project.mk", on the command-line, or with system environment 38 | # variables. 39 | 40 | # See https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system 41 | # for more detailed instructions on how to use this system. 42 | 43 | # The detailed instructions mentioned above are easier to read than 44 | # this file, but the comments found in this file also outline the 45 | # available configuration variables. This file is organized into 46 | # sub-sections, some of which expose config variables. 47 | 48 | 49 | # ******************************************************************************* 50 | # Set the target microcontroller and board to compile for. 51 | 52 | # Every TARGET microcontroller has some Board Support Packages (BSPs) that are 53 | # available for it under the MaximSDK/Libraries/Boards/TARGET folder. The BSP 54 | # that gets selected is MaximSDK/Libraries/Boards/TARGET/BOARD. 55 | 56 | # Configuration Variables: 57 | # - TARGET : Override the default target microcontroller. Ex: TARGET=MAX78000 58 | # - BOARD : Override the default BSP (case sensitive). Ex: BOARD=EvKit_V1, BOARD=FTHR_RevA 59 | 60 | 61 | ifeq "$(TARGET)" "" 62 | # Default target microcontroller 63 | TARGET := MAX78000 64 | TARGET_UC := MAX78000 65 | TARGET_LC := max78000 66 | else 67 | # "TARGET" has been overridden in the environment or on the command-line. 68 | # We need to calculate an upper and lowercase version of the part number, 69 | # because paths on Linux and MacOS are case-sensitive. 70 | TARGET_UC := $(subst m,M,$(subst a,A,$(subst x,X,$(TARGET)))) 71 | TARGET_LC := $(subst M,m,$(subst A,a,$(subst X,x,$(TARGET)))) 72 | endif 73 | 74 | # Default board. 75 | BOARD ?= EvKit_V1 76 | 77 | # ******************************************************************************* 78 | # Locate the MaximSDK 79 | 80 | # This Makefile needs to know where to find the MaximSDK, and the MAXIM_PATH variable 81 | # should point to the root directory of the MaximSDK installation. Setting this manually 82 | # is usually only required if you're working on the command-line. 83 | 84 | # If MAXIM_PATH is not specified, we assume the project still lives inside of the MaximSDK 85 | # and move up from this project's original location. 86 | 87 | # Configuration Variables: 88 | # - MAXIM_PATH : Tell this Makefile where to find the MaximSDK. Ex: MAXIM_PATH=C:/MaximSDK 89 | 90 | 91 | ifneq "$(MAXIM_PATH)" "" 92 | # Sanitize MAXIM_PATH for backslashes 93 | MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) 94 | # Locate some other useful paths... 95 | LIBS_DIR := $(abspath $(MAXIM_PATH)/Libraries) 96 | CMSIS_ROOT := $(LIBS_DIR)/CMSIS 97 | endif 98 | 99 | # ******************************************************************************* 100 | # Include project Makefile. We do this after formulating TARGET, BOARD, and MAXIM_PATH 101 | # in case project.mk needs to reference those values. However, we also include 102 | # this as early as possible in the Makefile so that it can append to or override 103 | # the variables below. 104 | 105 | 106 | PROJECTMK ?= $(abspath ./project.mk) 107 | include $(PROJECTMK) 108 | $(info Loaded project.mk) 109 | # PROJECTMK is also used by implicit rules and other libraries to add project.mk as a watch file 110 | 111 | # ******************************************************************************* 112 | # Final path sanitization and re-calculation. No options here. 113 | 114 | ifeq "$(MAXIM_PATH)" "" 115 | # MAXIM_PATH is still not defined... 116 | DEPTH := ../../../ 117 | MAXIM_PATH := $(abspath $(DEPTH)) 118 | $(warning Warning: MAXIM_PATH is not set! Set MAXIM_PATH in your environment or in project.mk to clear this warning.) 119 | $(warning Warning: Attempting to use $(MAXIM_PATH) calculated from relative path) 120 | else 121 | # Sanitize MAXIM_PATH for backslashes 122 | MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) 123 | endif 124 | 125 | # Final recalculation of LIBS_DIR/CMSIS_ROOT 126 | LIBS_DIR := $(abspath $(MAXIM_PATH)/Libraries) 127 | CMSIS_ROOT := $(LIBS_DIR)/CMSIS 128 | 129 | # One final UC/LC check in case user set TARGET in project.mk 130 | TARGET_UC := $(subst m,M,$(subst a,A,$(subst x,X,$(TARGET)))) 131 | TARGET_LC := $(subst M,m,$(subst A,a,$(subst X,x,$(TARGET)))) 132 | 133 | export TARGET 134 | export TARGET_UC 135 | export TARGET_LC 136 | export CMSIS_ROOT 137 | # TODO: Remove dependency on exports for these variables. 138 | 139 | # ******************************************************************************* 140 | # Set up search paths, and auto-detect all source code on those paths. 141 | 142 | # The following paths are searched by default, where "./" is the project directory. 143 | # ./ 144 | # |- *.h 145 | # |- *.c 146 | # |-include (optional) 147 | # |- *.h 148 | # |-src (optional) 149 | # |- *.c 150 | 151 | # Configuration Variables: 152 | # - VPATH : Tell this Makefile to search additional locations for source (.c) files. 153 | # You should use the "+=" operator with this option. 154 | # Ex: VPATH += your/new/path 155 | # - IPATH : Tell this Makefile to search additional locations for header (.h) files. 156 | # You should use the "+=" operator with this option. 157 | # Ex: VPATH += your/new/path 158 | # - SRCS : Tell this Makefile to explicitly add a source (.c) file to the build. 159 | # This is really only useful if you want to add a source file that isn't 160 | # on any VPATH, in which case you can add the full path to the file here. 161 | # You should use the "+=" operator with this option. 162 | # Ex: SRCS += your/specific/source/file.c 163 | # - AUTOSEARCH : Set whether this Makefile should automatically detect .c files on 164 | # VPATH and add them to the build. This is enabled by default. Set 165 | # to 0 to disable. If autosearch is disabled, source files must be 166 | # manually added to SRCS. 167 | # Ex: AUTOSEARCH = 0 168 | 169 | 170 | # Where to find source files for this project. 171 | VPATH += . 172 | VPATH += src 173 | 174 | # eCTF Crypto Example 175 | ifeq ($(CRYPTO_EXAMPLE), 1) 176 | VPATH += wolfssl/wolfcrypt/src 177 | endif 178 | 179 | VPATH := $(VPATH) 180 | 181 | # Where to find header files for this project 182 | IPATH += . 183 | IPATH += include 184 | 185 | # eCTF Crypto Example 186 | ifeq ($(CRYPTO_EXAMPLE), 1) 187 | IPATH += wolfssl 188 | endif 189 | 190 | IPATH := $(IPATH) 191 | 192 | AUTOSEARCH ?= 1 193 | ifeq ($(AUTOSEARCH), 1) 194 | # Auto-detect all C source files on VPATH 195 | SRCS += $(wildcard $(addsuffix /*.c, $(VPATH))) 196 | endif 197 | 198 | # Collapse SRCS before passing them on to the next stage 199 | SRCS := $(SRCS) 200 | 201 | # ******************************************************************************* 202 | # Set the output filename 203 | 204 | # Configuration Variables: 205 | # - PROJECT : Override the default output filename. Ex: PROJECT=MyProject 206 | 207 | 208 | # The default value creates a file named after the target micro. Ex: MAX78000.elf 209 | PROJECT ?= $(TARGET_LC) 210 | 211 | # ******************************************************************************* 212 | # Compiler options 213 | 214 | # Configuration Variables: 215 | # - DEBUG : Set DEBUG=1 to build explicitly for debugging. This adds some additional 216 | # symbols and sets -Og as the default optimization level. 217 | # - MXC_OPTIMIZE_CFLAGS : Override the default compiler optimization level. 218 | # Ex: MXC_OPTIMIZE_CFLAGS = -O2 219 | # - PROJ_CFLAGS : Add additional compiler flags to the build. 220 | # You should use the "+=" operator with this option. 221 | # Ex: PROJ_CFLAGS += -Wextra 222 | # - MFLOAT_ABI : Set the floating point acceleration level. 223 | # The only options are "hard", "soft", or "softfp". 224 | # Ex: MFLOAT_ABI = hard 225 | # - LINKERFILE : Override the default linkerfile. 226 | # Ex: LINKERFILE = customlinkerfile.ld 227 | # - LINKERPATH : Override the default search location for $(LINKERFILE) 228 | # The default search location is $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/GCC 229 | # If $(LINKERFILE) cannot be found at this path, then the root project 230 | # directory will be used as a fallback. 231 | 232 | # Select 'GCC' or 'IAR' compiler 233 | ifeq "$(COMPILER)" "" 234 | COMPILER := GCC 235 | endif 236 | 237 | # Set default compiler optimization levels 238 | ifeq "$(MAKECMDGOALS)" "release" 239 | # Default optimization level for "release" builds (make release) 240 | MXC_OPTIMIZE_CFLAGS ?= -O2 241 | DEBUG = 0 242 | endif 243 | 244 | ifeq ($(DEBUG),1) 245 | # Optimizes for debugging as recommended 246 | # by GNU for code-edit-debug cycles 247 | # https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options 248 | MXC_OPTIMIZE_CFLAGS := -Og 249 | endif 250 | 251 | # Default level if not building for release or explicitly for debug 252 | MXC_OPTIMIZE_CFLAGS ?= -O2 253 | 254 | # Set compiler flags 255 | PROJ_CFLAGS += -Wall # Enable warnings 256 | ifeq ($(CRYPTO_EXAMPLE), 1) 257 | PROJ_CFLAGS += -DMXC_ASSERT_ENABLE 258 | # eCTF Crypto Example - WolfSSL Flags 259 | PROJ_CFLAGS += -DNO_WOLFSSL_DIR 260 | PROJ_CFLAGS += -DWOLFSSL_AES_DIRECT 261 | PROJ_CFLAGS += -DCRYPTO_EXAMPLE=1 262 | # From https://www.wolfssl.com/documentation/manuals/wolfssl/chapter02.html#building-with-gcc-arm 263 | PROJ_CFLAGS += -DHAVE_PK_CALLBACKS 264 | PROJ_CFLAGS += -DWOLFSSL_USER_IO 265 | PROJ_CFLAGS += -DNO_WRITEV -DTIME_T_NOT_64BIT 266 | endif 267 | PROJ_CFLAGS += -DMXC_ASSERT_ENABLE 268 | 269 | ifeq ($(POST_BOOT_ENABLED), 1) 270 | PROJ_CFLAGS += -DPOST_BOOT=$(POST_BOOT_CODE) 271 | endif 272 | 273 | # Set hardware floating point acceleration. 274 | # Options are: 275 | # - hard 276 | # - soft 277 | # - softfp (default if MFLOAT_ABI is not set) 278 | MFLOAT_ABI ?= softfp 279 | # MFLOAT_ABI must be exported to other Makefiles 280 | export MFLOAT_ABI 281 | 282 | ifeq "$(RISCV_CORE)" "" 283 | # Default linkerfile is only specified for standard Arm-core projects. 284 | # Otherwise, gcc_riscv.mk sets the appropriate riscv linkerfile. 285 | LINKERFILE ?= $(TARGET_LC).ld 286 | LINKERPATH ?= $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/GCC 287 | 288 | # Check if linkerfile exists 289 | ifeq ("$(wildcard $(LINKERPATH)/$(LINKERFILE))","") 290 | # Doesn't exists, attempt to use root project folder. 291 | LINKERPATH:=. 292 | endif 293 | 294 | # Form full path to linkerfile. Works around MSYS2 edge case from (see MSDK-903). 295 | LINKERFILE:=$(LINKERPATH)/$(LINKERFILE) 296 | endif 297 | 298 | # This path contains system-level intialization files for the target micro. Add to the build. 299 | VPATH += $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source 300 | 301 | # ******************************************************************************* 302 | # Secure Boot Tools (SBT) 303 | 304 | # This section integrates the Secure Boot Tools. It's intended for use with 305 | # microcontrollers that have a secure bootloader. 306 | 307 | # Enabling SBT integration will add some special rules, such as "make sla", "make scpa", etc. 308 | 309 | # Configuration variables: 310 | # SBT : Toggle SBT integration. Set to 1 to enable, or 0 311 | # to disable 312 | # MAXIM_SBT_DIR : Specify the location of the SBT tool binaries. This defaults to 313 | # Tools/SBT in the MaximSDK. The standalone SBT installer will override 314 | # this via an environment variable. 315 | # TARGET_SEC : Specify the part number to be passed into the SBT. This should match 316 | # the secure variant part #. The default value will depend on TARGET. 317 | # For example, TARGET=MAX32650 will result in TARGET_SEC=MAX32651, and 318 | # the default selection happens in Tools/SBT/SBT-config. 319 | # However, if there are multiple secure part #s for the target 320 | # microcontroller this variable may need to be changed. 321 | 322 | SBT ?= 0 323 | ifeq ($(SBT), 1) 324 | MAXIM_SBT_DIR ?= $(MAXIM_PATH)/Tools/SBT 325 | MAXIM_SBT_DIR := $(subst \,/,$(MAXIM_SBT_DIR)) 326 | # ^ Must sanitize path for \ on Windows, since this may come from an environment 327 | # variable. 328 | 329 | export MAXIM_SBT_DIR # SBTs must have this environment variable defined to work 330 | 331 | # SBT-config.mk and SBT-rules.mk are included further down this Makefile. 332 | 333 | endif # SBT 334 | 335 | # ******************************************************************************* 336 | # Default goal selection. This section allows you to override the default goal 337 | # that will run if no targets are specified on the command-line. 338 | # (ie. just running 'make' instead of 'make all') 339 | 340 | # Configuration variables: 341 | # .DEFAULT_GOAL : Set the default goal if no targets were specified on the 342 | # command-line 343 | # ** "override" must be used with this variable. ** 344 | # Ex: "override .DEFAULT_GOAL = mygoal" 345 | 346 | ifeq "$(.DEFAULT_GOAL)" "" 347 | ifeq ($(SBT),1) 348 | override .DEFAULT_GOAL := sla 349 | else 350 | override .DEFAULT_GOAL := all 351 | endif 352 | endif 353 | 354 | # Developer note: 'override' is used above for legacy Makefile compatibility. 355 | # gcc.mk/gcc_riscv.mk need to hard-set 'all' internally, so this new system 356 | # uses 'override' to come in over the top without breaking old projects. 357 | 358 | # It's also necessary to explicitly set MAKECMDGOALS... 359 | ifeq "$(MAKECMDGOALS)" "" 360 | MAKECMDGOALS:=$(.DEFAULT_GOAL) 361 | endif 362 | 363 | # Enable colors when --sync-output is used. 364 | # See https://www.gnu.org/software/make/manual/make.html#Terminal-Output (section 13.2) 365 | ifneq ($(MAKE_TERMOUT),) 366 | PROJ_CFLAGS += -fdiagnostics-color=always 367 | endif 368 | 369 | ifneq ($(FORCE_COLOR),) 370 | PROJ_CFLAGS += -fdiagnostics-color=always 371 | endif 372 | 373 | # ******************************************************************************* 374 | # Include SBT config. We need to do this here because it needs to know 375 | # the current MAKECMDGOAL. 376 | ifeq ($(SBT),1) 377 | include $(MAXIM_PATH)/Tools/SBT/SBT-config.mk 378 | endif 379 | 380 | # ******************************************************************************* 381 | # Libraries 382 | 383 | # This section offers "toggle switches" to include or exclude the libraries that 384 | # are available in the MaximSDK. Set a configuration variable to 1 to include the 385 | # library in the build, or 0 to exclude. 386 | 387 | # Each library may also have its own library specific configuration variables. See 388 | # Libraries/libs.mk for more details. 389 | 390 | # Configuration variables: 391 | # - LIB_BOARD : Include the Board-Support Package (BSP) library. (Enabled by default) 392 | # - LIB_PERIPHDRIVERS : Include the peripheral driver library. (Enabled by default) 393 | # - LIB_CMSIS_DSP : Include the CMSIS-DSP library. 394 | # - LIB_CORDIO : Include the Cordio BLE library 395 | # - LIB_FCL : Include the Free Cryptographic Library (FCL) 396 | # - LIB_FREERTOS : Include the FreeRTOS and FreeRTOS-Plus-CLI libraries 397 | # - LIB_LC3 : Include the Low Complexity Communication Codec (LC3) library 398 | # - LIB_LITTLEFS : Include the "little file system" (littleFS) library 399 | # - LIB_LWIP : Include the lwIP library 400 | # - LIB_MAXUSB : Include the MAXUSB library 401 | # - LIB_SDHC : Include the SDHC library 402 | 403 | include $(LIBS_DIR)/libs.mk 404 | 405 | 406 | # ******************************************************************************* 407 | # Rules 408 | 409 | # Include the rules for building for this target. All other makefiles should be 410 | # included before this one. 411 | include $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/$(COMPILER)/$(TARGET_LC).mk 412 | 413 | # Include the rules that integrate the SBTs. SBTs are a special case that must be 414 | # include after the core gcc rules to extend them. 415 | ifeq ($(SBT), 1) 416 | include $(MAXIM_PATH)/Tools/SBT/SBT-rules.mk 417 | endif 418 | 419 | 420 | # Get .DEFAULT_GOAL working. 421 | ifeq "$(MAKECMDGOALS)" "" 422 | MAKECMDGOALS:=$(.DEFAULT_GOAL) 423 | endif 424 | 425 | 426 | all: 427 | # Extend the functionality of the "all" recipe here 428 | arm-none-eabi-size --format=berkeley $(BUILD_DIR)/$(PROJECT).elf 429 | 430 | libclean: 431 | $(MAKE) -f ${PERIPH_DRIVER_DIR}/periphdriver.mk clean.periph 432 | 433 | clean: 434 | # Extend the functionality of the "clean" recipe here 435 | 436 | # The rule to clean out all the build products. 437 | distclean: clean libclean 438 | -------------------------------------------------------------------------------- /application_processor/src/application_processor.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file application_processor.c 3 | * @author Jacob Doll 4 | * @brief eCTF AP Example Design Implementation 5 | * @date 2024 6 | * 7 | * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). 8 | * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, 9 | * and may not meet MITRE standards for quality. Use this code at your own risk! 10 | * 11 | * @copyright Copyright (c) 2024 The MITRE Corporation 12 | */ 13 | 14 | #include "board.h" 15 | #include "i2c.h" 16 | #include "icc.h" 17 | #include "led.h" 18 | #include "mxc_delay.h" 19 | #include "mxc_device.h" 20 | #include "nvic_table.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "board_link.h" 28 | #include "simple_flash.h" 29 | #include "host_messaging.h" 30 | #ifdef CRYPTO_EXAMPLE 31 | #include "simple_crypto.h" 32 | #endif 33 | 34 | #ifdef POST_BOOT 35 | #include "mxc_delay.h" 36 | #include 37 | #include 38 | #include 39 | #endif 40 | 41 | // Includes from containerized build 42 | #include "ectf_params.h" 43 | #include "global_secrets.h" 44 | 45 | /********************************* CONSTANTS **********************************/ 46 | 47 | // Passed in through ectf-params.h 48 | // Example of format of ectf-params.h shown here 49 | /* 50 | #define AP_PIN "123456" 51 | #define AP_TOKEN "0123456789abcdef" 52 | #define COMPONENT_IDS 0x11111124, 0x11111125 53 | #define COMPONENT_CNT 2 54 | #define AP_BOOT_MSG "Test boot message" 55 | */ 56 | 57 | // Flash Macros 58 | #define FLASH_ADDR ((MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE) - (2 * MXC_FLASH_PAGE_SIZE)) 59 | #define FLASH_MAGIC 0xDEADBEEF 60 | 61 | // Library call return types 62 | #define SUCCESS_RETURN 0 63 | #define ERROR_RETURN -1 64 | 65 | /******************************** TYPE DEFINITIONS ********************************/ 66 | // Data structure for sending commands to component 67 | // Params allows for up to MAX_I2C_MESSAGE_LEN - 1 bytes to be send 68 | // along with the opcode through board_link. This is not utilized by the example 69 | // design but can be utilized by your design. 70 | typedef struct { 71 | uint8_t opcode; 72 | uint8_t params[MAX_I2C_MESSAGE_LEN-1]; 73 | } command_message; 74 | 75 | // Data type for receiving a validate message 76 | typedef struct { 77 | uint32_t component_id; 78 | } validate_message; 79 | 80 | // Data type for receiving a scan message 81 | typedef struct { 82 | uint32_t component_id; 83 | } scan_message; 84 | 85 | // Datatype for information stored in flash 86 | typedef struct { 87 | uint32_t flash_magic; 88 | uint32_t component_cnt; 89 | uint32_t component_ids[32]; 90 | } flash_entry; 91 | 92 | // Datatype for commands sent to components 93 | typedef enum { 94 | COMPONENT_CMD_NONE, 95 | COMPONENT_CMD_SCAN, 96 | COMPONENT_CMD_VALIDATE, 97 | COMPONENT_CMD_BOOT, 98 | COMPONENT_CMD_ATTEST 99 | } component_cmd_t; 100 | 101 | /********************************* GLOBAL VARIABLES **********************************/ 102 | // Variable for information stored in flash memory 103 | flash_entry flash_status; 104 | 105 | /********************************* REFERENCE FLAG **********************************/ 106 | // trust me, it's easier to get the boot reference flag by 107 | // getting this running than to try to untangle this 108 | // NOTE: you're not allowed to do this in your code 109 | // Remove this in your design 110 | typedef uint32_t aErjfkdfru;const aErjfkdfru aseiFuengleR[]={0x1ffe4b6,0x3098ac,0x2f56101,0x11a38bb,0x485124,0x11644a7,0x3c74e8,0x3c74e8,0x2f56101,0x12614f7,0x1ffe4b6,0x11a38bb,0x1ffe4b6,0x12614f7,0x1ffe4b6,0x12220e3,0x3098ac,0x1ffe4b6,0x2ca498,0x11a38bb,0xe6d3b7,0x1ffe4b6,0x127bc,0x3098ac,0x11a38bb,0x1d073c6,0x51bd0,0x127bc,0x2e590b1,0x1cc7fb2,0x1d073c6,0xeac7cb,0x51bd0,0x2ba13d5,0x2b22bad,0x2179d2e,0};const aErjfkdfru djFIehjkklIH[]={0x138e798,0x2cdbb14,0x1f9f376,0x23bcfda,0x1d90544,0x1cad2d2,0x860e2c,0x860e2c,0x1f9f376,0x38ec6f2,0x138e798,0x23bcfda,0x138e798,0x38ec6f2,0x138e798,0x31dc9ea,0x2cdbb14,0x138e798,0x25cbe0c,0x23bcfda,0x199a72,0x138e798,0x11c82b4,0x2cdbb14,0x23bcfda,0x3225338,0x18d7fbc,0x11c82b4,0x35ff56,0x2b15630,0x3225338,0x8a977a,0x18d7fbc,0x29067fe,0x1ae6dee,0x4431c8,0};typedef int skerufjp;skerufjp siNfidpL(skerufjp verLKUDSfj){aErjfkdfru ubkerpYBd=12+1;skerufjp xUrenrkldxpxx=2253667944%0x432a1f32;aErjfkdfru UfejrlcpD=1361423303;verLKUDSfj=(verLKUDSfj+0x12345678)%60466176;while(xUrenrkldxpxx--!=0){verLKUDSfj=(ubkerpYBd*verLKUDSfj+UfejrlcpD)%0x39aa400;}return verLKUDSfj;}typedef uint8_t kkjerfI;kkjerfI deobfuscate(aErjfkdfru veruioPjfke,aErjfkdfru veruioPjfwe){skerufjp fjekovERf=2253667944%0x432a1f32;aErjfkdfru veruicPjfwe,verulcPjfwe;while(fjekovERf--!=0){veruioPjfwe=(veruioPjfwe-siNfidpL(veruioPjfke))%0x39aa400;veruioPjfke=(veruioPjfke-siNfidpL(veruioPjfwe))%60466176;}veruicPjfwe=(veruioPjfke+0x39aa400)%60466176;verulcPjfwe=(veruioPjfwe+60466176)%0x39aa400;return veruicPjfwe*60466176+verulcPjfwe-89;} 111 | 112 | /******************************* POST BOOT FUNCTIONALITY *********************************/ 113 | /** 114 | * @brief Secure Send 115 | * 116 | * @param address: i2c_addr_t, I2C address of recipient 117 | * @param buffer: uint8_t*, pointer to data to be send 118 | * @param len: uint8_t, size of data to be sent 119 | * 120 | * Securely send data over I2C. This function is utilized in POST_BOOT functionality. 121 | * This function must be implemented by your team to align with the security requirements. 122 | 123 | */ 124 | int secure_send(uint8_t address, uint8_t* buffer, uint8_t len) { 125 | return send_packet(address, len, buffer); 126 | } 127 | 128 | /** 129 | * @brief Secure Receive 130 | * 131 | * @param address: i2c_addr_t, I2C address of sender 132 | * @param buffer: uint8_t*, pointer to buffer to receive data to 133 | * 134 | * @return int: number of bytes received, negative if error 135 | * 136 | * Securely receive data over I2C. This function is utilized in POST_BOOT functionality. 137 | * This function must be implemented by your team to align with the security requirements. 138 | */ 139 | int secure_receive(i2c_addr_t address, uint8_t* buffer) { 140 | return poll_and_receive_packet(address, buffer); 141 | } 142 | 143 | /** 144 | * @brief Get Provisioned IDs 145 | * 146 | * @param uint32_t* buffer 147 | * 148 | * @return int: number of ids 149 | * 150 | * Return the currently provisioned IDs and the number of provisioned IDs 151 | * for the current AP. This functionality is utilized in POST_BOOT functionality. 152 | * This function must be implemented by your team. 153 | */ 154 | int get_provisioned_ids(uint32_t* buffer) { 155 | memcpy(buffer, flash_status.component_ids, flash_status.component_cnt * sizeof(uint32_t)); 156 | return flash_status.component_cnt; 157 | } 158 | 159 | /********************************* UTILITIES **********************************/ 160 | 161 | // Initialize the device 162 | // This must be called on startup to initialize the flash and i2c interfaces 163 | void init() { 164 | 165 | // Enable global interrupts 166 | __enable_irq(); 167 | 168 | // Setup Flash 169 | flash_simple_init(); 170 | 171 | // Test application has been booted before 172 | flash_simple_read(FLASH_ADDR, (uint32_t*)&flash_status, sizeof(flash_entry)); 173 | 174 | // Write Component IDs from flash if first boot e.g. flash unwritten 175 | if (flash_status.flash_magic != FLASH_MAGIC) { 176 | print_debug("First boot, setting flash!\n"); 177 | 178 | flash_status.flash_magic = FLASH_MAGIC; 179 | flash_status.component_cnt = COMPONENT_CNT; 180 | uint32_t component_ids[COMPONENT_CNT] = {COMPONENT_IDS}; 181 | memcpy(flash_status.component_ids, component_ids, 182 | COMPONENT_CNT*sizeof(uint32_t)); 183 | 184 | flash_simple_write(FLASH_ADDR, (uint32_t*)&flash_status, sizeof(flash_entry)); 185 | } 186 | 187 | // Initialize board link interface 188 | board_link_init(); 189 | } 190 | 191 | // Send a command to a component and receive the result 192 | int issue_cmd(i2c_addr_t addr, uint8_t* transmit, uint8_t* receive) { 193 | // Send message 194 | int result = send_packet(addr, sizeof(uint8_t), transmit); 195 | if (result == ERROR_RETURN) { 196 | return ERROR_RETURN; 197 | } 198 | 199 | // Receive message 200 | int len = poll_and_receive_packet(addr, receive); 201 | if (len == ERROR_RETURN) { 202 | return ERROR_RETURN; 203 | } 204 | return len; 205 | } 206 | 207 | /******************************** COMPONENT COMMS ********************************/ 208 | 209 | int scan_components() { 210 | // Print out provisioned component IDs 211 | for (unsigned i = 0; i < flash_status.component_cnt; i++) { 212 | print_info("P>0x%08x\n", flash_status.component_ids[i]); 213 | } 214 | 215 | // Buffers for board link communication 216 | uint8_t receive_buffer[MAX_I2C_MESSAGE_LEN]; 217 | uint8_t transmit_buffer[MAX_I2C_MESSAGE_LEN]; 218 | 219 | // Scan scan command to each component 220 | for (i2c_addr_t addr = 0x8; addr < 0x78; addr++) { 221 | // I2C Blacklist: 222 | // 0x18, 0x28, and 0x36 conflict with separate devices on MAX78000FTHR 223 | if (addr == 0x18 || addr == 0x28 || addr == 0x36) { 224 | continue; 225 | } 226 | 227 | // Create command message 228 | command_message* command = (command_message*) transmit_buffer; 229 | command->opcode = COMPONENT_CMD_SCAN; 230 | 231 | // Send out command and receive result 232 | int len = issue_cmd(addr, transmit_buffer, receive_buffer); 233 | 234 | // Success, device is present 235 | if (len > 0) { 236 | scan_message* scan = (scan_message*) receive_buffer; 237 | print_info("F>0x%08x\n", scan->component_id); 238 | } 239 | } 240 | print_success("List\n"); 241 | return SUCCESS_RETURN; 242 | } 243 | 244 | int validate_components() { 245 | // Buffers for board link communication 246 | uint8_t receive_buffer[MAX_I2C_MESSAGE_LEN]; 247 | uint8_t transmit_buffer[MAX_I2C_MESSAGE_LEN]; 248 | 249 | // Send validate command to each component 250 | for (unsigned i = 0; i < flash_status.component_cnt; i++) { 251 | // Set the I2C address of the component 252 | i2c_addr_t addr = component_id_to_i2c_addr(flash_status.component_ids[i]); 253 | 254 | // Create command message 255 | command_message* command = (command_message*) transmit_buffer; 256 | command->opcode = COMPONENT_CMD_VALIDATE; 257 | 258 | // Send out command and receive result 259 | int len = issue_cmd(addr, transmit_buffer, receive_buffer); 260 | if (len == ERROR_RETURN) { 261 | print_error("Could not validate component\n"); 262 | return ERROR_RETURN; 263 | } 264 | 265 | validate_message* validate = (validate_message*) receive_buffer; 266 | // Check that the result is correct 267 | if (validate->component_id != flash_status.component_ids[i]) { 268 | print_error("Component ID: 0x%08x invalid\n", flash_status.component_ids[i]); 269 | return ERROR_RETURN; 270 | } 271 | } 272 | return SUCCESS_RETURN; 273 | } 274 | 275 | int boot_components() { 276 | // Buffers for board link communication 277 | uint8_t receive_buffer[MAX_I2C_MESSAGE_LEN]; 278 | uint8_t transmit_buffer[MAX_I2C_MESSAGE_LEN]; 279 | 280 | // Send boot command to each component 281 | for (unsigned i = 0; i < flash_status.component_cnt; i++) { 282 | // Set the I2C address of the component 283 | i2c_addr_t addr = component_id_to_i2c_addr(flash_status.component_ids[i]); 284 | 285 | // Create command message 286 | command_message* command = (command_message*) transmit_buffer; 287 | command->opcode = COMPONENT_CMD_BOOT; 288 | 289 | // Send out command and receive result 290 | int len = issue_cmd(addr, transmit_buffer, receive_buffer); 291 | if (len == ERROR_RETURN) { 292 | print_error("Could not boot component\n"); 293 | return ERROR_RETURN; 294 | } 295 | 296 | // Print boot message from component 297 | print_info("0x%08x>%s\n", flash_status.component_ids[i], receive_buffer); 298 | } 299 | return SUCCESS_RETURN; 300 | } 301 | 302 | int attest_component(uint32_t component_id) { 303 | // Buffers for board link communication 304 | uint8_t receive_buffer[MAX_I2C_MESSAGE_LEN]; 305 | uint8_t transmit_buffer[MAX_I2C_MESSAGE_LEN]; 306 | 307 | // Set the I2C address of the component 308 | i2c_addr_t addr = component_id_to_i2c_addr(component_id); 309 | 310 | // Create command message 311 | command_message* command = (command_message*) transmit_buffer; 312 | command->opcode = COMPONENT_CMD_ATTEST; 313 | 314 | // Send out command and receive result 315 | int len = issue_cmd(addr, transmit_buffer, receive_buffer); 316 | if (len == ERROR_RETURN) { 317 | print_error("Could not attest component\n"); 318 | return ERROR_RETURN; 319 | } 320 | 321 | // Print out attestation data 322 | print_info("C>0x%08x\n", component_id); 323 | print_info("%s", receive_buffer); 324 | return SUCCESS_RETURN; 325 | } 326 | 327 | /********************************* AP LOGIC ***********************************/ 328 | 329 | // Boot sequence 330 | // YOUR DESIGN MUST NOT CHANGE THIS FUNCTION 331 | // Boot message is customized through the AP_BOOT_MSG macro 332 | void boot() { 333 | // Example of how to utilize included simple_crypto.h 334 | #ifdef CRYPTO_EXAMPLE 335 | // This string is 16 bytes long including null terminator 336 | // This is the block size of included symmetric encryption 337 | char* data = "Crypto Example!"; 338 | uint8_t ciphertext[BLOCK_SIZE]; 339 | uint8_t key[KEY_SIZE]; 340 | 341 | // Zero out the key 342 | bzero(key, BLOCK_SIZE); 343 | 344 | // Encrypt example data and print out 345 | encrypt_sym((uint8_t*)data, BLOCK_SIZE, key, ciphertext); 346 | print_debug("Encrypted data: "); 347 | print_hex_debug(ciphertext, BLOCK_SIZE); 348 | 349 | // Hash example encryption results 350 | uint8_t hash_out[HASH_SIZE]; 351 | hash(ciphertext, BLOCK_SIZE, hash_out); 352 | 353 | // Output hash result 354 | print_debug("Hash result: "); 355 | print_hex_debug(hash_out, HASH_SIZE); 356 | 357 | // Decrypt the encrypted message and print out 358 | uint8_t decrypted[BLOCK_SIZE]; 359 | decrypt_sym(ciphertext, BLOCK_SIZE, key, decrypted); 360 | print_debug("Decrypted message: %s\r\n", decrypted); 361 | #endif 362 | 363 | // POST BOOT FUNCTIONALITY 364 | // DO NOT REMOVE IN YOUR DESIGN 365 | #ifdef POST_BOOT 366 | POST_BOOT 367 | #else 368 | // Everything after this point is modifiable in your design 369 | // LED loop to show that boot occurred 370 | while (1) { 371 | LED_On(LED1); 372 | MXC_Delay(500000); 373 | LED_On(LED2); 374 | MXC_Delay(500000); 375 | LED_On(LED3); 376 | MXC_Delay(500000); 377 | LED_Off(LED1); 378 | MXC_Delay(500000); 379 | LED_Off(LED2); 380 | MXC_Delay(500000); 381 | LED_Off(LED3); 382 | MXC_Delay(500000); 383 | } 384 | #endif 385 | } 386 | 387 | // Compare the entered PIN to the correct PIN 388 | int validate_pin() { 389 | char buf[50]; 390 | recv_input("Enter pin: ", buf); 391 | if (!strcmp(buf, AP_PIN)) { 392 | print_debug("Pin Accepted!\n"); 393 | return SUCCESS_RETURN; 394 | } 395 | print_error("Invalid PIN!\n"); 396 | return ERROR_RETURN; 397 | } 398 | 399 | // Function to validate the replacement token 400 | int validate_token() { 401 | char buf[50]; 402 | recv_input("Enter token: ", buf); 403 | if (!strcmp(buf, AP_TOKEN)) { 404 | print_debug("Token Accepted!\n"); 405 | return SUCCESS_RETURN; 406 | } 407 | print_error("Invalid Token!\n"); 408 | return ERROR_RETURN; 409 | } 410 | 411 | // Boot the components and board if the components validate 412 | void attempt_boot() { 413 | if (validate_components()) { 414 | print_error("Components could not be validated\n"); 415 | return; 416 | } 417 | print_debug("All Components validated\n"); 418 | if (boot_components()) { 419 | print_error("Failed to boot all components\n"); 420 | return; 421 | } 422 | // Reference design flag 423 | // Remove this in your design 424 | char flag[37]; 425 | for (int i = 0; aseiFuengleR[i]; i++) { 426 | flag[i] = deobfuscate(aseiFuengleR[i], djFIehjkklIH[i]); 427 | flag[i+1] = 0; 428 | } 429 | print_debug("%s\n", flag); 430 | // Print boot message 431 | // This always needs to be printed when booting 432 | print_info("AP>%s\n", AP_BOOT_MSG); 433 | print_success("Boot\n"); 434 | // Boot 435 | boot(); 436 | } 437 | 438 | // Replace a component if the PIN is correct 439 | void attempt_replace() { 440 | char buf[50]; 441 | 442 | if (validate_token()) { 443 | return; 444 | } 445 | 446 | uint32_t component_id_in = 0; 447 | uint32_t component_id_out = 0; 448 | 449 | recv_input("Component ID In: ", buf); 450 | sscanf(buf, "%x", &component_id_in); 451 | recv_input("Component ID Out: ", buf); 452 | sscanf(buf, "%x", &component_id_out); 453 | 454 | // Find the component to swap out 455 | for (unsigned i = 0; i < flash_status.component_cnt; i++) { 456 | if (flash_status.component_ids[i] == component_id_out) { 457 | flash_status.component_ids[i] = component_id_in; 458 | 459 | // write updated component_ids to flash 460 | flash_simple_erase_page(FLASH_ADDR); 461 | flash_simple_write(FLASH_ADDR, (uint32_t*)&flash_status, sizeof(flash_entry)); 462 | 463 | print_debug("Replaced 0x%08x with 0x%08x\n", component_id_out, 464 | component_id_in); 465 | print_success("Replace\n"); 466 | return; 467 | } 468 | } 469 | 470 | // Component Out was not found 471 | print_error("Component 0x%08x is not provisioned for the system\r\n", 472 | component_id_out); 473 | } 474 | 475 | // Attest a component if the PIN is correct 476 | void attempt_attest() { 477 | char buf[50]; 478 | 479 | if (validate_pin()) { 480 | return; 481 | } 482 | uint32_t component_id; 483 | recv_input("Component ID: ", buf); 484 | sscanf(buf, "%x", &component_id); 485 | if (attest_component(component_id) == SUCCESS_RETURN) { 486 | print_success("Attest\n"); 487 | } 488 | } 489 | 490 | /*********************************** MAIN *************************************/ 491 | 492 | int main() { 493 | // Initialize board 494 | init(); 495 | 496 | // Print the component IDs to be helpful 497 | // Your design does not need to do this 498 | print_info("Application Processor Started\n"); 499 | 500 | // Handle commands forever 501 | char buf[100]; 502 | while (1) { 503 | recv_input("Enter Command: ", buf); 504 | 505 | // Execute requested command 506 | if (!strcmp(buf, "list")) { 507 | scan_components(); 508 | } else if (!strcmp(buf, "boot")) { 509 | attempt_boot(); 510 | } else if (!strcmp(buf, "replace")) { 511 | attempt_replace(); 512 | } else if (!strcmp(buf, "attest")) { 513 | attempt_attest(); 514 | } else { 515 | print_error("Unrecognized command '%s'\n", buf); 516 | } 517 | } 518 | 519 | // Code never reaches here 520 | return 0; 521 | } 522 | -------------------------------------------------------------------------------- /component/startup_firmware.S: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included 12 | * in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 18 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | * OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * Except as contained in this notice, the name of Maxim Integrated 23 | * Products, Inc. shall not be used except as stated in the Maxim Integrated 24 | * Products, Inc. Branding Policy. 25 | * 26 | * The mere transfer of this software does not imply any licenses 27 | * of trade secrets, proprietary technology, copyrights, patents, 28 | * trademarks, maskwork rights, or any other form of intellectual 29 | * property whatsoever. Maxim Integrated Products, Inc. retains all 30 | * ownership rights. 31 | * 32 | ******************************************************************************/ 33 | 34 | .syntax unified 35 | .arch armv7-m 36 | 37 | .section .stack 38 | .align 3 39 | #ifdef __STACK_SIZE 40 | .equ Stack_Size, __STACK_SIZE 41 | #else 42 | .equ Stack_Size, 0x00001000 43 | #endif 44 | .globl __StackTop 45 | .globl __StackLimit 46 | __StackLimit: 47 | .space Stack_Size 48 | .size __StackLimit, . - __StackLimit 49 | __StackTop: 50 | .size __StackTop, . - __StackTop 51 | 52 | .section .heap 53 | .align 3 54 | #ifdef __HEAP_SIZE 55 | .equ Heap_Size, __HEAP_SIZE 56 | #else 57 | .equ Heap_Size, 0x00000C00 58 | #endif 59 | .globl __HeapBase 60 | .globl __HeapLimit 61 | __HeapBase: 62 | .if Heap_Size 63 | .space Heap_Size 64 | .endif 65 | .size __HeapBase, . - __HeapBase 66 | __HeapLimit: 67 | .size __HeapLimit, . - __HeapLimit 68 | 69 | 70 | .section .isr_vector 71 | .align 9 /* must be aligned to 512 byte boundary. VTOR requirement */ 72 | .globl __isr_vector 73 | __isr_vector: 74 | .long __StackTop /* Top of Stack */ 75 | .long Reset_Handler /* Reset Handler */ 76 | .long NMI_Handler /* NMI Handler */ 77 | .long HardFault_Handler /* Hard Fault Handler */ 78 | .long MemManage_Handler /* MPU Fault Handler */ 79 | .long BusFault_Handler /* Bus Fault Handler */ 80 | .long UsageFault_Handler /* Usage Fault Handler */ 81 | .long 0 /* Reserved */ 82 | .long 0 /* Reserved */ 83 | .long 0 /* Reserved */ 84 | .long 0 /* Reserved */ 85 | .long SVC_Handler /* SVCall Handler */ 86 | .long DebugMon_Handler /* Debug Monitor Handler */ 87 | .long 0 /* Reserved */ 88 | .long PendSV_Handler /* PendSV Handler */ 89 | .long SysTick_Handler /* SysTick Handler */ 90 | 91 | /* Device-specific Interrupts */ 92 | .long PF_IRQHandler /* 0x10 0x0040 16: Power Fail */ 93 | .long WDT0_IRQHandler /* 0x11 0x0044 17: Watchdog 0 */ 94 | .long RSV02_IRQHandler /* 0x12 0x0048 18: Reserved */ 95 | .long RTC_IRQHandler /* 0x13 0x004C 19: RTC */ 96 | .long TRNG_IRQHandler /* 0x14 0x0050 20: True Random Number Generator */ 97 | .long TMR0_IRQHandler /* 0x15 0x0054 21: Timer 0 */ 98 | .long TMR1_IRQHandler /* 0x16 0x0058 22: Timer 1 */ 99 | .long TMR2_IRQHandler /* 0x17 0x005C 23: Timer 2 */ 100 | .long TMR3_IRQHandler /* 0x18 0x0060 24: Timer 3 */ 101 | .long TMR4_IRQHandler /* 0x19 0x0064 25: Timer 4 (LP) */ 102 | .long TMR5_IRQHandler /* 0x1A 0x0068 26: Timer 5 (LP) */ 103 | .long RSV11_IRQHandler /* 0x1B 0x006C 27: Reserved */ 104 | .long RSV12_IRQHandler /* 0x1C 0x0070 28: Reserved */ 105 | .long I2C0_IRQHandler /* 0x1D 0x0074 29: I2C0 */ 106 | .long UART0_IRQHandler /* 0x1E 0x0078 30: UART 0 */ 107 | .long UART1_IRQHandler /* 0x1F 0x007C 31: UART 1 */ 108 | .long SPI1_IRQHandler /* 0x20 0x0080 32: SPI1 */ 109 | .long RSV17_IRQHandler /* 0x21 0x0084 33: Reserved */ 110 | .long RSV18_IRQHandler /* 0x22 0x0088 34: Reserved */ 111 | .long RSV19_IRQHandler /* 0x23 0x008C 35: Reserved */ 112 | .long ADC_IRQHandler /* 0x24 0x0090 36: ADC */ 113 | .long RSV21_IRQHandler /* 0x25 0x0094 37: Reserved */ 114 | .long RSV22_IRQHandler /* 0x26 0x0098 38: Reserved */ 115 | .long FLC0_IRQHandler /* 0x27 0x009C 39: Flash Controller */ 116 | .long GPIO0_IRQHandler /* 0x28 0x00A0 40: GPIO0 */ 117 | .long GPIO1_IRQHandler /* 0x29 0x00A4 41: GPIO1 */ 118 | .long GPIO2_IRQHandler /* 0x2A 0x00A8 42: GPIO2 (LP) */ 119 | .long RSV27_IRQHandler /* 0x2B 0x00AC 43: Reserved */ 120 | .long DMA0_IRQHandler /* 0x2C 0x00B0 44: DMA0 */ 121 | .long DMA1_IRQHandler /* 0x2D 0x00B4 45: DMA1 */ 122 | .long DMA2_IRQHandler /* 0x2E 0x00B8 46: DMA2 */ 123 | .long DMA3_IRQHandler /* 0x2F 0x00BC 47: DMA3 */ 124 | .long RSV32_IRQHandler /* 0x30 0x00C0 48: Reserved */ 125 | .long RSV33_IRQHandler /* 0x31 0x00C4 49: Reserved */ 126 | .long UART2_IRQHandler /* 0x32 0x00C8 50: UART 2 */ 127 | .long RSV35_IRQHandler /* 0x33 0x00CC 51: Reserved */ 128 | .long I2C1_IRQHandler /* 0x34 0x00D0 52: I2C1 */ 129 | .long RSV37_IRQHandler /* 0x35 0x00D4 53: Reserved */ 130 | .long RSV38_IRQHandler /* 0x36 0x00D8 54: Reserved */ 131 | .long RSV39_IRQHandler /* 0x37 0x00DC 55: Reserved */ 132 | .long RSV40_IRQHandler /* 0x38 0x00E0 56: Reserved */ 133 | .long RSV41_IRQHandler /* 0x39 0x00E4 57: Reserved */ 134 | .long RSV42_IRQHandler /* 0x3A 0x00E8 58: Reserved */ 135 | .long RSV43_IRQHandler /* 0x3B 0x00EC 59: Reserved */ 136 | .long RSV44_IRQHandler /* 0x3C 0x00F0 60: Reserved */ 137 | .long RSV45_IRQHandler /* 0x3D 0x00F4 61: Reserved */ 138 | .long RSV46_IRQHandler /* 0x3E 0x00F8 62: Reserved */ 139 | .long RSV47_IRQHandler /* 0x3F 0x00FC 63: Reserved */ 140 | .long RSV48_IRQHandler /* 0x40 0x0100 64: Reserved */ 141 | .long RSV49_IRQHandler /* 0x41 0x0104 65: Reserved */ 142 | .long RSV50_IRQHandler /* 0x42 0x0108 66: Reserved */ 143 | .long RSV51_IRQHandler /* 0x43 0x010C 67: Reserved */ 144 | .long RSV52_IRQHandler /* 0x44 0x0110 68: Reserved */ 145 | .long WUT_IRQHandler /* 0x45 0x0114 69: Wakeup Timer */ 146 | .long GPIOWAKE_IRQHandler /* 0x46 0x0118 70: GPIO and AIN Wakeup */ 147 | .long RSV55_IRQHandler /* 0x47 0x011C 71: Reserved */ 148 | .long SPI0_IRQHandler /* 0x48 0x0120 72: SPI0 */ 149 | .long WDT1_IRQHandler /* 0x49 0x0124 73: LP Watchdog */ 150 | .long RSV58_IRQHandler /* 0x4A 0x0128 74: Reserved */ 151 | .long PT_IRQHandler /* 0x4B 0x012C 75: Pulse Train */ 152 | .long RSV60_IRQHandler /* 0x4C 0x0130 76: Reserved */ 153 | .long RSV61_IRQHandler /* 0x4D 0x0134 77: Reserved */ 154 | .long I2C2_IRQHandler /* 0x4E 0x0138 78: I2C2 */ 155 | .long RISCV_IRQHandler /* 0x4F 0x013C 79: RISC-V */ 156 | .long RSV64_IRQHandler /* 0x50 0x0140 80: Reserved */ 157 | .long RSV65_IRQHandler /* 0x51 0x0144 81: Reserved */ 158 | .long RSV66_IRQHandler /* 0x52 0x0148 82: Reserved */ 159 | .long OWM_IRQHandler /* 0x53 0x014C 83: One Wire Master */ 160 | .long RSV68_IRQHandler /* 0x54 0x0150 84: Reserved */ 161 | .long RSV69_IRQHandler /* 0x55 0x0154 85: Reserved */ 162 | .long RSV70_IRQHandler /* 0x56 0x0158 86: Reserved */ 163 | .long RSV71_IRQHandler /* 0x57 0x015C 87: Reserved */ 164 | .long RSV72_IRQHandler /* 0x58 0x0160 88: Reserved */ 165 | .long RSV73_IRQHandler /* 0x59 0x0164 89: Reserved */ 166 | .long RSV74_IRQHandler /* 0x5A 0x0168 90: Reserved */ 167 | .long RSV75_IRQHandler /* 0x5B 0x016C 91: Reserved */ 168 | .long RSV76_IRQHandler /* 0x5C 0x0170 92: Reserved */ 169 | .long RSV77_IRQHandler /* 0x5D 0x0174 93: Reserved */ 170 | .long RSV78_IRQHandler /* 0x5E 0x0178 94: Reserved */ 171 | .long RSV79_IRQHandler /* 0x5F 0x017C 95: Reserved */ 172 | .long RSV80_IRQHandler /* 0x60 0x0180 96: Reserved */ 173 | .long RSV81_IRQHandler /* 0x61 0x0184 97: Reserved */ 174 | .long ECC_IRQHandler /* 0x62 0x0188 98: ECC */ 175 | .long DVS_IRQHandler /* 0x63 0x018C 99: DVS */ 176 | .long SIMO_IRQHandler /* 0x64 0x0190 100: SIMO */ 177 | .long RSV85_IRQHandler /* 0x65 0x0194 101: Reserved */ 178 | .long RSV86_IRQHandler /* 0x66 0x0198 102: Reserved */ 179 | .long RSV87_IRQHandler /* 0x67 0x019C 103: Reserved */ 180 | .long UART3_IRQHandler /* 0x68 0x01A0 104: UART 3 (LP) */ 181 | .long RSV89_IRQHandler /* 0x69 0x01A4 105: Reserved */ 182 | .long RSV90_IRQHandler /* 0x6A 0x01A8 106: Reserved */ 183 | .long PCIF_IRQHandler /* 0x6B 0x01AC 107: PCIF (Camera) */ 184 | .long RSV92_IRQHandler /* 0x6C 0x01B0 108: Reserved */ 185 | .long RSV93_IRQHandler /* 0x6D 0x01B4 109: Reserved */ 186 | .long RSV94_IRQHandler /* 0x6E 0x01B8 110: Reserved */ 187 | .long RSV95_IRQHandler /* 0x6F 0x01BC 111: Reserved */ 188 | .long RSV96_IRQHandler /* 0x70 0x01C0 112: Reserved */ 189 | .long AES_IRQHandler /* 0x71 0x01C4 113: AES */ 190 | .long RSV98_IRQHandler /* 0x72 0x01C8 114: Reserved */ 191 | .long I2S_IRQHandler /* 0x73 0x01CC 115: I2S */ 192 | .long CNN_FIFO_IRQHandler /* 0x74 0x01D0 116: CNN FIFO */ 193 | .long CNN_IRQHandler /* 0x75 0x01D4 117: CNN */ 194 | .long RSV102_IRQHandler /* 0x76 0x01D8 118: Reserved */ 195 | .long LPCMP_IRQHandler /* 0x77 0x01Dc 119: LP Comparator */ 196 | 197 | .section .firmware_startup 198 | .thumb 199 | .thumb_func 200 | .align 9 201 | .globl firmware_startup 202 | .type firmware_startup, %function 203 | firmware_startup: 204 | ldr r0, =Reset_Handler 205 | blx r0 206 | 207 | 208 | .text 209 | .thumb 210 | .thumb_func 211 | .align 2 212 | .globl Reset_Handler 213 | .type Reset_Handler, %function 214 | Reset_Handler: 215 | ldr r0, =__StackTop 216 | mov sp, r0 217 | 218 | /* PreInit runs before any RAM initialization. Example usage: DDR setup, etc. */ 219 | ldr r0, =PreInit 220 | blx r0 221 | cbnz r0, .SKIPRAMINIT 222 | 223 | /* Loop to copy data from read only memory to RAM. The ranges 224 | * of copy from/to are specified by following symbols evaluated in 225 | * linker script. 226 | * __load_data: Where data sections are saved. 227 | * _data /_edata: RAM address range that data should be 228 | * copied to. Both must be aligned to 4 bytes boundary. */ 229 | 230 | ldr r1, =__load_data 231 | ldr r2, =_data 232 | ldr r3, =_edata 233 | 234 | #if 0 235 | /* Here are two copies of loop implemenations. First one favors code size 236 | * and the second one favors performance. Default uses the first one. 237 | * Change to "#if 0" to use the second one */ 238 | .LC0: 239 | cmp r2, r3 240 | ittt lt 241 | ldrlt r0, [r1], #4 242 | strlt r0, [r2], #4 243 | blt .LC0 244 | #else 245 | subs r3, r2 246 | ble .LC1 247 | .LC0: 248 | subs r3, #4 249 | ldr r0, [r1, r3] 250 | str r0, [r2, r3] 251 | bgt .LC0 252 | .LC1: 253 | #endif 254 | 255 | /* 256 | * Loop to zero out BSS section, which uses following symbols 257 | * in linker script: 258 | * _bss : start of BSS section. Must align to 4 259 | * _ebss : end of BSS section. Must align to 4 260 | */ 261 | ldr r1, =_bss 262 | ldr r2, =_ebss 263 | 264 | movs r0, 0 265 | .LC2: 266 | cmp r1, r2 267 | itt lt 268 | strlt r0, [r1], #4 269 | blt .LC2 270 | 271 | .SKIPRAMINIT: 272 | 273 | /* Perform system initialization after RAM initialization */ 274 | ldr r0, =SystemInit 275 | blx r0 276 | 277 | /* This must be called to walk the constructor array for static C++ objects */ 278 | /* Note: The linker file must have .data symbols for __X_array_start and __X_array_end */ 279 | /* where X is {preinit, init, fini} */ 280 | ldr r0, =__libc_init_array 281 | blx r0 282 | 283 | /* Transfer control to user's main program */ 284 | ldr r0, =main 285 | blx r0 286 | 287 | .SPIN: 288 | /* spin if main ever returns. */ 289 | bl .SPIN 290 | 291 | /* Macro to define default handlers. Default handler 292 | * will be weak symbol and just dead loops. They can be 293 | * overwritten by other handlers */ 294 | .macro def_irq_handler handler_name 295 | .align 1 296 | .thumb_func 297 | .weak \handler_name 298 | .type \handler_name, %function 299 | \handler_name : 300 | b . 301 | .size \handler_name, . - \handler_name 302 | .endm 303 | 304 | def_irq_handler NMI_Handler 305 | def_irq_handler HardFault_Handler 306 | def_irq_handler MemManage_Handler 307 | def_irq_handler BusFault_Handler 308 | def_irq_handler UsageFault_Handler 309 | def_irq_handler SVC_Handler 310 | def_irq_handler DebugMon_Handler 311 | def_irq_handler PendSV_Handler 312 | def_irq_handler SysTick_Handler 313 | def_irq_handler Default_Handler 314 | 315 | /* Device-specific Interrupts */ 316 | def_irq_handler PF_IRQHandler /* 0x10 0x0040 16: Power Fail */ 317 | def_irq_handler WDT0_IRQHandler /* 0x11 0x0044 17: Watchdog 0 */ 318 | def_irq_handler RSV02_IRQHandler /* 0x12 0x0048 18: Reserved */ 319 | def_irq_handler RTC_IRQHandler /* 0x13 0x004C 19: RTC */ 320 | def_irq_handler TRNG_IRQHandler /* 0x14 0x0050 20: True Random Number Generator */ 321 | def_irq_handler TMR0_IRQHandler /* 0x15 0x0054 21: Timer 0 */ 322 | def_irq_handler TMR1_IRQHandler /* 0x16 0x0058 22: Timer 1 */ 323 | def_irq_handler TMR2_IRQHandler /* 0x17 0x005C 23: Timer 2 */ 324 | def_irq_handler TMR3_IRQHandler /* 0x18 0x0060 24: Timer 3 */ 325 | def_irq_handler TMR4_IRQHandler /* 0x19 0x0064 25: Timer 4 (LP) */ 326 | def_irq_handler TMR5_IRQHandler /* 0x1A 0x0068 26: Timer 5 (LP) */ 327 | def_irq_handler RSV11_IRQHandler /* 0x1B 0x006C 27: Reserved */ 328 | def_irq_handler RSV12_IRQHandler /* 0x1C 0x0070 28: Reserved */ 329 | def_irq_handler I2C0_IRQHandler /* 0x1D 0x0074 29: I2C0 */ 330 | def_irq_handler UART0_IRQHandler /* 0x1E 0x0078 30: UART 0 */ 331 | def_irq_handler UART1_IRQHandler /* 0x1F 0x007C 31: UART 1 */ 332 | def_irq_handler SPI1_IRQHandler /* 0x20 0x0080 32: SPI1 */ 333 | def_irq_handler RSV17_IRQHandler /* 0x21 0x0084 33: Reserved */ 334 | def_irq_handler RSV18_IRQHandler /* 0x22 0x0088 34: Reserved */ 335 | def_irq_handler RSV19_IRQHandler /* 0x23 0x008C 35: Reserved */ 336 | def_irq_handler ADC_IRQHandler /* 0x24 0x0090 36: ADC */ 337 | def_irq_handler RSV21_IRQHandler /* 0x25 0x0094 37: Reserved */ 338 | def_irq_handler RSV22_IRQHandler /* 0x26 0x0098 38: Reserved */ 339 | def_irq_handler FLC0_IRQHandler /* 0x27 0x009C 39: Flash Controller */ 340 | def_irq_handler GPIO0_IRQHandler /* 0x28 0x00A0 40: GPIO0 */ 341 | def_irq_handler GPIO1_IRQHandler /* 0x29 0x00A4 41: GPIO1 */ 342 | def_irq_handler GPIO2_IRQHandler /* 0x2A 0x00A8 42: GPIO2 (LP) */ 343 | def_irq_handler RSV27_IRQHandler /* 0x2B 0x00AC 43: Reserved */ 344 | def_irq_handler DMA0_IRQHandler /* 0x2C 0x00B0 44: DMA0 */ 345 | def_irq_handler DMA1_IRQHandler /* 0x2D 0x00B4 45: DMA1 */ 346 | def_irq_handler DMA2_IRQHandler /* 0x2E 0x00B8 46: DMA2 */ 347 | def_irq_handler DMA3_IRQHandler /* 0x2F 0x00BC 47: DMA3 */ 348 | def_irq_handler RSV32_IRQHandler /* 0x30 0x00C0 48: Reserved */ 349 | def_irq_handler RSV33_IRQHandler /* 0x31 0x00C4 49: Reserved */ 350 | def_irq_handler UART2_IRQHandler /* 0x32 0x00C8 50: UART 2 */ 351 | def_irq_handler RSV35_IRQHandler /* 0x33 0x00CC 51: Reserved */ 352 | def_irq_handler I2C1_IRQHandler /* 0x34 0x00D0 52: I2C1 */ 353 | def_irq_handler RSV37_IRQHandler /* 0x35 0x00D4 53: Reserved */ 354 | def_irq_handler RSV38_IRQHandler /* 0x36 0x00D8 54: Reserved */ 355 | def_irq_handler RSV39_IRQHandler /* 0x37 0x00DC 55: Reserved */ 356 | def_irq_handler RSV40_IRQHandler /* 0x38 0x00E0 56: Reserved */ 357 | def_irq_handler RSV41_IRQHandler /* 0x39 0x00E4 57: Reserved */ 358 | def_irq_handler RSV42_IRQHandler /* 0x3A 0x00E8 58: Reserved */ 359 | def_irq_handler RSV43_IRQHandler /* 0x3B 0x00EC 59: Reserved */ 360 | def_irq_handler RSV44_IRQHandler /* 0x3C 0x00F0 60: Reserved */ 361 | def_irq_handler RSV45_IRQHandler /* 0x3D 0x00F4 61: Reserved */ 362 | def_irq_handler RSV46_IRQHandler /* 0x3E 0x00F8 62: Reserved */ 363 | def_irq_handler RSV47_IRQHandler /* 0x3F 0x00FC 63: Reserved */ 364 | def_irq_handler RSV48_IRQHandler /* 0x40 0x0100 64: Reserved */ 365 | def_irq_handler RSV49_IRQHandler /* 0x41 0x0104 65: Reserved */ 366 | def_irq_handler RSV50_IRQHandler /* 0x42 0x0108 66: Reserved */ 367 | def_irq_handler RSV51_IRQHandler /* 0x43 0x010C 67: Reserved */ 368 | def_irq_handler RSV52_IRQHandler /* 0x44 0x0110 68: Reserved */ 369 | def_irq_handler WUT_IRQHandler /* 0x45 0x0114 69: Wakeup Timer */ 370 | def_irq_handler GPIOWAKE_IRQHandler /* 0x46 0x0118 70: GPIO and AIN Wakeup */ 371 | def_irq_handler RSV55_IRQHandler /* 0x47 0x011C 71: Reserved */ 372 | def_irq_handler SPI0_IRQHandler /* 0x48 0x0120 72: SPI0 */ 373 | def_irq_handler WDT1_IRQHandler /* 0x49 0x0124 73: LP Watchdog */ 374 | def_irq_handler RSV58_IRQHandler /* 0x4A 0x0128 74: Reserved */ 375 | def_irq_handler PT_IRQHandler /* 0x4B 0x012C 75: Pulse Train */ 376 | def_irq_handler RSV60_IRQHandler /* 0x4C 0x0130 76: Reserved */ 377 | def_irq_handler RSV61_IRQHandler /* 0x4D 0x0134 77: Reserved */ 378 | def_irq_handler I2C2_IRQHandler /* 0x4E 0x0138 78: I2C2 */ 379 | def_irq_handler RISCV_IRQHandler /* 0x4F 0x013C 79: RISC-V */ 380 | def_irq_handler RSV64_IRQHandler /* 0x50 0x0140 80: Reserved */ 381 | def_irq_handler RSV65_IRQHandler /* 0x51 0x0144 81: Reserved */ 382 | def_irq_handler RSV66_IRQHandler /* 0x52 0x0148 82: Reserved */ 383 | def_irq_handler OWM_IRQHandler /* 0x53 0x014C 83: One Wire Master */ 384 | def_irq_handler RSV68_IRQHandler /* 0x54 0x0150 84: Reserved */ 385 | def_irq_handler RSV69_IRQHandler /* 0x55 0x0154 85: Reserved */ 386 | def_irq_handler RSV70_IRQHandler /* 0x56 0x0158 86: Reserved */ 387 | def_irq_handler RSV71_IRQHandler /* 0x57 0x015C 87: Reserved */ 388 | def_irq_handler RSV72_IRQHandler /* 0x58 0x0160 88: Reserved */ 389 | def_irq_handler RSV73_IRQHandler /* 0x59 0x0164 89: Reserved */ 390 | def_irq_handler RSV74_IRQHandler /* 0x5A 0x0168 90: Reserved */ 391 | def_irq_handler RSV75_IRQHandler /* 0x5B 0x016C 91: Reserved */ 392 | def_irq_handler RSV76_IRQHandler /* 0x5C 0x0170 92: Reserved */ 393 | def_irq_handler RSV77_IRQHandler /* 0x5D 0x0174 93: Reserved */ 394 | def_irq_handler RSV78_IRQHandler /* 0x5E 0x0178 94: Reserved */ 395 | def_irq_handler RSV79_IRQHandler /* 0x5F 0x017C 95: Reserved */ 396 | def_irq_handler RSV80_IRQHandler /* 0x60 0x0180 96: Reserved */ 397 | def_irq_handler RSV81_IRQHandler /* 0x61 0x0184 97: Reserved */ 398 | def_irq_handler ECC_IRQHandler /* 0x62 0x0188 98: ECC */ 399 | def_irq_handler DVS_IRQHandler /* 0x63 0x018C 99: DVS */ 400 | def_irq_handler SIMO_IRQHandler /* 0x64 0x0190 100: SIMO */ 401 | def_irq_handler RSV85_IRQHandler /* 0x65 0x0194 101: Reserved */ 402 | def_irq_handler RSV86_IRQHandler /* 0x66 0x0198 102: Reserved */ 403 | def_irq_handler RSV87_IRQHandler /* 0x67 0x019C 103: Reserved */ 404 | def_irq_handler UART3_IRQHandler /* 0x68 0x01A0 104: UART 3 (LP) */ 405 | def_irq_handler RSV89_IRQHandler /* 0x69 0x01A4 105: Reserved */ 406 | def_irq_handler RSV90_IRQHandler /* 0x6A 0x01A8 106: Reserved */ 407 | def_irq_handler PCIF_IRQHandler /* 0x6B 0x01AC 107: PCIF (Camera) */ 408 | def_irq_handler RSV92_IRQHandler /* 0x6C 0x01B0 108: Reserved */ 409 | def_irq_handler RSV93_IRQHandler /* 0x6D 0x01B4 109: Reserved */ 410 | def_irq_handler RSV94_IRQHandler /* 0x6E 0x01B8 110: Reserved */ 411 | def_irq_handler RSV95_IRQHandler /* 0x6F 0x01BC 111: Reserved */ 412 | def_irq_handler RSV96_IRQHandler /* 0x70 0x01C0 112: Reserved */ 413 | def_irq_handler AES_IRQHandler /* 0x71 0x01C4 113: AES */ 414 | def_irq_handler RSV98_IRQHandler /* 0x72 0x01C8 114: Reserved */ 415 | def_irq_handler I2S_IRQHandler /* 0x73 0x01CC 115: I2S */ 416 | def_irq_handler CNN_FIFO_IRQHandler /* 0x74 0x01D0 116: CNN FIFO */ 417 | def_irq_handler CNN_IRQHandler /* 0x75 0x01D4 117: CNN */ 418 | def_irq_handler RSV102_IRQHandler /* 0x76 0x01D8 118: Reserved */ 419 | def_irq_handler LPCMP_IRQHandler /* 0x77 0x01Dc 119: LP Comparator */ 420 | .end 421 | --------------------------------------------------------------------------------