- Raspberry Pi Boot관련정보
- cmdline.txt : kernel cmdline 수정가능
- config.txt : Raspberry 설정 파일
- bootcode.bin : Raspberry bootloader로 SoC에의해 Loading 되고 start*.elf를 로딩
- start.elf, start_x.elf, start_db.elf, start_cd.elf : firmware로 사용되지만 elf파일형식
- fixup.dat, fixup_x.dat, fixup_db.dat, fixup_cd.dat : start*.elf의 linker file
- *.dtb : Device Tree Blob
https://wikidocs.net/3198
https://wikidocs.net/18317
1.1 /boot 파일 확인
일단 아래를 보면, dtb 파일과 kernel.img가 많아서 현재 사용중인 이미지를 알아야겠다.
추측을 하면 아래의 것을 사용할 것으로 짐작
$ cd /boot bcm2708-rpi-0-w.dtb bcm2709-rpi-2-b.dtb bootcode.bin fixup_cd.dat issue.txt LICENSE.oracle start.elf bcm2708-rpi-b.dtb bcm2710-rpi-3-b.dtb cmdline.txt fixup.dat kernel7.img overlays start_x.elf bcm2708-rpi-b-plus.dtb bcm2710-rpi-3-b-plus.dtb config.txt fixup_db.dat kernel.img start_cd.elf bcm2708-rpi-cm.dtb bcm2710-rpi-cm3.dtb COPYING.linux fixup_x.dat LICENCE.broadcom start_db.elf
1.2 DTS 와 DTB 구조 복습 (Device Tree)
Device Tree 의 기본이해 (관련예제도 링크)
https://ahyuo79.blogspot.com/2015/08/kernel-boot-kernel-device-tree.html
https://www.elinux.org/images/a/ad/Arm-soc-checklist.pdf
Device Tree Spec (v0.2 와 v0.1) 및 각 문법 이해 (필독)
https://www.devicetree.org/specifications/
https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.2
https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.1
Device Tree 활용
https://elinux.org/Device_Tree_Usage
C와 같이 Preprocessor가 먼저 진행 빌드되므로 이점 주의
https://elinux.org/Device_Tree_Source_Undocumented
Kernel GPIO 기본사용법
https://www.kernel.org/doc/Documentation/gpio/gpio-legacy.txt
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842279/Build+Device+Tree+Blob
https://elinux.org/Device_Tree_Reference
https://elinux.org/Device_Tree_Reference
- DTS의 기본구조
- 상위기본구성 분석
- / 의 model= MACHINE 정보이름과 compatibale 에 해당 arch를 선택 (MACHINE 정보)
- #address-cells 1 , #size-cells 1 의 의미는
- child의 address cell u32 갯수와 size cell u32 갯수 말하며 이는 reg에 적용
- memory@0 의 의미는 memory address 0 의미
- reg = <0 0x20000000) address 와 size
- uart@fe00100 의 의미는 uart 의 address는 0xfe00100
- reg = <0xfe001000 0x100 > 은 address 와 size
- Sample DTS (Deivce Tree Syntax) 구조 (상위 Spec 문서참조)
C와 같이 Preprocessor가 먼저 진행 빌드되므로 이점 주의
$ vi arch/arm/boot/dts/mysample.dts //kernel or uboot /dts-v1/; // device tree spec 를 반드시 참조하며, 각 node의 manual 별도로 보자 #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> //커널의 ./include/dt-bindings/ //커널의 ./scripts/dtc/include-prefixes/dt-bindings // dtc는 ./scripts/dtc 에 존재 #include "sample.dtsi" // 아래와 같이 C처럼 Preprocess(상위 include)가 동작가능하며, 주석도 /**/ // 둘다 가능 #define TEST //preprocess 도 동작가능 C처럼 Preprocess가 다른 것 보다 먼저 실행되는 것을 주의 #if 1 // jhlee #endif #ifndef TEST #endif #ifdef TEST #endif #if defined(TEST) //jhlee #else //orgin #endif / { // / { 는 DTS Main을 의미하며, 만약 sample.dtsi 이 것이 포함이 되어 있다면, 그곳에 위치에 들어간다고 생각하면됨 //보통 Kernel에서 model 에 정보를 넣으면, 부팅시 Machine Name 확인가능 //조금 고급스럽게 하고자 하면 색 정보도 같이 넣어 만들자 //sample.dtsi 이미 있지만, 중복으로 넣어 최종이것으로 빌드하면 최종값으로 적용가능 //model = "fsl,mpc8572da"; //MACHINE 정보 Name이며 마음대로 변경,DT_MACHINE_START (Device Tree용) or MACHINE_START model = "EVM_JHLEE"; compatible = "fsl,mpc8572da"; //board 호환성이며, "manufacturer,model" kernel 검색 }; // }; 는 상위 model 때문에 삽입 #if 1 //아래 다시 중복설정할 경우 이것이 최종 값으로 결정되며, model만 재선언 (제조사 생략)하여, 내맘대로 변경 / { // Kernel Boot시 색깔까지 넣어 표시 model = "\x1b[1m \x1b[93m Jeonghun Board Ver 0.0 \x1b[0m"; // Machin Name을 변경 }; #endif // 주석 /* 주석 */ /* 보통 gpio node가 구성되고, PINMUX에서 GPIO로 설정하면, User에서 /sys/class/gpio/export 를 이용하여 직접사용가능 GPIO4_18 보통 (4-1)*32+18 = 114 GPIO4_19 보통 (4-1)*32+18 = 115 */ /* /sys/class/gpio/export /sys/class/gpio/gpio114/direction https://www.kernel.org/doc/Documentation/gpio/sysfs.txt 항상 compatible 에서 device driver와 연결하므로, Kernel에서 Pinmux를 하였다고, 자동으로 /sys/class/gpio/export에 적용되지 않는다 */
- 필요없는 부분 중복된 부분삭제 관련예제
- /delete-node/ : node or lable 삭제
- /delete-property/ : node 의 property 삭제
- /omit-if-no-ref/ : dtc에게 사용하지 않는다면, 삭제
상위에서 설명했듯이 중복많이 허용하며, 최종선언된 dts기준으로 파싱을 시작하기때문에 필요없다면,
나만의 dts를 만들경우 최종 dts include하고 필요없는 것을 정리하도록하자
// 이미 이전에 선언된 uart1 label 의 property의 status를 okay ->disabled 변경 &uart1 { status = "disabled"; }; // 이미 이전에 선언된 uart1 lalel 의 특정 property만 삭제 &uart1 { /delete-property/ fsl,uart-has-rtscts; }; /* node의 구성 은 보통 label: node로 or node로만 구성될 수가 있으며, label에는 &를 사용 label: node adv_bridge0: adv7535@3d { ... }; adv_bridge1: adv7535@3d { ... }; */ // node를 삭제방법은 label에는 &사용하며, node 를 직접입력할 경우 &불필요 /delete-node/ &adv_bridge0; /delete-node/ &adv_bridge1;
- OS에서는 호환성목적으로 aliases 기능을 사용
각 Chip label 이름이 다 다르게 정의될 수 있으므로, OS가 알수 있도록 이를 변경
// aliases는 node의 새로 naming 하여 쉽게 node구성하며, 주로 OS 즉 linux 호환성을위해서 사용해준다 // 구성은 이전과 같이 label에 &사용 aliases { rtc0 = &snvsrtc; rtc1 = &rtc; }; chosen { bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; }; https://elinux.org/Device_Tree_Usage#aliases_Node
- #xxx-cells 의 의미
child의 cells 의 갯수를 정의해주는 것으로 기본적인 address-cells 과 size-cells 이 존재한다.
더불어 다양한 #로 시작하는 cells들이 존재
/dts-v1/; / { #address-cells = <1>; // address-cells의 의미 child의 reg의 address u32 갯수 #size-cells = <1>; // size-cells 의 의미 child의 reg의 size u32 갯수 ... serial@101f0000 { compatible = "arm,pl011"; reg = <0x101f0000 0x1000 >; // 상위 address-cells 수(1) 와 size-cells 수(1)로 결정 }; serial@101f2000 { compatible = "arm,pl011"; reg = <0x101f2000 0x1000 >; }; gpio@101f3000 { compatible = "arm,pl061"; reg = <0x101f3000 0x1000 0x101f4000 0x0010>; // 상위 address-cells 수(1) 와 size-cells 수(1)로 결정 연속 2개 }; interrupt-controller@10140000 { compatible = "arm,pl190"; reg = <0x10140000 0x1000 >; }; spi@10115000 { compatible = "arm,pl022"; reg = <0x10115000 0x1000 >; }; ... https://elinux.org/Device_Tree_Usage#Memory_Mapped_Devices };
- range 의 의미
OS는 virtual address를 사용하며, 이를 위해서 memory map-io로 연결하여 사용한다.
이때 각 영역의 부분의 정의해주는 것이 range의 기능이다.
/dts-v1/; / { compatible = "acme,coyotes-revenge"; #address-cells = <1>; //parent의 reg의 address u32 수 #size-cells = <1> //parent의 reg의 size u32 수 ... external-bus { #address-cells = <2>; //child의 reg의 address u32 수 #size-cells = <1>; //child의 reg의 size u32 수 /* range(Address Translation) 는 address translation을 위한 list 구성 1. the child's #address-cells value(2), 2. the parent's #address-cells value(1), 3. the child's #size-cells(1) 마지막 size로 memory map을 하여 영역 넣어구성 아래와 같이 mapping - Offset 0 from chip select 0 is mapped to address range 0x10100000 - 0x1010ffff - Offset 0 from chip select 1 is mapped to address range 0x10160000 - 0x1016ffff - Offset 0 from chip select 2 is mapped to address range 0x30000000 - 0x30ffffff */ ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet 1 0 0x10160000 0x10000 // Chipselect 2, i2c controller 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash ethernet@0,0 { compatible = "smc,smc91c111"; reg = <0 0 0x1000>; // 상위 child address 2개 와 size 1 }; i2c@1,0 { compatible = "acme,a1234-i2c-bus"; #address-cells = <1>; // node child address u32 수 #size-cells = <0>; // node child reg의 e u32 수 reg = <1 0 0x1000>; // 상위 child address 2개 와 size 1 rtc@58 { compatible = "maxim,ds1338"; reg = <58>; //상위 node child (1,0) }; }; flash@2,0 { compatible = "samsung,k8f1315ebm", "cfi-flash"; reg = <2 0 0x4000000>; }; }; }; https://elinux.org/Device_Tree_Usage#Ranges_.28Address_Translation.29 https://elinux.org/Device_Tree_Usage#PCI_Host_Bridge https://elinux.org/Device_Tree_Usage#How_Interrupts_Work
Kernel GPIO 기본사용법
https://www.kernel.org/doc/Documentation/gpio/gpio-legacy.txt
- Device Tree 관련문서
Device Tree는 현재 각 Platform Device Driver마다 각각의 설정값들이 존재하는데, 관련부분을 아래에서 검색해서 찾자
https://www.kernel.org/doc/Documentation/devicetree/bindings/
1.3 Device Tree 비교 및 확인
Raspberry Pi에 dtc 설치 되었는지 확인
uImage라고 한다면, 64 byte의 헤더를 버려야 하지만, 상위 이미지를 보면 uImage 구조와 다른 것 같다.
zImage라고 생각이 들어 아래와 같이 시도해본다.
uImage 구조체
http://www.isysop.com/unpacking-and-repacking-u-boot-uimage-files/
http://forum.falinux.com/zbxe/index.php?document_srl=564748&mid=lecture_tip
zImage 구조
https://wiki.kldp.org/KoreanDoc/html/EmbeddedKernel-KLDP/kernel-image-file-structure.html
zImage (LZMA)
https://stackoverflow.com/questions/37672417/getting-kernel-version-from-the-compressed-kernel-image
GPIO
https://www.kosagi.com/w/index.php?title=Definitive_GPIO_guide
- DTB (Flattened Device Tree 라고 불림) 의 구조
1.3 Device Tree 비교 및 확인
Raspberry Pi에 dtc 설치 되었는지 확인
- 사용중인 Device Tree를 확인
$ dtc -I fs -O dts -o current.dts /proc/device-tree/
- DTB To DTS로 변경
$ sudo dtc -I dtb -O dts -o bcm2710-rpi-3-b-plus.dts /boot/bcm2710-rpi-3-b-plus.dtb $ sudo dtc -I dtb -O dts -o bcm2710-rpi-3-b.dts /boot/bcm2710-rpi-3-b.dtb $ sudo dtc -I dtb -O dts -o bcm2708-rpi-b-plus.dts /boot/bcm2708-rpi-b-plus.dtb
- DTS 비교
$ diff -urN current.dts bcm2710-rpi-3-b-plus.dts --- current.dts 2019-02-18 23:34:57.966477519 +0900 +++ bcm2710-rpi-3-b-plus.dts 2019-02-18 23:36:18.841755013 +0900 @@ -1,1159 +1,941 @@ /dts-v1/; +/memreserve/ 0x0000000000000000 0x0000000000001000; / { - compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; - serial-number = "000000003befb7f8"; - model = "Raspberry Pi 3 Model B Rev 1.2"; - memreserve = 0x3b400000 0x4c00000=""; + compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837"; + model = "Raspberry Pi 3 Model B+"; $ diff -urN current.dts bcm2710-rpi-3-b.dts --- current.dts 2019-02-18 23:34:57.966477519 +0900 +++ bcm2710-rpi-3-b.dts 2019-02-18 23:42:58.263596240 +0900 @@ -1,1159 +1,940 @@ /dts-v1/; +/memreserve/ 0x0000000000000000 0x0000000000001000; / { compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; - serial-number = "000000003befb7f8"; - model = "Raspberry Pi 3 Model B Rev 1.2"; - memreserve = <0x3b400000 0x4c00000="">; + model = "Raspberry Pi 3 Model B"; interrupt-parent = <0x1>; #address-cells = <0x1>; #size-cells = <0x1>; $ diff -urN current.dts bcm2708-rpi-b-plus.dts | head -n 30 --- current.dts 2019-02-18 23:34:57.966477519 +0900 +++ bcm2708-rpi-b-plus.dts 2019-02-18 23:51:14.696159160 +0900 @@ -1,1235 +1,1066 @@ /dts-v1/; +/memreserve/ 0x0000000000000000 0x0000000000001000; / { - compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; - serial-number = "000000003befb7f8"; - model = "Raspberry Pi 3 Model B Rev 1.2"; - memreserve = <0x3b400000 0x4c00000="">; + compatible = "brcm,bcm2835"; + model = "Raspberry Pi Model B+"; interrupt-parent = <0x1>; #address-cells = <0x1>; #size-cells = <0x1>;
- bootcode 분석
$ hd /boot/bootcode.bin ... 0000c6e0 75 70 0a 00 46 61 69 6c 65 64 20 74 6f 20 69 6e |up..Failed to in| 0000c6f0 69 74 69 61 6c 69 73 65 20 6c 69 6e 6b 0a 00 00 |itialise link...| 0000c700 49 6e 69 74 69 61 6c 69 73 65 20 68 75 62 0a 00 |Initialise hub..| 0000c710 46 6f 75 6e 64 20 25 64 20 70 6f 72 74 73 2c 20 |Found %d ports, | 0000c720 6d 75 6c 74 69 5f 74 74 20 3d 20 25 64 0a 00 53 |multi_tt = %d..S| 0000c730 65 74 74 69 6e 67 20 69 6e 74 65 72 66 61 63 65 |etting interface| 0000c740 20 25 64 0a 00 46 61 69 6c 65 64 20 74 6f 20 73 | %d..Failed to s| 0000c750 65 74 20 69 6e 74 65 72 66 61 63 65 20 25 64 0a |et interface %d.| 0000c760 00 45 6e 61 62 6c 69 6e 67 20 50 4f 52 54 20 50 |.Enabling PORT P| 0000c770 4f 57 45 52 20 6f 6e 20 70 6f 72 74 20 25 64 0a |OWER on port %d.| 0000c780 00 46 61 69 6c 65 64 20 74 6f 20 73 65 74 20 66 |.Failed to set f| 0000c790 65 61 74 75 72 65 20 48 55 42 5f 46 45 41 54 55 |eature HUB_FEATU| 0000c7a0 52 45 5f 50 4f 52 54 5f 50 4f 57 45 52 20 25 64 |RE_PORT_POWER %d| 0000c7b0 0a 00 57 61 69 74 69 6e 67 20 66 6f 72 20 64 65 |..Waiting for de| 0000c7c0 76 69 63 65 73 20 74 6f 20 72 65 73 70 6f 6e 64 |vices to respond| 0000c7d0 20 74 6f 20 72 65 73 65 74 0a 00 46 6f 75 6e 64 | to reset..Found| 0000c7e0 20 64 65 76 69 63 65 20 6f 6e 20 70 6f 72 74 20 | device on port | 0000c7f0 25 64 0a 00 46 6f 75 6e 64 20 68 69 67 68 73 70 |%d..Found highsp| 0000c800 65 65 64 20 64 65 76 69 63 65 0a 00 48 75 62 20 |eed device..Hub | 0000c810 64 65 76 69 63 65 20 66 6f 75 6e 64 20 61 74 20 |device found at | 0000c820 61 64 64 72 20 25 64 2c 20 65 6e 75 6d 65 72 61 |addr %d, enumera| 0000c830 74 69 6e 67 20 48 55 42 0a 00 44 65 76 69 63 65 |ting HUB..Device| 0000c840 20 66 6f 75 6e 64 3a 20 74 79 70 65 20 3d 20 25 | found: type = %| 0000c850 73 2c 20 61 64 64 72 20 3d 20 25 64 0a 00 4d 61 |s, addr = %d..Ma| 0000c860 73 73 20 73 74 6f 72 61 67 65 00 45 74 68 65 72 |ss storage.Ether| 0000c870 6e 65 74 20 61 64 61 70 74 65 72 00 49 67 6e 6f |net adapter.Igno| 0000c880 72 69 6e 67 20 6c 6f 77 20 73 70 65 65 64 20 64 |ring low speed d| 0000c890 65 76 69 63 65 0a 00 44 65 76 69 63 65 20 66 61 |evice..Device fa| 0000c8a0 69 6c 65 64 20 74 6f 20 72 65 73 70 6f 6e 64 20 |iled to respond | 0000c8b0 74 6f 20 72 65 73 65 74 0a 00 00 00 79 00 00 00 |to reset....y...| .... $ strings /boot/bootcode.bin | grep dtb
- 제공하는 Kernel Image 분석
$ cat /proc/version Linux version 4.14.34-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1110 SMP Mon Apr 16 15:18:51 BST 2018 $ hd /boot/kernel.img | grep 'Linux' $ strings /boot/kernel.img | grep 'Linux' Uncompressing Linux... $ strings /boot/kernel7.img | grep 'Linux' Uncompressing Linux...
uImage라고 한다면, 64 byte의 헤더를 버려야 하지만, 상위 이미지를 보면 uImage 구조와 다른 것 같다.
zImage라고 생각이 들어 아래와 같이 시도해본다.
uImage 구조체
http://www.isysop.com/unpacking-and-repacking-u-boot-uimage-files/
http://forum.falinux.com/zbxe/index.php?document_srl=564748&mid=lecture_tip
zImage 구조
https://wiki.kldp.org/KoreanDoc/html/EmbeddedKernel-KLDP/kernel-image-file-structure.html
zImage (LZMA)
https://stackoverflow.com/questions/37672417/getting-kernel-version-from-the-compressed-kernel-image
GPIO
https://www.kosagi.com/w/index.php?title=Definitive_GPIO_guide
- 사용중인 Kernel 분석
$ sudo strings /dev/mem | grep 'Linux' .... Booting Linux on physical CPU 0x0 Linux version 4.14.34-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1110 SMP Mon Apr 16 15:18:51 BST 2018