2 minute read

처음 목표로 커널 시작에 printk로 dmesg에 출력하는 간단한 예제를 시도해보려고 합니다.

커널 소스코드 컴파일에 대해서는 이 글을 참조했습니다.

다운로드 및 압축해제

wget으로 linux 커널 소스코드를 가져왔습니다: wget

압축해제

printk 추가

리눅스의 부팅 방법에 대해 조금 찾아봤는데, 커널 초기화 과정에서

arch/x86/kernel/head_64.S

을 불러오게 되는데, 이 head_64.S 파일은 같은 dir에 있는 head64.c의 함수를 가져오게 됩니다. 그런데 head64.c에서:

printk_nope

printk를 넣지 말라는 문구가 있어서 초기화 과정에는 printk를 넣을 수 없을것 같습니다.

그래서 start_kernel() 함수가 존재하는 init/main.c의 start_kernel()함수 첫단에 printk()를 넣었습니다.

custom_printk

여기까지만 하고 커널 컴파일을 진행했습니다.

우분투(linux) 전체 백업

처음에는 컴파일을 하고 적용하면 기존 리눅스 커널을 덮어쓰는걸로 착각해서 시스템 전체를 한번 백업했습니다.

tar cvpzf backup.tgz --exclude=/proc --exclude=/lost+found --exclude=/backup.tgz --exclude=/mnt --exclude=/sys --exclude=/dev /

참조

루트 디렉토리 아래의 필요없는 디렉토리를 제외하고 전체를 tgz파일로 만들어서 저장했습니다. 파일 크기는 8.8GiB정도 되는것 같습니다.

이후 커널 컴파일을 진행하고 설치를 하겠습니다.

커널 컴파일 과정

컴파일을 진행하기 전에 현재 machine의 .config 파일을 가져와서 설정을 진행하겠습니다.

$ cp -v /boot/config-$(uname -r) .config

현재 사용하는 커널의 .config 파일을 복사합니다.

$ make menuconfig

설정 화면을 띄웁니다.

make_menuconfig

이렇게 뜨는데 load로 가서 복사한 .config 파일을 불러오고 저장하면 됩니다.

.config 파일을 불러오고 저장후에,

$ make

로 컴파일을 진행하면 되는데, -j 옵션으로 병렬 처리가 가능합니다.

$ nproc

로 cpu(?)의 개수를 알 수 있다고 하는데, 제 서버는 듀얼코어에 4 threads 환경이라 아마 thread의 개수인 4를 보여주는 것 같습니다.

$ make -j 4

그래서 저는 4개로 진행했습니다 (tmux로 집 가는길에 백그라운드로 돌려놓을수도 있습니다) 서버 성능이 안좋아서 1~2시간 정도 걸린것 같습니다.

우분투에 경우 보안 설정을 해제해야 컴파일 된다고 합니다:

scripts/config –disable SYSTEM_TRUSTED_KEYS scripts/config –disable SYSTEM_REVOCATION_KEYS

저는 make 도중에 오류가 발생해서 위 2개의 명령어를 실행후 다시 make를 실행하니 정상적으로 컴파일이 되었습니다.

컴파일이 완료되면,

$ sudo make modules_install

로 모듈을 설치하고,

$ sudo make install

명령어로 커널을 설치하면 됩니다.

여기까지는 커널을 설치까지만 된것이고, grub(부트로더)에게 해당 커널로 부팅하게 설정을 해줘야 합니다. (make가 변경해준다고 하던데 제 서버는 변경되지 않아서 수동으로 변경해줬습니다.)

grub 설정

참조

리눅스 부팅 과정중에 shift를 눌러서 grub 화면을 갈 수 있는데 ssh에서는 부팅과정을 볼 수 없어서 grub 설정을 변경해줘야합니다.

먼저 가능하다면 서버에 모니터를 연결해서 부팅 과정중에 shift를 눌러서 grub 설정 화면을 보는 것이 좋은데, 이 화면에 따라 설정값이 달라서 그렇습니다. 저는 이걸 잘 몰라서 서버가 부팅이 안됬었습니다.

일단 ssh에서 grub에게 어떤 커널로 부팅할지 설정하는 방법을 보겠습니다.

$ sudo grep menuentry /boot/grub/grub.cfg

grub의 config 파일을 불러와서 현재 서버에 설치된 커널을 확인 할 수 있습니다.

kernel list

linux-x.x.x 같이 나와있는걸 0부터 세면 됩니다. 현재 설치된 커널은 5.15.0-100이므로 2번이고, 새로 설치한 커널인 6.1.81은 0번입니다.

이후 grub 설정파일을 변경해보겠습니다.

$ sudo vim /etc/default/grub

grub config

기본적으로

GRUB_DEFAULT=0

으로 되어있는데, 이 의미가 grub 화면에서 0번째 entry를 선택하겠다는 의미입니다. 여기서 문제가 발생하는데, grub 화면에 바로 커널 선택 화면이 나오는지, 1번을 선택해서 커널 선택 화면이 나오는지 모른다는것입니다…

저는 처음에 생각없이

GRUB_DEFAULT=2

를 해서 원래 커널로 부팅하려고 했는데 정상적으로 되지 않았습니다. 결국 모니터에 연결해서 grub 설정을 변경해줬습니다.

grub select

저도 이런식으로 처음에 1번을 누르고 커널을 선택하는 화면에서 원하는 커널 번호를 입력해야합니다. 저 같은 경우에는 5.15.0-100을 선택하고 싶으면:

GRUB_DEFAULT=’1>2’

새로 설치한 6.1.81을 선택하고 싶으면:

GRUB_DEFAULT=’1>0’

로 변경해주고 저장하면 됩니다.

마지막으로,

sudo update-grub

로 grub 설정을 업데이트 해주면 끝입니다.

일단 기본 커널의 dmesg를 확인해보면:

no_dmesg

당연히 제 printk문은 보이지 않습니다.

재부팅후 커널 버전과 dmesg를 확인해보면:

dmesg

정상적으로 printk문이 보입니다.

Comments