Update Mass Storage bootloader so that it can support devices with only 4KB bootloade...
authorDean Camera <dean@fourwalledcubicle.com>
Mon, 18 Mar 2013 17:18:11 +0000 (17:18 +0000)
committerDean Camera <dean@fourwalledcubicle.com>
Mon, 18 Mar 2013 17:18:11 +0000 (17:18 +0000)
12 files changed:
Bootloaders/MassStorage/BootloaderAPITable.S
Bootloaders/MassStorage/BootloaderMassStorage.c
Bootloaders/MassStorage/BootloaderMassStorage.h
Bootloaders/MassStorage/BootloaderMassStorage.txt
Bootloaders/MassStorage/Config/LUFAConfig.h
Bootloaders/MassStorage/Descriptors.c
Bootloaders/MassStorage/Descriptors.h
Bootloaders/MassStorage/Lib/SCSI.c
Bootloaders/MassStorage/Lib/SCSI.h
Bootloaders/MassStorage/Lib/VirtualFAT.c
Bootloaders/MassStorage/Lib/VirtualFAT.h
Bootloaders/MassStorage/makefile

index 2aded74..2d7610b 100644 (file)
   this software.\r
 */\r
 \r
+#if AUX_BOOT_SECTION_SIZE > 0\r
+\r
+#warning Using a AUX bootloader section in addition to the defined bootloader space (see documentation).\r
+\r
+; Trampoline to jump over the AUX bootloader section to the start of the bootloader,\r
+; on devices where an AUX bootloader section is used.\r
+.section .boot_aux_trampoline, "ax"\r
+.global Boot_AUX_Trampoline\r
+Boot_AUX_Trampoline:\r
+       jmp BOOT_START_ADDR\r
+\r
+#endif\r
+\r
 ; Trampolines to actual API implementations if the target address is outside the\r
 ; range of a rjmp instruction (can happen with large bootloader sections)\r
 .section .apitable_trampolines, "ax"\r
index 7adeace..a5e953a 100644 (file)
@@ -61,6 +61,25 @@ USB_ClassInfo_MS_Device_t Disk_MS_Interface =
        };
 
 
+void Application_Jump_Check(void)
+{
+       bool JumpToApplication = false;
+
+       #if (BOARD == BOARD_LEONARDO)
+               /* Enable pull-up on the IO13 pin so we can use it to select the mode */
+               PORTC |=  (1 << 7);
+               Delay_MS(10);
+               JumpToApplication |= ((PINC & (1 << 7)) != 0);
+               PORTC &= ~(1 << 7);
+       #endif
+
+       if (JumpToApplication)
+       {
+               // cppcheck-suppress constStatement
+               ((void (*)(void))0x0000)();
+       }
+}
+
 /** Main program entry point. This routine configures the hardware required by the application, then
  *  enters a loop to run the application tasks in sequence.
  */
@@ -85,9 +104,6 @@ static void SetupHardware(void)
        MCUSR &= ~(1 << WDRF);
        wdt_disable();
 
-       /* Disable clock division */
-       clock_prescale_set(clock_div_1);
-
        /* Relocate the interrupt vector table to the bootloader section */
        MCUCR = (1 << IVCE);
        MCUCR = (1 << IVSEL);
index b12cbaf..dd67381 100644 (file)
@@ -39,7 +39,6 @@
        /* Includes: */
                #include <avr/io.h>
                #include <avr/wdt.h>
-               #include <avr/power.h>
                #include <avr/interrupt.h>
                #include <string.h>
 
                #define LEDMASK_USB_BUSY          LEDS_LED2
 
        /* Function Prototypes: */
-               static void SetupHardware(void);
+               int main(void) AUX_BOOT_SECTION;
 
-               void EVENT_USB_Device_Connect(void);
-               void EVENT_USB_Device_Disconnect(void);
-               void EVENT_USB_Device_ConfigurationChanged(void);
-               void EVENT_USB_Device_ControlRequest(void);
+               static void SetupHardware(void) AUX_BOOT_SECTION;
 
-               bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+               void Application_Jump_Check(void) ATTR_INIT_SECTION(3);
+
+               void EVENT_USB_Device_Connect(void) AUX_BOOT_SECTION;
+               void EVENT_USB_Device_Disconnect(void) AUX_BOOT_SECTION;
+               void EVENT_USB_Device_ConfigurationChanged(void) AUX_BOOT_SECTION;
+               void EVENT_USB_Device_ControlRequest(void) AUX_BOOT_SECTION;
+
+               bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
 
 #endif
 
index 7ca7c1f..19751d3 100644 (file)
@@ -12,6 +12,8 @@
  *
  *  \li Series 7 USB AVRs (AT90USBxxx7)
  *  \li Series 6 USB AVRs (AT90USBxxx6)
+ *  \li Series 4 USB AVRs (ATMEGAxxU4) - <i>See \ref SSec_Aux_Space</i>
+ *  \li Series 2 USB AVRs (AT90USBxx2, ATMEGAxxU2) - <i>See \ref SSec_Aux_Space</i>
  *
  *  \section Sec_Info USB Information:
  *
@@ -49,7 +51,7 @@
  *  firmware image file, to load firmware onto the AVR.
  *
  *  Out of the box this bootloader builds for the AT90USB1287 with an 8KB bootloader section size, and will fit
- *  into 8KB of bootloader space. If you wish to alter this size and/or change the AVR model, you will need to
+ *  into 6KB of bootloader space. If you wish to alter this size and/or change the AVR model, you will need to
  *  edit the MCU, FLASH_SIZE_KB and BOOT_SECTION_SIZE_KB values in the accompanying makefile.
  *
  *  When the bootloader is running, the board's LED(s) will flash at regular intervals to distinguish the
  *  #define BOOTLOADER_ADDRESS_LENGTH          4
  *  \endcode
  *
+ *  From the application the API support of the bootloader can be detected by reading the FLASH memory bytes located at address
+ *  \c BOOTLOADER_MAGIC_SIGNATURE_START and comparing them to the value \c BOOTLOADER_MAGIC_SIGNATURE. The class of bootloader
+ *  can be determined by reading the FLASH memory bytes located at address \c BOOTLOADER_CLASS_SIGNATURE_START and comparing them
+ *  to the value \c BOOTLOADER_MASS_STORAGE_SIGNATURE. The start address of the bootloader can be retrieved by reading the bytes
+ *  of FLASH memory starting from address \c BOOTLOADER_ADDRESS_START.
+ *
+ *  \subsection SSec_Aux_Space Auxiliary Bootloader Section
+ *  To make the bootloader function on smaller devices (those with a physical bootloader section of smaller than 6KB) a second
+ *  section of memory (called the <i>Auxiliary Bootloader Section</i>) is added before the start of the real bootloader section,
+ *  and is filled with a portion of the bootloader code. This allows smaller devices to run the bootloader, at the cost of an
+ *  additional portion of the device's FLASH (the bootloader section size in KB subtracted from the 6KB total size). A small
+ *  trampoline is inserted at the start of the auxiliary section so that the bootloader will run normally in the case of a blank
+ *  application section.
+ *
+ *  On devices supporting a 8KB bootloader section size, the AUX section is not created in the final binary.
+ *
  *  \subsection SSec_API_MemLayout Device Memory Map
  *  The following illustration indicates the final memory map of the device when loaded with the bootloader.
  *
  *  |                            |
  *  |                            |
  *  |                            |
+ *  |                            |
+ *  +----------------------------+ FLASHEND - BOOT_SECTION_SIZE - BOOT_AUX_SECTION_SIZE
+ *  | Booloader Start Trampoline |
+ *  | (Not User App. Accessible) |
+ *  +----------------------------+ FLASHEND - BOOT_SECTION_SIZE - BOOT_AUX_SECTION_SIZE + 4
+ *  |                            |
+ *  |     Auxiliary Bootloader   |
+ *  |  Space for Smaller Devices |
+ *  | (Not User App. Accessible) |
+ *  |                            |
  *  +----------------------------+ FLASHEND - BOOT_SECTION_SIZE
  *  |                            |
  *  |   Bootloader Application   |
  *  +----------------------------+ FLASHEND
  *  \endverbatim
  *
- *  Bootloaders reporting a device release revision number of 1.00 or greater are bootloader API enabled. From the application
- *  the API support of the bootloader can be detected by reading the FLASH memory bytes located at address \c BOOTLOADER_MAGIC_SIGNATURE_START
- *  and comparing them to the value \c BOOTLOADER_MAGIC_SIGNATURE. The class of bootloader can be determined by reading the
- *  FLASH memory bytes located at address \c BOOTLOADER_CLASS_SIGNATURE_START and comparing them to the value \c BOOTLOADER_MASS_STORAGE_SIGNATURE.
- *  The start address of the bootloader can be retrieved by reading the bytes of FLASH memory starting from address \c BOOTLOADER_ADDRESS_START.
- *
  *  \section Sec_Options Project Options
  *
  *  The following defines can be found in this demo, which can control the demo behaviour when defined, or changed in value.
index b22e67f..fcc3ea8 100644 (file)
@@ -69,7 +69,7 @@
                #define USE_RAM_DESCRIPTORS
 //             #define USE_FLASH_DESCRIPTORS
 //             #define USE_EEPROM_DESCRIPTORS
-//             #define NO_INTERNAL_SERIAL
+               #define NO_INTERNAL_SERIAL
                #define FIXED_CONTROL_ENDPOINT_SIZE      8
                #define DEVICE_STATE_AS_GPIOR            0
                #define FIXED_NUM_CONFIGURATIONS         1
index 4de1207..cbc320f 100644 (file)
@@ -60,7 +60,7 @@ const USB_Descriptor_Device_t DeviceDescriptor =
 
        .ManufacturerStrIndex   = NO_DESCRIPTOR,
        .ProductStrIndex        = NO_DESCRIPTOR,
-       .SerialNumStrIndex      = USE_INTERNAL_SERIAL,
+       .SerialNumStrIndex      = NO_DESCRIPTOR,
 
        .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
 };
@@ -124,17 +124,6 @@ const USB_Descriptor_Configuration_t ConfigurationDescriptor =
                }
 };
 
-/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
- *  the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
- *  via the language ID table available at USB.org what languages the device supports for its string descriptors.
- */
-const USB_Descriptor_String_t LanguageString =
-{
-       .Header                 = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},
-
-       .UnicodeString          = {LANGUAGE_ID_ENG}
-};
-
 /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
  *  documentation) by the application code so that the address and size of a requested descriptor can be given
  *  to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
@@ -145,30 +134,21 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
                                     const uint8_t wIndex,
                                     const void** const DescriptorAddress)
 {
-       const uint8_t  DescriptorType   = (wValue >> 8);
-       const uint8_t  DescriptorNumber = (wValue & 0xFF);
+       const uint8_t DescriptorType = (wValue >> 8);
 
        const void* Address = NULL;
        uint16_t    Size    = NO_DESCRIPTOR;
 
-       switch (DescriptorType)
+       /* If/Else If chain compiles slightly smaller than a switch case */
+       if (DescriptorType == DTYPE_Device)
+       {
+               Address = &DeviceDescriptor;
+               Size    = sizeof(USB_Descriptor_Device_t);
+       }
+       else if (DescriptorType == DTYPE_Configuration)
        {
-               case DTYPE_Device:
-                       Address = &DeviceDescriptor;
-                       Size    = sizeof(USB_Descriptor_Device_t);
-                       break;
-               case DTYPE_Configuration:
-                       Address = &ConfigurationDescriptor;
-                       Size    = sizeof(USB_Descriptor_Configuration_t);
-                       break;
-               case DTYPE_String:
-                       if (!(DescriptorNumber))
-                       {
-                                       Address = &LanguageString;
-                                       Size    = pgm_read_byte(&LanguageString.Header.Size);
-                       }
-
-                       break;
+               Address = &ConfigurationDescriptor;
+               Size    = sizeof(USB_Descriptor_Configuration_t);
        }
 
        *DescriptorAddress = Address;
index 7261fab..4460fda 100644 (file)
@@ -70,7 +70,7 @@
                uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
                                                    const uint8_t wIndex,
                                                    const void** const DescriptorAddress)
-                                                   ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
+                                                   ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3) AUX_BOOT_SECTION;
 
 #endif
 
index 154fe48..0bb1c7a 100644 (file)
@@ -104,9 +104,6 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_READ_CAPACITY_10:
                        CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
                        break;
-               case SCSI_CMD_SEND_DIAGNOSTIC:
-                       CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
-                       break;
                case SCSI_CMD_WRITE_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
                        break;
@@ -116,6 +113,7 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_MODE_SENSE_6:
                        CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
                        break;
+               case SCSI_CMD_SEND_DIAGNOSTIC:
                case SCSI_CMD_START_STOP_UNIT:
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
@@ -227,33 +225,6 @@ static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInt
        return true;
 }
 
-/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the
- *  board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is
- *  supported.
- *
- *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
- *
- *  \return Boolean true if the command completed successfully, false otherwise.
- */
-static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
-{
-       /* Check to see if the SELF TEST bit is not set */
-       if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2)))
-       {
-               /* Only self-test supported - update SENSE key and fail the command */
-               SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
-                              SCSI_ASENSE_INVALID_FIELD_IN_CDB,
-                              SCSI_ASENSEQ_NO_QUALIFIER);
-
-               return false;
-       }
-
-       /* Succeed the command and update the bytes transferred counter */
-       MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
-
-       return true;
-}
-
 /** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address
  *  and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual
  *  reading and writing of the data.
index 54914f5..8eb817f 100644 (file)
@@ -42,7 +42,6 @@
 
                #include <LUFA/Drivers/USB/USB.h>
 
-               #include "../BootloaderMassStorage.h"
                #include "../Descriptors.h"
                #include "VirtualFAT.h"
 
                #define DEVICE_TYPE_BLOCK   0x00
 
        /* Function Prototypes: */
-               bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+               bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
 
                #if defined(INCLUDE_FROM_SCSI_C)
-                       static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
-                       static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
-                       static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
-                       static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+                       static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
+                       static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
+                       static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
                        static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
-                                                             const bool IsDataRead);
-                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+                                                             const bool IsDataRead) AUX_BOOT_SECTION;
+                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
                #endif
 
 #endif
index ee0107c..41c661e 100644 (file)
@@ -151,26 +151,28 @@ static void WriteVirtualBlock(const uint16_t BlockNumber)
 
        if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES))))
        {
+               #if (FLASHEND > 0xFFFF)
                uint32_t WriteFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
+               #else
+               uint16_t WriteFlashAddress = (uint16_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
+               #endif
 
                for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i += 2)
                {
                        if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
                        {
                                /* Erase the given FLASH page, ready to be programmed */
-                               boot_page_erase(WriteFlashAddress);
-                               boot_spm_busy_wait();
+                               BootloaderAPI_ErasePage(WriteFlashAddress);
                        }
 
                        /* Write the next data word to the FLASH page */
-                       boot_page_fill(WriteFlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
+                       BootloaderAPI_FillWord(WriteFlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
                        WriteFlashAddress += 2;
 
                        if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
                        {
                                /* Write the filled FLASH page to memory */
-                               boot_page_write(WriteFlashAddress - SPM_PAGESIZE);
-                               boot_spm_busy_wait();
+                               BootloaderAPI_WritePage(WriteFlashAddress - SPM_PAGESIZE);
                        }
                }
        }
@@ -219,10 +221,17 @@ static void ReadVirtualBlock(const uint16_t BlockNumber)
                default: /* Blocks 4 onwards: Data allocation section */
                        if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES))))
                        {
+                               #if (FLASHEND > 0xFFFF)
                                uint32_t ReadFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
 
                                for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
                                  BlockBuffer[i] = pgm_read_byte_far(ReadFlashAddress++);
+                               #else
+                               uint16_t ReadFlashAddress = (uint16_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
+
+                               for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
+                                 BlockBuffer[i] = pgm_read_byte(ReadFlashAddress++);
+                               #endif
                        }
 
                        break;
@@ -237,8 +246,8 @@ static void ReadVirtualBlock(const uint16_t BlockNumber)
  *  PC via the USB Mass Storage interface.
  *
  *  \param[in] MSInterfaceInfo  Pointer to a structure containing a Mass Storage Class configuration and state
- *  \param[in] BlockAddress  Data block starting address for the write sequence
- *  \param[in] TotalBlocks   Number of blocks of data to write
+ *  \param[in] BlockAddress     Data block starting address for the write sequence
+ *  \param[in] TotalBlocks      Number of blocks of data to write
  */
 void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                             const uint32_t BlockAddress,
@@ -256,8 +265,8 @@ void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
  *  to the host PC via the USB Mass Storage interface.
  *
  *  \param[in] MSInterfaceInfo  Pointer to a structure containing a Mass Storage Class configuration and state
- *  \param[in] BlockAddress  Data block starting address for the read sequence
- *  \param[in] TotalBlocks   Number of blocks of data to read
+ *  \param[in] BlockAddress     Data block starting address for the read sequence
+ *  \param[in] TotalBlocks      Number of blocks of data to read
  */
 void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                            const uint32_t BlockAddress,
index 16b4b73..8019691 100644 (file)
 
                #include <LUFA/Drivers/USB/USB.h>
 
+               #include "../BootloaderAPI.h"
+
        /* Macros: */
                /** Size of the virtual FIRMWARE.BIN file in bytes. */
-               #define FIRMWARE_FILE_SIZE_BYTES  (FLASHEND - (FLASHEND - BOOT_START_ADDR))
+               #define FIRMWARE_FILE_SIZE_BYTES  (FLASHEND - (FLASHEND - BOOT_START_ADDR) - AUX_BOOT_SECTION_SIZE)
 
                /** Number of sectors that comprise a single logical disk cluster. */
                #define SECTOR_PER_CLUSTER        4
                #if defined(INCLUDE_FROM_VIRTUAL_FAT_C)
                        static void UpdateFAT12ClusterEntry(uint8_t* const FATTable,
                                                            const uint16_t Index,
-                                                           const uint16_t ChainEntry);
-                       static void WriteVirtualBlock(const uint16_t BlockNumber);
-                       static void ReadVirtualBlock(const uint16_t BlockNumber);
+                                                           const uint16_t ChainEntry) AUX_BOOT_SECTION;
+                       static void WriteVirtualBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;
+                       static void ReadVirtualBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;
                #endif
 
                void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                            const uint32_t BlockAddress,
-                                           uint16_t TotalBlocks);
+                                           uint16_t TotalBlocks) AUX_BOOT_SECTION;
 
                void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                           const uint32_t BlockAddress,
-                                          uint16_t TotalBlocks);
+                                          uint16_t TotalBlocks) AUX_BOOT_SECTION;
 #endif
index 68b26b1..c23e62f 100644 (file)
@@ -27,20 +27,33 @@ LD_FLAGS     = -Wl,--section-start=.text=$(BOOT_START_OFFSET) $(BOOT_API_LD_FLAG
 # match the target's total FLASH size and the bootloader size set in the\r
 # device's fuses.\r
 FLASH_SIZE_KB         = 128\r
-BOOT_SECTION_SIZE_KB  = 8\r
+BOOT_SECTION_SIZE_KB  = 4\r
 \r
 # Bootloader address calculation formulas\r
 # Do not modify these macros, but rather modify the dependent values above.\r
 CALC_ADDRESS_IN_HEX   = $(shell printf "0x%X" $$(( $(1) )) )\r
 BOOT_START_OFFSET     = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) - $(BOOT_SECTION_SIZE_KB)) * 1024 )\r
-BOOT_SEC_OFFSET       = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) * 1024) - $(strip $(1)) )\r
+BOOT_SEC_OFFSET       = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) * 1024) - ($(strip $(1))) )\r
 \r
 # Bootloader linker section flags for relocating the API table sections to\r
 # known FLASH addresses - these should not normally be user-edited.\r
-BOOT_SECTION_LD_FLAG  = -Wl,--section-start=.apitable_$(strip $(1))=$(call BOOT_SEC_OFFSET, $(3)) -Wl,--undefined=BootloaderAPI_$(strip $(2))\r
-BOOT_API_LD_FLAGS     = $(call BOOT_SECTION_LD_FLAG, trampolines, Trampolines, 96)\r
-BOOT_API_LD_FLAGS    += $(call BOOT_SECTION_LD_FLAG, jumptable,   JumpTable,   32)\r
-BOOT_API_LD_FLAGS    += $(call BOOT_SECTION_LD_FLAG, signatures,  Signatures,  8)\r
+BOOT_SECTION_LD_FLAG  = -Wl,--section-start=$(strip $(1))=$(call BOOT_SEC_OFFSET, $(3)) -Wl,--undefined=$(strip $(2))\r
+BOOT_API_LD_FLAGS     = $(call BOOT_SECTION_LD_FLAG, .apitable_trampolines, BootloaderAPI_Trampolines, 96)\r
+BOOT_API_LD_FLAGS    += $(call BOOT_SECTION_LD_FLAG, .apitable_jumptable,   BootloaderAPI_JumpTable,   32)\r
+BOOT_API_LD_FLAGS    += $(call BOOT_SECTION_LD_FLAG, .apitable_signatures,  BootloaderAPI_Signatures,  8)\r
+\r
+# Check if the bootloader needs an AUX section, located before the real bootloader section to store some of the\r
+# bootloader code. This is required for 32KB and smaller devices, where the actual bootloader is 6KB but the maximum\r
+# bootloader section size is 4KB. The actual usable application space will be reduced by 6KB for these devices.\r
+ifeq ($(BOOT_SECTION_SIZE_KB),8)\r
+  CC_FLAGS           += -DAUX_BOOT_SECTION='' -DAUX_BOOT_SECTION_SIZE=0\r
+else\r
+  AUX_BOOT_SECTION_KB = (6 - $(BOOT_SECTION_SIZE_KB))\r
+\r
+  CC_FLAGS           += -DAUX_BOOT_SECTION='__attribute__((section(".boot_aux")))' -DAUX_BOOT_SECTION_SIZE='($(AUX_BOOT_SECTION_KB) * 1024)'\r
+  LD_FLAGS           += -Wl,--section-start=.boot_aux=$(call BOOT_SEC_OFFSET, (($(BOOT_SECTION_SIZE_KB) + $(AUX_BOOT_SECTION_KB)) * 1024 - 16))\r
+  LD_FLAGS           += $(call BOOT_SECTION_LD_FLAG, .boot_aux_trampoline, Boot_AUX_Trampoline, ($(BOOT_SECTION_SIZE_KB) + $(AUX_BOOT_SECTION_KB)) * 1024)\r
+endif\r
 \r
 # Default target\r
 all:\r