본문 바로가기
Linux BSP

[RaspberryPi DeviceDriver] Yocto Project 설정 초기화 및 디바이스 파일 만들어보기

by TYB 2024. 2. 21.
반응형
 

[Linux File System] Yocto Project 2

이전 글 먼저 진행해야됩니다! [Linux File System] Yocto Project Linux에서 부팅되고, 로그인되고, 다양한 데몬 구동, 배쉬 할당 등을 위해 반드시 필요한 파일들을 Root File System이라고 함. 폴더 만드는 건

program-developers-story.tistory.com

일단 이전 글에서 했던 Yocto Project의 휴유증으로 라즈베리파이 sd카드가 정상이 아니므로 이전에 받아놨던 백업본으로 다시 sd카드에 write해주겠음.

 


어디에 백업했는지 기억이 안난다면?

ubuntu@ubuntu8:~$ sudo updatedb
[sudo] password for ubuntu:
/usr/bin/find: '/run/user/1000/gvfs': Permission denied

ubuntu@ubuntu8:~$ locate sdimage_wcm.img
/home/ubuntu/.local/share/Trash/files/sdimage_wcm.img
/home/ubuntu/.local/share/Trash/info/sdimage_wcm.img.trashinfo
/home/ubuntu/sdimage_wcm.img
/srv/samba/sdimage_wcm.img

 

updatedb가 실행이 안된다면?

$ sudo apt install locate

 

라즈베리파이 sd카드 usb에 곶고 virtualbox 장치-> usb에서 sd카드 리더기 선택

 

df명령어 쳐서 장치 마운트 상태 확인 sdb, sdc, ... 이런식으로 뜰거임.

 

언마운트 해주고 

ubuntu@ubuntu8:~$ sudo umount /dev/sdb*

파일 write드가자

ubuntu@ubuntu8:~$ sudo dd if=sdimage_wcm.img of=/dev/sdb bs=1 status=progress

dd는 disk direct의 약자로 블록단위로 데이터를 복사하고 write할 때 사용하는 명령어

block size = 1MB

status=progress 진행상태를 보여달라.


윈도우에서 할라면 백업한 이미지를 pi imager를 통해서 write 할 수 도 있음.

 

 

 


다 써졌으면 이제 이전에 썼던 kernel을 sd카드에 써야됨.

 

디바이스 드라이버를 사용하려는 커널과 동일한 버전의 커널이 올라가 있어야 디바이스 드라이버 적용이 가능함.

디바이스 드라이버는 커널 위에서 돌기 때문.

ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ cat build.sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage
cp arch/arm/boot/zImage /srv/nfs/zImage



ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ ./build.sh

 

$ df
/dev/sdb1         261108    75820    185288  30% /media/ubuntu/bootfs
/dev/sdb2       30322460 15917604  13048344  55% /media/ubuntu/rootfs
~/pi_bsp/kernel/linux$ sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/media/ubuntu/rootfs modules_install
~/pi_bsp/kernel/linux$ sudo cp /media/ubuntu/bootfs/kernel7l.img /media/ubuntu/bootfs/kernel7l-backup.img
~/pi_bsp/kernel/linux$ sudo cp arch/arm/boot/zImage /media/ubuntu/bootfs/kernel7l.img
~/pi_bsp/kernel/linux$ sudo cp arch/arm/boot/dts/*.dtb /media/ubuntu/bootfs/
~/pi_bsp/kernel/linux$ sudo cp arch/arm/boot/dts/overlays/*.dtb* /media/ubuntu/bootfs/overlays/
~/pi_bsp/kernel/linux$ sudo cp arch/arm/boot/dts/overlays/README /media/ubuntu/bootfs/overlays/
~/pi_bsp/kernel/linux$ sudo vi /media/ubuntu/bootfs/config.txt    //제일 아래 추가
------------
arm_64bit=0
------------

 

 

$ sudo umount /dev/sdb*

 

쳐주고

 

sd카드 빼주고 라즈베리파이에 꽂아서 재부팅하면 아래 화면 뜨면 정상~

 

커널 버전 6.1.77-v7l+가 나오면 커널 잘 올라간거고

pi@pi08:~ $ uname -a
Linux pi08 6.1.77-v7l+ #10 SMP Fri Feb 16 15:47:31 KST 2024 armv7l GNU/Linux

 

lsmod를 했을 때 다 나오면 device driver 모듈이 다 다운로드 된 상태라는 뜻임.

pi@pi08:~ $ lsmod
Module                  Size  Used by
rpcsec_gss_krb5        28672  0
snd_seq_dummy          16384  0
snd_hrtimer            16384  2
snd_seq                73728  13 snd_seq_dummy
snd_seq_device         16384  1 snd_seq
regmap_i2c             16384  0
brcmfmac              344064  0
brcmutil               20480  1 brcmfmac
btbcm                  20480  0
bluetooth             532480  1 btbcm
cfg80211              835584  1 brcmfmac
v3d                    86016  0
gpu_sched              49152  1 v3d
drm_shmem_helper       24576  1 v3d
binfmt_misc            20480  1
rpivid_hevc            45056  0
ecdh_generic           16384  1 bluetooth
bcm2835_v4l2           49152  0
i2c_mux_pinctrl        16384  0
bcm2835_isp            32768  0
bcm2835_codec          49152  0
ecc                    40960  1 ecdh_generic
i2c_mux                16384  1 i2c_mux_pinctrl
raspberrypi_hwmon      16384  0
bcm2835_mmal_vchiq     36864  3 bcm2835_isp,bcm2835_codec,bcm2835_v4l2
v4l2_mem2mem           40960  2 rpivid_hevc,bcm2835_codec
videobuf2_dma_contig    20480  3 rpivid_hevc,bcm2835_isp,bcm2835_codec
videobuf2_vmalloc      16384  1 bcm2835_v4l2
videobuf2_memops       16384  2 videobuf2_dma_contig,videobuf2_vmalloc
videobuf2_v4l2         32768  5 rpivid_hevc,bcm2835_isp,bcm2835_codec,bcm2835_v4l2,v4l2_mem2mem
i2c_brcmstb            16384  0
rfkill                 32768  5 bluetooth,cfg80211
videobuf2_common       65536  9 rpivid_hevc,bcm2835_isp,bcm2835_codec,videobuf2_dma_contig,videobuf2_vmalloc,videobuf2_memops,bcm2835_v4l2,v4l2_mem2mem,videobuf2_v4l2
videodev              270336  7 rpivid_hevc,bcm2835_isp,bcm2835_codec,videobuf2_common,bcm2835_v4l2,v4l2_mem2mem,videobuf2_v4l2
snd_bcm2835            24576  1
snd_compress           20480  0
snd_pcm_dmaengine      20480  0
snd_pcm               126976  3 snd_compress,snd_pcm_dmaengine,snd_bcm2835
i2c_bcm2835            16384  1
vc_sm_cma              36864  2 bcm2835_isp,bcm2835_mmal_vchiq
snd_timer              36864  3 snd_seq,snd_hrtimer,snd_pcm
raspberrypi_gpiomem    16384  0
fb_sys_fops            16384  0
snd                    94208  12 snd_compress,snd_seq,snd_timer,snd_seq_device,snd_bcm2835,snd_pcm
mc                     57344  7 rpivid_hevc,bcm2835_isp,bcm2835_codec,videobuf2_common,videodev,v4l2_mem2mem,videobuf2_v4l2
syscopyarea            16384  0
sysfillrect            16384  0
sysimgblt              16384  0
nvmem_rmem             16384  0
uio_pdrv_genirq        16384  0
uio                    24576  1 uio_pdrv_genirq
i2c_dev                16384  0
drm                   548864  4 v3d,drm_shmem_helper,gpu_sched
fuse                  135168  1
dm_mod                139264  0
drm_panel_orientation_quirks    16384  1 drm
backlight              20480  1 drm
nfsd                  516096  5
ip_tables              28672  0
x_tables               36864  1 ip_tables
ipv6                  536576  74

 


 

만약 uname-a에서 커널버전은 맞는데 lsmod가 안나온다?

아래 디렉터리 가서 봤을 때 아래처럼 안나온다?
pi@pi08:/lib/modules $ ls
6.1.0-rpi7-rpi-v6  6.1.0-rpi7-rpi-v7l  6.1.77-v7l+
6.1.0-rpi7-rpi-v7  6.1.0-rpi7-rpi-v8

라즈베리 전원 끄고 sd카드 빼서 ubuntu에서 켜서 아래 명령어부터 다시 치고 sd카드로 복사하면 된다. 

아래 명령어를 실행 안했을 때 lsmod가 안나옴.

sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/media/ubuntu/rootfs modules_install

자 이제 우리가 image를 32GB에서 7GB로 줄여놨으니, 하드디스크 용량을 7GB -> 32GB로 늘려줘야함.

 

여러 방법이 있음.

gparted도 있으나, 라즈베리파이에선 config에서 지원해줌 bb

 

엔터 치고 ok하고 finish 하고 reboot 해주면 됨.

 

재부팅 되면

pi@pi08:~ $ df -h


이제 디바이스 드라이버에 커널을 포함시켜보자.

 

디바이스 드라이버를 다룰 때는 주로 root 권한으로 실행해야 되는데 su를 통해 root 환경에서 해도 되나, sudo로 최대한 해보는걸로.

 

 

ubuntu@ubuntu8:/lib/modules/5.15.0-94-generic$ ls -l  build
lrwxrwxrwx 1 root root 40  1월 16 22:17 build -> /usr/src/linux-headers-5.15.0-94-generic

심볼릭 링크 되어 있는데 이 파일이 커널이 들어있는 소스를 가리키고 있음.

이 위치가 커널의 홈 디렉터리 라는 뜻이기도 함.

ubuntu@ubuntu8:/lib/modules/5.15.0-94-generic$ cd  /usr/src/linux-headers-5.15.0-94-generic

아래 명령어도 실행이 됨. 만약 우분투 x86 커널을 수정하고 싶다면 바로 바꿔도 되는거임.

ubuntu@ubuntu8:/usr/src/linux-headers-5.15.0-94-generic$ sudo make menuconfig

 

하지만 우리는 타켓보드가 라즈베리이므로 아래처럼 arm 명령어를 줘가면서 make를 해주는거임.

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





ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ ARCH=arm make tags
  GEN     tags

 

 

 

 

ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ ls -lh tags
-rw-rw-r-- 1 ubuntu ubuntu 903M  2월 21 13:18 tags
ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ pwd
/home/ubuntu/pi_bsp/kernel/linux

 

ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ vi ~/.vimrc

 

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

 

ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ vi -t include/linux/start_kernel.h

태그가 됬으니까 ctrl ]로 함수의 원형에 접근이 가능하다.

 

 



ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ ls -l /dev

디바이스 파일은 일반적인 파일과 다르게 하드웨어 장치와 상호 작용하기 위한 인터페이스로 사용되는 특별한 파일

리눅스와 유닉스 계열 운영 체제에서는 /dev 디렉터리에 위치하며, 각각의 파일은 특정한 하드웨어 디바이스

                                    주번호7, 부번호64 
crw-rw----  1 root   tty       7,  64  2월 21 09:29 vcsu
crw-rw----  1 root   tty       7,  65  2월 21 09:29 vcsu1
crw-rw----  1 root   tty       7,  66  2월 21 09:29 vcsu2
crw-rw----  1 root   tty       7,  67  2월 21 09:29 vcsu3
crw-rw----  1 root   tty       7,  68  2월 21 09:29 vcsu4
crw-rw----  1 root   tty       7,  69  2월 21 09:29 vcsu5
crw-rw----  1 root   tty       7,  70  2월 21 09:29 vcsu6

  1. Major Number (주번호): Major number는 디바이스 드라이버에게 해당 디바이스의 종류를 식별하는 데 사용됩니다. Major number는 해당 디바이스를 제어하는 드라이버를 가리키며, 동일한 주번호를 가진 디바이스는 동일한 드라이버에 의해 제어됩니다.
  2. Minor Number (부번호): Minor number는 동일한 드라이버에 의해 제어되는 여러 디바이스를 구별하는 데 사용됩니다. Major number로 식별된 드라이버가 여러 개의 디바이스를 다룰 때, 각 디바이스에 부번호를 할당하여 각각을 식별할 수 있게 됩니다.

예를 들어, /dev/sda라는 블록 디바이스 파일이 있다면, sda는 해당 드라이버에 의해 다루어지는 여러 디바이스 중 하나를 나타내는 부번호입니다. 이 디바이스 파일의 주번호는 해당 드라이버의 종류를 나타내며, 이 드라이버가 여러 디바이스를 다루는 경우에는 부번호로 각 디바이스를 식별합니다.


디바이스 드라이버에서는 커널 타이머를 사용함.

 

어플리케이션에서 디바이스 드라이버의 메모리에 접근할 수 있는 기능을 메모리 매핑이라고 하고

대용량 데이터를 고속으로 처리할 수 있음. nmap을 주로 많이 사용함.


안정적으로 나온 커널 버전은 6.7.5고 longterm은 5년간 kernel 버그 발생 시 유지보수를 해주는 버전들임.

현재 pi에서 쓰고 있는게 6.1.77 6이 버전, 1이 주번호, 77이 부번호

버전이 바뀌면 커널이 획기적으로 바뀐거임. 호환이 안될 가능성이 높음

주번호는 구조적인 큰 번회는 없지만, 내부적으로 구현되는 방식에 여러 변화가 생기면 바뀜 /짝수는 안정 버전이고 홀수는 테스트 버전

부번호는 개선사항이 적용된 버전

 

필요한게 있으면 HTTP로 들어가서 /linux/kernel/v6.x/

 

Index of /pub/linux/kernel/v6.x/

 

mirrors.edge.kernel.org

 

 

 


파일이름이 kcci인 파일을 찾겠다.
ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ find . | grep kcci



파일 내부의 내용에 kcci가 들어간 파일을 보겠다.
ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ grep kcci * -r





ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ grep kcci * -r |grep .c$

 

 

 

 

초기에는 디바이스 드라이버도 커널 수정하는 것처럼 커널 소스에 모듈을 포함시켜야 했는데 커널 전체 컴파일이라는 매우 긴 작업임. 이런 방식을 개선시킨게 디바이스 드라이버의 모듈화임.

 

그래서 디바이스 드라이버를 수정할 때는 커널 컴파일이 필요가 없다~b

 


 

ubuntu@ubuntu8:~/pi_bsp/kernel/linux$ ls -l /dev|more

 

  • -: 일반 파일 (Regular file)
  • b: 블록 특수 파일 (Block special file)
  • c: 문자 특수 파일 (Character special file)
  • d: 디렉터리 (Directory)
  • l: 심볼릭 링크 (Symbolic link)
  1. 일반 파일 (-): 가장 흔한 유형의 파일로, 일반적인 데이터를 저장하는 데 사용됩니다. 대부분의 파일이 이 유형에 속합니다.
  2. 예시: -rw-r--r-- 1 user group 1024 Feb 21 10:30 filename
  3. 블록 특수 파일 (b): 블록 장치에 대한 특수 파일로, 데이터를 블록 단위로 읽거나 쓰는 데 사용됩니다. 주로 하드 디스크와 같은 블록 기반의 저장 장치를 나타냅니다.
  4. 예시: brw-rw---- 1 user disk 8, 1 Feb 21 10:30 blockfile
  5. 문자 특수 파일 (c): 문자 장치에 대한 특수 파일로, 데이터를 문자 단위로 읽거나 쓰는 데 사용됩니다. 주로 터미널, 마우스 등과 같은 문자 기반 장치를 나타냅니다.
  6. 예시: crw-rw-r-- 1 user tty 5, 1 Feb 21 10:30 charfile
  7. 디렉터리 (d): 다른 파일이나 디렉터리를 포함하는 디렉터리를 나타냅니다. 디렉터리에 접근하려면 'x' 권한이 필요합니다.
  8. 예시: drwxr-xr-x 2 user group 4096 Feb 21 10:30 dirname
  9. 심볼릭 링크 (l): 다른 파일이나 디렉터리에 대한 참조를 나타내는 심볼릭 링크를 나타냅니다.
  10. 예시: lrwxrwxrwx 1 user group 6 Feb 21 10:30 linkname -> target

디바이스 드라이버에서 중요한 건 char 파일인지, 주번호와 부번호가 몇번인지가 가장 중요함.

 


디바이스 드라이버는 굉장히 다양한 디바이스를 제어하는데 사용되는데 어떤 디바이스를 제어 가능한 드라이버 들이 있는지 보려면

ubuntu@ubuntu8:/lib/modules/5.15.0-94-generic/kernel/drivers$ ls

 

 


저수준 파일 입출력이 필요한 이유?

실시간으로 입출력을 해야 하므로 중간에 버퍼를 사용하지 않고 바로 메모리에 접근하는 저수준의 파일입출력이 필요함

디바이스 파일에 위에 나와있는 저수준 파일 입출력 함수들이 쓰인다.

v4l(vedio4linux)같은 경우는 read, write 대신 ioctl을 사용해서 비디오를 제어함. 영상을 읽고 쓰고 띄울 때 다 ioctl사용함.

 

 

/dev/sdb아래에 sdb1, sdb2가 있는데 1,2가 부번호인거임.

 

디바이스 파일은 파일안에 정보를 저장하는게 아니라 

 

ubuntu@ubuntu8:~$ ls -l /

drwxr-xr-x  19 root root       4240  2월 21 10:34 dev

dev는 group과 others에 대한 write권한이 없음. 그래서 file 소유주인 root 권한으로 하는겨

 

root passwd 부여하는 방법

확인하려면

ubuntu@ubuntu8:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash

 

ubuntu@ubuntu8:~$ sudo cat /etc/shadow
root:$6$lkfQ1KOOIs3FURsv$.T0FWoIdN8GyXpU1t5o4.U0s4excUEE9NVyJehmoYSoURxYALCCYKhUBz8IILfv8fChZevAre.ADsmV3B2rG2.:19752:0:99999:7:::

 

shadow파일의 root: 뒤에 !가 있으면 비번이 없는거임.

 

ubuntu@ubuntu8:~$ sudo passwd root
New password:
Retype new password:
passwd: password updated successfully

 

ubuntu@ubuntu8:~$ su - root
Password:
root@ubuntu8:~#

 

 

Device 파일 만드는 방법

ubuntu@ubuntu8:~$ su - root
Password:
root@ubuntu8:~# mknod /dev/devfile c 240 1
root@ubuntu8:~# ls -l /dev/devfile
crw-r--r-- 1 root root 240, 1  2월 21 13:50 /dev/devfile

일반 파일은 user group 다음에 file size가 나오는데 device 파일은 주번호가 나온다.

 

root@ubuntu8:~# rm /dev/devfile

ctrl+d로 로그아웃하거나 exit을 쳐서 로그아웃

 

 

root 권한으로 로그인하는 대신 sudo 명령어를 통해서도 가능함

ubuntu@ubuntu8:~$ sudo mknod /dev/devfile c 240 2
ubuntu@ubuntu8:~$ ls -l /dev/devfile
crw-r--r-- 1 root root 240, 2  2월 21 13:53 /dev/devfile
ubuntu@ubuntu8:~$ sudo rm /dev/devfile

 

모듈 형태로 디바이스 드라이버를 만들고 device driver안에 open이라는 함수를 정의한 후  커널에 적재한 후, device를 사용하면 그 때 디바이스 file의 open 함수를 호출해서 디바이스를 사용하는 거임.

주번호에 등록되있는 device driver의 open함수가 호출되는거임.

 

 


Device 파일 C코드로 만드는 방법

ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ vi makeDeviceFile.c

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
        int ret;
        ret = mknod("/dev/test", S_IRWXU|S_IRWXG|S_IFCHR, (240<<8)|1);
        if (ret <0 )
        {
                perror("mknod()");//문자 내용이 출력되고 그 뒤에 오류내용이 출력됨
                return ret;
        }
        //S_IRWXU는 사용자의 읽기 쓰기 권한
        //S_IRWXG는 그룹의 읽기 쓰기 권한
        //S_IFCHR는 문자 디바이스
        //S_IFBLK는 블록 디바이스
        return 0;
}

연산자 우선순위가 | or연산보다 보다 << 비트 연산자가 더 높지만 그래도 가독성을 위해 괄호를 쳐주는게 좋음

 

tag 등록되어 있으니까 따라가보면 각각의 값이 어떠한 상수를 갖고 있는지 알 수 있음.

 

코드작성에서 제일 중요한건 다른 사람이 쉽게 알아 볼 수 있도록 괄호를 쳐주는게 좋음.

 

실행해보자

ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ gcc makeDeviceFile.c -o makeDeviceFile ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ ./makeDeviceFile
mknod(): Permission denied

ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ sudo ./makeDeviceFile
[sudo] password for ubuntu:

 

생성됬는지 확인해보자

ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ ls -l /dev/test
crwxr-x--- 1 root root 240, 1  2월 21 14:30 /dev/test

c로 시작하는 권한이 나옴. 잘되있고

 

 

code 10번줄의 S_IF CHR을 S_IFBLK로 바꿔주면 b로 시작하는 권한이 나옴.

        ret = mknod("/dev/test", S_IRWXU|S_IRWXG|S_IFBLK, (240<<8)|1);
ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ ls -l /dev/test
brwxr-x--- 1 root root 240, 1  2월 21 14:32 /dev/test

근데 지금 발견했는데 왜 권한을 wrxwrx가 가능하도록 작성했는데 user는 rwx ok 근데 group은 왜 r-x가 되어있을까? 라고 했을 때 umask를 확인해보면 답이 나온다.

root가 만든 파일이니까 root의 umask를 봐보자

ubuntu@ubuntu8:~/pi_bsp/drivers/p87$ su - root
Password:
root@ubuntu8:~# umask
0022

0022이죠? 그러니까 초기권한값은 0770이었는데 umask0022을 뺀 결과 0750이 되어버린거임.

 



시스템 콜 함수에서 에러가 발생했을 때 return해주는 에러값들은 음수임. 그래서 ret값을 받았다면 -를 적용해준 뒤 리턴해주면 값을 정확하게 확인 할 수가 있다시~

직접 에러코드를 넣어줘야될 상황이라면 우측 사진에서 잘 찾아가지고 뽑아서 써주면 된다.

return -ENXIO; 이런식으로 -를 붙여서 쓰면 되겠음.


 

반응형