diff --git a/release.Makefile b/release.Makefile index 8bc500f..857aeb7 100644 --- a/release.Makefile +++ b/release.Makefile @@ -31,7 +31,10 @@ BUILD_DIR ?= ./build all: dapboot-bluepill.bin \ dapboot-maplemini.bin \ - dapboot-stlink.bin + dapboot-stlink.bin \ + dapboot-bluepill-128.bin \ + dapboot-maplemini-128.bin \ + dapboot-stlink-128.bin clean: $(Q)$(RM) $(BUILD_DIR)/*.bin @@ -59,3 +62,21 @@ dapboot-maplemini.bin: | $(BUILD_DIR) $(Q)$(MAKE) TARGET=MAPLEMINI -C src/ clean $(Q)$(MAKE) TARGET=MAPLEMINI -C src/ $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@) + +dapboot-bluepill-128.bin: | $(BUILD_DIR) + @printf " BUILD $(@)\n" + $(Q)$(MAKE) TARGET=BLUEPILL_128 -C src/ clean + $(Q)$(MAKE) TARGET=BLUEPILL_128 -C src/ + $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@) + +dapboot-stlink-128.bin: | $(BUILD_DIR) + @printf " BUILD $(@)\n" + $(Q)$(MAKE) TARGET=STLINK_128 -C src/ clean + $(Q)$(MAKE) TARGET=STLINK_128 -C src/ + $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@) + +dapboot-maplemini-128.bin: | $(BUILD_DIR) + @printf " BUILD $(@)\n" + $(Q)$(MAKE) TARGET=MAPLEMINI_128 -C src/ clean + $(Q)$(MAKE) TARGET=MAPLEMINI_128 -C src/ + $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@) diff --git a/src/Makefile b/src/Makefile index bb68e9b..e3ce053 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,6 +25,7 @@ include targets.mk SRCS := $(wildcard *.c) SRCS += $(wildcard $(TARGET_COMMON_DIR)/*.c) SRCS += $(wildcard $(TARGET_SPEC_DIR)/*.c) +SRCS += $(wildcard ./libc/*.c) OBJS += $(SRCS:.c=.o) DEPS = $(SRCS:.c=.d) diff --git a/src/dapboot.c b/src/dapboot.c index a43a524..cc894b8 100644 --- a/src/dapboot.c +++ b/src/dapboot.c @@ -31,8 +31,10 @@ static inline void __set_MSP(uint32_t topOfMainStack) { asm("msr msp, %0" : : "r" (topOfMainStack)); } +extern volatile const vector_table_t vector_table; + bool validate_application(void) { - if ((*(volatile uint32_t *)APP_BASE_ADDRESS & 0x2FFE0000) == 0x20000000) { + if (((uint32_t)(vector_table.reserved_x001c[0]) & 0x2FFE0000) == 0x20000000) { return true; } return false; @@ -41,20 +43,16 @@ bool validate_application(void) { static void jump_to_application(void) __attribute__ ((noreturn)); static void jump_to_application(void) { - vector_table_t* app_vector_table = (vector_table_t*)APP_BASE_ADDRESS; - - /* Use the application's vector table */ - target_relocate_vector_table(); /* Do any necessary early setup for the application */ target_pre_main(); /* Initialize the application's stack pointer */ - __set_MSP((uint32_t)(app_vector_table->initial_sp_value)); + __set_MSP((uint32_t)(vector_table.reserved_x001c[0])); /* Jump to the application entry point */ - app_vector_table->reset(); - + vector_table.reserved_x001c[1](); + while (1); } diff --git a/src/dfu.c b/src/dfu.c index 7351eb6..c96ed03 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -21,6 +21,7 @@ #include #include +#include #include "dfu.h" #include "usb_conf.h" @@ -94,6 +95,23 @@ static void dfu_on_download_request(usbd_device* usbd_dev, struct usb_setup_data (void)usbd_dev; (void)req; + if (current_dfu_offset == 0) { + if (dfu_download_size < offsetof(vector_table_t, reserved_x001c[1])) { + /* Can't handle splitting the vector table right now */ + dfu_set_status(DFU_STATUS_ERR_VENDOR); + } else { + vector_table_t* app_vector_table = (vector_table_t*)dfu_download_buffer; + /* Stash the application's initial stack value and reset + pointer in unused vector table entries */ + app_vector_table->reserved_x001c[0] = (vector_table_entry_t)(app_vector_table->initial_sp_value); + app_vector_table->reserved_x001c[1] = app_vector_table->reset; + /* Overwrite the stack and reset pointer to run the + bootloader instead */ + app_vector_table->initial_sp_value = &_stack; + app_vector_table->reset = reset_handler; + } + } + const uint16_t* data = (uint16_t*)dfu_download_buffer; uint16_t* dest = (uint16_t*)(APP_BASE_ADDRESS + current_dfu_offset); @@ -234,7 +252,6 @@ static int dfu_control_class_request(usbd_device *usbd_dev, __attribute__ ((fallthrough)); } case STATE_DFU_UPLOAD_IDLE: { - *buf = (uint8_t*)(APP_BASE_ADDRESS + current_dfu_offset); uint16_t len_to_copy = req->wLength; size_t max_firmware_size = target_get_max_firmware_size(); if (current_dfu_offset + req->wLength > max_firmware_size) { @@ -244,6 +261,23 @@ static int dfu_control_class_request(usbd_device *usbd_dev, dfu_set_state(STATE_DFU_UPLOAD_IDLE); } *len = len_to_copy; + if (current_dfu_offset < sizeof(vector_table_t)) { + /* Copy the flash memory to the download buffer, to + undo the vector modifications. */ + memcpy(dfu_download_buffer, (const void*)(APP_BASE_ADDRESS), + sizeof(dfu_download_buffer)); + vector_table_t* app_vector_table = (vector_table_t*)dfu_download_buffer; + /* Put the original stack pointer and reset vectors + back */ + app_vector_table->initial_sp_value = (unsigned int*)(app_vector_table->reserved_x001c[0]); + app_vector_table->reset = app_vector_table->reserved_x001c[1]; + app_vector_table->reserved_x001c[0] = 0; + app_vector_table->reserved_x001c[1] = 0; + /* Return the correct pointer */ + *buf = dfu_download_buffer + current_dfu_offset; + } else { + *buf = (uint8_t*)(APP_BASE_ADDRESS + current_dfu_offset); + } current_dfu_offset += len_to_copy; break; } diff --git a/src/libc/memcpy.c b/src/libc/memcpy.c new file mode 100644 index 0000000..9beacb6 --- /dev/null +++ b/src/libc/memcpy.c @@ -0,0 +1,19 @@ +/* + * memcpy.c: Smaller memcpy implementation. + */ + +#include + +// This makes GCC avoid replacing this with a call to builtin_memcpy +#pragma GCC optimize "Os" + +void *memcpy(void *dst, const void *src, size_t len) +{ + char *d = (char *)dst; + const char *s = (const char *)src; + + while(len--) + *d++ = *s++; + + return dst; +} diff --git a/src/libc/strlen.c b/src/libc/strlen.c new file mode 100644 index 0000000..46f79a7 --- /dev/null +++ b/src/libc/strlen.c @@ -0,0 +1,15 @@ +/* + * strlen.c: Smaller strlen implementation. + */ + +#include + +// This makes GCC avoid replacing this with a call to builtin_strlen +#pragma GCC optimize "Os" + +size_t strlen(const char *str) +{ + const char *start = str + 1; + while(*str++); + return str - start; +} diff --git a/src/libc/strncpy.c b/src/libc/strncpy.c new file mode 100644 index 0000000..dbfe893 --- /dev/null +++ b/src/libc/strncpy.c @@ -0,0 +1,15 @@ +/* + * strncpy.c: Smaller strncpy implementation. + */ + +#include + +// This makes GCC avoid replacing this with a call to builtin_strncpy +#pragma GCC optimize "Os" + +char *strncpy(char *dst, const char *src, size_t len) +{ + char *d = dst; + while( len-- && '\0' != (*d++ = *src++) ); + return dst; +} diff --git a/src/stm32f103/bluepill/config.h b/src/stm32f103/bluepill/config.h index c0df9e0..add4a57 100644 --- a/src/stm32f103/bluepill/config.h +++ b/src/stm32f103/bluepill/config.h @@ -20,7 +20,7 @@ #define CONFIG_H_INCLUDED #ifndef APP_BASE_ADDRESS -#define APP_BASE_ADDRESS 0x08002000 +#define APP_BASE_ADDRESS 0x08000000 #endif #ifndef FLASH_SIZE_OVERRIDE #define FLASH_SIZE_OVERRIDE 0x20000 diff --git a/src/stm32f103/common.ld b/src/stm32f103/common.ld new file mode 100644 index 0000000..e3db3ae --- /dev/null +++ b/src/stm32f103/common.ld @@ -0,0 +1,109 @@ +/* + * This file is part of the dapboot project. + * + * Copyright (C) 2016 Devan Lai + * Copyright (C) 2015 Karl Palsson + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Common linker script */ + +/* Enforce emission of the vector table. */ +EXTERN (vector_table) + +/* Define the entry point of the output file. */ +ENTRY(reset_handler) + +/* Define sections. */ +SECTIONS +{ + /* Vector table for the initial upload */ + .vectors : { + *(.vectors) + } >bootstrap + + .text : { + *(.text*) /* Program code */ + . = ALIGN(4); + *(.rodata*) /* Read-only data */ + . = ALIGN(4); + } >rom + + /* C++ Static constructors/destructors, also used for __attribute__ + * ((constructor)) and the likes */ + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >rom + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >rom + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >rom + + /* + * Another section used by C++ stuff, appears when using newlib with + * 64bit (long long) printf support + */ + .ARM.extab : { + *(.ARM.extab*) + } >rom + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >rom + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) /* Read-write initialized data */ + . = ALIGN(4); + _edata = .; + } >ram AT >rom + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) /* Read-write zero initialized data */ + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram + + /* + * The .eh_frame section appears to be used for C++ exception handling. + * You may need to fix this if you're using C++. + */ + /DISCARD/ : { *(.eh_frame) } + + . = ALIGN(4); + end = .; +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); diff --git a/src/stm32f103/generic/config.h b/src/stm32f103/generic/config.h index 8bfe845..c5902c8 100644 --- a/src/stm32f103/generic/config.h +++ b/src/stm32f103/generic/config.h @@ -20,7 +20,7 @@ #define CONFIG_H_INCLUDED #ifndef APP_BASE_ADDRESS -#define APP_BASE_ADDRESS 0x08002000 +#define APP_BASE_ADDRESS 0x08000000 #endif #ifndef FLASH_SIZE_OVERRIDE #define FLASH_SIZE_OVERRIDE 0x20000 diff --git a/src/stm32f103/maplemini/config.h b/src/stm32f103/maplemini/config.h index f44ebc2..64f76ad 100644 --- a/src/stm32f103/maplemini/config.h +++ b/src/stm32f103/maplemini/config.h @@ -20,7 +20,7 @@ #define CONFIG_H_INCLUDED #ifndef APP_BASE_ADDRESS -#define APP_BASE_ADDRESS 0x08002000 +#define APP_BASE_ADDRESS 0x08000000 #endif #ifndef FLASH_PAGE_SIZE #define FLASH_PAGE_SIZE 1024 diff --git a/src/stm32f103/stlink/config.h b/src/stm32f103/stlink/config.h index b0127b4..c152692 100644 --- a/src/stm32f103/stlink/config.h +++ b/src/stm32f103/stlink/config.h @@ -20,7 +20,7 @@ #define CONFIG_H_INCLUDED #ifndef APP_BASE_ADDRESS -#define APP_BASE_ADDRESS 0x08002000 +#define APP_BASE_ADDRESS 0x08000000 #endif #ifndef FLASH_SIZE_OVERRIDE #define FLASH_SIZE_OVERRIDE 0x20000 diff --git a/src/stm32f103/stm32f103x8.ld b/src/stm32f103/stm32f103x8.ld index 68645d8..6af3bfa 100644 --- a/src/stm32f103/stm32f103x8.ld +++ b/src/stm32f103/stm32f103x8.ld @@ -1,7 +1,9 @@ /* - * This file is part of the libopencm3 project. + * This file is part of the dapboot project. * + * Copyright (C) 2016 Devan Lai * Copyright (C) 2015 Karl Palsson + * Copyright (C) 2009 Uwe Hermann * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -20,12 +22,14 @@ /* Linker script for STM32F103x8, 64k flash, 20k RAM. */ /* Define memory regions. */ -/* 8k for the bootloader */ +/* 6.5k for the bootloader at the end, with a copy of the vector table at the + * beginning to bootstrap the bootloader + */ MEMORY { - rom (rx) : ORIGIN = 0x08000000, LENGTH = 8K + bootstrap (rx) : ORIGIN = 0x08000000, LENGTH = 1K + rom (rx) : ORIGIN = 0x0800e600, LENGTH = 0x1A00 ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K } -/* Include the common ld script. */ -INCLUDE libopencm3_stm32f1.ld +INCLUDE stm32f103/common.ld diff --git a/src/stm32f103/stm32f103xB.ld b/src/stm32f103/stm32f103xB.ld new file mode 100644 index 0000000..7e03308 --- /dev/null +++ b/src/stm32f103/stm32f103xB.ld @@ -0,0 +1,35 @@ +/* + * This file is part of the dapboot project. + * + * Copyright (C) 2016 Devan Lai + * Copyright (C) 2015 Karl Palsson + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F103xB, 128k flash, 20k RAM. */ + +/* Define memory regions. */ +/* 6.5k for the bootloader at the end, with a copy of the vector table at + * the beginning to bootstrap the bootloader + */ +MEMORY +{ + bootstrap (rx) : ORIGIN = 0x08000000, LENGTH = 1K + rom (rx) : ORIGIN = 0x0801e600, LENGTH = 0x1A00 + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +INCLUDE stm32f103/common.ld diff --git a/src/targets.mk b/src/targets.mk index d93a11a..59e955b 100644 --- a/src/targets.mk +++ b/src/targets.mk @@ -26,18 +26,36 @@ ifeq ($(TARGET),BLUEPILL) LDSCRIPT := ./stm32f103/stm32f103x8.ld ARCH = STM32F1 endif +ifeq ($(TARGET),BLUEPILL_128) + TARGET_COMMON_DIR := ./stm32f103 + TARGET_SPEC_DIR := ./stm32f103/bluepill + LDSCRIPT := ./stm32f103/stm32f103xB.ld + ARCH = STM32F1 +endif ifeq ($(TARGET),MAPLEMINI) TARGET_COMMON_DIR := ./stm32f103 TARGET_SPEC_DIR := ./stm32f103/maplemini LDSCRIPT := ./stm32f103/stm32f103x8.ld ARCH = STM32F1 endif +ifeq ($(TARGET),MAPLEMINI_128) + TARGET_COMMON_DIR := ./stm32f103 + TARGET_SPEC_DIR := ./stm32f103/maplemini + LDSCRIPT := ./stm32f103/stm32f103xB.ld + ARCH = STM32F1 +endif ifeq ($(TARGET),STLINK) TARGET_COMMON_DIR := ./stm32f103 TARGET_SPEC_DIR := ./stm32f103/stlink LDSCRIPT := ./stm32f103/stm32f103x8.ld ARCH = STM32F1 endif +ifeq ($(TARGET),STLINK_128) + TARGET_COMMON_DIR := ./stm32f103 + TARGET_SPEC_DIR := ./stm32f103/stlink + LDSCRIPT := ./stm32f103/stm32f103xB.ld + ARCH = STM32F1 +endif ifndef ARCH $(error Unknown target $(TARGET))