본문 바로가기
Linux BSP

[Linux BSP] Ubuntu에서 RaspberryPi U-Boot 코드 환경 분석

by TYB 2024. 2. 8.
반응형

3dw 3칸 삭제하겠다

. 아까전에 했던 명령어 다시 실행하겠다.

ubuntu@ubuntu8:~/pi_bsp/u-boot$  vi build.sh

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all

 

ubuntu@ubuntu8:~/pi_bsp/u-boot$ chmod u+x build.sh

ubuntu@ubuntu8:~/pi_bsp/u-boot$ ./build.sh
  UPD     include/generated/timestamp_autogenerated.h
  CC      common/version.o
  AR      common/built-in.o
  LD      u-boot
  OBJCOPY u-boot.srec
  OBJCOPY u-boot-nodtb.bin
  COPY    u-boot.bin
  SYM     u-boot.sym
  OFCHK   .config

 

모든 오브젝트 파일은 다 지우는거

ubuntu@ubuntu8:~/pi_bsp/u-boot$ make clean

지우고 다시

./build.sh

 

 

ubuntu@ubuntu8:~/pi_bsp/u-boot$ ARCH=arm make tags

 

ubuntu@ubuntu8:~/pi_bsp/u-boot$ ls -l tags
lrwxrwxrwx 1 ubuntu ubuntu 5  2월  8 13:18 tags -> ctags

심볼릭 링크, 같은파일임.

 

ubuntu@ubuntu8:~/pi_bsp/u-boot$ vi ~/.vimrc

G로 최하단으로 가서

set tags+=/home/ubuntu/pi_bsp/u-boot

넣고 dd로 잘라내기

6번라인에 커서 위치하고 p로 아랫줄에 붙여넣기

최종 ~/.vimrc

 1 set number
  2 set autoindent
  3 set cindent
  4 set smartindent
  5 set shiftwidth=4
  6 set ts=4
  7 set tags+=/home/ubuntu/pi_bsp/u-boot
  8 set tags+=/usr/include/tags

 

 

 

코드의 시작점인 엔트리 포인트

 

 

u-boot의 c코드에서 tag를 이용해서 얽혀있는 함수나 변수가 호출되는 원위치를 찾고 싶다.

그걸 위해서 vimrc에 tag주소를 걸어준거임.

 

 

 

1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2 OUTPUT_ARCH(arm)
  3 ENTRY(_start)
  4 SECTIONS
  5 {
  6  . = 0x00000000;
  7  . = ALIGN(4);
  8  .text :
  9  {
 10   *(.__image_copy_start)
 11   *(.vectors)
 12   arch/arm/cpu/armv7/start.o (.text*)
 13  }
 14  .__efi_runtime_start : {
 15   *(.__efi_runtime_start)
 16  }
 17  .efi_runtime : {
 18   *(.text.efi_runtime*)
 19   *(.rodata.efi_runtime*)
 20   *(.data.efi_runtime*)
 21  }
 22  .__efi_runtime_stop : {
 23   *(.__efi_runtime_stop)
 24  }
 25  .text_rest :
 26  {
 27   *(.text*)
 28  }
 29  . = ALIGN(4);
 30  .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 31  . = ALIGN(4);
 32  .data : {
 33   *(.data*)
 34  }
 35  . = ALIGN(4);

 36  . = .;
 37  . = ALIGN(4);
 38  __u_boot_list : {
 39   KEEP(*(SORT(__u_boot_list*)));
 40  }
 41  . = ALIGN(4);
 42  .efi_runtime_rel_start :
 43  {
 44   *(.__efi_runtime_rel_start)
 45  }
 46  .efi_runtime_rel : {
 47   *(.rel*.efi_runtime)
 48   *(.rel*.efi_runtime.*)
 49  }
 50  .efi_runtime_rel_stop :
 51  {
 52   *(.__efi_runtime_rel_stop)
 53  }
 54  . = ALIGN(4);
 55  .image_copy_end :
 56  {
 57   *(.__image_copy_end)
 58  }
 59  .rel_dyn_start :
 60  {
 61   *(.__rel_dyn_start)
 62  }
 63  .rel.dyn : {
 64   *(.rel*)
 65  }
 66  .rel_dyn_end :
 67  {
 68   *(.__rel_dyn_end)

 69  }
 70  .end :
 71  {
 72   *(.__end)
 73  }
 74  _image_binary_end = .;
 75  . = ALIGN(4096);
 76  .mmutable : {
 77   *(.mmutable)
 78  }
 79  .bss_start __rel_dyn_start (OVERLAY) : {
 80   KEEP(*(.__bss_start));
 81   __bss_base = .;
 82  }
 83  .bss __bss_base (OVERLAY) : {
 84   *(.bss*)
 85    . = ALIGN(4);
 86    __bss_limit = .;
 87  }
 88  .bss_end __bss_limit (OVERLAY) : {
 89   KEEP(*(.__bss_end));
 90  }
 91  .dynsym _image_binary_end : { *(.dynsym) }
 92  .dynbss : { *(.dynbss) }
 93  .dynstr : { *(.dynstr*) }
 94  .dynamic : { *(.dynamic*) }
 95  .plt : { *(.plt*) }
 96  .interp : { *(.interp*) }
 97  .gnu.hash : { *(.gnu.hash) }
 98  .gnu : { *(.gnu*) }
 99  .ARM.exidx : { *(.ARM.exidx*) }
100  .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
101 }

1번라인은 리틀엔디안이라는 듯이고

3번라인이 있는 부분부터 봐야되는거고

4번은 메모리의 영역을 구분할 때 사용하는 섹션(힙,스택 등등 구분)

7번 메모리에 바이너리를 배치할 때 4바이트씩 잘라서 배치해라

8번 0번지에 code를 배치해라

12 start.o 파일에 start를 배치해라

 

8~13번 라인까지 이렇게 배치하는 이유는 SoC칩 안에 internal SRAM이 4KB 밖에 안되기 때문에 실행될 때 10번 라인을 통해 복사하는 코드랑 메모리 초기화하는 시작점을 넣어주는 거임

81번 bss는 초기화 되지 않은 전역변수가 들어가 있는 공간

 

 

결론: 12번 라인에 나온 위치( arch/arm/cpu/armv7/start.o (.text*) )에 start가 들어가 있겠구나~!

 

 

ubuntu@ubuntu8:~/pi_bsp/u-boot$ vi arch/arm/cpu/armv7/start.S

명령 입력을 들어가서 /_start 안나옴..;

 

그러면 다른 파일에 있겠거니 하고

 

:tj _start

 

4번 누르고 엔터

 

어셈블리에서는 라벨명 c에서는 함수명이라고 하는데 컴파일 하면 결국 주소가 됨.

 

113번 라인부터 보면 0번지에 reset의 주소 4번지에 _undefine의 주소 이런식으로 쭉 4바이트씩 할당해줌.

MCU에 보면 보드 위에 RST 버튼이 다 있는데 그걸 누르면 0번지로 와서 처음부터 다시 쭉 실행하는 그런 개념인거임.

 

.globl은 다른 파일에서 쓰인 변수를 쓰기 위해 사용하는 거임. export와 비슷한 느낌.

 

39번 라인에 reset이 있고

 

127G 를 누르면 127번 라인으로 이동하고

이 코드의 의미를 살펴보면 bl은 다른 곳으로 분기해라 라는 뜻이고 return하고 바로 다른 곳으로 분기함.

 

127번 라인에서 O(대문자o)를 눌러서 위에 글자 입력해주고

bl kcci_led_test

추가

 

G눌러서 제일 뒤로 가고 아래에 아래 ARM에서 사용되는 어셈블리코드 추가

396 ENTRY(kcci_led_test)
397     ldr r0,=0xFE200000
398     ldr r1,=0x09240000
399     str r1,[r0,#0x00]
400     ldr r1,=0x00000040
401
402     mov r2, #4
403 ledloop:
404     str r1, [r0,#0x1C]
405     ldr r3,=0x400000
406 delay:
407     subs r3,r3, #1
408     bne delay
409     str r1,[r0,#0x28]
410     mov r1,r1,LSL #1
411     subs r2,r2,#1
412     bne ledloop
413     mov pc,lr
414 ENDPROC(kcci_led_test)

이 코드를 분석해보면

#은 상수를 의미하는 거고 상수는 data의 read only에 잡힘. 명령어는 32bit고 메모리의 size도 32bit이기 때문에 남는 공간이 없음. 그래서 32bit 값을 보내려면 0xFE200000을 잡는거임. 그래서 데이터의 read only 영역에 저장해놓고 명령어에 맞게 0xFE200000이게 read only로 저장되어 있는 메모리의 주소로 접근해서 작업하는거임.

 

407 r3에는 delay count 0x400000이 저장되어 있고 이만큼 delay 하다가 다음 작업 수행하는거임. 0.7767sec 정도 됨.

407 Program Status Register라는 특수목적 레지스터가 있는데, subs는  그 레지스터에 수행 결과를 반영하는거임.

408 bne는 그 전 줄에 실행결과가 not equal 0이면 즉, 0이 아니면 branch 하라는 뜻임. 고로 r3에서 1을 뺀 값은 이전 r3값과 같기 때문에 0이되고 보통 408번 라인을 지나쳐서 409로 간다고 보면됨.

 

bl은 다음주소를 link register에 저장하고 분기

 

410번 라인의 LSL은 Logical Shift Left 좌로 1만큼 shift하는 거고 0x00000040이 0x00000080이 되는거임.

411에서 r2가 1이되면 수행 결과가 0이 되니까

412에서 더 이상 분기를 안함.

 

 

 

저장하고 나가서

./build.sh

 

build가 완료되면 ls -l u-boot.bin 해주고

파일을 라즈베리파이에 넣어주면 되는거임.

 

시간 최신화 되있구요

 

ubuntu@ubuntu8:~/pi_bsp/u-boot$ sudo cp u-boot.bin /srv/nfs/

 

pi@pi08:/mnt/ubuntu_nfs$ ls
a.txt  main  u-boot.bin

 

 

pi@pi08:/mnt/ubuntu_nfs$ ls -l /boot/firmware/.

nfs로 sudo cp u-boot.bin /boot/firmware/. 로 넣어주고 라즈베리파이 serial putty로 재부팅해주면 되는거임.

 

 

 

 

이제 라즈베리파이 재부팅 해봅싀다..!

 

 

재부팅하면 전원 켜지고나서 led가 1~4번까지 켜졌다 꺼졌다 하고 난뒤에 u-boot으로 넘어감. b

요렇게~ 

 

nfs, hw연결 안되있으면 이전 글을 참고하세유~

 

 

 

4개만 켰는데 아쉬우니까 8개를 켜봅싀당..!

 

 

 

396 ENTRY(kcci_led_test)
397     ldr r0,=0xFE200000
398     ldr r1,=0x09240000
399     str r1,[r0,#0x00]
400
401     ldr r1,=0x00012249
402     str r1,[r0,#0x04]
403
404
405     ldr r1,=0x00000040
406
407     mov r2, #8
408 ledloop:
409     str r1, [r0,#0x1C]
410     ldr r3,=0x400000
411 delay:
412     subs r3,r3, #1
413     bne delay
414     str r1,[r0,#0x28]
415     mov r1,r1,LSL #1
416     subs r2,r2,#1
417     bne ledloop
418     mov pc,lr
419 ENDPROC(kcci_led_test)

401번, 402번 라인 추가해주고 407번 라인 4에서 8로 바꾸고나서 다시 make하고

nfs에 파일 복사해주고 라즈베리파이에 받아서 boot에 적용해주고 재부팅 하면 1~8까지 led가 켜진다.

 

 

 

 

 

위에 했던 어셈블리어 코드를 분석해보고 싶다면 아래 링크로 이동

 

 

[ARM] ARM 어셈블리어 분석

아래 글 먼저 했다는 가정 하에 arm 어셈블리어 분석해보겠음. [Linux BSP] Ubuntu에서 RaspberryPi U-Boot 코드 환경 분석 3dw 3칸 삭제하겠다 . 아까전에 했던 명령어 다시 실행하겠다. ubuntu@ubuntu8:~/pi_bsp/u-bo

program-developers-story.tistory.com

 

 

반응형