일단 이전 글에서 했던 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
- Major Number (주번호): Major number는 디바이스 드라이버에게 해당 디바이스의 종류를 식별하는 데 사용됩니다. Major number는 해당 디바이스를 제어하는 드라이버를 가리키며, 동일한 주번호를 가진 디바이스는 동일한 드라이버에 의해 제어됩니다.
- Minor Number (부번호): Minor number는 동일한 드라이버에 의해 제어되는 여러 디바이스를 구별하는 데 사용됩니다. Major number로 식별된 드라이버가 여러 개의 디바이스를 다룰 때, 각 디바이스에 부번호를 할당하여 각각을 식별할 수 있게 됩니다.
예를 들어, /dev/sda라는 블록 디바이스 파일이 있다면, sda는 해당 드라이버에 의해 다루어지는 여러 디바이스 중 하나를 나타내는 부번호입니다. 이 디바이스 파일의 주번호는 해당 드라이버의 종류를 나타내며, 이 드라이버가 여러 디바이스를 다루는 경우에는 부번호로 각 디바이스를 식별합니다.
디바이스 드라이버에서는 커널 타이머를 사용함.
어플리케이션에서 디바이스 드라이버의 메모리에 접근할 수 있는 기능을 메모리 매핑이라고 하고
대용량 데이터를 고속으로 처리할 수 있음. nmap을 주로 많이 사용함.
현재 pi에서 쓰고 있는게 6.1.77 6이 버전, 1이 주번호, 77이 부번호
버전이 바뀌면 커널이 획기적으로 바뀐거임. 호환이 안될 가능성이 높음
주번호는 구조적인 큰 번회는 없지만, 내부적으로 구현되는 방식에 여러 변화가 생기면 바뀜 /짝수는 안정 버전이고 홀수는 테스트 버전
부번호는 개선사항이 적용된 버전
필요한게 있으면 HTTP로 들어가서 /linux/kernel/v6.x/
파일이름이 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)
- 일반 파일 (-): 가장 흔한 유형의 파일로, 일반적인 데이터를 저장하는 데 사용됩니다. 대부분의 파일이 이 유형에 속합니다.
- 예시: -rw-r--r-- 1 user group 1024 Feb 21 10:30 filename
- 블록 특수 파일 (b): 블록 장치에 대한 특수 파일로, 데이터를 블록 단위로 읽거나 쓰는 데 사용됩니다. 주로 하드 디스크와 같은 블록 기반의 저장 장치를 나타냅니다.
- 예시: brw-rw---- 1 user disk 8, 1 Feb 21 10:30 blockfile
- 문자 특수 파일 (c): 문자 장치에 대한 특수 파일로, 데이터를 문자 단위로 읽거나 쓰는 데 사용됩니다. 주로 터미널, 마우스 등과 같은 문자 기반 장치를 나타냅니다.
- 예시: crw-rw-r-- 1 user tty 5, 1 Feb 21 10:30 charfile
- 디렉터리 (d): 다른 파일이나 디렉터리를 포함하는 디렉터리를 나타냅니다. 디렉터리에 접근하려면 'x' 권한이 필요합니다.
- 예시: drwxr-xr-x 2 user group 4096 Feb 21 10:30 dirname
- 심볼릭 링크 (l): 다른 파일이나 디렉터리에 대한 참조를 나타내는 심볼릭 링크를 나타냅니다.
- 예시: 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; 이런식으로 -를 붙여서 쓰면 되겠음.
'Linux BSP' 카테고리의 다른 글
Makefile은 왜 사용하며, 어떻게 사용하는가 (2) | 2024.02.22 |
---|---|
[RaspberryPi DeviceDriver] 디바이스 드라이버 코드 수정해서 커널에 포함시키기 (0) | 2024.02.21 |
[Linux File System] Yocto Project 2 (0) | 2024.02.20 |
[Linux] fork()와 exec()를 이용한 프로세스 생성 과정 (1) | 2024.02.19 |
[Linux File System] Linux Root File System (0) | 2024.02.19 |