~ruther/qmk_firmware

6bc870d899c474bce82457699ec4b753d1538123 — Ryan 3 years ago cffe143
Refactor `bootloader_jump()` implementations (#15450)

* Refactor `bootloader_jump()` implementations

* Fix tests?

* Rename `atmel-samba` to `md-boot`
M build_test.mk => build_test.mk +1 -0
@@ 43,6 43,7 @@ all: elf
VPATH += $(COMMON_VPATH)
PLATFORM:=TEST
PLATFORM_KEY:=test
BOOTLOADER_TYPE:=none

ifeq ($(strip $(DEBUG)), 1)
CONSOLE_ENABLE = yes

M builddefs/bootloader.mk => builddefs/bootloader.mk +38 -2
@@ 30,6 30,7 @@
#     bootloadhid  HIDBootFlash compatible (ATmega32A)
#     usbasploader USBaspLoader (ATmega328P)
# ARM:
#     halfkay      PJRC Teensy
#     kiibohd      Input:Club Kiibohd bootloader (only used on their boards)
#     stm32duino   STM32Duino (STM32F103x8)
#     stm32-dfu    STM32 USB DFU in ROM


@@ 43,6 44,8 @@
ifeq ($(strip $(BOOTLOADER)), atmel-dfu)
    OPT_DEFS += -DBOOTLOADER_ATMEL_DFU
    OPT_DEFS += -DBOOTLOADER_DFU
    BOOTLOADER_TYPE = dfu

    ifneq (,$(filter $(MCU), at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647))
        BOOTLOADER_SIZE = 4096
    endif


@@ 53,6 56,8 @@ endif
ifeq ($(strip $(BOOTLOADER)), lufa-dfu)
    OPT_DEFS += -DBOOTLOADER_LUFA_DFU
    OPT_DEFS += -DBOOTLOADER_DFU
    BOOTLOADER_TYPE = dfu

    ifneq (,$(filter $(MCU), at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647))
        BOOTLOADER_SIZE ?= 4096
    endif


@@ 63,6 68,8 @@ endif
ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
    OPT_DEFS += -DBOOTLOADER_QMK_DFU
    OPT_DEFS += -DBOOTLOADER_DFU
    BOOTLOADER_TYPE = dfu

    ifneq (,$(filter $(MCU), at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647))
        BOOTLOADER_SIZE ?= 4096
    endif


@@ 73,10 80,14 @@ endif
ifeq ($(strip $(BOOTLOADER)), qmk-hid)
    OPT_DEFS += -DBOOTLOADER_QMK_HID
    OPT_DEFS += -DBOOTLOADER_HID
    BOOTLOADER_TYPE = dfu

    BOOTLOADER_SIZE ?= 4096
endif
ifeq ($(strip $(BOOTLOADER)), halfkay)
    OPT_DEFS += -DBOOTLOADER_HALFKAY
    BOOTLOADER_TYPE = halfkay

    ifeq ($(strip $(MCU)), atmega32u4)
        BOOTLOADER_SIZE = 512
    endif


@@ 86,18 97,26 @@ ifeq ($(strip $(BOOTLOADER)), halfkay)
endif
ifeq ($(strip $(BOOTLOADER)), caterina)
    OPT_DEFS += -DBOOTLOADER_CATERINA
    BOOTLOADER_TYPE = caterina

    BOOTLOADER_SIZE = 4096
endif
ifneq (,$(filter $(BOOTLOADER), bootloadhid bootloadHID))
    OPT_DEFS += -DBOOTLOADER_BOOTLOADHID
    BOOTLOADER_TYPE = bootloadhid

    BOOTLOADER_SIZE = 4096
endif
ifneq (,$(filter $(BOOTLOADER), usbasploader USBasp))
    OPT_DEFS += -DBOOTLOADER_USBASP
    BOOTLOADER_TYPE = usbasploader

    BOOTLOADER_SIZE = 4096
endif
ifeq ($(strip $(BOOTLOADER)), lufa-ms)
    OPT_DEFS += -DBOOTLOADER_MS
    BOOTLOADER_TYPE = dfu

    BOOTLOADER_SIZE ?= 8192
    FIRMWARE_FORMAT = bin
cpfirmware: lufa_warning


@@ 115,6 134,7 @@ endif

ifeq ($(strip $(BOOTLOADER)), stm32-dfu)
    OPT_DEFS += -DBOOTLOADER_STM32_DFU
    BOOTLOADER_TYPE = stm32_dfu

    # Options to pass to dfu-util when flashing
    DFU_ARGS ?= -d 0483:DF11 -a 0 -s 0x08000000:leave


@@ 122,6 142,7 @@ ifeq ($(strip $(BOOTLOADER)), stm32-dfu)
endif
ifeq ($(strip $(BOOTLOADER)), apm32-dfu)
    OPT_DEFS += -DBOOTLOADER_APM32_DFU
    BOOTLOADER_TYPE = stm32_dfu

    # Options to pass to dfu-util when flashing
    DFU_ARGS ?= -d 314B:0106 -a 0 -s 0x08000000:leave


@@ 129,6 150,7 @@ ifeq ($(strip $(BOOTLOADER)), apm32-dfu)
endif
ifeq ($(strip $(BOOTLOADER)), gd32v-dfu)
    OPT_DEFS += -DBOOTLOADER_GD32V_DFU
    BOOTLOADER_TYPE = gd32v_dfu

    # Options to pass to dfu-util when flashing
    DFU_ARGS ?= -d 28E9:0189 -a 0 -s 0x08000000:leave


@@ 136,6 158,8 @@ ifeq ($(strip $(BOOTLOADER)), gd32v-dfu)
endif
ifeq ($(strip $(BOOTLOADER)), kiibohd)
    OPT_DEFS += -DBOOTLOADER_KIIBOHD
    BOOTLOADER_TYPE = kiibohd

    ifeq ($(strip $(MCU_ORIG)), MK20DX128)
        MCU_LDSCRIPT = MK20DX128BLDR4
    endif


@@ 151,8 175,7 @@ ifeq ($(strip $(BOOTLOADER)), stm32duino)
    OPT_DEFS += -DBOOTLOADER_STM32DUINO
    MCU_LDSCRIPT = STM32F103x8_stm32duino_bootloader
    BOARD = STM32_F103_STM32DUINO
    # STM32F103 does NOT have an USB bootloader in ROM (only serial), so setting anything here does not make much sense
    STM32_BOOTLOADER_ADDRESS = 0x80000000
    BOOTLOADER_TYPE = stm32duino

    # Options to pass to dfu-util when flashing
    DFU_ARGS = -d 1EAF:0003 -a 2 -R


@@ 160,4 183,17 @@ ifeq ($(strip $(BOOTLOADER)), stm32duino)
endif
ifeq ($(strip $(BOOTLOADER)), tinyuf2)
    OPT_DEFS += -DBOOTLOADER_TINYUF2
    BOOTLOADER_TYPE = tinyuf2
endif
ifeq ($(strip $(BOOTLOADER)), halfkay)
    OPT_DEFS += -DBOOTLOADER_HALFKAY
    BOOTLOADER_TYPE = halfkay
endif
ifeq ($(strip $(BOOTLOADER)), md-boot)
    OPT_DEFS += -DBOOTLOADER_MD_BOOT
    BOOTLOADER_TYPE = md_boot
endif

ifeq ($(strip $(BOOTLOADER_TYPE)),)
    BOOTLOADER_TYPE = none
endif

M data/schemas/keyboard.jsonschema => data/schemas/keyboard.jsonschema +1 -1
@@ 57,7 57,7 @@
        },
        "bootloader": {
            "type": "string",
            "enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2"],
            "enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2"],
        },
        "bootloader_instructions": {
            "type": "string",

M keyboards/handwired/onekey/teensy_32/rules.mk => keyboards/handwired/onekey/teensy_32/rules.mk +3 -0
@@ 1,5 1,8 @@
# MCU name
MCU = MK20DX256

# Bootloader selection
BOOTLOADER = halfkay

# Enter lower-power sleep mode when on the ChibiOS idle thread
OPT_DEFS += -DCORTEX_ENABLE_WFI_IDLE=TRUE

M keyboards/handwired/onekey/teensy_lc/rules.mk => keyboards/handwired/onekey/teensy_lc/rules.mk +3 -0
@@ 2,5 2,8 @@
MCU = MKL26Z64
USE_CHIBIOS_CONTRIB = yes

# Bootloader selection
BOOTLOADER = halfkay

# Enter lower-power sleep mode when on the ChibiOS idle thread
OPT_DEFS += -DCORTEX_ENABLE_WFI_IDLE=TRUE

M keyboards/massdrop/alt/rules.mk => keyboards/massdrop/alt/rules.mk +3 -0
@@ 5,6 5,9 @@ SRC += config_led.c
ARM_ATSAM = SAMD51J18A
MCU = cortex-m4

# Bootloader selection
BOOTLOADER = md-boot

# Build Options
#   change yes to no to disable
#

M keyboards/massdrop/ctrl/rules.mk => keyboards/massdrop/ctrl/rules.mk +3 -0
@@ 5,6 5,9 @@ SRC += config_led.c
ARM_ATSAM = SAMD51J18A
MCU = cortex-m4

# Bootloader selection
BOOTLOADER = md-boot

# Build Options
#   change yes to no to disable
#

M keyboards/mechlovin/olly/jf/rules.mk => keyboards/mechlovin/olly/jf/rules.mk +2 -2
@@ 5,7 5,7 @@ MCU = atmega32a
F_CPU = 16000000

# Bootloader selection
BOOTLOADER = USBasp
BOOTLOADER = usbasploader

# Build Options
#   change yes to no to disable


@@ 21,4 21,4 @@ RGBLIGHT_ENABLE = yes       # Enable keyboard RGB underglow
AUDIO_ENABLE = no           # Audio output
CUSTOM_MATRIX = lite

SRC += matrix.c
\ No newline at end of file
SRC += matrix.c

M keyboards/rocketboard_16/rules.mk => keyboards/rocketboard_16/rules.mk +1 -1
@@ 8,7 8,7 @@ MCU = STM32F103
MCU_LDSCRIPT = STM32F103xB_stm32duino_bootloader
OPT_DEFS += -DBOOTLOADER_STM32DUINO
BOARD = STM32_F103_STM32DUINO
STM32_BOOTLOADER_ADDRESS = 0x80000000
BOOTLOADER_TYPE = stm32duino
DFU_ARGS = -d 1EAF:0003 -a 2 -R
DFU_SUFFIX_ARGS = -v 1EAF -p 0003


M keyboards/tgr/jane/v2ce/rules.mk => keyboards/tgr/jane/v2ce/rules.mk +1 -1
@@ 2,7 2,7 @@
MCU = atmega32a

# Bootloader selection
BOOTLOADER = bootloadHID
BOOTLOADER = bootloadhid

# Build Options
#   change yes to no to disable

R platforms/arm_atsam/bootloader.c => platforms/arm_atsam/bootloaders/md_boot.c +26 -17
@@ 15,13 15,18 @@
 */

#include "bootloader.h"

#include "samd51j18a.h"
#include "md_bootloader.h"

// Set watchdog timer to reset. Directs the bootloader to stay in programming mode.
void bootloader_jump(void) {
#ifdef KEYBOARD_massdrop_ctrl
    // CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
// WARNING: These are only for CTRL bootloader release "v2.18Jun 22 2018 17:28:08" for bootloader_jump support
extern uint32_t _eram;

#define BOOTLOADER_MAGIC 0x3B9ACA00
#define MAGIC_ADDR (uint32_t *)((intptr_t)(&_eram) - 4)

// CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
void bootloader_jump(void) {
    uint8_t  ver_ram_method[] = "v2.18Jun 22 2018 17:28:08";  // The version to match (NULL terminated by compiler)
    uint8_t *ver_check        = ver_ram_method;               // Pointer to version match string for traversal
    uint8_t *ver_rom          = (uint8_t *)0x21A0;            // Pointer to address in ROM where this specific bootloader version would exist


@@ 34,24 39,28 @@ void bootloader_jump(void) {
    if (!*ver_check) {                   // If check version pointer is NULL, all characters have matched
        *MAGIC_ADDR = BOOTLOADER_MAGIC;  // Set magic number into RAM
        NVIC_SystemReset();              // Perform system reset
        while (1) {
        }  // Won't get here

        while (1);  // Won't get here
    }
#endif
}

#else

// Set watchdog timer to reset. Directs the bootloader to stay in programming mode.
void bootloader_jump(void) {
    WDT->CTRLA.bit.ENABLE = 0;
    while (WDT->SYNCBUSY.bit.ENABLE) {
    }
    while (WDT->CTRLA.bit.ENABLE) {
    }

    while (WDT->SYNCBUSY.bit.ENABLE);
    while (WDT->CTRLA.bit.ENABLE);

    WDT->CONFIG.bit.WINDOW   = 0;
    WDT->CONFIG.bit.PER      = 0;
    WDT->EWCTRL.bit.EWOFFSET = 0;
    WDT->CTRLA.bit.ENABLE    = 1;
    while (WDT->SYNCBUSY.bit.ENABLE) {
    }
    while (!WDT->CTRLA.bit.ENABLE) {
    }
    while (1) {
    }  // Wait on timeout

    while (WDT->SYNCBUSY.bit.ENABLE);
    while (!WDT->CTRLA.bit.ENABLE);

    while (1);  // Wait on timeout
}
#endif

D platforms/avr/bootloader.c => platforms/avr/bootloader.c +0 -293
@@ 1,293 0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include "bootloader.h"
#include <avr/boot.h>

#ifdef PROTOCOL_LUFA
#    include <LUFA/Drivers/USB/USB.h>
#endif

/** \brief Bootloader Size in *bytes*
 *
 * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
 * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
 *
 * Size of Bootloaders in bytes:
 *   Atmel DFU loader(ATmega32U4)   4096
 *   Atmel DFU loader(AT90USB128)   8192
 *   LUFA bootloader(ATmega32U4)    4096
 *   Arduino Caterina(ATmega32U4)   4096
 *   USBaspLoader(ATmega***)        2048
 *   Teensy   halfKay(ATmega32U4)   512
 *   Teensy++ halfKay(AT90USB128)   1024
 *
 * AVR Boot section is located at the end of Flash memory like the followings.
 *
 * byte     Atmel/LUFA(ATMega32u4)          byte     Atmel(AT90SUB128)
 * 0x0000   +---------------+               0x00000  +---------------+
 *          |               |                        |               |
 *          |               |                        |               |
 *          |  Application  |                        |  Application  |
 *          |               |                        |               |
 *          =               =                        =               =
 *          |               | 32KB-4KB               |               | 128KB-8KB
 * 0x7000   +---------------+               0x1E000  +---------------+
 *          |  Bootloader   | 4KB                    |  Bootloader   | 8KB
 * 0x7FFF   +---------------+               0x1FFFF  +---------------+
 *
 *
 * byte     Teensy(ATMega32u4)              byte     Teensy++(AT90SUB128)
 * 0x0000   +---------------+               0x00000  +---------------+
 *          |               |                        |               |
 *          |               |                        |               |
 *          |  Application  |                        |  Application  |
 *          |               |                        |               |
 *          =               =                        =               =
 *          |               | 32KB-512B              |               | 128KB-1KB
 * 0x7E00   +---------------+               0x1FC00  +---------------+
 *          |  Bootloader   | 512B                   |  Bootloader   | 1KB
 * 0x7FFF   +---------------+               0x1FFFF  +---------------+
 */
#define FLASH_SIZE (FLASHEND + 1L)

#if !defined(BOOTLOADER_SIZE)
uint16_t bootloader_start;
#endif

// compatibility between ATMega8 and ATMega88
#if !defined(MCUCSR)
#    if defined(MCUSR)
#        define MCUCSR MCUSR
#    endif
#endif

/** \brief Entering the Bootloader via Software
 *
 * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
 */
#define BOOTLOADER_RESET_KEY 0xB007B007
uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));

/** \brief initialize MCU status by watchdog reset
 *
 * FIXME: needs doc
 */
__attribute__((weak)) void bootloader_jump(void) {
#if !defined(BOOTLOADER_SIZE)
    uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);

    if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) {
        bootloader_start = (FLASH_SIZE - 512) >> 1;
    } else if (high_fuse & ~(FUSE_BOOTSZ1)) {
        bootloader_start = (FLASH_SIZE - 1024) >> 1;
    } else if (high_fuse & ~(FUSE_BOOTSZ0)) {
        bootloader_start = (FLASH_SIZE - 2048) >> 1;
    } else {
        bootloader_start = (FLASH_SIZE - 4096) >> 1;
    }
#endif

    // Something like this might work, but it compiled larger than the block above
    // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1));

#if defined(BOOTLOADER_HALFKAY)
    //  http://www.pjrc.com/teensy/jump_to_bootloader.html
    cli();
    // disable watchdog, if enabled (it's not)
    // disable all peripherals
    // a shutdown call might make sense here
    UDCON  = 1;
    USBCON = (1 << FRZCLK);  // disable USB
    UCSR1B = 0;
    _delay_ms(5);
#    if defined(__AVR_AT90USB162__)  // Teensy 1.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    UCSR1B = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    asm volatile("jmp 0x3E00");
#    elif defined(__AVR_ATmega32U4__)   // Teensy 2.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    ADCSRA = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    TIMSK3 = 0;
    TIMSK4 = 0;
    UCSR1B = 0;
    TWCR   = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    DDRE   = 0;
    DDRF   = 0;
    TWCR   = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0x7E00");
#    elif defined(__AVR_AT90USB646__)   // Teensy++ 1.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    ADCSRA = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    TIMSK2 = 0;
    TIMSK3 = 0;
    UCSR1B = 0;
    TWCR   = 0;
    DDRA   = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    DDRE   = 0;
    DDRF   = 0;
    PORTA  = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0xFC00");
#    elif defined(__AVR_AT90USB1286__)  // Teensy++ 2.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    ADCSRA = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    TIMSK2 = 0;
    TIMSK3 = 0;
    UCSR1B = 0;
    TWCR   = 0;
    DDRA   = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    DDRE   = 0;
    DDRF   = 0;
    PORTA  = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0x1FC00");
#    endif

#elif defined(BOOTLOADER_CATERINA)
    // this block may be optional
    // TODO: figure it out

    uint16_t *const bootKeyPtr = (uint16_t *)0x0800;

    // Value used by Caterina bootloader use to determine whether to run the
    // sketch or the bootloader programmer.
    uint16_t bootKey = 0x7777;

    *bootKeyPtr = bootKey;

    // setup watchdog timeout
    wdt_enable(WDTO_60MS);

    while (1) {
    }  // wait for watchdog timer to trigger

#elif defined(BOOTLOADER_USBASP)
    // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
    wdt_enable(WDTO_15MS);
    wdt_reset();
    asm volatile("cli                    \n\t"
                 "ldi    r29 ,       %[ramendhi] \n\t"
                 "ldi    r28 ,       %[ramendlo] \n\t"
#    if (FLASHEND > 131071)
                 "ldi    r18 ,       %[bootaddrhi]   \n\t"
                 "st     Y+,         r18     \n\t"
#    endif
                 "ldi    r18 ,       %[bootaddrme]   \n\t"
                 "st     Y+,     r18     \n\t"
                 "ldi    r18 ,       %[bootaddrlo]   \n\t"
                 "st     Y+,     r18     \n\t"
                 "out    %[mcucsrio],    __zero_reg__    \n\t"
                 "bootloader_startup_loop%=:         \n\t"
                 "rjmp bootloader_startup_loop%=     \n\t"
                 :
                 : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
#    if (FLASHEND > 131071)
                   [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
#    else
                   [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
#    endif
                   [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));

#else  // Assume remaining boards are DFU, even if the flag isn't set

#    if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__))  // no USB - maybe BOOTLOADER_BOOTLOADHID instead though?
    UDCON  = 1;
    USBCON = (1 << FRZCLK);  // disable USB
    UCSR1B = 0;
    _delay_ms(5);  // 5 seems to work fine
#    endif

#    ifdef BOOTLOADER_BOOTLOADHID
    // force bootloadHID to stay in bootloader mode, so that it waits
    // for a new firmware to be flashed
    eeprom_write_byte((uint8_t *)1, 0x00);
#    endif

    // watchdog reset
    reset_key = BOOTLOADER_RESET_KEY;
    wdt_enable(WDTO_250MS);
    for (;;)
        ;
#endif
}

/* this runs before main() */
void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
void bootloader_jump_after_watchdog_reset(void) {
#ifndef BOOTLOADER_HALFKAY
    if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
        reset_key = 0;

        // My custom USBasploader requires this to come up.
        MCUCSR = 0;

        // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
        MCUCSR &= ~(1 << WDRF);
        wdt_disable();

// This is compled into 'icall', address should be in word unit, not byte.
#    ifdef BOOTLOADER_SIZE
        ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
#    else
        asm("ijmp" ::"z"(bootloader_start));
#    endif
    }
#endif
}

A platforms/avr/bootloaders/bootloadhid.c => platforms/avr/bootloaders/bootloadhid.c +34 -0
@@ 0,0 1,34 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <avr/eeprom.h>
#include <avr/wdt.h>

__attribute__((weak))
void bootloader_jump(void) {
    // force bootloadHID to stay in bootloader mode, so that it waits
    // for a new firmware to be flashed
    // NOTE: this byte is part of QMK's "magic number" - changing it causes the EEPROM to be re-initialized
    // thus every time the device is flashed the EEPROM will be wiped
    eeprom_write_byte((uint8_t *)1, 0x00);

    // watchdog reset
    wdt_enable(WDTO_250MS);
    for (;;)
        ;
}

A platforms/avr/bootloaders/caterina.c => platforms/avr/bootloaders/caterina.c +39 -0
@@ 0,0 1,39 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <avr/wdt.h>

__attribute__((weak))
void bootloader_jump(void) {
    // this block may be optional
    // TODO: figure it out

    uint16_t *const bootKeyPtr = (uint16_t *)0x0800;

    // Value used by Caterina bootloader use to determine whether to run the
    // sketch or the bootloader programmer.
    uint16_t bootKey = 0x7777;

    *bootKeyPtr = bootKey;

    // setup watchdog timeout
    wdt_enable(WDTO_60MS);

    // wait for watchdog timer to trigger
    while (1) { }
}

A platforms/avr/bootloaders/dfu.c => platforms/avr/bootloaders/dfu.c +53 -0
@@ 0,0 1,53 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <avr/wdt.h>
#include <util/delay.h>

#define FLASH_SIZE (FLASHEND + 1L)

/** \brief Entering the Bootloader via Software
 *
 * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
 */
#define BOOTLOADER_RESET_KEY 0xB007B007
uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));

__attribute__((weak))
void bootloader_jump(void) {
    UDCON  = 1;
    USBCON = (1 << FRZCLK);  // disable USB
    UCSR1B = 0;
    _delay_ms(5);  // 5 seems to work fine

    // watchdog reset
    reset_key = BOOTLOADER_RESET_KEY;
    wdt_enable(WDTO_250MS);
    for (;;)
        ;
}

/* this runs before main() */
void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
void bootloader_jump_after_watchdog_reset(void) {
    if ((MCUSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
        reset_key = 0;

        ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
    }
}

A platforms/avr/bootloaders/halfkay.c => platforms/avr/bootloaders/halfkay.c +129 -0
@@ 0,0 1,129 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <avr/interrupt.h>
#include <util/delay.h>

__attribute__((weak))
void bootloader_jump(void) {
    // http://www.pjrc.com/teensy/jump_to_bootloader.html

    cli();
    // disable watchdog, if enabled (it's not)
    // disable all peripherals
    // a shutdown call might make sense here
    UDCON  = 1;
    USBCON = (1 << FRZCLK);  // disable USB
    UCSR1B = 0;
    _delay_ms(5);

#if defined(__AVR_AT90USB162__)  // Teensy 1.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    UCSR1B = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    asm volatile("jmp 0x3E00");
#elif defined(__AVR_ATmega32U4__)   // Teensy 2.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    ADCSRA = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    TIMSK3 = 0;
    TIMSK4 = 0;
    UCSR1B = 0;
    TWCR   = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    DDRE   = 0;
    DDRF   = 0;
    TWCR   = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0x7E00");
#elif defined(__AVR_AT90USB646__)   // Teensy++ 1.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    ADCSRA = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    TIMSK2 = 0;
    TIMSK3 = 0;
    UCSR1B = 0;
    TWCR   = 0;
    DDRA   = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    DDRE   = 0;
    DDRF   = 0;
    PORTA  = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0xFC00");
#elif defined(__AVR_AT90USB1286__)  // Teensy++ 2.0
    EIMSK  = 0;
    PCICR  = 0;
    SPCR   = 0;
    ACSR   = 0;
    EECR   = 0;
    ADCSRA = 0;
    TIMSK0 = 0;
    TIMSK1 = 0;
    TIMSK2 = 0;
    TIMSK3 = 0;
    UCSR1B = 0;
    TWCR   = 0;
    DDRA   = 0;
    DDRB   = 0;
    DDRC   = 0;
    DDRD   = 0;
    DDRE   = 0;
    DDRF   = 0;
    PORTA  = 0;
    PORTB  = 0;
    PORTC  = 0;
    PORTD  = 0;
    PORTE  = 0;
    PORTF  = 0;
    asm volatile("jmp 0x1FC00");
#endif
}

A platforms/avr/bootloaders/none.c => platforms/avr/bootloaders/none.c +20 -0
@@ 0,0 1,20 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

__attribute__((weak))
void bootloader_jump(void) { }

A platforms/avr/bootloaders/usbasploader.c => platforms/avr/bootloaders/usbasploader.c +57 -0
@@ 0,0 1,57 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <avr/wdt.h>

#define FLASH_SIZE (FLASHEND + 1L)

#if !defined(MCUCSR)
#    if defined(MCUSR)
#        define MCUCSR MCUSR
#    endif
#endif

__attribute__((weak))
void bootloader_jump(void) {
    // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c

    wdt_enable(WDTO_15MS);
    wdt_reset();
    asm volatile("cli                    \n\t"
                 "ldi    r29 ,       %[ramendhi] \n\t"
                 "ldi    r28 ,       %[ramendlo] \n\t"
#if (FLASHEND > 131071)
                 "ldi    r18 ,       %[bootaddrhi]   \n\t"
                 "st     Y+,         r18     \n\t"
#endif
                 "ldi    r18 ,       %[bootaddrme]   \n\t"
                 "st     Y+,     r18     \n\t"
                 "ldi    r18 ,       %[bootaddrlo]   \n\t"
                 "st     Y+,     r18     \n\t"
                 "out    %[mcucsrio],    __zero_reg__    \n\t"
                 "bootloader_startup_loop%=:         \n\t"
                 "rjmp bootloader_startup_loop%=     \n\t"
                 :
                 : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
#if (FLASHEND > 131071)
                   [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
#else
                   [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
#endif
                   [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
}

A platforms/chibios/bootloaders/gd32v_dfu.c => platforms/chibios/bootloaders/gd32v_dfu.c +40 -0
@@ 0,0 1,40 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <ch.h>

#define DBGMCU_KEY_UNLOCK 0x4B5A6978
#define DBGMCU_CMD_RESET 0x1

__IO uint32_t *DBGMCU_KEY = (uint32_t *)DBGMCU_BASE + 0x0CU;
__IO uint32_t *DBGMCU_CMD = (uint32_t *)DBGMCU_BASE + 0x08U;

__attribute__((weak))
void bootloader_jump(void) {
    /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
     * register to generate a software reset request.
     * BUT instead two undocumented registers in the debug peripheral
     * that allow issueing a software reset. WHO would need the MSFRST
     * register anyway? Source:
     * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h */
    *DBGMCU_KEY = DBGMCU_KEY_UNLOCK;
    *DBGMCU_CMD = DBGMCU_CMD_RESET;
}

/* Jumping to bootloader is not possible from user code. */
void enter_bootloader_mode_if_requested(void) { }

A platforms/chibios/bootloaders/halfkay.c => platforms/chibios/bootloaders/halfkay.c +26 -0
@@ 0,0 1,26 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <ch.h>
#include "wait.h"

__attribute__((weak))
void bootloader_jump(void) {
    wait_ms(100);
    __BKPT(0);
}

A platforms/chibios/bootloaders/kiibohd.c => platforms/chibios/bootloaders/kiibohd.c +33 -0
@@ 0,0 1,33 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <ch.h>

/* Kiibohd Bootloader (MCHCK and Infinity KB) */
#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000

const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";

__attribute__((weak))
void bootloader_jump(void) {
    void *volatile vbat = (void *)VBAT;
    __builtin_memcpy(vbat, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));

    // request reset
    SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
}

A platforms/chibios/bootloaders/none.c => platforms/chibios/bootloaders/none.c +20 -0
@@ 0,0 1,20 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

__attribute__((weak))
void bootloader_jump(void) { }

R platforms/chibios/bootloader.c => platforms/chibios/bootloaders/stm32_dfu.c +29 -78
@@ 1,37 1,32 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <ch.h>
#include <hal.h>
#include "wait.h"

/* This code should be checked whether it runs correctly on platforms */
#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
#define BOOTLOADER_MAGIC 0xDEADBEEF
#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
extern uint32_t __ram0_end__;

#ifndef STM32_BOOTLOADER_DUAL_BANK
#    define STM32_BOOTLOADER_DUAL_BANK FALSE
#endif

#ifdef BOOTLOADER_TINYUF2

#    define DBL_TAP_MAGIC 0xf01669ef  // From tinyuf2's board_api.h

// defined by linker script
extern uint32_t _board_dfu_dbl_tap[];
#    define DBL_TAP_REG _board_dfu_dbl_tap[0]

void bootloader_jump(void) {
    DBL_TAP_REG = DBL_TAP_MAGIC;
    NVIC_SystemReset();
}

void enter_bootloader_mode_if_requested(void) { /* not needed, no two-stage reset */
}

#elif STM32_BOOTLOADER_DUAL_BANK

// Need pin definitions
#if STM32_BOOTLOADER_DUAL_BANK
#    include "config_common.h"

#    ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO


@@ 46,9 41,8 @@ void enter_bootloader_mode_if_requested(void) { /* not needed, no two-stage rese
#        define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000
#    endif

extern uint32_t __ram0_end__;

__attribute__((weak)) void bootloader_jump(void) {
__attribute__((weak))
void bootloader_jump(void) {
    // For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
    // bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
    // it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to


@@ 68,13 62,18 @@ __attribute__((weak)) void bootloader_jump(void) {
    NVIC_SystemReset();
}

void enter_bootloader_mode_if_requested(void) {}  // not needed at all, but if anybody attempts to invoke it....
// not needed at all, but if anybody attempts to invoke it....
void enter_bootloader_mode_if_requested(void) { }

#elif defined(STM32_BOOTLOADER_ADDRESS)  // STM32_BOOTLOADER_DUAL_BANK
#else

extern uint32_t __ram0_end__;
/* This code should be checked whether it runs correctly on platforms */
#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
#define BOOTLOADER_MAGIC 0xDEADBEEF
#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)

__attribute__((weak)) void bootloader_jump(void) {
__attribute__((weak))
void bootloader_jump(void) {
    *MAGIC_ADDR = BOOTLOADER_MAGIC;  // set magic flag => reset handler will jump into boot loader
    NVIC_SystemReset();
}


@@ 94,52 93,4 @@ void enter_bootloader_mode_if_requested(void) {
            ;
    }
}

#elif defined(GD32VF103)

#    define DBGMCU_KEY_UNLOCK 0x4B5A6978
#    define DBGMCU_CMD_RESET 0x1

__IO uint32_t *DBGMCU_KEY = (uint32_t *)DBGMCU_BASE + 0x0CU;
__IO uint32_t *DBGMCU_CMD = (uint32_t *)DBGMCU_BASE + 0x08U;

__attribute__((weak)) void bootloader_jump(void) {
    /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
     * register to generate a software reset request.
     * BUT instead two undocumented registers in the debug peripheral
     * that allow issueing a software reset. WHO would need the MSFRST
     * register anyway? Source:
     * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h */
    *DBGMCU_KEY = DBGMCU_KEY_UNLOCK;
    *DBGMCU_CMD = DBGMCU_CMD_RESET;
}

void enter_bootloader_mode_if_requested(void) { /* Jumping to bootloader is not possible from user code. */
}

#elif defined(KL2x) || defined(K20x) || defined(MK66F18) || defined(MIMXRT1062)  // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
/* Kinetis */

#    if defined(BOOTLOADER_KIIBOHD)
/* Kiibohd Bootloader (MCHCK and Infinity KB) */
#        define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
const uint8_t              sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
__attribute__((weak)) void bootloader_jump(void) {
    void *volatile vbat = (void *)VBAT;
    __builtin_memcpy(vbat, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
    // request reset
    SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
}

#    else /* defined(BOOTLOADER_KIIBOHD) */
/* Default for Kinetis - expecting an ARM Teensy */
#        include "wait.h"
__attribute__((weak)) void bootloader_jump(void) {
    wait_ms(100);
    __BKPT(0);
}
#    endif /* defined(BOOTLOADER_KIIBOHD) */

#else /* neither STM32 nor KINETIS */
__attribute__((weak)) void bootloader_jump(void) {}
#endif

A platforms/chibios/bootloaders/stm32duino.c => platforms/chibios/bootloaders/stm32duino.c +24 -0
@@ 0,0 1,24 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <ch.h>

__attribute__((weak))
void bootloader_jump(void) {
    NVIC_SystemReset();
}

A platforms/chibios/bootloaders/tinyuf2.c => platforms/chibios/bootloaders/tinyuf2.c +35 -0
@@ 0,0 1,35 @@
/* Copyright 2021 QMK
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bootloader.h"

#include <ch.h>

// From tinyuf2's board_api.h
#define DBL_TAP_MAGIC 0xF01669EF

// defined by linker script
extern uint32_t _board_dfu_dbl_tap[];
#define DBL_TAP_REG _board_dfu_dbl_tap[0]

__attribute__((weak))
void bootloader_jump(void) {
    DBL_TAP_REG = DBL_TAP_MAGIC;
    NVIC_SystemReset();
}

/* not needed, no two-stage reset */
void enter_bootloader_mode_if_requested(void) { }

M platforms/common.mk => platforms/common.mk +1 -1
@@ 4,7 4,7 @@ TMK_COMMON_SRC +=	\
	$(PLATFORM_COMMON_DIR)/platform.c \
	$(PLATFORM_COMMON_DIR)/suspend.c \
	$(PLATFORM_COMMON_DIR)/timer.c \
	$(PLATFORM_COMMON_DIR)/bootloader.c \
	$(PLATFORM_COMMON_DIR)/bootloaders/$(BOOTLOADER_TYPE).c

# Search Path
VPATH += $(PLATFORM_PATH)

R platforms/test/bootloader.c => platforms/test/bootloaders/none.c +1 -1
@@ 16,4 16,4 @@

#include "bootloader.h"

void bootloader_jump(void) {}
void bootloader_jump(void) { }

M tmk_core/protocol/arm_atsam/arm_atsam_protocol.h => tmk_core/protocol/arm_atsam/arm_atsam_protocol.h +0 -1
@@ 19,7 19,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define _ARM_ATSAM_PROTOCOL_H_

#include "samd51j18a.h"
#include "md_bootloader.h"

#include "timer.h"
#include "d51_util.h"

D tmk_core/protocol/arm_atsam/md_bootloader.h => tmk_core/protocol/arm_atsam/md_bootloader.h +0 -24
@@ 1,24 0,0 @@
#ifndef _MD_BOOTLOADER_H_
#define _MD_BOOTLOADER_H_

extern uint32_t _srom;
extern uint32_t _lrom;
extern uint32_t _erom;

#define BOOTLOADER_SERIAL_MAX_SIZE 20  // DO NOT MODIFY!

#ifdef KEYBOARD_massdrop_ctrl
// WARNING: These are only for CTRL bootloader release "v2.18Jun 22 2018 17:28:08" for bootloader_jump support
extern uint32_t _eram;
#    define BOOTLOADER_MAGIC 0x3B9ACA00
#    define MAGIC_ADDR (uint32_t *)((intptr_t)(&_eram) - 4)
#endif

#ifdef MD_BOOTLOADER

#    define MCU_HZ 48000000
#    define I2C_HZ 0  // Not used

#endif  // MD_BOOTLOADER

#endif  //_MD_BOOTLOADER_H_

M tmk_core/protocol/arm_atsam/startup.c => tmk_core/protocol/arm_atsam/startup.c +5 -1
@@ 28,7 28,6 @@
 */

#include "samd51.h"
#include "md_bootloader.h"

/* Initialize segments */
extern uint32_t _sfixed;


@@ 496,6 495,11 @@ __attribute__((section(".vectors"))) const DeviceVectors exception_table = {
#endif
};

// WARNING: These are only for CTRL bootloader release "v2.18Jun 22 2018 17:28:08" for bootloader_jump support
extern uint32_t _eram;
#define BOOTLOADER_MAGIC 0x3B9ACA00
#define MAGIC_ADDR (uint32_t *)((intptr_t)(&_eram) - 4)

/**
 * \brief This is the code that gets called on processor reset.
 * To initialize the device, and call the main() routine.

M tmk_core/protocol/arm_atsam/usb/udc.c => tmk_core/protocol/arm_atsam/usb/udc.c +4 -1
@@ 51,7 51,8 @@
#include "udi_device_conf.h"
#include "udi.h"
#include "udc.h"
#include "md_bootloader.h"

#define BOOTLOADER_SERIAL_MAX_SIZE 20  // DO NOT MODIFY!

/**
 * \ingroup udc_group


@@ 122,6 123,8 @@ static uint8_t udc_string_product_name[] = USB_DEVICE_PRODUCT_NAME;
#    define USB_DEVICE_SERIAL_NAME_SIZE 0
#endif

extern uint32_t _srom;

uint8_t     usb_device_serial_name_size = 0;
#if defined USB_DEVICE_SERIAL_USE_BOOTLOADER_SERIAL
uint8_t     bootloader_serial_number[BOOTLOADER_SERIAL_MAX_SIZE + 1] = "";