티스토리 뷰

WICED의 OTA(Over The Air) update는 ELF(Executable and Linkable Format) 파일을 이용하여 업그레이드를 한다. ELF를 사용하게되면 설치될 위치가 ELF 파일에 있으므로 원하는 부분을 업그레이드 하기에 편할 수 도 있다. 


최신 버전인 WICED 3.7.0 을 보면 OTA update 로직은 WICED/platform/MCU/wiced_waf_common.c 부터 따라가면 된다. 이 함수를 상위 application에서 직접 사용하지는 않고, include/wiced_framework.h 에 wrapping되어 있는 wicked_framework_xxxx() 함수들을 사용한다. 


기본적인 업데이트 절차는 다음과 같다.

- ELF 형식의 fw image를 다운로드 받으면서 flash에 write 한다. MCU internal flash 용량이 적기 때문에 보통은 외부에 연결한 serial flash에 저장하기도 한다. 

- Flash 저장이 완료되면 wiced_framework_set_boot()를 호출하여 DCT(Device Configuration Table)에 flag를 설정한다.

- 리부팅

- 리부팅 후 WICED의 bootloader에서 DCT를 확인하여 flag가 설정되어 있으면 ELF 이미지를 읽어서 해당 flash 영역에 write한다. 

- Flash write 후 DCT 영역의 flag를 지운다. 


이와 같은 일을 수행하는 bootloader는 아래 위치에 있다.

- apps/waf/bootloader/bootloader.c

- apps/waf/ota2_bootloader/ota2_bootloader.c


DCT 영역은 이중화 되어 있기 때문에 업그레이드 과정에서 전원이 손실되는 등의 문제가 발생하여도 다시 전원을 켜면 정상적으로 업그레이드가 된다.


bootloader에서 업그레이드를 위하여 wiced_waf_app_load()를 호출하는데, 이 함수가 실제적인 업그레이드 함수이다. 기본적인 동작원리를 이해하기 위하여는 ELF 포멧 구조를 이해하여야 한다. 여기에서는 WICED에서 ELF를 참조하는 로직에 대해서 간략하게 정리한다. ELF 포멧에 대한 자세한 구조를 알기를 원한다면 아래 문서를 참고할 수 있다. 

Executable and Linkable Format (ELF)


예로 만든 elf image의 program header와 section header를 보면 아래와 같다. 

$ arm-none-eabi-readelf -lS  sample-image-NetX.stripped.elf

There are 8 section headers, starting at offset 0x40be4:


Section Headers:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                   NULL            00000000 000000 000000 00      0    0

  [ 1] .vectors          PROGBITS        0800c000 004000 000184 00  WA  0    4

  [ 2] .text             PROGBITS        0800c190 004190 03b570 00  AX  0   0 16

  [ 3] .ARM.exidx        ARM_EXIDX       08047700 03f700 000008 00  AL  2    4

  [ 4] .data             PROGBITS        20000000 040000 000bac 00  WA  0    8

  [ 5] .bss              NOBITS          20000bb0 040bb0 00cc68 00  WA  0    8

  [ 6] .stack            NOBITS          2000d818 040bb0 000320 00  WA  0    1

  [ 7] .shstrtab         STRTAB          00000000 040bac 000037 00      0    1

Key to Flags:

  W (write), A (alloc), X (execute), M (merge), S (strings)

  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)

  O (extra OS processing required) o (OS specific), p (processor specific)


Elf file type is EXEC (Executable file)

Entry point 0x800c4d9

There are 4 program headers, starting at offset 52


Program Headers:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align

  EXIDX          0x03f700 0x08047700 0x08047700 0x00008 0x00008 R   0x4

  LOAD           0x004000 0x0800c000 0x0800c000 0x3b708 0x3b708 RWE 0x8000

  LOAD           0x040000 0x20000000 0x08047708 0x00bac 0x00bac RW  0x8000

  LOAD           0x040bb0 0x20000bb0 0x20000bb0 0x00000 0x0cf88 RW  0x8000


 Section to Segment mapping:

  Segment Sections...

   00     .ARM.exidx

   01     .vectors .text .ARM.exidx

   02     .data

   03     .bss .stack


- 업그레이드 루틴은 ELF 정보의 program header만 참조하여 flash 업그레이드를 수행한다. 

- Program header 영역 중 type이 loadable segment(LOAD)이고 file size가 0 보다 큰 부분이 실제로 복사할 영역이다. 

- 이 영역의 Physical Addres(PhysAddr)와 Size(FileSiz)를 참조하여 해당 영역의 flash를 erase하고 writing 한다. 파일에서의 위치는 Offset 필드이다. 


ELF를 참조하는 방식의 업그레이드 루틴도 의외로 단순하다. 참고로 업그레이드 하는 program header의 두 영역 중 첫번째 영역은 section header의 .vectors, .text, .ARM.exidx 영역으로 code 부분이고, 두번째 영역은 .data로 초기화값이 있는 데이타 부분이다. Binary 파일에 비하여 ELF는 크기가 커진다는 단점은 있다. 위 파일의 경우 binary는 246,340B, elf는 디버깅 정보를 모두 strip으로 제거한 파일이지만 265,508B로 약 19,168B 정도 overhead가 있다. 실제 순수한 header 정보는 500B 정도 인데 이와 같이 커진 이유는 padding이 들어가 있기 때문이다. 위의 예에서 program header 두번째 영역을 보면 Offset이 0x004000 으로 이 앞부분에 header가 들어가고 남는 부분은 padding 영역이다. 이 영역까지 줄인다면 차이는 크게 줄일 수 있지만 binutils을 수정하여야 할 듯 하다. 


이와 같은 overhead가 있긴 하지만 필요시 DCT 영역이나 다른 영역에 data를 overwrite 하여야 할 때도 linker script를 수정해 주면 되므로 유연성이 있어 ELF 형식의 업그레이드도 괜찮아 보인다. 

댓글
댓글쓰기 폼