From 1c14a9005346a5d74eb039f64b12427ab901c2d1 Mon Sep 17 00:00:00 2001 From: mwachs5 Date: Wed, 11 Jan 2017 12:30:45 -0800 Subject: Add the 'bootloader' which ships on HiFive1 Boards. --- software/double_tap_dontboot/Makefile | 6 + software/double_tap_dontboot/double_tap_dontboot.c | 146 +++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 software/double_tap_dontboot/Makefile create mode 100644 software/double_tap_dontboot/double_tap_dontboot.c (limited to 'software') diff --git a/software/double_tap_dontboot/Makefile b/software/double_tap_dontboot/Makefile new file mode 100644 index 0000000..ae89c51 --- /dev/null +++ b/software/double_tap_dontboot/Makefile @@ -0,0 +1,6 @@ +TARGET = double_tap_dontboot +C_SRCS += double_tap_dontboot.c +CFLAGS += -O2 -fno-builtin-printf -DNO_INIT + +BSP_BASE = ../../bsp +include $(BSP_BASE)/env/common.mk diff --git a/software/double_tap_dontboot/double_tap_dontboot.c b/software/double_tap_dontboot/double_tap_dontboot.c new file mode 100644 index 0000000..7e290dc --- /dev/null +++ b/software/double_tap_dontboot/double_tap_dontboot.c @@ -0,0 +1,146 @@ +// See LICENSE for license details. + +// This is the 'bootloader' which ships on HiFive1 boards, +// at SPI Flash location 0x20000000. +// HiFive1 boards have code burned into their OTP which ends with +// a jump to 0x20000000. The Freedom E SDK and the Arduino IDE +// linker scripts cause user programs to be compiled and +// flashed at 0x20400000. Therefore, this code ultimately jumps +// to 0x20400000, while attempting to leave the machine state as close +// to its reset state as possible. +// +// When compiled in the freedom-e-sdk environment, this code will +// be compiled as a user program at 0x20400000, so will continuously jump to itself. +// It is provided in the freedom-e-sdk mostly for reference purposes, so +// users know what is running on their board. Replacing the bootloader +// at 0x20000000 is not currently supported by the SDK. +// +// These are the instructions for the user of this program, from the +// HiFive1 Getting Started Guide: +// +// This program is designed to allow quick boot, but +// also a "safe" reboot option if a "bad" program +// is flashed into the HiFive1's SPI Flash. A "bad" program +// is one which makes it impossible for the programmer +// to communicate with the HiFive1. For example, a program which +// disables FE310's active clock, or which puts the FE310 to sleep +// with no way of waking it up. Bad programs can always be restarted using +// the RESET button, and using the "safe" bootloader can be halted +// before they perform any unsafe behavior. +// +// To activate "normal" boot mode, press the RESET button on +// the HiFive1. After approximately 1s, the green LED will flash +// for 1/2 second, then the user program will execute. +// +// To activate "safe" boot mode, press the RESET button. When +// the green LED flashes, immediately press the RESET button again. +// After 1 second, the red LED will blink. The user program will not +// execute, and the programmer can connect. To exit "safe" boot mode, +// press the RESET button a final time. + +#include +#include "platform.h" +#include "encoding.h" + +#define BACKUP15_MAGIC 0xD027B007 + +#define FINAL_ADDRESS 0x20400000 + +#define RED_LED 22 +#define GREEN_LED 19 + +int main(void) +{ + uint64_t now; + uint64_t then; + + + // Restore the default mtvec (which may have been set by initialization + // code, depending on the environment in which this C code is compiled). + // By default, this would cause an infinite loop upon exception, which is + // also "safe" behavior and the debugger can connect. + + write_csr(mtvec, 0x0); + + // How did we get here? We only want to execute this code + // on resets (vs waking up from sleep). + if ((AON_REG(AON_PMUCAUSE) & AON_PMUCAUSE_WAKEUPCAUSE) == + AON_WAKEUPCAUSE_RESET) { + + if (AON_REG(AON_BACKUP15) == BACKUP15_MAGIC) { + // Reset was "double-tapped". + + // Re-arm the reset double-tap + AON_REG(AON_BACKUP15) = 0; + + // PWM Red LED + + GPIO_REG(GPIO_IOF_EN) |= (1 << RED_LED); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << RED_LED); + GPIO_REG(GPIO_IOF_SEL) |= (1 << RED_LED); + + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << GREEN_LED); + GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << GREEN_LED); + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << GREEN_LED); + + PWM1_REG(PWM_CFG) = 0; + PWM1_REG(PWM_COUNT) = 0; + PWM1_REG(PWM_CMP0) = 0xFF; + PWM1_REG(PWM_CMP3) = 0xFF; + PWM1_REG(PWM_CFG) = PWM_CFG_ENALWAYS; + + int pwm_val = 255; + + // Wait for debugger or another RESET press. + while(1){ + + // Make the PWM a fade. This is preferable to just a PWM blink + // because it makes it clear that the processor is actually + // running this code, not just the PWM hardware. + + now = *((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)); + then = now + 32768/500; + while (*((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)) < then) { + asm volatile (""); + } + pwm_val = (pwm_val == 0) ? 255 : (pwm_val -1); + PWM1_REG(PWM_CMP3) = pwm_val << 4; + } + + } // If Magic + + // Turn on Green LED to indicate time-to-double-tap + // LEDs are Active-Low + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED); + GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << GREEN_LED); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << GREEN_LED); + + // Re-arm the reset double-tap + uint32_t save = AON_REG(AON_BACKUP15); + + AON_REG(AON_BACKUP15) = BACKUP15_MAGIC; + + // Wait 500 ms. If reset is tapped at this point, + // we will execute the "magic" loop above. + now = *((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)); + then = now + 32768/2; + while (*((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)) < then) { + asm volatile (""); + } + + // Re-arm the reset double-tap + AON_REG(AON_BACKUP15) = save; + + } + + // Restore the GPIO Registers to their default + GPIO_REG(GPIO_OUTPUT_VAL) = 0; + GPIO_REG(GPIO_OUTPUT_XOR) = 0; + GPIO_REG(GPIO_OUTPUT_EN) = 0; + + // Jump to "user code" in SPI Flash. + void (*pgm_start)(void) = (void*) FINAL_ADDRESS; + pgm_start(); + + return (1234567); +} -- cgit v1.2.1-18-gbd029