dfu.ld 1.69 KB
/* DFU transfers can serve two purposes:
 *  - Transfering RAM data between the machine and the host, e.g. Python scripts
 *  - Upgrading the flash memory to perform a software update
 *
 * The second case raises a huge issue: code cannot be executed from memory that
 * is being modified. We're solving this issue by copying the DFU code in RAM.
 *
 * This linker script will generate some code that expects to be executed from a
 * fixed address in RAM. The corresponding instructions will be embedded in the
 * main Epsilon ELF file, and copied to that address before execution.
 *
 * This address needs to live in RAM, and needs to be temporarily overwriteable
 * when the program is being run. Epsilon has a large stack to allow deeply
 * recursive code to run. But when doing DFU transfers it is safe to assume we
 * will need very little stack space. We're therefore using the topmost 8K of
 * the stack reserved by Epsilon.
 *
 * Last but not least, we'll want to jump to a known entry point when running
 * the DFU code (namely, Ion::USB::Device::Calculator::Poll). We're simply
 * making sure this is the first symbol output. */

EPSILON_STACK_END = 0x20000000 + 256K - 32K;

MEMORY {
  RAM_BUFFER (rw) : ORIGIN = EPSILON_STACK_END, LENGTH = 8K
}

SECTIONS {
  .text : {
    . = ALIGN(4);
    KEEP(*(.text._ZN3Ion3USB6Device10Calculator12PollAndResetEb))
    *(.text)
    *(.text.*)
  } >RAM_BUFFER

  .rodata : {
    *(.rodata)
    *(.rodata.*)
  } >RAM_BUFFER

  /DISCARD/ : {
    /* For now, we do not need .bss and .data sections. This allows us to simply
     * skip any rt0-style initialization and jump straight into the PollAndReset
     * routine. */
    *(.bss)
    *(.bss.*)
    *(.data)
    *(.data.*)
  }
}