Yocto Project : 임베디드 리눅스 빌드 프로그램 / 빌드 후 이론 수업을 하기로 했다
루트 파일 시스템 : 루트 폴더(최상위 디렉토리)에 부팅에 필요한 파일들을 모아놓은 것
실무에서 yocto를 많이 사용함
~/pi_bsp$ mkdir rootfs ; cd rootfs
~/pi_bsp/rootfs$ mkdir yocto ; cd yocto
~/pi_bsp/rootfs$ sudo apt update
~/pi_bsp/rootfs$ sudo apt-get install gawk wget git diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm python zstd liblz4-tool -y
~/pi_bsp/rootfs/yocto$ git clone -b kirkstone git://git.yoctoproject.org/poky.git
임베디드 파일 시스템은 크기가 작다
~/pi_bsp/rootfs/yocto/poky$ git clone -b kirkstone git://git.yoctoproject.org/meta-raspberrypi
~/pi_bsp/rootfs/yocto/poky$ source oe-init-build-env // 경로들을 잡아준다
~/pi_bsp/rootfs/yocto/poky/build$ vi conf/local.conf
38 shift g
38번째 라인을 #으로 막고
39번째 라인에 MACHINE ??= "raspberrypi4" 를 추가한다
그리고
~/pi_bsp/rootfs/yocto/poky/build$ vi conf/bblayers.conf
12번 라인에 추가한다
/home/ubuntu/pi_bsp/rootfs/yocto/poky/meta-raspberrypi \
저장하고
~/pi_bsp/rootfs/yocto/poky/build$ bitbake core-image-minimal
굉장히 오래 걸린다
커널 : 운영체제의 핵심
리눅스는 모놀리틱 커널이다 : 커널이 운영체제가 관장하는 모든 서비스를 가짐
cpu가 성능이 우수해서 하나의 프로세스만으로는 아깝다
더 낮은 클럭의 mcu는 1개로 여러개를 조종할 수 있다
멀티 프로세싱을 하기 위해 cpu 속도는 더 빨라야함
그래서 운영체제가 필요하다
또, 메모리 관리, IPC(프로세스간의 통신/signal,pipe,socket,message Queue),
virtual file system : 파일 일부분을 메모리처럼 사용 (스왑, 디바이스를 파일처럼 취급)
프로세스 스케쥴러
~/pi_bsp/kernel/linux$ vi .config // 이런식으로 볼 수 있다
네트워크 인터페이스 : 표준 네트워크 프로토콜과 드라이버 제공
프로세스
멀티 프로세싱
프로그램이 아님
한 순간에 오직 하나의 프로세스만이 CPU 점유 가능
선점형/비선점형
Context switch
리눅스의 프로세스 스케쥴링
Task structure
State of Process
fork
새 프로세스 생성 시 부모 프로세스 정보를 메모리 공간에 복사
-1이면 에러
0이면 자식
나머지는 부모 이다.
exec : 프로세스를 교체하여 실행
실습으로 확인한다
~/pi_bsp/kernel$ vi fork.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int fatal(char *s);
int main(void)
{
pid_t pid;
switch(pid=fork()){
case -1:
fatal("fork failed");
break;
case 0:
execl("/bin/ls", "ls", "-l", NULL);
fatal("exec failed");
break;
default:
wait((int *)0);
printf("ls completed\n");
exit(0);
}
}
int fatal(char *s)
{
perror(s);
exit(1);
}
ls -l 명령어랑 동일하다
execl을 만나는 순간 자식 프로세스가 생성되어 프로그램이 달라진다
그래서 fatal 문을 실행하지 않고 ls -l만 실행되고 종료된다
그리고 wait에서 결과를 받고 ls completed가 실행된다
자동으로 왼쪽으로 8번 쉬프트 되므로 출력할 때는 오른쪽으로 8번 쉬프트한다
이렇게 없는 폴더를 넣어주면
정상적으로 ls는 실행되고 없다는 에러메시지가 perror를 통해 나온다
만약 wait를 없애면 좀비프로세스가 된다
커널 쓰레드
~/pi_bsp/kernel$ ps -ef | more
명령어로 커널 스레드를 볼 수 있다
시스템 관리를 위한 백그라운드 동작이다
rc5.d에 여러 데몬들이 있다
PID 모든 프로세스는 PID를 가진다
파일을 문자열로 구분하지만 시스템은 숫자로 기억한다
ls -i 하면 번호가 나온다(i nod 구조)
pstree 하면 프로세스 구조가 나온다
exit는 자기 자신을 종료
abort, kill은 부모에 의해 강제적으로 종료
메모리 : 프로그램과 데이터(변수)를 저장하는 공간, 물리적 주소를 사용하여 지정(8비트)
메모리 사이즈에 따라 주소가 고정됨
논리주소=선형주소 : 가상주소 라고도 함 / 1기가까지 커널, 3기가까지 사용자가 사용, 4기가까지 가능 / 부족한 메모리를 가상으로 할당 - MMU table에서 가상과 물리를 매핑함
물리주소
내가 할당받지 않은 메모리 공간에 접근하면 exception-segmentation fault
개별 주소 사용
heap(동적 영역) malloc으로 메모리 할당 후 free로 반환
시스템 콜 mmap app을 이용하면 실제 하드웨어 주소공간에 어플리케이션에서 공유하도록 지정
디바이스 드라이브 구현해야함
리눅스의 메모리 관리
- 큰 주소 공간 사용 : 가상메모리로 더 큰 메모리 공간을 가지고 있는 것처럼 사용 가능
- 메모리 보호 : 가상메모리를 사용할 수 없는 경우 다른 프로세슷는 동일한 메모리공간을 참고 불가능
- 메모리 매핑
- 공유 메모리를 여러 프로세스가 공정하게 사용
- 프로세스 간 메모리 공유를 위한 방법 제공
물리 주소 공간의 조각화
세그멘테이션과 페이지는 물리 주소 공간을 쪼갠다
4k로 쪼갠다
Demand paging : 필요할 때마다 메모리에 할당
COW(copy on write) : 자식 프로세스 생성 시 공유된 프레임에 쓸때 페이지 프레임을 복사
스와핑 : 디스크의 일부 공간을 램의 확장으로 사용
p1 - p2 데이터 주고 받으려면
프로세스간 통신을 사용
IPC
read() : blocking 함수
멀티프로세스 기반 다중서버 하려면 서버를 fork 하고 복제된 것과 통신을 한다
또 다른 클라이언트와 연결할 때 서버를 복제해서 1:1 통신을 하게된다
클라이언트가 늘면 늘수록 cpu 입장에서 보면 메모리를 많이 할당 받는다
그런데 클라이언트끼리는 연결이 안돼서 각각의 복제된 서버 프로세스들끼리 연결을 하는데 그것이 바로 IPC이다
전역변수를 지정하면 하나의 프로세스에만 써야한다 만약 다른 프로세스가 접근하면 락을 걸어서 못오게 막아야한다 대신 큰 하나의 프로세스로 만들어서 락언락을 적용하면 하나 고장나면 다 못쓴다?
시그널
pi를 킨다
켜놓고 우분투에서
~/pi_bsp/rootfs$ wget https://downloads.raspberrypi.org/NOOBS_latest
근데 용량이 너무 커서 복사받기로 했다
그 전에 너무 번거로운 복사과정때문에 우리의 ubuntu와 교수님 ubuntu를 mount 하기로 했다
-교수님-
/srv$ sudo mkdir lect_nfs
-나-
vi .profile
맨 아래에
if [ -f /mnt/nfs.sh ] ; then
. /mnt/nfs.sh
fi
그리고 /mnt$ sudo vi nfs.sh
들어가서
#!/bin/bash
SERVIP=10.10.15.71
if ! df | grep lect_nfs > /dev/null ; then
ping -c 1 $SERVIP > /dev/null
if [ $? -eq 0 ] ; then
sudo mount -t nfs $SERVIP:/srv/lect_nfs /mnt/lect_nfs
df | grep lect_nfs
fi
fi
저장한다
source nfs.sh 실행하면 mount 된다
~/pi_bsp/rootfs$ unzip -d noops NOOBS_latest
~/pi_bsp/rootfs$ cd noops/os/RaspiOS_Full_armhf/
이것이 루트 파일 시스템이다
~/pi_bsp/rootfs$ mkdir rootfs
~/pi_bsp/rootfs$ sudo tar xvfp root.tar.xz -C ./rootfs
압축을 푼다
계정을 하나 만들 것이다
~$ sudo adduser pi
~$ cat /etc/passwd
내가 입력한 내용이 들어가있다
~$ sudo cat /etc/shadow하면 맨 아래에 pi에 대한 내용이 있는데
~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf/rootfs/etc$ sudo vi shadow에
pi:$6$0L5suchDSQEs1t/h$ImQpaW7NLS0LYNZfq3BW7ywwTH/KiwGXvC0NDoFhs3NEZa.1VArld4y76gPnN2y3uQEFBYhSkbPTvqh/bbiJQ.:19772:0:99999:7::: 를 복사한다
그리고 복사하기 위해 다 지운다
~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf/rootfs$ sudo rm -rf /media/ubuntu/rootfs/
이제 다시 복사한다
~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf$ sudo cp -ra rootfs/* /media/ubuntu/rootfs/.
a는 원본 파일의 속성, 링크 정보까지 모두 복사한다는 뜻
~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf$ sudo blkid
/media/ubuntu/rootfs$ sudo vi etc/fstab
ced3dfde 이거로 수정해준다(사람마다 다름)
/media/ubuntu/rootfs$ cd ../bootfs
/media/ubuntu/bootfs$ sudo touch ssh
이후 umount 해준다
SD카드 제거 후 라즈베리파이에 넣고 다시 킨다
아이피가 바뀐 모습
다시 우분투에서
~$ cd pi_bsp/rootfs/yocto/poky/build/tmp/deploy/images/raspberrypi4/
~/pi_bsp/rootfs/yocto/poky/build/tmp/deploy/images/raspberrypi4$ ls -l *.ext3
12메가짜리 아주 작은 루트 파일 시스템이 만들어졌다
$ cp
~/ipc$ gcc sigloop.c -o sigloop
~/ipc$ ./sigloop
이 상태에서 ctrl+c를 눌러도 종료가 안된다! -> kill 해야함
~$ sudo kill -9 2472443(다른 창으로)
-9 : 매우 강력하게
~/ipc$ vi sigloop.c
SIGINT : ctrl+c
~/ipc$ ./sigloop
~/ipc$ ps auwx | grep sigloop(창 여러개로)
s+ : sleep
pause : signal에 의해 깨어나는 함수
이렇게 수정해서 ctrl+c 누르면 2초마다 알람주는 코드로 바꿨다
그리고 sigkill.c를 본다
~/ipc$ ./sigloop
~/ipc$ gcc sigkill.c -o sigkill
~/ipc$ ./sigkill 2472947 2
sigkill에서 sigloop로 통신을 한 것이다(IPC)
if(signo == SIGINT)
{
printf("Catch SIGINT!, but no stop%d\n", signo);
exit(0);
}
이렇게 종료 조건을 넣으면 ctrl+c 눌렀을 때 종료된다