initial commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_bootloader.h
|
||||
//!
|
||||
//! @brief
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef AM_BOOTLOADER_H
|
||||
#define AM_BOOTLOADER_H
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Macros
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define AM_BOOTLOADER_DISABLE_OVERRIDE_PIN (0xFFFFFFFF)
|
||||
#define AM_BOOTLOADER_OVERRIDE_HIGH (0x1)
|
||||
#define AM_BOOTLOADER_OVERRIDE_LOW (0x0)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Structure to keep track of boot image information.
|
||||
// In the flash, the structure contains a 4 byte CRC for integrity
|
||||
// verification. It needs to be ensured that the size of this structure is
|
||||
// not more than AM_HAL_FLASH_PAGE_SIZE bytes
|
||||
//
|
||||
//*****************************************************************************
|
||||
typedef struct
|
||||
{
|
||||
// Starting address where the image was linked to run.
|
||||
uint32_t *pui32LinkAddress;
|
||||
|
||||
// Length of the executable image in bytes.
|
||||
uint32_t ui32NumBytes;
|
||||
|
||||
// CRC-32 Value for the full image.
|
||||
uint32_t ui32CRC;
|
||||
|
||||
// Override GPIO number. (Can be used to force a new image load)
|
||||
uint32_t ui32OverrideGPIO;
|
||||
|
||||
// Polarity for the override pin.
|
||||
uint32_t ui32OverridePolarity;
|
||||
|
||||
// Stack pointer location.
|
||||
uint32_t *pui32StackPointer;
|
||||
|
||||
// Reset vector location.
|
||||
uint32_t *pui32ResetVector;
|
||||
|
||||
// Protection status of image in flash
|
||||
uint32_t bEncrypted;
|
||||
|
||||
// CRC-32 value of this structure
|
||||
uint32_t ui32Checksum;
|
||||
}
|
||||
am_bootloader_image_t;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// External function declarations.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern uint32_t am_bootloader_crc32(const void *pvData, uint32_t ui32Length);
|
||||
extern uint32_t am_bootloader_fast_crc32(const void *pvData, uint32_t ui32NumBytes);
|
||||
extern void am_bootloader_partial_crc32(const void *pvData, uint32_t ui32NumBytes, uint32_t *pui32CRC);
|
||||
extern bool am_bootloader_image_check(am_bootloader_image_t *psImage);
|
||||
extern bool am_bootloader_flash_check(am_bootloader_image_t *psImage);
|
||||
extern int am_bootloader_flag_page_update(am_bootloader_image_t *psImage, uint32_t *pui32FlagPage);
|
||||
extern bool am_bootloader_validate_structure(uint32_t *pInfo, uint32_t size);
|
||||
extern bool am_hal_bootloader_override_check(am_bootloader_image_t *psImage);
|
||||
extern void am_bootloader_image_run(am_bootloader_image_t *psImage);
|
||||
extern bool am_bootloader_check_index(uint32_t index, uint32_t *pMask);
|
||||
extern void am_bootloader_write_flash_within_page(uint32_t ui32WriteAddr,
|
||||
uint32_t *pui32ReadAddr, uint32_t ui32NumWords);
|
||||
|
||||
extern void am_bootloader_program_flash_page(uint32_t ui32WriteAddr,
|
||||
uint32_t *pui32ReadAddr, uint32_t numBytes);
|
||||
extern void am_bootloader_erase_flash_page(uint32_t ui32Addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AM_BOOTLOADER_H
|
||||
@@ -0,0 +1,651 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_ios_boot_handlers.c
|
||||
//!
|
||||
//! @brief Boot related functions for the IOS interface.
|
||||
//!
|
||||
//! This file contains the main state machine for handling boot commands via
|
||||
//! the I2C interface.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
#include "am_multi_boot_private.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// SPI Slave Configuration
|
||||
//
|
||||
//*****************************************************************************
|
||||
static am_hal_ios_config_t g_sIOSConfig =
|
||||
{
|
||||
// Configure the IOS in SPI mode.
|
||||
.ui32InterfaceSelect = AM_HAL_IOS_USE_SPI,
|
||||
|
||||
// Eliminate the "read-only" section, so an external host can use the
|
||||
// entire "direct write" section.
|
||||
.ui32ROBase = 0x78,
|
||||
|
||||
// Set the FIFO base to the maximum value, making the "direct write"
|
||||
// section as big as possible.
|
||||
.ui32FIFOBase = 0x78,
|
||||
|
||||
// We don't need any RAM space, so extend the FIFO all the way to the end
|
||||
// of the LRAM.
|
||||
.ui32RAMBase = 0x100,
|
||||
};
|
||||
static uint32_t g_iosIntPin;
|
||||
|
||||
static volatile bool g_bIosImageValid = false;
|
||||
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
void *g_IOSHandle;
|
||||
|
||||
#define TEST_ACC_INT 1
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// GPIO Configuration
|
||||
//
|
||||
//*****************************************************************************
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_IOS_SCL =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_0_SLSCL,
|
||||
.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA,
|
||||
.eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_IOS_SDA =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_1_SLSDAWIR3,
|
||||
.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K,
|
||||
.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA,
|
||||
.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_IOS_SCK =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_0_SLSCK,
|
||||
.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA,
|
||||
.eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_IOS_CE =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_3_SLnCE,
|
||||
.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA,
|
||||
.eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE,
|
||||
.uNCE = 0,
|
||||
.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_IOS_MISO =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_2_SLMISO
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_IOS_MOSI =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_1_SLMOSI,
|
||||
.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA,
|
||||
.eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_ENABLE =
|
||||
{
|
||||
.uFuncSel = AM_HAL_PIN_0_GPIO,
|
||||
.eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE,
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_ENABLE =
|
||||
{
|
||||
.uFuncSel = 3,
|
||||
.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL
|
||||
};
|
||||
|
||||
const am_hal_gpio_pincfg_t g_AM_BOOT_GPIO_DISABLE =
|
||||
{
|
||||
.uFuncSel = 3,
|
||||
.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Multiboot protocol handler for IOS implemented in IOS-ACC ISR
|
||||
//!
|
||||
//! This function should be invoked from respective IOS-ACC ISR
|
||||
//!
|
||||
//! @return none.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_multiboot_ios_acc_isr_handler(void)
|
||||
{
|
||||
uint32_t ui32Status;
|
||||
uint32_t *pui32Packet;
|
||||
|
||||
//
|
||||
// Check to see what caused this interrupt, then clear the bit from the
|
||||
// interrupt register.
|
||||
//
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_ios_control(g_IOSHandle, AM_HAL_IOS_REQ_ACC_INTGET, &ui32Status);
|
||||
am_hal_ios_control(g_IOSHandle, AM_HAL_IOS_REQ_ACC_INTCLR, &ui32Status);
|
||||
#else
|
||||
ui32Status = am_hal_ios_access_int_status_get(false);
|
||||
am_hal_ios_access_int_clear(ui32Status);
|
||||
#endif
|
||||
//
|
||||
// Set up a pointer for writing 32-bit aligned packets through the IO slave
|
||||
// interface.
|
||||
//
|
||||
pui32Packet = (uint32_t *) am_hal_ios_pui8LRAM;
|
||||
|
||||
if ( ui32Status & AM_HAL_IOS_ACCESS_INT_03 )
|
||||
{
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_SET);
|
||||
#else
|
||||
am_hal_gpio_out_bit_set(g_iosIntPin);
|
||||
#endif
|
||||
//
|
||||
// Figure out what to do next based on the packet header.
|
||||
//
|
||||
switch(pui32Packet[0])
|
||||
{
|
||||
case AM_BOOTLOADER_NEW_IMAGE:
|
||||
|
||||
//
|
||||
// Parse the image packet, and store the result to the global
|
||||
// image structure.
|
||||
//
|
||||
g_bIosImageValid = image_start_packet_read(&g_sImage,
|
||||
(uint32_t *) am_hal_ios_pui8LRAM);
|
||||
|
||||
//
|
||||
// Make sure the image packet had reasonable contents. If it
|
||||
// didn't, we need to let the host know.
|
||||
//
|
||||
if ( g_bIosImageValid )
|
||||
{
|
||||
//
|
||||
// Good image; Send back a "READY" packet.
|
||||
//
|
||||
pui32Packet[0] = AM_BOOTLOADER_READY;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Bad image; Send back an error.
|
||||
//
|
||||
pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_SET_OVERRIDE_CMD:
|
||||
//
|
||||
// Set the override GPIO settings based on the packet
|
||||
// information.
|
||||
//
|
||||
g_sImage.ui32OverrideGPIO = pui32Packet[1];
|
||||
g_sImage.ui32OverridePolarity = pui32Packet[2];
|
||||
|
||||
//
|
||||
// Send back a "READY" packet.
|
||||
//
|
||||
pui32Packet[0] = AM_BOOTLOADER_READY;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_NEW_PACKET:
|
||||
//
|
||||
// Only take new packets if our image structure is valid.
|
||||
//
|
||||
if ( !g_bIosImageValid )
|
||||
{
|
||||
pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the size information from the packet header, and set the src pointer
|
||||
// to the beginning of the actual data.
|
||||
//
|
||||
//
|
||||
// Parse the reset of the packet sitting in the IOS LRAM.
|
||||
//
|
||||
image_data_packet_read((uint8_t *)(am_hal_ios_pui8LRAM + 8),
|
||||
*((uint32_t *) (am_hal_ios_pui8LRAM + 4)));
|
||||
|
||||
//
|
||||
// If this packet completed the image...
|
||||
//
|
||||
if ( g_ui32BytesReceived == g_sImage.ui32NumBytes )
|
||||
{
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
if ( (g_ui32CRC != g_sImage.ui32CRC) || multiboot_secure_verify(&g_sImage.ui32CRC) )
|
||||
{
|
||||
pui32Packet[0] = AM_BOOTLOADER_BAD_CRC;
|
||||
}
|
||||
#else
|
||||
if ( g_ui32CRC != g_sImage.ui32CRC )
|
||||
{
|
||||
pui32Packet[0] = AM_BOOTLOADER_BAD_CRC;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
// Protect (and optionally write if stored in SRAM)
|
||||
// image in flash now as it has been validated now
|
||||
program_image(g_sImage.bEncrypted);
|
||||
// Validate the flash contents of a boot image to make
|
||||
// sure it's safe to run
|
||||
if ( am_bootloader_flash_check(&g_sImage) )
|
||||
{
|
||||
pui32Packet[0] = AM_BOOTLOADER_IMAGE_COMPLETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If this wasn't the end of the image, just send back a
|
||||
// "READY" packet.
|
||||
//
|
||||
pui32Packet[0] = AM_BOOTLOADER_READY;
|
||||
}
|
||||
//
|
||||
// Assert the interrupt line so the host knows we have a
|
||||
// message.
|
||||
//
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_RESET:
|
||||
if ( USE_FLAG_PAGE )
|
||||
{
|
||||
//
|
||||
// Write the flag page.
|
||||
//
|
||||
am_bootloader_flag_page_update(&g_sImage, (uint32_t *)FLAG_PAGE_LOCATION);
|
||||
}
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
wipe_sram();
|
||||
#endif
|
||||
|
||||
case AM_BOOTLOADER_RESTART:
|
||||
//
|
||||
// Perform a software reset.
|
||||
//
|
||||
#if AM_APOLLO3_RESET
|
||||
am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI, 0);
|
||||
#else // AM_APOLLO3_RESET
|
||||
am_hal_reset_poi();
|
||||
#endif // AM_APOLLO3_RESET
|
||||
|
||||
//
|
||||
// Wait for the reset to take effect.
|
||||
//
|
||||
while (1);
|
||||
|
||||
case AM_BOOTLOADER_BL_VERSION_CMD:
|
||||
//
|
||||
// Respond with the version number.
|
||||
//
|
||||
pui32Packet[0] = AM_BOOTLOADER_BL_VERSION;
|
||||
pui32Packet[1] = AM_BOOTLOADER_VERSION_NUM;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_ACK_CMD:
|
||||
case AM_BOOTLOADER_NAK_CMD:
|
||||
break;
|
||||
|
||||
default:
|
||||
// Error
|
||||
pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Configure the IOS for IOS boot
|
||||
//!
|
||||
//! @param interruptPin is the handshake pin to use for interrupting host.
|
||||
//!
|
||||
//! This function configures the IOS for bootloader
|
||||
//!
|
||||
//! @return none
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_multiboot_setup_ios_interface(uint32_t interruptPin)
|
||||
{
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
uint32_t ui32Arg = 0;
|
||||
//
|
||||
// Check pin 0 to see if we should be using SPI or I2C
|
||||
//
|
||||
am_hal_gpio_pinconfig(0, g_AM_HAL_GPIO_INPUT_ENABLE);
|
||||
am_hal_gpio_state_read(0, AM_HAL_GPIO_INPUT_READ, &ui32Arg);
|
||||
if ( ui32Arg )
|
||||
{
|
||||
//
|
||||
// If the clock line is high, we'll assume I2C.
|
||||
//
|
||||
am_hal_gpio_pinconfig(0, g_AM_BOOT_GPIO_IOS_SCL);
|
||||
am_hal_gpio_pinconfig(1, g_AM_BOOT_GPIO_IOS_SDA);
|
||||
|
||||
g_sIOSConfig.ui32InterfaceSelect = (AM_HAL_IOS_USE_I2C |
|
||||
AM_HAL_IOS_I2C_ADDRESS(I2C_SLAVE_ADDR << 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If the clock line is low, we'll assume SPI.
|
||||
//
|
||||
am_hal_gpio_pinconfig(0, g_AM_BOOT_GPIO_IOS_SCK);
|
||||
am_hal_gpio_pinconfig(1, g_AM_BOOT_GPIO_IOS_MISO);
|
||||
am_hal_gpio_pinconfig(2, g_AM_BOOT_GPIO_IOS_MOSI);
|
||||
am_hal_gpio_pinconfig(3, g_AM_BOOT_GPIO_IOS_CE);
|
||||
|
||||
g_sIOSConfig.ui32InterfaceSelect = AM_HAL_IOS_USE_SPI;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure the IOS interface and LRAM structure.
|
||||
//
|
||||
am_hal_ios_initialize(0, &g_IOSHandle);
|
||||
am_hal_ios_power_ctrl(g_IOSHandle, AM_HAL_SYSCTRL_WAKE, false);
|
||||
am_hal_ios_configure(g_IOSHandle, &g_sIOSConfig);
|
||||
g_iosIntPin = interruptPin;
|
||||
|
||||
//
|
||||
// Make sure the interrupt pin is set up correctly
|
||||
//
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_SET);
|
||||
am_hal_gpio_pinconfig(g_iosIntPin, g_AM_BOOT_GPIO_ENABLE);
|
||||
|
||||
//
|
||||
// Clear out any IOS register-access interrupts that may be active, and
|
||||
// enable interrupts for the registers we're interested in.
|
||||
//
|
||||
#ifdef TEST_ACC_INT
|
||||
ui32Arg = AM_HAL_IOS_ACCESS_INT_ALL;
|
||||
am_hal_ios_control(g_IOSHandle, AM_HAL_IOS_REQ_ACC_INTCLR, &ui32Arg);
|
||||
ui32Arg = AM_HAL_IOS_ACCESS_INT_03;
|
||||
am_hal_ios_control(g_IOSHandle, AM_HAL_IOS_REQ_ACC_INTEN, &ui32Arg);
|
||||
#endif
|
||||
am_hal_ios_interrupt_clear(g_IOSHandle, AM_HAL_IOS_INT_ALL);
|
||||
am_hal_ios_interrupt_enable(g_IOSHandle, AM_HAL_IOS_INT_FSIZE);
|
||||
|
||||
//
|
||||
// Set the bit in the NVIC to accept access interrupts from the IO Slave.
|
||||
//
|
||||
#if AM_CMSIS_REGS
|
||||
NVIC_EnableIRQ(IOSLAVEACC_IRQn);
|
||||
// NVIC_EnableIRQ(IOSLAVE_IRQn);
|
||||
#else // AM_CMSIS_REGS
|
||||
am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOSACC);
|
||||
// am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOSLAVE);
|
||||
#endif // AM_CMSIS_REGS
|
||||
|
||||
//
|
||||
// Notify the host that we're ready to receive data.
|
||||
//
|
||||
*((uint32_t *) am_hal_ios_pui8LRAM) = AM_BOOTLOADER_READY;
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
//
|
||||
// Check pin 0 to see if we should be using SPI or I2C
|
||||
//
|
||||
am_hal_gpio_pin_config(0, AM_HAL_GPIO_INPUT);
|
||||
if ( am_hal_gpio_input_bit_read(0) )
|
||||
{
|
||||
//
|
||||
// If the clock line is high, we'll assume I2C.
|
||||
//
|
||||
am_hal_gpio_pin_config(0, AM_HAL_PIN_0_SLSCL);
|
||||
am_hal_gpio_pin_config(1, AM_HAL_PIN_1_SLSDA);
|
||||
|
||||
g_sIOSConfig.ui32InterfaceSelect = (AM_HAL_IOS_USE_I2C |
|
||||
AM_HAL_IOS_I2C_ADDRESS(I2C_SLAVE_ADDR << 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If the clock line is low, we'll assume SPI.
|
||||
//
|
||||
am_hal_gpio_pin_config(0, AM_HAL_PIN_0_SLSCK);
|
||||
am_hal_gpio_pin_config(1, AM_HAL_PIN_1_SLMISO);
|
||||
am_hal_gpio_pin_config(2, AM_HAL_PIN_2_SLMOSI);
|
||||
am_hal_gpio_pin_config(3, AM_HAL_PIN_3_SLnCE);
|
||||
|
||||
g_sIOSConfig.ui32InterfaceSelect = AM_HAL_IOS_USE_SPI;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure the IOS interface and LRAM structure.
|
||||
//
|
||||
am_hal_ios_config(&g_sIOSConfig);
|
||||
g_iosIntPin = interruptPin;
|
||||
|
||||
//
|
||||
// Make sure the interrupt pin is set up correctly
|
||||
//
|
||||
am_hal_gpio_out_bit_set(g_iosIntPin);
|
||||
am_hal_gpio_pin_config(g_iosIntPin, AM_HAL_PIN_OUTPUT);
|
||||
|
||||
//
|
||||
// Clear out any IOS register-access interrupts that may be active, and
|
||||
// enable interrupts for the registers we're interested in.
|
||||
//
|
||||
am_hal_ios_access_int_clear(AM_HAL_IOS_ACCESS_INT_ALL);
|
||||
am_hal_ios_access_int_enable(AM_HAL_IOS_ACCESS_INT_03);
|
||||
|
||||
am_hal_ios_int_clear(AM_HAL_IOS_INT_ALL);
|
||||
am_hal_ios_int_enable(AM_HAL_IOS_INT_FSIZE);
|
||||
|
||||
//
|
||||
// Set the bit in the NVIC to accept access interrupts from the IO Slave.
|
||||
//
|
||||
am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOSACC);
|
||||
// am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOSLAVE);
|
||||
|
||||
//
|
||||
// Notify the host that we're ready to receive data.
|
||||
//
|
||||
*((uint32_t *) am_hal_ios_pui8LRAM) = AM_BOOTLOADER_READY;
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Cleanup the IOS
|
||||
//!
|
||||
//! This function un-configures the IOS
|
||||
//!
|
||||
//! @return none
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_multiboot_cleanup_ios_interface(void)
|
||||
{
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_pinconfig(0, g_AM_BOOT_GPIO_DISABLE);
|
||||
am_hal_gpio_pinconfig(1, g_AM_BOOT_GPIO_DISABLE);
|
||||
am_hal_gpio_pinconfig(2, g_AM_BOOT_GPIO_DISABLE);
|
||||
am_hal_gpio_pinconfig(3, g_AM_BOOT_GPIO_DISABLE);
|
||||
#else
|
||||
am_hal_gpio_pin_config(0, AM_HAL_PIN_DISABLE);
|
||||
am_hal_gpio_pin_config(1, AM_HAL_PIN_DISABLE);
|
||||
am_hal_gpio_pin_config(2, AM_HAL_PIN_DISABLE);
|
||||
am_hal_gpio_pin_config(3, AM_HAL_PIN_DISABLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
//*****************************************************************************
|
||||
//
|
||||
// IO Slave Main ISR.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_ioslave_ios_isr(void)
|
||||
{
|
||||
uint32_t ui32Status;
|
||||
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
//
|
||||
// Check to see what caused this interrupt, then clear the bit from the
|
||||
// interrupt register.
|
||||
//
|
||||
am_hal_ios_interrupt_status_get(g_IOSHandle, false, &ui32Status);
|
||||
am_hal_ios_interrupt_clear(g_IOSHandle, ui32Status);
|
||||
|
||||
//
|
||||
// Service the I2C slave FIFO if necessary.
|
||||
//
|
||||
am_hal_ios_interrupt_service(g_IOSHandle, ui32Status);
|
||||
#else
|
||||
//
|
||||
// Check to see what caused this interrupt, then clear the bit from the
|
||||
// interrupt register.
|
||||
//
|
||||
ui32Status = am_hal_ios_int_status_get(false);
|
||||
am_hal_ios_int_clear(ui32Status);
|
||||
|
||||
//
|
||||
// Service the I2C slave FIFO if necessary.
|
||||
//
|
||||
am_hal_ios_fifo_service(ui32Status);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// IO Slave handshake
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool
|
||||
am_ioslave_handshake(uint32_t ui32Timeout)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t *pui32Packet;
|
||||
bool bReturnVal = false;
|
||||
|
||||
//
|
||||
// Set up a pointer for writing 32-bit aligned packets through the IO slave
|
||||
// interface.
|
||||
//
|
||||
pui32Packet = (uint32_t *) am_hal_ios_pui8LRAM;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_SET);
|
||||
#else
|
||||
am_hal_gpio_out_bit_set(g_iosIntPin);
|
||||
#endif
|
||||
|
||||
for ( i = 0; i < ui32Timeout; i++ )
|
||||
{
|
||||
if ( pui32Packet[0] == 0x5A )
|
||||
{
|
||||
bReturnVal = true;
|
||||
|
||||
//
|
||||
// Notify the host that we're ready to receive data.
|
||||
//
|
||||
*((uint32_t *) am_hal_ios_pui8LRAM) = AM_BOOTLOADER_READY;
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
am_hal_gpio_state_write(g_iosIntPin, AM_HAL_GPIO_OUTPUT_CLEAR);
|
||||
#else
|
||||
am_hal_gpio_out_bit_clear(g_iosIntPin);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
am_util_delay_us(1);
|
||||
}
|
||||
return bReturnVal;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,925 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_multi_boot.c
|
||||
//!
|
||||
//! @brief Bootloader implementation accepting multiple host protocols.
|
||||
//!
|
||||
//! This is a bootloader implementation that supports flash programming over
|
||||
//! UART, SPI, and I2C. The correct protocol is selected automatically at boot
|
||||
//! time. The messaging is expected to follow little-endian format, which is
|
||||
//! native to Apollo1/2.
|
||||
//!
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#include <string.h>
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
#include "am_multi_boot_private.h"
|
||||
#include "am_multi_boot.h"
|
||||
|
||||
// Protection against NULL pointer
|
||||
#define FLASH_OPERATE(pFlash, func) ((pFlash)->func ? (pFlash)->func() : 0)
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Message buffers.
|
||||
//
|
||||
// Note: The RX buffer needs to be 32-bit aligned to be compatible with the
|
||||
// flash helper functions, but we also need an 8-bit pointer to it for copying
|
||||
// data from the IOS interface, which is only 8 bits wide.
|
||||
//
|
||||
//*****************************************************************************
|
||||
typedef struct
|
||||
{
|
||||
uint32_t *pui32UserBuf;
|
||||
uint8_t *pui8RxBuffer;
|
||||
uint32_t ui32BytesInBuffer;
|
||||
bool bStoreInSRAM;
|
||||
uint32_t *pui32WriteAddress;
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
uint32_t ui32SramBytesUsed;
|
||||
#endif
|
||||
} am_multiboot_t;
|
||||
|
||||
static am_multiboot_t g_am_multiboot = {
|
||||
.pui32UserBuf = NULL,
|
||||
.pui8RxBuffer = NULL,
|
||||
.ui32BytesInBuffer = 0,
|
||||
.bStoreInSRAM = 0,
|
||||
.pui32WriteAddress = 0,
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
.ui32SramBytesUsed = 0,
|
||||
#endif
|
||||
} ;
|
||||
|
||||
static bool
|
||||
check_flash_address_range(uint32_t address, uint32_t size);
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Globals to keep track of the image write state.
|
||||
//
|
||||
//*****************************************************************************
|
||||
uint32_t g_ui32BytesReceived = 0;
|
||||
uint32_t g_ui32CRC = 0;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Image structure to hold data about the downloaded boot image.
|
||||
//
|
||||
//*****************************************************************************
|
||||
am_bootloader_image_t g_sImage =
|
||||
{
|
||||
DEFAULT_LINK_ADDRESS,
|
||||
0,
|
||||
0,
|
||||
DEFAULT_OVERRIDE_GPIO,
|
||||
DEFAULT_OVERRIDE_POLARITY,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Flag page information.
|
||||
//
|
||||
//*****************************************************************************
|
||||
am_bootloader_image_t *g_psBootImage = (am_bootloader_image_t *) FLAG_PAGE_LOCATION;
|
||||
|
||||
// Checks that the address does not overlap with bootloader or flag page
|
||||
// It also checks that the address is inside the internal flash
|
||||
static bool
|
||||
check_flash_address_range(uint32_t address, uint32_t size)
|
||||
{
|
||||
static uint32_t g_intFlashSize = 0;
|
||||
am_hal_mcuctrl_device_t sDevice;
|
||||
|
||||
uint32_t ui32Start = address;
|
||||
uint32_t ui32End = address + size - 1 ;
|
||||
|
||||
if (g_intFlashSize == 0) // First call
|
||||
{
|
||||
// Get chip specific info
|
||||
#if AM_APOLLO3_MCUCTRL
|
||||
am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_DEVICEID, &sDevice);
|
||||
#else // AM_APOLLO3_MCUCTRL
|
||||
am_hal_mcuctrl_device_info_get(&sDevice);
|
||||
#endif // AM_APOLLO3_MCUCTRL
|
||||
|
||||
g_intFlashSize = sDevice.ui32FlashSize;
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure the address is within flash.
|
||||
//
|
||||
//
|
||||
// Check to make sure address is not within bootloader program
|
||||
//
|
||||
if ( ui32Start < MAX_BOOTLOADER_SIZE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check to make sure the address is not beyond the flash
|
||||
if (ui32End >= g_intFlashSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( USE_FLAG_PAGE )
|
||||
{
|
||||
//
|
||||
// Check to make sure address is not in the flag page
|
||||
//
|
||||
if ( (FLAG_PAGE_LOCATION == ui32Start) ||
|
||||
((FLAG_PAGE_LOCATION < ui32Start) &&
|
||||
((FLAG_PAGE_LOCATION + AM_HAL_FLASH_PAGE_SIZE) > ui32Start)) ||
|
||||
((FLAG_PAGE_LOCATION > ui32Start) &&
|
||||
(FLAG_PAGE_LOCATION <= ui32End))
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Internal Flash handler wrapper
|
||||
//
|
||||
//*****************************************************************************
|
||||
static int
|
||||
am_multiboot_flash_read_page(uint32_t ui32DestAddr, uint32_t *pSrc, uint32_t ui32Length)
|
||||
{
|
||||
if (check_flash_address_range((uint32_t)pSrc, ui32Length))
|
||||
{
|
||||
memcpy((uint8_t *)ui32DestAddr, (uint8_t *)pSrc, ui32Length);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
am_multiboot_flash_write_page(uint32_t ui32DestAddr, uint32_t *pSrc, uint32_t ui32Length)
|
||||
{
|
||||
if (check_flash_address_range(ui32DestAddr, ui32Length))
|
||||
{
|
||||
am_bootloader_program_flash_page(ui32DestAddr, pSrc, ui32Length);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int am_multiboot_flash_erase_page(uint32_t ui32DestAddr)
|
||||
{
|
||||
if (check_flash_address_range(ui32DestAddr, 4))
|
||||
{
|
||||
am_bootloader_erase_flash_page(ui32DestAddr);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
am_multiboot_flash_info_t g_intFlash =
|
||||
{
|
||||
// flagPageSize could be set as small as 4 Bytes, and as large as
|
||||
// AM_HAL_FLASH_PAGE_SIZE, since Read/Write on internal flash are
|
||||
// allowed at 4 byte granularity
|
||||
// It is set to max for power optimization
|
||||
// This may have indirect impact on temp storage needed, so it can
|
||||
// be reduced as a trade-off
|
||||
.flashPageSize = AM_HAL_FLASH_PAGE_SIZE,
|
||||
.flashSectorSize = AM_HAL_FLASH_PAGE_SIZE,
|
||||
.flash_init = NULL,
|
||||
.flash_deinit = NULL,
|
||||
.flash_enable = NULL,
|
||||
.flash_disable = NULL,
|
||||
.flash_read_page = am_multiboot_flash_read_page,
|
||||
.flash_write_page = am_multiboot_flash_write_page,
|
||||
.flash_erase_sector = am_multiboot_flash_erase_page,
|
||||
};
|
||||
|
||||
am_multiboot_flash_info_t *g_pFlashInfo;
|
||||
uint32_t *g_pTempBuf;
|
||||
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
// Wipe Clean SRAM up to the specified address
|
||||
// CAUTION!!!
|
||||
// This will wipe the complete SRAM including stack of the caller
|
||||
// This should be called as the last thing before calling reset
|
||||
void wipe_sram(void)
|
||||
{
|
||||
//
|
||||
// Wipe SRAM (without using variables).
|
||||
//
|
||||
// Use the first SRAM location as temp
|
||||
// Last SRAM word = lastAddr = SRAM_BASEADDR + g_am_multiboot.ui32SramBytesUsed - 4;
|
||||
*((volatile uint32_t *)(SRAM_BASEADDR)) =
|
||||
SRAM_BASEADDR + g_am_multiboot.ui32SramBytesUsed - 4;
|
||||
|
||||
// Can not use any local variables from now on
|
||||
while ( *((volatile uint32_t *)(SRAM_BASEADDR)) != SRAM_BASEADDR )
|
||||
{
|
||||
*(*((volatile uint32_t **)(SRAM_BASEADDR))) = 0x0;
|
||||
*((volatile uint32_t *)(SRAM_BASEADDR)) -= 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Programs the flash based on g_am_multiboot.pui32WriteAddress, g_am_multiboot.pui8RxBuffer & g_am_multiboot.ui32BytesInBuffer
|
||||
void
|
||||
program_image(uint32_t bEncrypted)
|
||||
{
|
||||
uint32_t ui32WriteAddr = (uint32_t)g_am_multiboot.pui32WriteAddress;
|
||||
uint32_t *pui32ReadAddr = (uint32_t *)g_am_multiboot.pui8RxBuffer;
|
||||
uint32_t ui32NumBytes = g_am_multiboot.ui32BytesInBuffer;
|
||||
|
||||
if ( g_am_multiboot.bStoreInSRAM )
|
||||
{
|
||||
while ( ui32NumBytes )
|
||||
{
|
||||
am_bootloader_program_flash_page(ui32WriteAddr, pui32ReadAddr,
|
||||
(ui32NumBytes > AM_HAL_FLASH_PAGE_SIZE) ? AM_HAL_FLASH_PAGE_SIZE: ui32NumBytes);
|
||||
if ( ui32NumBytes > AM_HAL_FLASH_PAGE_SIZE )
|
||||
{
|
||||
ui32NumBytes -= AM_HAL_FLASH_PAGE_SIZE;
|
||||
ui32WriteAddr += AM_HAL_FLASH_PAGE_SIZE;
|
||||
pui32ReadAddr += AM_HAL_FLASH_PAGE_SIZE / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Apply necessary protections to flash
|
||||
// Need to add flash protection - chunk by chunk including potentially
|
||||
// the last partial chunk
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Initialize multiboot
|
||||
//!
|
||||
//! @param pBuf is the temporary buffer for multiboot to operate on. This should
|
||||
//! be at least equal to the AM_HAL_FLASH_PAGE_SIZE
|
||||
//! @param bufSize is the temporary buffer size
|
||||
//!
|
||||
//! This function provides multiboot with the scratch memory in SRAM
|
||||
//!
|
||||
//! @return true if the parameters are acceptable.
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool
|
||||
am_multiboot_init(uint32_t *pBuf, uint32_t bufSize)
|
||||
{
|
||||
bool ret = false;
|
||||
if (pBuf && (bufSize >= AM_HAL_FLASH_PAGE_SIZE))
|
||||
{
|
||||
g_am_multiboot.pui32UserBuf = pBuf;
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Read an image start packet
|
||||
//!
|
||||
//! @param psImage is the image structure to read the packet into.
|
||||
//!
|
||||
//! This function reads the "new image" packet, and uses that
|
||||
//! packet to fill in a bootloader image structure. The caller is responsible
|
||||
//! for verifying the packet type before calling this function.
|
||||
//! Packet Structure:
|
||||
//! word0 = Link Address
|
||||
//! word1 = Number of Bytes (Image Size)
|
||||
//! word2 = CRC
|
||||
//! ENCRYPTED?? (#ifdef MULTIBOOT_SECURE)
|
||||
//! word3 = Security Trailer Length
|
||||
//!
|
||||
//! @return true if the image parameters are acceptable.
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool
|
||||
image_start_packet_read(am_bootloader_image_t *psImage, uint32_t *pui32Packet)
|
||||
{
|
||||
am_hal_mcuctrl_device_t sDevice;
|
||||
|
||||
// Get chip specific info
|
||||
#if AM_APOLLO3_MCUCTRL
|
||||
am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_DEVICEID, &sDevice);
|
||||
#else // AM_APOLLO3_MCUCTRL
|
||||
// Get chip specific info
|
||||
am_hal_mcuctrl_device_info_get(&sDevice);
|
||||
#endif // AM_APOLLO3_MCUCTRL
|
||||
|
||||
//
|
||||
// Set the image structure parameters based on the information in the
|
||||
// packet.
|
||||
//
|
||||
psImage->pui32LinkAddress = (uint32_t *)(pui32Packet[1]);
|
||||
psImage->ui32NumBytes = pui32Packet[2];
|
||||
psImage->ui32CRC = pui32Packet[3];
|
||||
psImage->ui32OverrideGPIO = DEFAULT_OVERRIDE_GPIO;
|
||||
psImage->ui32OverridePolarity = DEFAULT_OVERRIDE_POLARITY;
|
||||
psImage->bEncrypted = 0; // This only indicates Copy-Protection in flash
|
||||
|
||||
//
|
||||
// We'll need to fill in the stack pointer and reset vector a little later
|
||||
// in the process.
|
||||
//
|
||||
psImage->pui32StackPointer = 0;
|
||||
psImage->pui32ResetVector = 0;
|
||||
|
||||
//
|
||||
// Check to make sure we're not overwriting the bootloader or the flag page.
|
||||
//
|
||||
if (!check_flash_address_range((uint32_t)psImage->pui32LinkAddress,
|
||||
psImage->ui32NumBytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Determine if we can gather image in SRAM completely before flashing all at once
|
||||
// This implementation uses the excess SRAM available in the system
|
||||
// CAUTION!!!: For this to work it is essential that the unused SRAM banks are
|
||||
// not powered down
|
||||
if ((sDevice.ui32SRAMSize - MAX_SRAM_USED) >= psImage->ui32NumBytes)
|
||||
{
|
||||
g_am_multiboot.bStoreInSRAM = 1;
|
||||
g_am_multiboot.pui8RxBuffer = (uint8_t *)(SRAM_BASEADDR + MAX_SRAM_USED);
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
g_am_multiboot.ui32SramBytesUsed = sDevice.ui32SRAMSize;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
g_am_multiboot.bStoreInSRAM = 0;
|
||||
if (g_am_multiboot.pui32UserBuf == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
g_am_multiboot.pui8RxBuffer = (uint8_t *)g_am_multiboot.pui32UserBuf;
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
g_am_multiboot.ui32SramBytesUsed = MAX_SRAM_USED;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
// Validate the security trailer & Initialize the security params
|
||||
if ( init_multiboot_secure(pui32Packet[4], &pui32Packet[5], g_am_multiboot.bStoreInSRAM,
|
||||
psImage, &psImage->bEncrypted) != 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// Otherwise, the image is presumed to be reasonable. Set our global
|
||||
// variables based on the new image structure.
|
||||
//
|
||||
g_am_multiboot.pui32WriteAddress = psImage->pui32LinkAddress;
|
||||
g_ui32BytesReceived = 0;
|
||||
g_am_multiboot.ui32BytesInBuffer = 0;
|
||||
g_ui32CRC = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Read an image start packet
|
||||
//!
|
||||
//! @param psImage is the image structure to read the packet into.
|
||||
//!
|
||||
//! This function reads the "new image" packet, and uses that
|
||||
//! packet to fill in a bootloader image structure. The caller is responsible
|
||||
//! for verifying the packet type before calling this function.
|
||||
//!
|
||||
//! @return None.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
image_data_packet_read(uint8_t *pui8Src, uint32_t ui32Size)
|
||||
{
|
||||
uint32_t i;
|
||||
//
|
||||
// Loop through the data, copying it into the global buffer.
|
||||
//
|
||||
for ( i = 0; i < ui32Size; i++ )
|
||||
{
|
||||
g_am_multiboot.pui8RxBuffer[g_am_multiboot.ui32BytesInBuffer] = *pui8Src++;
|
||||
|
||||
//
|
||||
// Keep track of how much data we've copied into the SRAM buffer.
|
||||
//
|
||||
g_am_multiboot.ui32BytesInBuffer++;
|
||||
g_ui32BytesReceived++;
|
||||
|
||||
//
|
||||
// Whenever we hit a page boundary or the end of the image, we should
|
||||
// write to flash.
|
||||
//
|
||||
if ( (!g_am_multiboot.bStoreInSRAM && (g_am_multiboot.ui32BytesInBuffer == AM_HAL_FLASH_PAGE_SIZE)) ||
|
||||
g_ui32BytesReceived == g_sImage.ui32NumBytes )
|
||||
{
|
||||
//
|
||||
// Run a quick CRC on the received bytes, holding on to the result in a
|
||||
// global variable, so we can pick up where we left off on the next pass.
|
||||
//
|
||||
am_bootloader_partial_crc32(g_am_multiboot.pui8RxBuffer, g_am_multiboot.ui32BytesInBuffer, &g_ui32CRC);
|
||||
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
// Decrypt in place
|
||||
multiboot_secure_decrypt(g_am_multiboot.pui8RxBuffer, g_am_multiboot.ui32BytesInBuffer);
|
||||
#endif
|
||||
|
||||
//
|
||||
// If this is the first block of our new image, we need to record
|
||||
// the reset vector and stack pointer information for inclusion in
|
||||
// the flag page.
|
||||
//
|
||||
if ( g_am_multiboot.bStoreInSRAM || (g_ui32BytesReceived <= AM_HAL_FLASH_PAGE_SIZE) )
|
||||
{
|
||||
g_sImage.pui32StackPointer = (uint32_t *)(((uint32_t *)g_am_multiboot.pui8RxBuffer)[0]);
|
||||
g_sImage.pui32ResetVector = (uint32_t *)(((uint32_t *)g_am_multiboot.pui8RxBuffer)[1]);
|
||||
}
|
||||
|
||||
if ( !g_am_multiboot.bStoreInSRAM )
|
||||
{
|
||||
am_bootloader_program_flash_page((uint32_t)g_am_multiboot.pui32WriteAddress,
|
||||
(uint32_t *)g_am_multiboot.pui8RxBuffer, g_am_multiboot.ui32BytesInBuffer);
|
||||
//
|
||||
// Adjust the global variables.
|
||||
//
|
||||
g_am_multiboot.pui32WriteAddress += (g_am_multiboot.ui32BytesInBuffer / 4);
|
||||
g_am_multiboot.ui32BytesInBuffer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Check if we should be booting from flash with a valid image
|
||||
//!
|
||||
//! @param pbOverride is the return parameter, used to pass back the override status
|
||||
//! @param ppsImage is the return parameter, used to pass back the image structure.
|
||||
//!
|
||||
//! This function checks the flag page (if enabled) and verifies the flash image
|
||||
//! for integrity. It also checks for the override pin status in case forced
|
||||
//! host boot is requested..
|
||||
//!
|
||||
//! @return true if it's okay to boot from flash (returns the image structure).
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool
|
||||
am_multiboot_check_boot_from_flash(bool *pbOverride, am_bootloader_image_t **ppsImage)
|
||||
{
|
||||
bool bValid = false;
|
||||
//
|
||||
// If we're using a flag page, we can run a full CRC check to verify the
|
||||
// integrity of our image. If not, we'll just check the override pin.
|
||||
// First check if the flag page is valid
|
||||
//
|
||||
if ( USE_FLAG_PAGE &&
|
||||
( am_bootloader_validate_structure((uint32_t *)g_psBootImage, sizeof(*g_psBootImage)) ))
|
||||
{
|
||||
//
|
||||
// Check the flag page (including the stored CRC) and the override pin
|
||||
// to make sure we have a valid image and the host isn't requesting an
|
||||
// upgrade.
|
||||
//
|
||||
if (am_hal_bootloader_override_check(g_psBootImage))
|
||||
{
|
||||
*pbOverride = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbOverride = false;
|
||||
if ( am_bootloader_flash_check(g_psBootImage) )
|
||||
{
|
||||
*ppsImage = g_psBootImage;
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Check the override pin to make sure the host isn't requesting an
|
||||
// upgrade, and do a quick check to make sure an image actually exists
|
||||
// at the default application location.
|
||||
//
|
||||
if (am_hal_bootloader_override_check(&g_sImage))
|
||||
{
|
||||
*pbOverride = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbOverride = false;
|
||||
if ( *(g_sImage.pui32LinkAddress) != 0xFFFFFFFF)
|
||||
{
|
||||
*ppsImage = &g_sImage;
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bValid;
|
||||
}
|
||||
|
||||
|
||||
// Erases the flash based on ui32Addr & ui32NumBytes
|
||||
void
|
||||
erase_ota_image(uint32_t ui32Addr, uint32_t ui32NumBytes, am_multiboot_flash_info_t *pFlash)
|
||||
{
|
||||
// Erase the image
|
||||
while ( ui32NumBytes )
|
||||
{
|
||||
pFlash->flash_erase_sector(ui32Addr);
|
||||
if ( ui32NumBytes > pFlash->flashSectorSize )
|
||||
{
|
||||
ui32NumBytes -= pFlash->flashSectorSize;
|
||||
ui32Addr += pFlash->flashSectorSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can write across pages
|
||||
// The write address should be page aligned & the length in multiple of page size
|
||||
int
|
||||
write_to_flash(uint32_t ui32DestAddr, uint32_t *pSrc, uint32_t ui32Length, am_multiboot_flash_info_t *pFlash)
|
||||
{
|
||||
if (ui32DestAddr & (pFlash->flashPageSize - 1))
|
||||
{
|
||||
return -1 ;
|
||||
}
|
||||
while (ui32Length)
|
||||
{
|
||||
uint32_t ui32BytesInPage =
|
||||
(ui32Length > pFlash->flashPageSize) ? \
|
||||
pFlash->flashPageSize : ui32Length;
|
||||
// Writes are always page size
|
||||
pFlash->flash_write_page(ui32DestAddr, pSrc, pFlash->flashPageSize);
|
||||
pSrc += ui32BytesInPage / 4;
|
||||
ui32Length -= ui32BytesInPage;
|
||||
ui32DestAddr += ui32BytesInPage;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Can read across pages
|
||||
int
|
||||
read_from_flash(uint32_t ui32DestAddr, uint32_t *pSrc, uint32_t ui32Length, am_multiboot_flash_info_t *pFlash)
|
||||
{
|
||||
uint32_t ui32Preceding = (uint32_t)pSrc & (pFlash->flashPageSize - 1);
|
||||
while (ui32Length)
|
||||
{
|
||||
uint32_t ui32BytesInPage =
|
||||
((ui32Preceding + ui32Length) > pFlash->flashPageSize) ? \
|
||||
(pFlash->flashPageSize - ui32Preceding) : ui32Length;
|
||||
pFlash->flash_read_page(ui32DestAddr, pSrc, ui32BytesInPage);
|
||||
pSrc += ui32BytesInPage / 4;
|
||||
ui32Length -= ui32BytesInPage;
|
||||
ui32DestAddr += ui32BytesInPage;
|
||||
ui32Preceding = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// We can not read and program the same flash bank
|
||||
// So - we need to first copy data to SRAM, and then flash...block by block
|
||||
static void
|
||||
program_image_from_flash(uint32_t ui32WriteAddr, uint32_t *pui32ReadAddr,
|
||||
uint32_t ui32NumBytes, bool bDecrypt,
|
||||
am_multiboot_flash_info_t *pReadFlash,
|
||||
am_multiboot_flash_info_t *pWriteFlash)
|
||||
{
|
||||
uint32_t ui32NumBytesInPage;
|
||||
uint32_t *pStart = g_pTempBuf;
|
||||
// Determine the preceding data bytes at the destination page
|
||||
uint32_t ui32PrecedingBytes = ui32WriteAddr & (pWriteFlash->flashSectorSize - 1);
|
||||
// Flash Write can only happen in terms of pages
|
||||
// So, if the image does not start on page boundary - need to take proper precautions
|
||||
// to preserve other data in the page
|
||||
if (ui32PrecedingBytes)
|
||||
{
|
||||
// Page aligned
|
||||
ui32WriteAddr &= ~(pWriteFlash->flashSectorSize - 1);
|
||||
// Copy the preceding content at destination page in buffer
|
||||
read_from_flash((uint32_t)g_pTempBuf, (uint32_t *)ui32WriteAddr, ui32PrecedingBytes, pWriteFlash);
|
||||
}
|
||||
while ( ui32NumBytes )
|
||||
{
|
||||
pStart = g_pTempBuf + ui32PrecedingBytes / 4;
|
||||
if ((ui32PrecedingBytes + ui32NumBytes) > pWriteFlash->flashSectorSize)
|
||||
{
|
||||
ui32NumBytesInPage = pWriteFlash->flashSectorSize - ui32PrecedingBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Last sector to be written
|
||||
ui32NumBytesInPage = ui32NumBytes;
|
||||
if ((ui32NumBytesInPage + ui32PrecedingBytes) != pWriteFlash->flashSectorSize)
|
||||
{
|
||||
// Copy the trailing content at destination page in buffer
|
||||
read_from_flash((uint32_t)pStart + ui32NumBytesInPage,
|
||||
pui32ReadAddr + ui32NumBytesInPage / 4,
|
||||
pWriteFlash->flashSectorSize - (ui32NumBytesInPage + ui32PrecedingBytes),
|
||||
pWriteFlash);
|
||||
}
|
||||
}
|
||||
// Read the image data from source
|
||||
read_from_flash((uint32_t)pStart, pui32ReadAddr, ui32NumBytesInPage, pReadFlash);
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
if (bDecrypt)
|
||||
{
|
||||
// Decrypt in place
|
||||
multiboot_secure_decrypt(pStart, ui32NumBytesInPage);
|
||||
}
|
||||
#endif
|
||||
// erase the sector
|
||||
pWriteFlash->flash_erase_sector(ui32WriteAddr);
|
||||
// Write the flash sector
|
||||
write_to_flash(ui32WriteAddr, g_pTempBuf, pWriteFlash->flashSectorSize, pWriteFlash);
|
||||
|
||||
ui32WriteAddr += pWriteFlash->flashSectorSize;
|
||||
pui32ReadAddr += ui32NumBytesInPage / 4;
|
||||
ui32NumBytes -= ui32NumBytesInPage;
|
||||
ui32PrecedingBytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Multiboot protocol handler for OTA update
|
||||
//!
|
||||
//! @param pOtaInfo is the pointer to OTA descriptor with image information
|
||||
//! @param pTempBuf is the pointer to a temporary buffer, sized to one flash
|
||||
//! page (bigger of internal and external flash page, if ext flash is being used)
|
||||
//! @param invalidateOtaFunc is the function called to invalidate the OTA for
|
||||
//! subsequent boots
|
||||
//! @param pExtFlash is the pointer external flash access info if needed
|
||||
//!
|
||||
//! This function validates the OTA blob, and installs the image if verified.
|
||||
//! It updates the flag page with the new image information and issues a POI
|
||||
//!
|
||||
//! @return false if OTA upgrade fails. Otherwise this function does not return
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool
|
||||
am_multiboot_ota_handler(am_multiboot_ota_t *pOtaInfo, uint32_t *pTempBuf,
|
||||
uint32_t tempBufSize, invalidate_ota_func_t invalidateOtaFunc,
|
||||
am_multiboot_flash_info_t *pExtFlash)
|
||||
{
|
||||
am_bootloader_image_t *psImage = &g_sImage;
|
||||
am_multiboot_flash_info_t *pFlash;
|
||||
|
||||
if ((pTempBuf == NULL) || (pOtaInfo == NULL) || (pOtaInfo->magicNum != OTA_INFO_MAGIC_NUM))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the contents
|
||||
if ( !am_bootloader_validate_structure((uint32_t *)pOtaInfo, sizeof(*pOtaInfo)) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Check to make sure we're not overwriting the bootloader or the flag page.
|
||||
//
|
||||
if (!check_flash_address_range((uint32_t)pOtaInfo->pui32LinkAddress,
|
||||
pOtaInfo->ui32NumBytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Validate the ext flash info
|
||||
if (pOtaInfo->ui32Options & OTA_INFO_OPTIONS_EXT_FLASH)
|
||||
{
|
||||
if (pExtFlash && pExtFlash->flash_read_page &&
|
||||
pExtFlash->flash_write_page && pExtFlash->flash_erase_sector &&
|
||||
(pExtFlash->flashSectorSize <= tempBufSize))
|
||||
{
|
||||
pFlash = pExtFlash;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Validate the address and the temp buf size
|
||||
if (g_intFlash.flashSectorSize > tempBufSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pFlash = &g_intFlash;
|
||||
}
|
||||
|
||||
g_pTempBuf = pTempBuf;
|
||||
|
||||
//
|
||||
// Set the image structure parameters based on the information in the
|
||||
// packet.
|
||||
//
|
||||
psImage->pui32LinkAddress = pOtaInfo->pui32LinkAddress;
|
||||
psImage->ui32NumBytes = pOtaInfo->ui32NumBytes;
|
||||
psImage->ui32CRC = pOtaInfo->ui32ImageCrc;
|
||||
psImage->ui32OverrideGPIO = DEFAULT_OVERRIDE_GPIO;
|
||||
psImage->ui32OverridePolarity = DEFAULT_OVERRIDE_POLARITY;
|
||||
psImage->bEncrypted = 0; // This only indicates Copy-Protection in flash
|
||||
|
||||
//
|
||||
// We'll need to fill in the stack pointer and reset vector a little later
|
||||
// in the process.
|
||||
//
|
||||
psImage->pui32StackPointer = 0;
|
||||
psImage->pui32ResetVector = 0;
|
||||
|
||||
g_am_multiboot.bStoreInSRAM = 0;
|
||||
|
||||
g_am_multiboot.pui8RxBuffer = (uint8_t *)pOtaInfo->pui32ImageAddr;
|
||||
g_am_multiboot.ui32BytesInBuffer = pOtaInfo->ui32NumBytes;
|
||||
|
||||
if (FLASH_OPERATE(pFlash, flash_init) == 0)
|
||||
{
|
||||
if (FLASH_OPERATE(pFlash, flash_enable) != 0)
|
||||
{
|
||||
FLASH_OPERATE(pFlash, flash_deinit);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
g_am_multiboot.ui32SramBytesUsed = MAX_SRAM_USED;
|
||||
// Validate the security trailer & Initialize the security params
|
||||
// CAUTION: If the secInfo is in ext flash, it is assumed that the function would
|
||||
// have means to access it within
|
||||
// Ambiq OTA copies the secInfo always in internal flash, so that would not be
|
||||
// an issue
|
||||
if ( init_multiboot_secure(pOtaInfo->secInfoLen, pOtaInfo->pui32SecInfoPtr,
|
||||
1, psImage, &psImage->bEncrypted) != 0 )
|
||||
{
|
||||
FLASH_OPERATE(pFlash, flash_disable);
|
||||
FLASH_OPERATE(pFlash, flash_deinit);
|
||||
return false;
|
||||
}
|
||||
// Decrypt page by page
|
||||
program_image_from_flash((uint32_t)pOtaInfo->pui32ImageAddr, pOtaInfo->pui32ImageAddr,
|
||||
pOtaInfo->ui32NumBytes, true, pFlash, pFlash);
|
||||
// Verify
|
||||
if ( multiboot_secure_verify(&psImage->ui32CRC) )
|
||||
{
|
||||
// Erase the OTA image
|
||||
erase_ota_image((uint32_t)pOtaInfo->pui32ImageAddr, pOtaInfo->ui32NumBytes, pFlash);
|
||||
FLASH_OPERATE(pFlash, flash_disable);
|
||||
FLASH_OPERATE(pFlash, flash_deinit);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
psImage->pui32StackPointer = (uint32_t *)(((uint32_t *)pOtaInfo->pui32ImageAddr)[0]);
|
||||
psImage->pui32ResetVector = (uint32_t *)(((uint32_t *)pOtaInfo->pui32ImageAddr)[1]);
|
||||
|
||||
//
|
||||
// The image is presumed to be reasonable. Set our global
|
||||
// variables based on the new image structure.
|
||||
//
|
||||
g_am_multiboot.pui32WriteAddress = psImage->pui32LinkAddress;
|
||||
|
||||
program_image_from_flash((uint32_t)pOtaInfo->pui32LinkAddress, pOtaInfo->pui32ImageAddr,
|
||||
pOtaInfo->ui32NumBytes, false, pFlash, &g_intFlash);
|
||||
// Protect the image if needed
|
||||
program_image(psImage->bEncrypted);
|
||||
if ( !(pOtaInfo->ui32Options & OTA_INFO_OPTIONS_DATA) && USE_FLAG_PAGE )
|
||||
{
|
||||
//
|
||||
// Write the flag page.
|
||||
//
|
||||
am_bootloader_flag_page_update(&g_sImage, (uint32_t *)FLAG_PAGE_LOCATION);
|
||||
}
|
||||
if (invalidateOtaFunc)
|
||||
{
|
||||
invalidateOtaFunc(pOtaInfo);
|
||||
}
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
// Erase the OTA image
|
||||
// Special handling for the case when the install address overlaps with the OTA image
|
||||
// We need to add special handling so as to now erase part of freshly installed image
|
||||
if (((uint32_t)pOtaInfo->pui32LinkAddress < (uint32_t)pOtaInfo->pui32ImageAddr) &&
|
||||
((uint32_t)pOtaInfo->pui32LinkAddress + pOtaInfo->ui32NumBytes > (uint32_t)pOtaInfo->pui32ImageAddr))
|
||||
{
|
||||
uint32_t skipBytes = (uint32_t)pOtaInfo->pui32LinkAddress + pOtaInfo->ui32NumBytes - (uint32_t)pOtaInfo->pui32ImageAddr;
|
||||
// Multiple of sector size
|
||||
skipBytes = (skipBytes + pFlash->flashSectorSize - 1) & ~(pFlash->flashSectorSize - 1);
|
||||
erase_ota_image((uint32_t)pOtaInfo->pui32ImageAddr + skipBytes, pOtaInfo->ui32NumBytes - skipBytes, pFlash);
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_ota_image((uint32_t)g_am_multiboot.pui8RxBuffer, g_am_multiboot.ui32BytesInBuffer, pFlash);
|
||||
}
|
||||
wipe_sram();
|
||||
#endif
|
||||
//
|
||||
// Perform a software reset.
|
||||
//
|
||||
#if AM_APOLLO3_RESET
|
||||
am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI, 0);
|
||||
#else // AM_APOLLO3_RESET
|
||||
am_hal_reset_poi();
|
||||
#endif // AM_APOLLO3_RESET
|
||||
|
||||
// Should never reach here
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Get the information about the main image
|
||||
//!
|
||||
//! @param pui32LinkAddr - Used to return the link address for main image
|
||||
//! @param pui32Length - Used to return the length of the image
|
||||
//!
|
||||
//! This function is used to determine attributes of the main image currently
|
||||
//! in flash
|
||||
//!
|
||||
//! @return false if there is no valid flag page
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool
|
||||
am_multiboot_get_main_image_info(uint32_t *pui32LinkAddr, uint32_t *pui32Length)
|
||||
{
|
||||
bool bValid = false;
|
||||
//
|
||||
// If we're using a flag page, we can run a full CRC check to verify the
|
||||
// integrity of our image. If not, we'll just check the override pin.
|
||||
//
|
||||
if ( USE_FLAG_PAGE )
|
||||
{
|
||||
// First check if the flag page is valid
|
||||
if ( am_bootloader_validate_structure((uint32_t *)g_psBootImage, sizeof(*g_psBootImage)) )
|
||||
{
|
||||
*pui32LinkAddr = (uint32_t)g_psBootImage->pui32LinkAddress;
|
||||
*pui32Length = g_psBootImage->ui32NumBytes;
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
return bValid;
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_multi_boot.h
|
||||
//!
|
||||
//! @brief Prototype for Multi Protocol Bootloader implementation
|
||||
//!
|
||||
//! This is a bootloader program that supports flash programming over UART,
|
||||
//! SPI, and I2C. The correct protocol is selected automatically at boot time.
|
||||
//!
|
||||
//! SWO is configured in 1M baud, 8-n-1 mode.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef AM_MULTI_BOOT_H
|
||||
#define AM_MULTI_BOOT_H
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bootloader.h"
|
||||
|
||||
// All functions return 0 on success
|
||||
typedef int (*flash_read_func_t)(uint32_t ui32DestAddr, uint32_t *pSrc, uint32_t ui32Length);
|
||||
typedef int (*flash_write_func_t)(uint32_t ui32DestAddr, uint32_t *pSrc, uint32_t ui32Length);
|
||||
typedef int (*flash_erase_func_t)(uint32_t ui32Addr);
|
||||
typedef int (*flash_init_func_t)(void);
|
||||
typedef int (*flash_deinit_func_t)(void);
|
||||
typedef int (*flash_enable_func_t)(void);
|
||||
typedef int (*flash_disable_func_t)(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Granularity for Write
|
||||
// Should be power of 2
|
||||
uint32_t flashPageSize;
|
||||
// Granularity for Erase
|
||||
// Should be power of 2
|
||||
uint32_t flashSectorSize;
|
||||
// Initialize the flash device
|
||||
flash_init_func_t flash_init;
|
||||
// De-Initialize the flash device
|
||||
flash_deinit_func_t flash_deinit;
|
||||
// Enable (Power up) the flash device
|
||||
flash_enable_func_t flash_enable;
|
||||
// Disable (Put in Low power mode) the flash device
|
||||
flash_disable_func_t flash_disable;
|
||||
// Read a block of data from within a flash page
|
||||
flash_read_func_t flash_read_page;
|
||||
// Read a block of data within a flash page
|
||||
flash_write_func_t flash_write_page;
|
||||
// Erase the flash sector corresponding to address specified
|
||||
flash_erase_func_t flash_erase_sector;
|
||||
} am_multiboot_flash_info_t;
|
||||
|
||||
#define OTA_INFO_OPTIONS_EXT_FLASH 0x1
|
||||
#define OTA_INFO_OPTIONS_DATA 0x2
|
||||
#define OTA_INFO_MAGIC_NUM 0xDEADCAFE
|
||||
typedef struct
|
||||
{
|
||||
// Should be set to OTA_INFO_MAGIC_NUM
|
||||
uint32_t magicNum;
|
||||
// Address in flash where the new image should be programmed
|
||||
uint32_t *pui32LinkAddress;
|
||||
// Length of image blob
|
||||
uint32_t ui32NumBytes;
|
||||
// CRC of the image blob
|
||||
uint32_t ui32ImageCrc;
|
||||
// (Optional) Security Info length
|
||||
uint32_t secInfoLen;
|
||||
// Options - e.g. Read from external flash device
|
||||
uint32_t ui32Options;
|
||||
// (optional) Security Information location
|
||||
uint32_t *pui32SecInfoPtr;
|
||||
// Location of image blob - Address needs to be aligned to 4 Byte address
|
||||
uint32_t *pui32ImageAddr;
|
||||
// CRC to confirm integrity of the OTA Descriptor structure
|
||||
uint32_t ui32Crc;
|
||||
} am_multiboot_ota_t;
|
||||
|
||||
typedef void (*invalidate_ota_func_t)(am_multiboot_ota_t *pOtaInfo);
|
||||
|
||||
|
||||
// Internal flash info and handlers
|
||||
extern am_multiboot_flash_info_t g_intFlash;
|
||||
|
||||
extern bool am_multiboot_init(uint32_t *pBuf, uint32_t bufSize);
|
||||
|
||||
extern void am_multiboot_uart_isr_handler(uint32_t ui32Module);
|
||||
extern uint32_t am_multiboot_uart_detect_baudrate(uint32_t ui32RxPin);
|
||||
extern void am_multiboot_setup_serial(int32_t i32Module, uint32_t ui32BaudRate);
|
||||
|
||||
extern void am_multiboot_ios_acc_isr_handler(void);
|
||||
extern void am_multiboot_setup_ios_interface(uint32_t interruptPin);
|
||||
extern void am_multiboot_cleanup_ios_interface(void);
|
||||
|
||||
// pExtFlash - can be NULL if using internal flash
|
||||
// pTempBuf should point to a memory big enough to hold one flash sector (int or ext) worth of data
|
||||
extern bool am_multiboot_ota_handler(am_multiboot_ota_t *pOtaInfo, uint32_t *pTempBuf,
|
||||
uint32_t tempBufSize, invalidate_ota_func_t invalidateOtaFunc,
|
||||
am_multiboot_flash_info_t *pExtFlash);
|
||||
|
||||
extern bool am_multiboot_check_boot_from_flash(bool *pbOverride, am_bootloader_image_t **ppsImage);
|
||||
extern bool am_multiboot_get_main_image_info(uint32_t *pui32LinkAddr, uint32_t *pui32Length);
|
||||
|
||||
#endif // AM_MULTI_BOOT_H
|
||||
@@ -0,0 +1,208 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_multi_boot_private.h
|
||||
//!
|
||||
//! @brief Internal definitions/structures shared within multiboot
|
||||
//!
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef AM_MULTI_BOOT_PRIVATE_H
|
||||
#define AM_MULTI_BOOT_PRIVATE_H
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
// Include config before other bootloader files
|
||||
#ifdef AM_MULTIBOOT_CONFIG_FILE
|
||||
#include AM_MULTIBOOT_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
#include "am_bootloader.h"
|
||||
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
#include "am_multi_boot_secure.h"
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// I2C Address to use
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef I2C_SLAVE_ADDR
|
||||
#define I2C_SLAVE_ADDR 0x10
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Run without flag page.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef USE_FLAG_PAGE
|
||||
#define USE_FLAG_PAGE 0
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Location of the flag page.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef FLAG_PAGE_LOCATION
|
||||
#define FLAG_PAGE_LOCATION 0x00004000
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Max Size of Bootloader.
|
||||
//
|
||||
//*****************************************************************************
|
||||
// The value here must match (at least) with the ROLength restriction imposed at
|
||||
// bootloader linker configuration
|
||||
#ifndef MAX_BOOTLOADER_SIZE
|
||||
#define MAX_BOOTLOADER_SIZE 0x00004000
|
||||
#endif
|
||||
// The value here must match (at least) with the RWLength restriction imposed at
|
||||
// bootloader linker configuration
|
||||
#ifndef MAX_SRAM_USED
|
||||
#define MAX_SRAM_USED 0x00004000
|
||||
#endif
|
||||
|
||||
extern am_bootloader_image_t *g_psBootImage;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Safety Checks.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#if USE_FLAG_PAGE == 1
|
||||
#if FLAG_PAGE_LOCATION & (AM_HAL_FLASH_PAGE_SIZE - 1)
|
||||
#error "Flag Page address not page aligned"
|
||||
#endif
|
||||
#if FLAG_PAGE_LOCATION < MAX_BOOTLOADER_SIZE
|
||||
#error "Flag Page overlaps with Bootloader"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Default settings.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef DEFAULT_LINK_ADDRESS
|
||||
#define DEFAULT_LINK_ADDRESS ((uint32_t *) 0x00008000)
|
||||
#endif
|
||||
// Default override configured as invalid
|
||||
#ifndef DEFAULT_OVERRIDE_GPIO
|
||||
#define DEFAULT_OVERRIDE_GPIO (0xFFFFFFFF)
|
||||
#endif
|
||||
#ifndef DEFAULT_OVERRIDE_POLARITY
|
||||
#define DEFAULT_OVERRIDE_POLARITY AM_BOOTLOADER_OVERRIDE_LOW
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Boot Loader Version Number
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define AM_BOOTLOADER_VERSION_NUM 0x00000001
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Boot messages.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define AM_BOOTLOADER_ACK 0x00000000
|
||||
#define AM_BOOTLOADER_NAK 0x00000001
|
||||
#define AM_BOOTLOADER_READY 0x00000002
|
||||
#define AM_BOOTLOADER_IMAGE_COMPLETE 0x00000003
|
||||
#define AM_BOOTLOADER_BAD_CRC 0x00000004
|
||||
#define AM_BOOTLOADER_ERROR 0x00000005
|
||||
#define AM_BOOTLOADER_BL_VERSION 0x00000006
|
||||
#define AM_BOOTLOADER_FW_VERSION 0x00000007
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Boot Commands.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define AM_BOOTLOADER_ACK_CMD 0x00000000
|
||||
#define AM_BOOTLOADER_NAK_CMD 0x00000001
|
||||
#define AM_BOOTLOADER_NEW_IMAGE 0x00000002
|
||||
#define AM_BOOTLOADER_NEW_PACKET 0x00000003
|
||||
#define AM_BOOTLOADER_RESET 0x00000004
|
||||
#define AM_BOOTLOADER_SET_OVERRIDE_CMD 0x00000005
|
||||
#define AM_BOOTLOADER_BL_VERSION_CMD 0x00000006
|
||||
#define AM_BOOTLOADER_FW_VERSION_CMD 0x00000007
|
||||
#define AM_BOOTLOADER_NEW_ENCRYPTED_IMAGE 0x00000008
|
||||
#define AM_BOOTLOADER_RESTART 0x00000009
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Globals to keep track of the image write state.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern uint32_t g_ui32BytesReceived;
|
||||
extern uint32_t g_ui32CRC;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Image structure to hold data about the downloaded boot image.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern am_bootloader_image_t g_sImage;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function declarations.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern bool
|
||||
image_start_packet_read(am_bootloader_image_t *psImage, uint32_t *pui32Packet);
|
||||
extern void
|
||||
image_data_packet_read(uint8_t *pui8Src, uint32_t ui32Size);
|
||||
extern void
|
||||
program_image(uint32_t bEncrypted);
|
||||
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
extern void wipe_sram(void);
|
||||
#endif
|
||||
|
||||
#endif // AM_MULTI_BOOT_PRIVATE_H
|
||||
@@ -0,0 +1,124 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_multi_boot_secure.h
|
||||
//!
|
||||
//! @brief Secure Bootloader Definitions
|
||||
//! This file declares the customizable secure boot function hooks
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef AM_MULTI_BOOT_SECURE_H
|
||||
#define AM_MULTI_BOOT_SECURE_H
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bootloader.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief This func verifies the security trailer & initializes security params
|
||||
//!
|
||||
//! @param length - Length of the security trailer
|
||||
//! @param pData - Pointer to the security trailer
|
||||
//! @param bStoreInSram - -Indicates if the image can be accumulated in SRAM as
|
||||
//! a whole. If not set, multiboot would need to keep flashing the image
|
||||
//! segments as they arrive overwriting the existing content, even before the
|
||||
//! image could be verified.
|
||||
//! @param psImage - Pointer to the image properties as operated upon by multiboot
|
||||
//! @param pProtect - Used to pass information back to multiboot, if the flashed
|
||||
//! image needs any protection features. This is a place holder for future.
|
||||
//!
|
||||
//! This func verifies the security trailer & initializes security engine
|
||||
//! required for decryption. It could also be used to verify the validity of the
|
||||
//! key used for encryption.
|
||||
//!
|
||||
//! @return 0 for success, non-zero for failure.
|
||||
//
|
||||
//*****************************************************************************
|
||||
int
|
||||
init_multiboot_secure(uint32_t length, uint32_t *pData,
|
||||
bool bStoreInSram, am_bootloader_image_t *pImage,
|
||||
uint32_t *pProtect);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief This func performs in-place decryption of the supplied block of data
|
||||
//!
|
||||
//! @param pData - Pointer to encrypted image data in SRAM
|
||||
//! @param ui32NumBytes - Length of data
|
||||
//!
|
||||
//!
|
||||
//! This function should implement an in-place decryption of the data using the
|
||||
//! selected security algorithm. The decryption engine should have been
|
||||
//! initialized as part of init_multiboot_secure implementation.
|
||||
//! This function should also compute the running CRC for the clear image.
|
||||
//! This function could also be used to implement any other verification on the
|
||||
//! image - based on prior knowledge of image structure.
|
||||
//!
|
||||
//! @return none.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
multiboot_secure_decrypt(void *pData, uint32_t ui32NumBytes);
|
||||
|
||||
// Authenticate/Validate the image
|
||||
// Return Clear CRC of the image
|
||||
// for validation on subsequent boots
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief This func performs final verification of the downloaded image
|
||||
//!
|
||||
//! @param ui32NumBytes - Pointer used to return the CRC of the clear image
|
||||
//!
|
||||
//!
|
||||
//! This function could implement additional verification or authentication of
|
||||
//! the downloaded (and decrypted) image. On successful verification, and if the
|
||||
//! image did not need copy-protection in flash, it returns the clear image in
|
||||
//! flash, so that on subsequent boots the bootloader can check the image for
|
||||
//! integrity.
|
||||
//!
|
||||
//! @return It returns 0 if the verification succeeds, non-zero for failure
|
||||
//
|
||||
//*****************************************************************************
|
||||
int
|
||||
multiboot_secure_verify(uint32_t *pui32ClearCRC);
|
||||
|
||||
#endif // AM_MULTI_BOOT_SECURE_H
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file am_uart_boot_handlers.c
|
||||
//!
|
||||
//! @brief Boot related functions for the UART interface.
|
||||
//!
|
||||
//! This file contains the main state machine for handling boot commands via
|
||||
//! the UART interface.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
#include "am_multi_boot_private.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART configuration settings.
|
||||
//
|
||||
//*****************************************************************************
|
||||
am_hal_uart_config_t g_sUartConfig =
|
||||
{
|
||||
.ui32BaudRate = 115200,
|
||||
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
|
||||
.bTwoStopBits = false,
|
||||
.ui32Parity = AM_HAL_UART_PARITY_NONE,
|
||||
.ui32FlowCtrl = AM_HAL_UART_FLOW_CTRL_NONE,
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
#define MAX_CHUNK_SIZE 512 // Support max 512B chunks
|
||||
#define MAX_BUFFER (MAX_CHUNK_SIZE + 8)
|
||||
volatile uint32_t ui32_serial_status;
|
||||
volatile unsigned char cRecChar, RX_FIFO_FULL, RX_FIFO_EMPTY;
|
||||
volatile unsigned char uart_RX_buffer[MAX_BUFFER];
|
||||
volatile uint32_t uart_RX_cnt, uart_RX_head, uart_RX_tail;
|
||||
// ************************************
|
||||
unsigned char cTxChar, TX_FIFO_FULL, TX_FIFO_EMPTY;
|
||||
unsigned char uart_TX_buffer[8];
|
||||
unsigned char uart_TX_cnt, uart_TX_head, uart_TX_tail;
|
||||
// ************************************
|
||||
|
||||
uint32_t command;
|
||||
uint32_t packet_cnt, pkt_size;
|
||||
|
||||
volatile bool g_bUartImageValid = false;
|
||||
|
||||
//
|
||||
void
|
||||
ser_out(uint32_t ui32Module, unsigned char data)
|
||||
{
|
||||
AM_REGn(UART, ui32Module, DR) = data;
|
||||
while ( AM_BFRn(UART, ui32Module, FR, TXFF) );
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Configure the UART port for UART boot
|
||||
//!
|
||||
//! @param i32Module is UART port to configure.
|
||||
//! @param ui32BaudRate is requested baud rate.
|
||||
//!
|
||||
//! This function configures the UART port
|
||||
//!
|
||||
//! @return none
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_multiboot_setup_serial(int32_t i32Module, uint32_t ui32BaudRate)
|
||||
{
|
||||
uint32_t uartInt = AM_HAL_INTERRUPT_UART;
|
||||
command = 0;
|
||||
uart_RX_head = uart_RX_tail = uart_RX_cnt = 0;
|
||||
RX_FIFO_FULL = 0; // check serial FIFO operation
|
||||
RX_FIFO_EMPTY = 1;
|
||||
packet_cnt = 0xff;
|
||||
|
||||
//
|
||||
// Power on the selected UART
|
||||
//
|
||||
am_hal_uart_pwrctrl_enable(i32Module);
|
||||
|
||||
//
|
||||
// Start the UART interface, apply the desired configuration settings, and
|
||||
// enable the FIFOs.
|
||||
//
|
||||
am_hal_uart_clock_enable(i32Module);
|
||||
|
||||
//
|
||||
// Disable the UART before configuring it.
|
||||
//
|
||||
am_hal_uart_disable(i32Module);
|
||||
|
||||
//
|
||||
// Configure the UART.
|
||||
//
|
||||
g_sUartConfig.ui32BaudRate = ui32BaudRate;
|
||||
am_hal_uart_config(i32Module, &g_sUartConfig);
|
||||
|
||||
//
|
||||
// Enable the UART FIFO.
|
||||
//
|
||||
am_hal_uart_fifo_config(i32Module,
|
||||
AM_HAL_UART_TX_FIFO_3_4 | AM_HAL_UART_RX_FIFO_3_4);
|
||||
|
||||
// am_util_delay_ms(100);
|
||||
//
|
||||
// Enable the UART.
|
||||
//
|
||||
am_hal_uart_enable(i32Module);
|
||||
|
||||
am_hal_uart_int_clear(i32Module, AM_HAL_UART_INT_RX | AM_HAL_UART_INT_RX_TMOUT);
|
||||
am_hal_uart_int_enable(i32Module, AM_HAL_UART_INT_RX | AM_HAL_UART_INT_RX_TMOUT);
|
||||
|
||||
#ifndef AM_PART_APOLLO
|
||||
if (i32Module == 1)
|
||||
{
|
||||
uartInt = AM_HAL_INTERRUPT_UART1;
|
||||
}
|
||||
#endif
|
||||
am_hal_interrupt_enable(uartInt);
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Multiboot protocol handler for UART implemented in ISR
|
||||
//!
|
||||
//! @param i32Module is UART port being used for bootloader.
|
||||
//!
|
||||
//! This function should be invoked from respective UART ISR.
|
||||
//!
|
||||
//! @return none.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_multiboot_uart_isr_handler(uint32_t ui32Module)
|
||||
{
|
||||
uint32_t *rx_pui32Packet;
|
||||
unsigned char send_byte_cnt, flush = 0;
|
||||
uint32_t cnt = 0;
|
||||
uint32_t *tx_pui32Packet;
|
||||
|
||||
uint32_t ui32Status;
|
||||
uint8_t rxData;
|
||||
|
||||
//
|
||||
// Check to see what caused this interrupt, then clear the bit from the
|
||||
// interrupt register.
|
||||
//
|
||||
ui32Status = am_hal_uart_int_status_get(ui32Module, false);
|
||||
am_hal_uart_int_clear(ui32Module, ui32Status);
|
||||
// ui32_serial_status = ui32Status;
|
||||
//
|
||||
// Service the uart FIFO.
|
||||
//
|
||||
|
||||
|
||||
RX_FIFO_EMPTY = 0;
|
||||
// Read the UART FIFO till we have data
|
||||
while ( !AM_BFRn(UART, ui32Module, FR, RXFE) )
|
||||
{
|
||||
if ( uart_RX_head == MAX_BUFFER )
|
||||
{
|
||||
// We should never reach here!
|
||||
RX_FIFO_FULL = 1;
|
||||
tx_pui32Packet = (uint32_t *) uart_TX_buffer;
|
||||
//
|
||||
// Bad packet; Send back an error.
|
||||
//
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
flush = 1;
|
||||
send_byte_cnt = 4;
|
||||
break;
|
||||
}
|
||||
rxData = AM_REGn(UART, ui32Module, DR);
|
||||
uart_RX_buffer[uart_RX_head++] = rxData;
|
||||
|
||||
uart_RX_cnt++;
|
||||
cnt++;
|
||||
|
||||
if ( uart_RX_cnt == 4 ) // cmd received, wait for parameters
|
||||
{
|
||||
command = uart_RX_buffer[0];
|
||||
switch (command)
|
||||
{
|
||||
case AM_BOOTLOADER_NEW_IMAGE:
|
||||
#ifndef MULTIBOOT_SECURE
|
||||
packet_cnt = 16;
|
||||
#endif
|
||||
break;
|
||||
case AM_BOOTLOADER_SET_OVERRIDE_CMD:
|
||||
packet_cnt = 12;
|
||||
break;
|
||||
case AM_BOOTLOADER_NEW_PACKET:
|
||||
// packet_cnt = pkt_size+8;
|
||||
break;
|
||||
case AM_BOOTLOADER_RESET:
|
||||
packet_cnt = 4;
|
||||
break;
|
||||
case AM_BOOTLOADER_BL_VERSION_CMD:
|
||||
packet_cnt = 4;
|
||||
break;
|
||||
case AM_BOOTLOADER_ACK_CMD:
|
||||
packet_cnt = 4;
|
||||
break;
|
||||
case AM_BOOTLOADER_NAK_CMD:
|
||||
packet_cnt = 4;
|
||||
break;
|
||||
case AM_BOOTLOADER_RESTART:
|
||||
packet_cnt = 4;
|
||||
break;
|
||||
default:
|
||||
// Unknown command
|
||||
packet_cnt = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (command == AM_BOOTLOADER_NEW_PACKET) && (uart_RX_cnt == 8) )
|
||||
{
|
||||
pkt_size = *(uint32_t *) (&uart_RX_buffer[4]);
|
||||
packet_cnt = pkt_size + 8;
|
||||
}
|
||||
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
if ( (command == AM_BOOTLOADER_NEW_IMAGE) && (uart_RX_cnt == 20) )
|
||||
{
|
||||
pkt_size = *(uint32_t *) (&uart_RX_buffer[16]);
|
||||
packet_cnt = pkt_size + 20;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( (uart_RX_cnt >= 4) && (uart_RX_cnt == packet_cnt) )
|
||||
{
|
||||
rx_pui32Packet = (uint32_t *) uart_RX_buffer;
|
||||
tx_pui32Packet = (uint32_t *) uart_TX_buffer;
|
||||
|
||||
switch (rx_pui32Packet[0])
|
||||
{
|
||||
case AM_BOOTLOADER_NEW_IMAGE:
|
||||
//
|
||||
// Parse the image packet, and store the result to the global
|
||||
// image structure.
|
||||
//
|
||||
g_bUartImageValid = image_start_packet_read(&g_sImage,
|
||||
(uint32_t *) uart_RX_buffer);
|
||||
|
||||
//
|
||||
// Make sure the image packet had reasonable contents. If it
|
||||
// didn't, we need to let the host know.
|
||||
//
|
||||
if ( g_bUartImageValid )
|
||||
{
|
||||
//
|
||||
// Good image; Send back a "READY" packet.
|
||||
//
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_READY;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Bad image; Send back an error.
|
||||
//
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
}
|
||||
|
||||
flush = 1;
|
||||
send_byte_cnt = 4;
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_SET_OVERRIDE_CMD:
|
||||
//
|
||||
// Set the override GPIO settings based on the packet
|
||||
// information.
|
||||
//
|
||||
g_sImage.ui32OverrideGPIO = rx_pui32Packet[1];
|
||||
g_sImage.ui32OverridePolarity = rx_pui32Packet[2];
|
||||
|
||||
//
|
||||
// Send back a "READY" packet.
|
||||
//
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_READY;
|
||||
flush = 1;
|
||||
send_byte_cnt = 4;
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_NEW_PACKET:
|
||||
//
|
||||
// Only take new packets if our image structure is valid.
|
||||
//
|
||||
if ( !g_bUartImageValid )
|
||||
{
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse the rest of the packet sitting in the IOS LRAM.
|
||||
//
|
||||
image_data_packet_read((uint8_t *)(uart_RX_buffer + 8),
|
||||
*((uint32_t *)(uart_RX_buffer + 4)));
|
||||
|
||||
//
|
||||
// If this packet completed the image...
|
||||
//
|
||||
if ( g_ui32BytesReceived == g_sImage.ui32NumBytes )
|
||||
{
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
if ( (g_ui32CRC != g_sImage.ui32CRC) || multiboot_secure_verify(&g_sImage.ui32CRC) )
|
||||
{
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_BAD_CRC;
|
||||
}
|
||||
#else
|
||||
if ( g_ui32CRC != g_sImage.ui32CRC )
|
||||
{
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_BAD_CRC;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
// Protect (and optionally write if stored in SRAM)
|
||||
// image in flash now as it has been validated now
|
||||
program_image(g_sImage.bEncrypted);
|
||||
// Validate the flash contents of a boot image to make
|
||||
// sure it's safe to run
|
||||
if ( am_bootloader_flash_check(&g_sImage) )
|
||||
{
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_IMAGE_COMPLETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If this wasn't the end of the image, just send back a
|
||||
// "READY" packet.
|
||||
//
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_READY;
|
||||
}
|
||||
|
||||
flush = 1;
|
||||
send_byte_cnt = 4;
|
||||
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_RESET:
|
||||
if ( USE_FLAG_PAGE )
|
||||
{
|
||||
//
|
||||
// Write the flag page.
|
||||
//
|
||||
am_bootloader_flag_page_update(&g_sImage,
|
||||
(uint32_t *)FLAG_PAGE_LOCATION);
|
||||
}
|
||||
#ifdef MULTIBOOT_SECURE
|
||||
wipe_sram();
|
||||
#endif
|
||||
|
||||
case AM_BOOTLOADER_RESTART:
|
||||
//
|
||||
// Perform a software reset.
|
||||
//
|
||||
#if AM_APOLLO3_RESET
|
||||
am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI);
|
||||
#else // AM_APOLLO3_RESET
|
||||
am_hal_reset_poi();
|
||||
#endif // AM_APOLLO3_RESET
|
||||
|
||||
//
|
||||
// Wait for the reset to take effect.
|
||||
//
|
||||
while (1);
|
||||
|
||||
case AM_BOOTLOADER_BL_VERSION_CMD:
|
||||
//
|
||||
// Respond with the version number.
|
||||
//
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_BL_VERSION;
|
||||
tx_pui32Packet[1] = AM_BOOTLOADER_VERSION_NUM;
|
||||
|
||||
flush = 1;
|
||||
send_byte_cnt = 8;
|
||||
break;
|
||||
|
||||
case AM_BOOTLOADER_ACK_CMD:
|
||||
case AM_BOOTLOADER_NAK_CMD:
|
||||
break;
|
||||
|
||||
default:
|
||||
// Error
|
||||
tx_pui32Packet[0] = AM_BOOTLOADER_ERROR;
|
||||
flush = 1;
|
||||
send_byte_cnt = 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flush )
|
||||
{
|
||||
uart_TX_tail = 0;
|
||||
|
||||
for ( cnt = 0; cnt < send_byte_cnt; cnt++ )
|
||||
{
|
||||
ser_out(ui32Module, uart_TX_buffer[uart_TX_tail++]);
|
||||
}
|
||||
command = 0;
|
||||
uart_RX_head = uart_RX_tail = uart_RX_cnt = 0;
|
||||
RX_FIFO_FULL = 0; // check serial FIFO operation
|
||||
RX_FIFO_EMPTY = 1;
|
||||
flush = 0;
|
||||
send_byte_cnt = 0;
|
||||
packet_cnt = 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief implementation to detect the baudrate configuration from host
|
||||
//!
|
||||
//! @param ui32RxPin is the Pin used for UART-Rx
|
||||
//!
|
||||
//! This function implements a simple algorithm to compute the host baud rate.
|
||||
//! It expects host to send 0x55 on the UART. Baudrate is computed based on the
|
||||
//! timing of the bits.
|
||||
//! It assumes that systick is configured and operational at the core frequency
|
||||
//!
|
||||
//! @return the computed baud rate.
|
||||
//
|
||||
//*****************************************************************************
|
||||
uint32_t am_multiboot_uart_detect_baudrate(uint32_t ui32RxPin)
|
||||
{
|
||||
uint32_t ui32Start, ui32End, ui32Counts, ui32BaudRate;
|
||||
|
||||
//
|
||||
// Check the time, and record this as the "start" time.
|
||||
//
|
||||
// We need to hit this register as early as possible, so we are skipping
|
||||
// all of the normal logic that checks to make sure we are responding to
|
||||
// the right GPIO. In the interest of time, we will just assume that this
|
||||
// interrupt is coming from the UART RX pin.
|
||||
//
|
||||
ui32Start = am_hal_systick_count();
|
||||
|
||||
//
|
||||
// Wait for exactly 9 edges on the UART RX pin. This corresponds to the
|
||||
// number of edges in the byte 0x55 after the start bit. Using a simple
|
||||
// polling approach here gives us the best possible chance to catch every
|
||||
// single edge.
|
||||
//
|
||||
while ( !am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( !am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( !am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( !am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
while ( !am_hal_gpio_input_bit_read(ui32RxPin) );
|
||||
|
||||
//
|
||||
// Record the "end" time.
|
||||
//
|
||||
ui32End = am_hal_systick_count();
|
||||
am_hal_systick_stop();
|
||||
|
||||
//
|
||||
// At this point, the timing-critical portion of the interrupt handler is
|
||||
// complete, and we are free to clean up our interrupt status. We only
|
||||
// intend to perform the automatic baud-rate detection once, so we will go
|
||||
// ahead and disable the interrupt on the UART RX pin now.
|
||||
//
|
||||
am_hal_gpio_int_disable(AM_HAL_GPIO_BIT(ui32RxPin));
|
||||
am_hal_gpio_int_clear(AM_HAL_GPIO_BIT(ui32RxPin));
|
||||
|
||||
//
|
||||
// Check to see how long those nine edges took to arrive. This should
|
||||
// correspond to exactly nine bit-times of UART traffic from the host. From
|
||||
// there, we can use the speed of the processor (which is known) to
|
||||
// calculate the host's baud rate.
|
||||
//
|
||||
ui32Counts = ui32Start - ui32End;
|
||||
ui32BaudRate = AM_HAL_CLKGEN_FREQ_MAX_HZ * 9 / ui32Counts;
|
||||
return ui32BaudRate;
|
||||
}
|
||||
Reference in New Issue
Block a user