buildroot 패키지를 사용해 리눅스 드라이버 모듈 추가.
외부 QEMU 커널 모듈 테스트
소스 트리 구조:
buildroot/: Buildroot 파일 시스템 사용.
kernel_module/: 외부 모듈 패키지 테스트
config.in
external.mk
Makefile
hello.c : 간단한 모듈 테스트 파일
1) 커널 모듈 환경 설정 파일
kernel_module/Config.in:
config BR2_PACKAGE_KERNEL_MODULE
bool "kernel_module"
depends on BR2_LINUX_KERNEL
help
Linux Kernel Module Cheat.
2) 외부 커널 모듈 선언
kernel_module/external.mk:
KERNEL_MODULE_VERSION = 1.0
KERNEL_MODULE_SITE = $(BR2_EXTERNAL_KERNEL_MODULE_PATH)
KERNEL_MODULE_SITE_METHOD = local
$(eval $(kernel-module))
$(eval $(generic-package))
3) 빌드 환경 구성
kernel_module/Makefile:
obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))
ccflags-y := -DDEBUG -g -std=gnu99 -Wno-declaration-after-statement
.PHONY: all clean
all:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules
clean:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean
4) 테스트할 모듈 코드 작성
kernel_module/hello.c:
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
static int myinit(void)
{
printk(KERN_INFO "hello init\n");
return 0;
}
static void myexit(void)
{
printk(KERN_INFO "hello exit\n");
}
module_init(myinit)
module_exit(myexit)
테스트
cd buildroot
make BR2_EXTERNAL="$(pwd)/../kernel_module" qemu_x86_64_defconfig
echo 'BR2_PACKAGE_KERNEL_MODULE=y' >> .config
make BR2_JLEVEL="$(($(nproc) - 2))" all
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append root=/dev/vda -net nic,model=virtio -net user
QEMU 접근 테스트
root
modprobe hello
modprobe -r hello
커널 dmesg 명령어로 메세지 확인
hello init
hello exit
커널 등록 흐름 키워드 정리, $(eval $(kernel-module)) external.mk 환경 변수를 통해 모든 것이 설정된다.
저 두개의 환경변수를 보고 modprobe가 /lib/modules/*/extra/hello.ko 포함 할 수 있다.
modprobe dep 명령어는 modules.dep에 대한 정보를 보고 모듈간 종속성을 확인한다.
종속 참고: https://nautiluslee.blogspot.com/2019/01/blog-post_5.html
시작시 모듈 자동 등록
BR2_ROOTFS_OVERLAY="../rootfs_overlay"
rootfs_overlay/etc/init.d/S99modules
modprobe
카테고리
asm
(27)
bootloader_x86_grub
(1)
C
(92)
compile
(11)
config
(76)
CPP
(13)
CSS
(1)
debugging
(7)
gimp
(1)
Go
(1)
html
(1)
Java
(1)
JavaScript
(1)
kernel
(19)
LibreOffice
(3)
Linux system progamming
(21)
MFC
(1)
opencv
(4)
OpenGL
(1)
PHP
(1)
Python
(4)
qemu
(29)
shell
(3)
socket
(7)
troubleshooting
(2)
ubuntu18.04
(2)
windows
(1)
2019/01/05
커널 모듈 종속성 관련
리눅스 커널 모듈 종속성 예제.
테스트 모듈 파일 1
dep.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
int lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", lkmc_dep);
usleep_range(1000000, 1000001);
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
테스트 모듈 파일 2
dep2.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
extern int lkmc_dep;
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
usleep_range(1000000, 1000001);
lkmc_dep++;
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
컴파일
Makefile:
obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))
ccflags-y := -DDEBUG -g -std=gnu99 -Wno-declaration-after-statement
.PHONY: all clean
all:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules
clean:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean
모듈 로딩
insmod dep.ko
insmod dep2.ko
/lib/module/*/depmod의존성 정보를 가지고 있으므로 depmod 구성 하고 있기 때문에 두 가지 모도 로드할 수 있음.
modprobe dep
비 정적 변수 확인
CONFIG_KALLSYMS_ALL = y 확인
grep lkmc_dep /proc/kallsyms
이 파일은 커널에 다음과 같이 정이된다.
const_debug unsigned int sysctl_sched_nr_migrate = 32;
테스트 모듈 파일 1
dep.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
int lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", lkmc_dep);
usleep_range(1000000, 1000001);
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
테스트 모듈 파일 2
dep2.c
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
extern int lkmc_dep;
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
usleep_range(1000000, 1000001);
lkmc_dep++;
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
컴파일
Makefile:
obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))
ccflags-y := -DDEBUG -g -std=gnu99 -Wno-declaration-after-statement
.PHONY: all clean
all:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules
clean:
$(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean
모듈 로딩
insmod dep.ko
insmod dep2.ko
/lib/module/*/depmod의존성 정보를 가지고 있으므로 depmod 구성 하고 있기 때문에 두 가지 모도 로드할 수 있음.
modprobe dep
비 정적 변수 확인
CONFIG_KALLSYMS_ALL = y 확인
grep lkmc_dep /proc/kallsyms
이 파일은 커널에 다음과 같이 정이된다.
const_debug unsigned int sysctl_sched_nr_migrate = 32;
busybox qemu 설치
rootfs 단일 실행 파일
최소 단일 루트 파일 시스템 init은 여기 참고 https://nautiluslee.blogspot.com/2019/01/init-hello-world.html
리눅스 가장 작은 라이브 이미지 파일 다운로드 후 qemu 설치
프로젝트 사이트 : https://github.com/ivandavidov/minimal
- 커널 및 비지박스 다운로드
- 다운로드 받은 파일 컴파일
- 8MB 부팅 가능한 ISO 파일 생성
ISO 이미지 파일은 BysyBox 지원하는 쉘과 연동하게 한다.
QEMU를 사용해 부팅 테스트.
커널 소스 디렉토리에서 실행 되도록 커널 수정
git clone https://github.com/ivandavidov/minimal
cd minimal/src
./build_minimal_linux_live.sh
# QEMU 설치.
# minimal_linux_live.iso 생성.
./qemu64.sh
루트파일 시스템 빌드
Makefile 스크립트로 프로젝트 관리:
- gcc 크로스 컴파일 툴체인
- 커널 컴파일
- 부트로더 컴파일
- rootfs 생성
- GTK와 같은 복잡한 내용을 포함하여 소스 트리에서 수많은 의존성 패키지 다운로드.
git clone git://git.buildroot.net/buildroot
cd buildroot
git checkout 2016.05
make qemu_x86_defconfig
# -jN 대신, `BR2_JLEVEL=2`를 사용.
BR2_JLEVEL=2 make
# cat board/qemu/x86_64/readme.txt
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append root=/dev/vda -net nic,model=virtio -net user
# BusyBox 쉘 동작.
X11 추가 하고 참고:
https://nautiluslee.blogspot.com/2019/01/x11-blackbox-qemu.html
5MB인 임베디드용 패키지 https://github.com/gliderlabs/docker-alpine
busybox 보다 더욱 가벼운.
qemu x11 설치
X11 패키지 모음 사이트
https://github.com/buildroot/buildroot/tree/2016.05/package/x11r7
https://github.com/buildroot/buildroot/tree/2018.02.x/package/x11r7
https://github.com/buildroot/buildroot/tree/2018.11.x/package/x11r7
시작 명령어.
startx
qemu_x86_64_x11_defconfig
https://github.com/cirosantilli/buildroot-configs/blob/44b45b5c7f68e44abcda360a2b980f8301901a9a/qemu_x86_64_x11_defconfig
최소한의 X11 구성 파일
BR2_PACKAGE_XAPP_TWM=y
BR2_PACKAGE_XAPP_XCALC=y
BR2_PACKAGE_XAPP_XCLOCK=y
BR2_PACKAGE_XAPP_XEYES=y
BR2_PACKAGE_XAPP_XINIT=y
BR2_PACKAGE_XDRIVER_XF86_INPUT_KEYBOARD=y
BR2_PACKAGE_XDRIVER_XF86_INPUT_MOUSE=y
BR2_PACKAGE_XDRIVER_XF86_VIDEO_CIRRUS=y
BR2_PACKAGE_XDRIVER_XF86_VIDEO_FBDEV=y
BR2_PACKAGE_XDRIVER_XF86_VIDEO_VESA=y
BR2_PACKAGE_XORG7=y
BR2_PACKAGE_XSERVER_XORG_SERVER=y
BR2_PACKAGE_XTERM=y
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_TOOLCHAIN_BUILDROOT_WCHAR=y
BR2_USE_WCHAR=y
.config 추가 방법.
cat configs/qemu_x86_64_defconfig br_config_frag > .config
make olddefconfig
선택 옵션 발견:
make menuconfig
커널 체크 박스 에서 검색 /
xeyes에 대한 dependes 확인.
두개의 서로 다른 인터페이스 패키지가 구현되는 상황. (X.Org 모듈과 KDrive 둘 다 X11 서버 구현하는 경우) 기본적으로 선택되지 않는 상황 때문에 어떻한 작업을 할 것인지에 대해 알고 있어야 한다.
윈도우메니지먼트 참고: https://nautiluslee.blogspot.com/2019/01/x11-blackbox-qemu.html
동작 구현
make BR2_JLEVEL=$(nproc)
qemu-system-x86_64 \
-enable-kvm \
-M pc \
-m 512 \
-kernel output/images/bzImage \
-drive file=output/images/rootfs.ext2,if=virtio,format=raw \
-append root=/dev/vda \
-net nic,model=virtio \
-net user
QEMU 접근
root
startx
이미지 크기: 28M
startx 명령어 실행 후 /etc/X11/xinit/xinitrc 파일를 참고해 GUI 호출
vi xinitrc
twm &
xclock -geometry 50x50-1+1 &
xterm -geometry 80x50+494+51 &
xterm -geometry 80x20+494-0 &
exec xterm -geometry 80x66+0+0 -name login
윈도우 메니지먼트 시작됨.
QEMU SSH 사용해 게스트 접근 방법.
-net nic,model=virtio \
-net user,hostfwd=tcp::5901-:5900
추가 후 게스트에서 startx 실행
x11vnc
호스트 환경으로 넘어와:
sudo apt-get install vinagre
vinagre localhost::5901
x로만 로그인 할 경우
대상 패키지 -> 그래픽 라이브러리 및 응용프로그램 ->
X.Org X Window System : y 클릭
X11R7 Application -> xconsole(xdm 기본 설정)
xdm
루트 로그인 할 수 없음.
xdm 로그: /var/log/sdm.log
x 메니지먼트 호출 체인 방식
/init (BysyBox 사용)
/etc/inittab 내용 :: sysinit:/etc/init.d/rcS
/etc/init.d/rcS
/etc/init.d/S99xdm
/usr/bin/xdm
x11 blackbox 윈도우메니지먼트 qemu 설치 테스트
일반 사용타 루트파일 시스템 다운로드
$ cd
$ git clone git://git.buildroot.net/buildroot
$ cd buildroot && make menuconf
커널 설정
Toolchain —>
[X] Enable large file (files > 2 GB) support
[X] Enable WCHAR support
[X] Enable C++ support
Package Selection for the target —>
Graphic libraries and applications (graphic/text) —>
[X] X.org X Window System, X11R7, release 7.5 —>
X Window System server type —>
[X] Modular X.org
X11R7 Applications —>
[X] setxkbmap // 선택 사항: us 이외의 다른 키보드 맵 지원
[X] twm
[X] xclock
[X] xinit
[X] xinput // 선택 사항: 입력 장치 문제 찾기
[X] xkbcomp
X11R7 Drivers —>
[X] xf86-input-evdev
[X] xf86-input-keyboard
[X] xf86-input-mouse
[X] xf86-video-cirrus // NOTE : qemu 그래픽 보드
[X] xf86-video-fbdev
[X] xf86-video-vesa
(호환성 드라이버 점검.)
[X] Liberation (Free fonts)
[X] xterm
Libraries –>
Text and terminal handling —>
[X] ncurses // xterm 종속성 확인 , see http://lists.busybox.net/pipermail/buildroot/2011-March/041737.html
Hardware handling —>
[*] udev
Kernel —>
[X] Linux Kernel
Defconfig name : i386
Target filesystem options —>
[X] iso image (optional, only if you want to burn on a CD)
[X] initramfs for initial ramdisk of linux kernel
uncheck others
빌드
$ make
qemu 테스트
$ qemu -kernel output/images/bzImage -m 256
로그인
root/패스워드 없음)
x11 실행
# startx
TODO : qemu 마우스 커서 움직임 버그 존재(hal 패키지 설치)
USB 실제 컴퓨터 부팅시 마우스 잘 동작 함.
입력 장치 값: https://wiki.ubuntu.com/X/Config/Input
하드웨어 프레임 버퍼 활성화.
$ make linux-menuconfig
호환성 모두 포함
Device drivers —>
Graphics support —>
Support for frame buffer devices —>
Check everything
재 빌드 및 테스트
$ make && qemu -kernel output/images/bzImage -m 256
X11 시작
# startx
선택 사항
디버깅 xorg.conf 파일 수정
# X -configure
# mkdir -p /etc/X11
# cp xorg.conf.new /etc/X11/xorg.conf
# vi /etc/X11/xorg.conf
팁 : CTRL-ALT-BACKSPACE X를 죽이려면 xorg.conf 수정
vi xorg.conf
keyboard section :
Option “XkbOptions” “terminate:ctrl_alt_bksp”
and add in a ServerFlags section :
Section “ServerFlags”
Option “DontZap” “false”
EndSection
</optional>
작은 윈도우 매니저머트 추가
$ make menuconfig
Package Selection for the target —>
Graphic libraries and applications (graphic/text) —>
[X] blackbox
참고: blackbox 기본 구성은 bitstream Vera 9 글꼴 사용. 글꼴이 추가되지 않으면 종료 됨.
재 빌드 테스트
$ make && qemu -kernel output/images/bzImage -m 256
바탕 화면 오른쪽 마우스 클릭 Blackbox 메뉴가 생성
rootfs 추가 준비
$ cd <your buildroot home>/output/target
선택 사항 busubox 용 키맵(여기서는 us keymap file, us.kmap) 만들고 복사한다.
$ sudo busybox dumpkmap >etc/us.kmap
부팅 시퀀서 수정
$ nano etc/init.d/rcS
loadkmap </etc/us.kmap
x윈도우 시작
startx
x 윈도우 시작 스크립트 수정
$ nano usr/lib/X11/xinit/xinitrc
주석 처리
#twm &
#xclock -geometry 50×50-1+1 &
#xterm -geometry 80×50+494+51 &
#xterm -geometry 80×20+494-0 &
#exec xterm -geometry 80×66+0+0 -name login
다음 추가
setxkbmap us
xterm &
# 윈도우 메니지먼트
exec blackbox
최종 테스트
$ cd <your buildroot home>
$ make && qemu -kernel output/images/bzImage -m 256
$ cd
$ git clone git://git.buildroot.net/buildroot
$ cd buildroot && make menuconf
커널 설정
Toolchain —>
[X] Enable large file (files > 2 GB) support
[X] Enable WCHAR support
[X] Enable C++ support
Package Selection for the target —>
Graphic libraries and applications (graphic/text) —>
[X] X.org X Window System, X11R7, release 7.5 —>
X Window System server type —>
[X] Modular X.org
X11R7 Applications —>
[X] setxkbmap // 선택 사항: us 이외의 다른 키보드 맵 지원
[X] twm
[X] xclock
[X] xinit
[X] xinput // 선택 사항: 입력 장치 문제 찾기
[X] xkbcomp
X11R7 Drivers —>
[X] xf86-input-evdev
[X] xf86-input-keyboard
[X] xf86-input-mouse
[X] xf86-video-cirrus // NOTE : qemu 그래픽 보드
[X] xf86-video-fbdev
[X] xf86-video-vesa
(호환성 드라이버 점검.)
[X] Liberation (Free fonts)
[X] xterm
Libraries –>
Text and terminal handling —>
[X] ncurses // xterm 종속성 확인 , see http://lists.busybox.net/pipermail/buildroot/2011-March/041737.html
Hardware handling —>
[*] udev
Kernel —>
[X] Linux Kernel
Defconfig name : i386
Target filesystem options —>
[X] iso image (optional, only if you want to burn on a CD)
[X] initramfs for initial ramdisk of linux kernel
uncheck others
빌드
$ make
qemu 테스트
$ qemu -kernel output/images/bzImage -m 256
로그인
root/패스워드 없음)
x11 실행
# startx
TODO : qemu 마우스 커서 움직임 버그 존재(hal 패키지 설치)
USB 실제 컴퓨터 부팅시 마우스 잘 동작 함.
입력 장치 값: https://wiki.ubuntu.com/X/Config/Input
하드웨어 프레임 버퍼 활성화.
$ make linux-menuconfig
호환성 모두 포함
Device drivers —>
Graphics support —>
Support for frame buffer devices —>
Check everything
재 빌드 및 테스트
$ make && qemu -kernel output/images/bzImage -m 256
X11 시작
# startx
선택 사항
디버깅 xorg.conf 파일 수정
# X -configure
# mkdir -p /etc/X11
# cp xorg.conf.new /etc/X11/xorg.conf
# vi /etc/X11/xorg.conf
팁 : CTRL-ALT-BACKSPACE X를 죽이려면 xorg.conf 수정
vi xorg.conf
keyboard section :
Option “XkbOptions” “terminate:ctrl_alt_bksp”
and add in a ServerFlags section :
Section “ServerFlags”
Option “DontZap” “false”
EndSection
</optional>
작은 윈도우 매니저머트 추가
$ make menuconfig
Package Selection for the target —>
Graphic libraries and applications (graphic/text) —>
[X] blackbox
참고: blackbox 기본 구성은 bitstream Vera 9 글꼴 사용. 글꼴이 추가되지 않으면 종료 됨.
재 빌드 테스트
$ make && qemu -kernel output/images/bzImage -m 256
바탕 화면 오른쪽 마우스 클릭 Blackbox 메뉴가 생성
rootfs 추가 준비
$ cd <your buildroot home>/output/target
선택 사항 busubox 용 키맵(여기서는 us keymap file, us.kmap) 만들고 복사한다.
$ sudo busybox dumpkmap >etc/us.kmap
부팅 시퀀서 수정
$ nano etc/init.d/rcS
loadkmap </etc/us.kmap
x윈도우 시작
startx
x 윈도우 시작 스크립트 수정
$ nano usr/lib/X11/xinit/xinitrc
주석 처리
#twm &
#xclock -geometry 50×50-1+1 &
#xterm -geometry 80×50+494+51 &
#xterm -geometry 80×20+494-0 &
#exec xterm -geometry 80×66+0+0 -name login
다음 추가
setxkbmap us
xterm &
# 윈도우 메니지먼트
exec blackbox
최종 테스트
$ cd <your buildroot home>
$ make && qemu -kernel output/images/bzImage -m 256
runlinux 커널 소스 해킹 및 디버깅 방법.
리눅스 실행
작업중인 커널을 다운로드하는 대신 기존 커널 소스를 재사용해 커널을 해킹한 후 개발 용으로 테스트 한다.
최소한의 리눅스 이미지 사용.
설치
sudo apt-get install git qemu
sudo apt-get build-dep busybox linux-image-$(uname -r)
mkdir -p ~/bin
cd ~/bin
git clone --recursive https://github.com/cirosantilli/runlinux
echo 'PATH="$PATH:'$(pwd)'/runlinux"' >> ~/.bashrc
. ~/.bashrc
예제
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.2
runlinux
처음 부팅시 시간이 걸린다.
부팅 되면 커널 소스를 해킹
runlinux
사용자 정의 구성 외부 트리 빌드:
export KBUILD_OUTPUT="$(pwd)/../build"
make menuconfig
runlinux
기존 구성 파이리이 없으면 KBUILD_OUTPUT, make defconfig 사용.
QEMU 추가 옵션 설정.
runlinux -- -bios ~/path/to/OVMF.fd
bios 대신 UEFI x64 사용시 다운로드.
https://sourceforge.net/projects/edk2/files/OVMF/OVMF-X64-r15214.zip
실 하드웨어 실행
빌드 디렉토리에 main.img 파일 생성:
runlinux -i
usb 장치 연결
sudo lsblk
sudo fdisk -l
usb 이미지 굽기
sudo dd if=main.img of=/dev/sdx
실제 컴퓨터 바이오스 부팅 시퀀서 USB 변경
이미지 동작 확인.
qemu-system-x86_64 -enable-kvm -hda main.img
선택사항
사용자 정의 initrd 생성
n
BysyBox 무시 한 후 사용자정의 루트파일 시스템 사용.
runlinux -n /path/to/my/directory/
runlinux -n /path/to/my/init
경로 설정:
- 디렉토리 압축
리눅스 부팅시 가장 먼저 /init 디렉토리를 찾아 실행함.
- init 파일을 사용하면 압축된 파일 시스템의 루트 이름이 바뀜.
initrd 참고: https://nautiluslee.blogspot.com/2019/01/init-hello-world.html
GDB 커널 디버깅:
../runlinux/runlinux -g
CONFIG_DEBUG_INFO 필요한 경우, 커널 옵션을 설정한 후 커널 다시 빌드.
QEMU를 실행 후 GDB 활성화.
디버깅 준비 예:
hbreak start_kernel
list
continue
작업중인 커널을 다운로드하는 대신 기존 커널 소스를 재사용해 커널을 해킹한 후 개발 용으로 테스트 한다.
최소한의 리눅스 이미지 사용.
설치
sudo apt-get install git qemu
sudo apt-get build-dep busybox linux-image-$(uname -r)
mkdir -p ~/bin
cd ~/bin
git clone --recursive https://github.com/cirosantilli/runlinux
echo 'PATH="$PATH:'$(pwd)'/runlinux"' >> ~/.bashrc
. ~/.bashrc
예제
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.2
runlinux
처음 부팅시 시간이 걸린다.
부팅 되면 커널 소스를 해킹
runlinux
사용자 정의 구성 외부 트리 빌드:
export KBUILD_OUTPUT="$(pwd)/../build"
make menuconfig
runlinux
기존 구성 파이리이 없으면 KBUILD_OUTPUT, make defconfig 사용.
QEMU 추가 옵션 설정.
runlinux -- -bios ~/path/to/OVMF.fd
bios 대신 UEFI x64 사용시 다운로드.
https://sourceforge.net/projects/edk2/files/OVMF/OVMF-X64-r15214.zip
실 하드웨어 실행
빌드 디렉토리에 main.img 파일 생성:
runlinux -i
usb 장치 연결
sudo lsblk
sudo fdisk -l
usb 이미지 굽기
sudo dd if=main.img of=/dev/sdx
실제 컴퓨터 바이오스 부팅 시퀀서 USB 변경
이미지 동작 확인.
qemu-system-x86_64 -enable-kvm -hda main.img
선택사항
사용자 정의 initrd 생성
n
BysyBox 무시 한 후 사용자정의 루트파일 시스템 사용.
runlinux -n /path/to/my/directory/
runlinux -n /path/to/my/init
경로 설정:
- 디렉토리 압축
리눅스 부팅시 가장 먼저 /init 디렉토리를 찾아 실행함.
- init 파일을 사용하면 압축된 파일 시스템의 루트 이름이 바뀜.
initrd 참고: https://nautiluslee.blogspot.com/2019/01/init-hello-world.html
GDB 커널 디버깅:
../runlinux/runlinux -g
CONFIG_DEBUG_INFO 필요한 경우, 커널 옵션을 설정한 후 커널 다시 빌드.
QEMU를 실행 후 GDB 활성화.
디버깅 준비 예:
hbreak start_kernel
list
continue
init hello world 프로그램
init hello world 프로그램
init.S 추가
.global _start
_start:
mov $1, %rax
mov $1, %rdi
mov $message, %rsi
mov $message_len, %rdx
syscall
jmp .
message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
.equ message_len, . - message
종료 시스템 호출 및 커널 패닉 사용할 수 없을 때:
mkdir d
as --64 -o init.o init.S # assemble
ld -o d/init init.o # link
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"
hello world 정보를 가진 init 파일 시스템 생성.
커널 소스 다운로드
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
QEMU 실행
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"
메세지 확인
FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR
C 프로그램 사용.
#include <stdio.h>
#include <unistd.h>
int main() {
printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
sleep(0xFFFFFFFF);
return 0;
}
컴파일
gcc -static init.c -o init
usb 부팅 실 하드웨어 테스트
make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX
init.S 추가
.global _start
_start:
mov $1, %rax
mov $1, %rdi
mov $message, %rsi
mov $message_len, %rdx
syscall
jmp .
message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
.equ message_len, . - message
종료 시스템 호출 및 커널 패닉 사용할 수 없을 때:
mkdir d
as --64 -o init.o init.S # assemble
ld -o d/init init.o # link
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"
hello world 정보를 가진 init 파일 시스템 생성.
커널 소스 다운로드
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
QEMU 실행
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"
메세지 확인
FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR
C 프로그램 사용.
#include <stdio.h>
#include <unistd.h>
int main() {
printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
sleep(0xFFFFFFFF);
return 0;
}
컴파일
gcc -static init.c -o init
usb 부팅 실 하드웨어 테스트
make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX
GDB 커널 단계별 디버깅
GDB 단계별 디버깅
리눅스 커널 디버깅
./run -d
start_kernel 부트 시퀀스와 같은 심볼에서 직접 접근
./rungdb start_kernel
QEMU 정지, GDB 명령어 사용 활성화:
l
n
c
부팅 건너 뛰려면 다음 실행.
./rungdb
gdm 모드 정지 ctrl + c
QEMU 내부 스크립트 테스트
./count.sh
stdout 무한대 계산, GDB 다음과 같이 계산됨.
Ctrl + C
break sys_write
continue
continue
continue
커널 모듈 디버깅
./run -d
./rungdb
QEMU 모드 진입:
insmod /fops.ko
정지 CTRL + C
scanning for modules in ../kernel_module-1.0/
loading @0xffffffffa0000000: ../kernel_module-1.0//fops.ko
간단한 심볼
b fop_write
c
QEMU 모드 진입:
printf a >/sys/kernel/debug/lkmc_fops/f
GDB 브레이크 포인트 fop_write 지정
rmmod 하기 전 브레이크 포인트 해제, 그렇지 않으면 브레이크 포이트 정보 가지고 있음.
하드코어 방식의 디버깅, 별로 사용하지 않는 방식
insmod /fops.ko
cat /proc/modules
fops 2327 0 - Live 0xfffffffa00000000
모듈로드 정보 GDB 전달
Ctrl + C
add-symbol-file ../kernel_module-1.0/fops.ko 0xfffffffa00000000
커널 초기 디버그 부팅
./rungdb extract_kernel
./rungdb main
리눅스 커널 디버깅
./run -d
start_kernel 부트 시퀀스와 같은 심볼에서 직접 접근
./rungdb start_kernel
QEMU 정지, GDB 명령어 사용 활성화:
l
n
c
부팅 건너 뛰려면 다음 실행.
./rungdb
gdm 모드 정지 ctrl + c
QEMU 내부 스크립트 테스트
./count.sh
stdout 무한대 계산, GDB 다음과 같이 계산됨.
Ctrl + C
break sys_write
continue
continue
continue
커널 모듈 디버깅
./run -d
./rungdb
QEMU 모드 진입:
insmod /fops.ko
정지 CTRL + C
scanning for modules in ../kernel_module-1.0/
loading @0xffffffffa0000000: ../kernel_module-1.0//fops.ko
간단한 심볼
b fop_write
c
QEMU 모드 진입:
printf a >/sys/kernel/debug/lkmc_fops/f
GDB 브레이크 포인트 fop_write 지정
rmmod 하기 전 브레이크 포인트 해제, 그렇지 않으면 브레이크 포이트 정보 가지고 있음.
하드코어 방식의 디버깅, 별로 사용하지 않는 방식
insmod /fops.ko
cat /proc/modules
fops 2327 0 - Live 0xfffffffa00000000
모듈로드 정보 GDB 전달
Ctrl + C
add-symbol-file ../kernel_module-1.0/fops.ko 0xfffffffa00000000
커널 초기 디버그 부팅
./rungdb extract_kernel
./rungdb main
qemu 스냅 샷
스냅샷 생성
QEMU 원본 이미지를 참조하는 이미지 생성.
기존 이미지 스탭 샵을 만든 후 다음 버전의 스냅샷으로 작업을 진행하는 이미지 원리.
-b : 백업
qemu-img create -f qcow2 -b centos-cleaninstall.img snapshot.img
이전 버전 돌아가기
변경된 스탭 샷 이미지는 원래 상태로 되돌릴 수 없다.
대신 첫 번째 스냅 샷 이미지를 생성하고, 그 이미지 파일을 사용한다.
백업 파일 수정
$ qemu-img info snapshot.img
임시 스탭 샵.
qemu -hda centos-cleaninstall.img -snapshot
QEMU 원본 이미지를 참조하는 이미지 생성.
기존 이미지 스탭 샵을 만든 후 다음 버전의 스냅샷으로 작업을 진행하는 이미지 원리.
-b : 백업
qemu-img create -f qcow2 -b centos-cleaninstall.img snapshot.img
이전 버전 돌아가기
변경된 스탭 샷 이미지는 원래 상태로 되돌릴 수 없다.
대신 첫 번째 스냅 샷 이미지를 생성하고, 그 이미지 파일을 사용한다.
백업 파일 수정
$ qemu-img info snapshot.img
임시 스탭 샵.
qemu -hda centos-cleaninstall.img -snapshot
우분투 18.04 qemu 호스트/게스트 설정
우분투 18.04 qemu 호스트/게스트 설정
wget http://releases.ubuntu.com/18.04/ubuntu-18.04.1-desktop-amd64.iso
qemu-img create -f qcow2 ubuntu-18.04-desktop-amd64.img.qcow2 64G
qemu-system-x86_64 \
-cdrom ubuntu-18.04-desktop-amd64.iso \
-drive file=ubuntu-18.04-desktop-amd64.img.qcow2,format=qcow2 \
-enable-kvm \
-m 2G \
-smp 2 \
-vga virtio \
;
GUI 에서 우분투 설치
기본 버전 이미지 생성(초기 버전)
qemu-img create -f qcow2 -b ubuntu-18.04-desktop-amd64.img.qcow2 \
ubuntu-18.04-desktop-amd64.snapshot.qcow2
시스템 다시 시작.
qemu-system-x86_64 \
-drive file=ubuntu-18.04-desktop-amd64.snapshot.qcow2,format=qcow2 \
-enable-kvm \
-m 2G \
-smp 2 \
-soundhw hda \
-vga virtio \
;
설치부터 다시 할 경우 실행
qemu-img create -f qcow2 -b ubuntu-18.04-desktop-amd64.img.qcow2 \
ubuntu-18.04-desktop-amd64.snapshot.qcow2
스냅 샷은 원본 이미지 사이의 차이점만 저장하기 때문에 디스크 공간을 많이 차지하지 않음
해상도 설정 옵션
-vga virtio
전체 화면 사용
-full-screen
Ctrl + Alt + F
QEMU 기본 비활성화
-soundhw hda
부팅 시간 단축 및 부팅 메시지 표시
printf 'GRUB_TIMEOUT=1\nGRUB_CMDLINE_LINUX_DEFAULT=""\n' | sudo tee -a /etc/default/grub
sudo update-grub
접속
1. virt-manager에 spice-gtk 클라이언트가 내장됨.
vm 호스트에서 python-spice-client-gtk 설치.
virt-manager를 사용하여 다른 호스트에서 ssh를 통해 VM 호스트에 원격으로 연결하는 경우 해당 시스템에 python-spice-client-gtk도 설치해야함.
2. virt-manager 시작
3. 가상화 컴퓨터 시작
4. 가상화 컴퓨터 전원 ON
5. ssh 게스트 연결, 게스트에서 spice-vdagent 설치하고 spice-vdagentd 시작 되었는 지 확인
6. 가상환경 하드웨어 세부 정보 표시
7. Display VNC 선택하고 VNC를 Spice 변경한 후 수락해 채널 추가
8. Cirrus(기본값)에서 QXL 비디오 모델 변경
9. virt-manager 다시 시작하고 가상 시스템 전원을 켠다.
x 값 없을때 해결방법(단 호스트환경에서 VM으로 ssh 접근 할 수 있다는 전제 조건)
~$ssh user@host
~$ssh user@guest
설치
프로젝트 사이트: https://www.spice-space.org/download.html
sudo apt install spice-vdagent
설정 방법.
https://wiki.archlinux.org/index.php/QEMU#SPICE
https://www.linux-kvm.org/page/SPICE
시도,
-spice port=5930,disable-ticketing+ remote-viewer spice://127.0.0.1:5930, 그리고 spice-vdagent 게스트 설치, 성공하지 못함.
근본 원인은 QEMU devs 안정적 구현하지 않음, QEMU 개발 방법은 비대화 형 개발에 더 중점을 둔다.
참고:
호스트 3D 가속. SPICE 및 QXL을 glxgears사용하는 경우 1k FPS를 제공하고 일반 SDL과 동리 함.
호스트에서 __GL_SYNC_TO_VBLANK=0 vblank_mode=0 glxgears20k FPS를 제공하므로 그래픽이 가속되지 않은 것으로 보임.
wget http://releases.ubuntu.com/18.04/ubuntu-18.04.1-desktop-amd64.iso
qemu-img create -f qcow2 ubuntu-18.04-desktop-amd64.img.qcow2 64G
qemu-system-x86_64 \
-cdrom ubuntu-18.04-desktop-amd64.iso \
-drive file=ubuntu-18.04-desktop-amd64.img.qcow2,format=qcow2 \
-enable-kvm \
-m 2G \
-smp 2 \
-vga virtio \
;
GUI 에서 우분투 설치
기본 버전 이미지 생성(초기 버전)
qemu-img create -f qcow2 -b ubuntu-18.04-desktop-amd64.img.qcow2 \
ubuntu-18.04-desktop-amd64.snapshot.qcow2
시스템 다시 시작.
qemu-system-x86_64 \
-drive file=ubuntu-18.04-desktop-amd64.snapshot.qcow2,format=qcow2 \
-enable-kvm \
-m 2G \
-smp 2 \
-soundhw hda \
-vga virtio \
;
설치부터 다시 할 경우 실행
qemu-img create -f qcow2 -b ubuntu-18.04-desktop-amd64.img.qcow2 \
ubuntu-18.04-desktop-amd64.snapshot.qcow2
스냅 샷은 원본 이미지 사이의 차이점만 저장하기 때문에 디스크 공간을 많이 차지하지 않음
해상도 설정 옵션
-vga virtio
전체 화면 사용
-full-screen
Ctrl + Alt + F
QEMU 기본 비활성화
-soundhw hda
부팅 시간 단축 및 부팅 메시지 표시
printf 'GRUB_TIMEOUT=1\nGRUB_CMDLINE_LINUX_DEFAULT=""\n' | sudo tee -a /etc/default/grub
sudo update-grub
접속
1. virt-manager에 spice-gtk 클라이언트가 내장됨.
vm 호스트에서 python-spice-client-gtk 설치.
virt-manager를 사용하여 다른 호스트에서 ssh를 통해 VM 호스트에 원격으로 연결하는 경우 해당 시스템에 python-spice-client-gtk도 설치해야함.
2. virt-manager 시작
3. 가상화 컴퓨터 시작
4. 가상화 컴퓨터 전원 ON
5. ssh 게스트 연결, 게스트에서 spice-vdagent 설치하고 spice-vdagentd 시작 되었는 지 확인
6. 가상환경 하드웨어 세부 정보 표시
7. Display VNC 선택하고 VNC를 Spice 변경한 후 수락해 채널 추가
8. Cirrus(기본값)에서 QXL 비디오 모델 변경
9. virt-manager 다시 시작하고 가상 시스템 전원을 켠다.
x 값 없을때 해결방법(단 호스트환경에서 VM으로 ssh 접근 할 수 있다는 전제 조건)
~$ssh user@host
~$ssh user@guest
설치
프로젝트 사이트: https://www.spice-space.org/download.html
sudo apt install spice-vdagent
설정 방법.
https://wiki.archlinux.org/index.php/QEMU#SPICE
https://www.linux-kvm.org/page/SPICE
시도,
-spice port=5930,disable-ticketing+ remote-viewer spice://127.0.0.1:5930, 그리고 spice-vdagent 게스트 설치, 성공하지 못함.
근본 원인은 QEMU devs 안정적 구현하지 않음, QEMU 개발 방법은 비대화 형 개발에 더 중점을 둔다.
참고:
호스트 3D 가속. SPICE 및 QXL을 glxgears사용하는 경우 1k FPS를 제공하고 일반 SDL과 동리 함.
호스트에서 __GL_SYNC_TO_VBLANK=0 vblank_mode=0 glxgears20k FPS를 제공하므로 그래픽이 가속되지 않은 것으로 보임.
node.js 버전별 관리 프로젝트
프로젝트 사이트
https://github.com/creationix/nvm
다운로드
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | sh
source ~/.nvm/nvm.sh
nvm install --lts
nvm use --lts
npm install --global vaca
vaca
bashrc 추가.
f="$HOME/.nvm/nvm.sh"
if [ -r "$f" ]; then
. "$f" &>'/dev/null'
nvm use --lts &>'/dev/null'
fi
장점:
sudo 없이 Node 버전 사용
가능한 바이너리 파일을 설치
버전별 전환 방법
nvm install 0.9.0
nvm install 0.9.9
nvm use 0.9.0
node --version
#v0.9.0
nvm use 0.9.9
node --version
#v0.9.9
https://github.com/creationix/nvm
다운로드
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | sh
source ~/.nvm/nvm.sh
nvm install --lts
nvm use --lts
npm install --global vaca
vaca
bashrc 추가.
f="$HOME/.nvm/nvm.sh"
if [ -r "$f" ]; then
. "$f" &>'/dev/null'
nvm use --lts &>'/dev/null'
fi
장점:
sudo 없이 Node 버전 사용
가능한 바이너리 파일을 설치
버전별 전환 방법
nvm install 0.9.0
nvm install 0.9.9
nvm use 0.9.0
node --version
#v0.9.0
nvm use 0.9.9
node --version
#v0.9.9
debootstrap_x86 qemu 자동 설치 스크립트
#!/usr/bin/env bash
set -eux
suite=xenial
debootstrap_dir=$suite
img_file=${suite}.ext4.img
kernel=/vmlinuz
initrd=/initrd.img
sudo apt install -y \
debootstrap \
qemu-system-x86 \
;
if [ ! -d "$debootstrap_dir" ]; then
# Create debootstrap directory.
sudo debootstrap \
"$suite" \
"$debootstrap_dir" \
http://archive.ubuntu.com/ubuntu \
;
# Set root password.
echo 'root:root' | sudo chroot "$debootstrap_dir" chpasswd
# Remount root filesystem as rw.
cat << EOF | sudo tee "$debootstrap_dir/etc/fstab"
/dev/sda / ext4 errors=remount-ro,acl 0 1
EOF
# Automaticaly start networking.
# Otherwise network commands fail with:
# Temporary failure in name resolution
# https://gist.github.com/corvax19/6230283#gistcomment-1940694
cat << EOF | sudo tee "$debootstrap_dir/etc/systemd/system/dhclient.service"
[Unit]
Description=DHCP Client
Documentation=man:dhclient(8)
Wants=network.target
Before=network.target
[Service]
Type=forking
PIDFile=/var/run/dhclient.pid
ExecStart=/sbin/dhclient -4 -q
[Install]
WantedBy=multi-user.target
EOF
sudo ln -sf /etc/systemd/system/dhclient.service \
"${debootstrap_dir}/etc/systemd/system/multi-user.target.wants/dhclient.service"
fi
if [ ! -f "$img_file" ]; then
# Create disk image
dd if=/dev/null of="$img_file" bs=1M seek=2048
mkfs.ext4 "$img_file"
mnt_dir="${suite}_mnt"
mkdir "$mnt_dir"
sudo mount -t ext4 "$img_file" "$mnt_dir"
sudo cp -r "$debootstrap_dir/." "$mnt_dir"
sudo umount "$mnt_dir"
rmdir "$mnt_dir"
fi
sudo qemu-system-x86_64 \
-append 'console=ttyS0 root=/dev/sda' \
-drive "file=${img_file},format=raw" \
-enable-kvm \
-nographic \
-serial mon:stdio \
-m 2G \
-kernel "$kernel" \
-initrd "$initrd" \
;
set -eux
suite=xenial
debootstrap_dir=$suite
img_file=${suite}.ext4.img
kernel=/vmlinuz
initrd=/initrd.img
sudo apt install -y \
debootstrap \
qemu-system-x86 \
;
if [ ! -d "$debootstrap_dir" ]; then
# Create debootstrap directory.
sudo debootstrap \
"$suite" \
"$debootstrap_dir" \
http://archive.ubuntu.com/ubuntu \
;
# Set root password.
echo 'root:root' | sudo chroot "$debootstrap_dir" chpasswd
# Remount root filesystem as rw.
cat << EOF | sudo tee "$debootstrap_dir/etc/fstab"
/dev/sda / ext4 errors=remount-ro,acl 0 1
EOF
# Automaticaly start networking.
# Otherwise network commands fail with:
# Temporary failure in name resolution
# https://gist.github.com/corvax19/6230283#gistcomment-1940694
cat << EOF | sudo tee "$debootstrap_dir/etc/systemd/system/dhclient.service"
[Unit]
Description=DHCP Client
Documentation=man:dhclient(8)
Wants=network.target
Before=network.target
[Service]
Type=forking
PIDFile=/var/run/dhclient.pid
ExecStart=/sbin/dhclient -4 -q
[Install]
WantedBy=multi-user.target
EOF
sudo ln -sf /etc/systemd/system/dhclient.service \
"${debootstrap_dir}/etc/systemd/system/multi-user.target.wants/dhclient.service"
fi
if [ ! -f "$img_file" ]; then
# Create disk image
dd if=/dev/null of="$img_file" bs=1M seek=2048
mkfs.ext4 "$img_file"
mnt_dir="${suite}_mnt"
mkdir "$mnt_dir"
sudo mount -t ext4 "$img_file" "$mnt_dir"
sudo cp -r "$debootstrap_dir/." "$mnt_dir"
sudo umount "$mnt_dir"
rmdir "$mnt_dir"
fi
sudo qemu-system-x86_64 \
-append 'console=ttyS0 root=/dev/sda' \
-drive "file=${img_file},format=raw" \
-enable-kvm \
-nographic \
-serial mon:stdio \
-m 2G \
-kernel "$kernel" \
-initrd "$initrd" \
;
피드 구독하기:
글 (Atom)