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에서는 함수명이라고 하는데 컴파일 하면 결국 주소가 됨.
MCU에 보면 보드 위에 RST 버튼이 다 있는데 그걸 누르면 0번지로 와서 처음부터 다시 쭉 실행하는 그런 개념인거임.
.globl은 다른 파일에서 쓰인 변수를 쓰기 위해 사용하는 거임. export와 비슷한 느낌.
127G 를 누르면 127번 라인으로 이동하고
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가 켜진다.
위에 했던 어셈블리어 코드를 분석해보고 싶다면 아래 링크로 이동
'Linux BSP' 카테고리의 다른 글
[Ubuntu-RaspberryPi] C언어로 U-Boot gpio제어를 통한 led 동작시키는 명령어 추가 (1) | 2024.02.13 |
---|---|
[ARM] 어셈블리코드 문법 (0) | 2024.02.08 |
[Linux BSP] U-Boot 어셈블리어로 메모리 read/write로 led on/off 하기 (0) | 2024.02.07 |
[Linux] 부트 로더 Boot Loader란? (0) | 2024.02.07 |
[Linux BSP] U-Boot Bootloader 빌드(ubuntu 호스트 크로스 컴파일) (0) | 2024.02.07 |