Numworks Epsilon  1.4.1
Graphing Calculator Operating System
dfu_relocated.cpp
Go to the documentation of this file.
1 #include <ion/usb.h>
2 #include <string.h>
3 #include <assert.h>
4 
5 extern char _stack_end;
7 extern char _dfu_bootloader_flash_end;
8 
9 namespace Ion {
10 namespace USB {
11 
12 typedef void (*PollFunctionPointer)(bool exitWithKeyboard);
13 
14 void DFU() {
15 
16  /* DFU transfers can serve two purposes:
17  * - Transfering RAM data between the machine and a host, e.g. Python scripts
18  * - Upgrading the flash memory to perform a software update
19  *
20  * The second case raises a huge issue: code cannot be executed from memory
21  * that is being modified. We're solving this issue by copying the DFU code in
22  * RAM.
23  *
24  * The new DFU address in RAM needs to be temporarily overwriteable when the
25  * program is being run. Epsilon has a large stack to allow deeply recursive
26  * code to run, but when doing DFU transfers it is safe to assume we will need
27  * very little stack space. We're therefore using the topmost 8K of the stack
28  * reserved by Epsilon. */
29 
30  /* 1- The stack being in reverse order, the end of the stack will be the
31  * beginning of the DFU bootloader copied in RAM. */
32 
33  size_t dfu_bootloader_size = &_dfu_bootloader_flash_end - &_dfu_bootloader_flash_start;
34  char * dfu_bootloader_ram_start = reinterpret_cast<char *>(&_stack_end);
35  assert(&_stack_end == (void *)(0x20000000 + 256*1024 - 32*1024));
36 
37  /* 2- Verify there is enough free space on the stack to copy the DFU code. */
38 
39  char foo;
40  char * stackPointer = &foo;
41  if (dfu_bootloader_ram_start + dfu_bootloader_size > stackPointer) {
42  // There is not enough room on the stack to copy the DFU bootloader.
43  return;
44  }
45 
46  /* 3- Copy the DFU bootloader from Flash to RAM. */
47 
48  memcpy(dfu_bootloader_ram_start, &_dfu_bootloader_flash_start, dfu_bootloader_size);
49 
50  /* 4- Jump to DFU bootloader code. We made sure in the linker script that the
51  * first function we want to call is at the beginning of the DFU code. */
52 
53  PollFunctionPointer dfu_bootloader_entry = reinterpret_cast<PollFunctionPointer>(dfu_bootloader_ram_start);
54 
55  /* To have the right debug symbols for the reallocated code, break here and:
56  * - Get the address of the new .text section
57  * In a terminal: arm-none-eabi-readelf -a ion/src/device/usb/dfu.elf
58  * - Delete the current symbol table
59  * symbol-file
60  * - Add the new symbol table, with the address of the new .text section
61  * add-symbol-file ion/src/device/usb/dfu.elf 0x20038000
62  */
63 
64  dfu_bootloader_entry(true);
65 
66  /* 5- That's all. The DFU bootloader on the stack is now dead code that will
67  * be overwritten when the stack grows. */
68 }
69 
70 }
71 }
#define assert(e)
Definition: assert.h:9
void(* PollFunctionPointer)(bool exitWithKeyboard)
char _dfu_bootloader_flash_start
Definition: app.cpp:5
void DFU()
char _stack_end
char _dfu_bootloader_flash_end
Definition: backlight.h:6
void * memcpy(void *dst, const void *src, size_t n)
Definition: memcpy.c:3