Blame view

build6/epsilon-master/ion/src/device/usb/dfu_relocated.cpp 2.57 KB
6663b6c9   adorian   projet complet av...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  #include <ion/usb.h>
  #include <string.h>
  #include <assert.h>
  
  extern char _stack_end;
  extern char _dfu_bootloader_flash_start;
  extern char _dfu_bootloader_flash_end;
  
  namespace Ion {
  namespace USB {
  
  typedef void (*PollFunctionPointer)(bool exitWithKeyboard);
  
  void DFU() {
  
    /* DFU transfers can serve two purposes:
     *  - Transfering RAM data between the machine and a 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.
     *
     * The new DFU address in RAM 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. */
  
    /* 1- The stack being in reverse order, the end of the stack will be the
     * beginning of the DFU bootloader copied in RAM. */
  
    size_t dfu_bootloader_size = &_dfu_bootloader_flash_end - &_dfu_bootloader_flash_start;
    char * dfu_bootloader_ram_start = reinterpret_cast<char *>(&_stack_end);
    assert(&_stack_end == (void *)(0x20000000 + 256*1024 - 32*1024));
  
    /* 2- Verify there is enough free space on the stack to copy the DFU code. */
  
    char foo;
    char * stackPointer = &foo;
    if (dfu_bootloader_ram_start + dfu_bootloader_size > stackPointer) {
      // There is not enough room on the stack to copy the DFU bootloader.
      return;
    }
  
    /* 3- Copy the DFU bootloader from Flash to RAM. */
  
    memcpy(dfu_bootloader_ram_start, &_dfu_bootloader_flash_start, dfu_bootloader_size);
  
    /* 4- Jump to DFU bootloader code. We made sure in the linker script that the
     * first function we want to call is at the beginning of the DFU code. */
  
    PollFunctionPointer dfu_bootloader_entry = reinterpret_cast<PollFunctionPointer>(dfu_bootloader_ram_start);
  
    /* To have the right debug symbols for the reallocated code, break here and:
     *  - Get the address of the new .text section
     *        In a terminal: arm-none-eabi-readelf -a ion/src/device/usb/dfu.elf
     *  - Delete the current symbol table
     *        symbol-file
     *  - Add the new symbol table, with the address of the new .text section
     *        add-symbol-file ion/src/device/usb/dfu.elf 0x20038000
     */
  
    dfu_bootloader_entry(true);
  
    /* 5- That's all. The DFU bootloader on the stack is now dead code that will
     * be overwritten when the stack grows. */
  }
  
  }
  }