카테고리

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

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

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

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

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

우분투 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를 제공하므로 그래픽이 가속되지 않은 것으로 보임.

pdf 파일 편집

설치:
sudo apt-get install libreoffice
libreoffice my.pdf

페이지 삭제
페이지 순서 변경
기존 텍스트 필드
새 텍스트 필드 추가 
텍스트 필드가 아닌 객체 편집(머리글, 바닥글, 행)
채울 수있는 PDF 양식 생성(양식 * 도구 모음 사용 및 "PDF 양식 만들기" 선택)

일부 PDF 형식 지원 문제점 있음.

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

wifi tui 대화형 설정.

콘솔 환경에서 대화형 방식으로 인터넷 설정.
shell> nmtui

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" \
;

2019/01/04

debootstrap arm64 qemu 설치

debootstrap arm64
1)
-- foreign 패키지 다운로드.
-- chroot 사용
-- --second-stage + QEMU 사용자 모드 에물레이션 사용.(binfmt_misc)

2) 커널 vfs 패닉
[    0.773665] Please append a correct "root=" boot option; here are the available partitions:
[    0.774033] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
파일 시스템 지원 확인.

CONFIG_VIRTIO_BLK=y

initrd에서 모듈이 로드되어야 하기 때문에 ISO 이미지를 사용해서 동작 시켜야 할 듯 함.

다른 유형의 파일시스템 유형을 사용하려고 시도했지만 커널 지원 문제가 있어, 커널 컴파일을 해야함.
-drive if= -M virt

데비안 계열 우분투 패키지 커널을 사용할 때 arm64 커널 빌드 명령어.
처음 빌드 시
export ARCH=arm64
export $(dpkg-architecture -aarm64); export CROSS_COMPILE=aarch64-linux-gnu-

fakeroot debian/rules clean
debian/rules build
fakeroot debian/rules binary

두번째 이상 빌드시.
rm debian/stamps/stamp-build*
debian/rules build
fakeroot debian/rules binary

커널 설정 옵션에서 개발자 모드를 활성화.
Ubuntu devs, CONFIG y

인터넷 동작 문제.
systemctl status dhclient.service
cat f

자동 설치 스크립트
#!/usr/bin/env bash

# https://askubuntu.com/questions/281763/is-there-any-prebuilt-qemu-ubuntu-image32bit-online/1081171#1081171

set -eux

debootstrap_dir=debootstrap
root_filesystem=debootstrap.ext2.qcow2

sudo apt-get install \
  gcc-aarch64-linux-gnu \
  debootstrap \
  libguestfs-tools \
  qemu-system-aarch64 \
  qemu-user-static \
;

if [ ! -d "$debootstrap_dir" ]; then
  sudo debootstrap \
    --arch arm64 \
    --foreign \
    bionic \
    "$debootstrap_dir" \
    http://ports.ubuntu.com/ubuntu-ports \
  ;
  sudo mkdir -p "${debootstrap_dir}/usr/bin"
  sudo cp "$(which qemu-aarch64-static)" "${debootstrap_dir}/usr/bin"
  sudo chroot "$debootstrap_dir" /debootstrap/debootstrap --second-stage
  sudo rm -f "$root_filesystem"
fi

linux_image="$(printf "${debootstrap_dir}/boot/vmlinuz-"*)"

if [ ! -f "$root_filesystem" ]; then
  # 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

  # https://askubuntu.com/questions/1045278/ubuntu-server-18-04-temporary-failure-in-name-resolution/1080902#1080902
  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 "${debootstrap_dir}/etc/systemd/system/dhclient.service" \
    "${debootstrap_dir}/etc/systemd/system/multi-user.target.wants/dhclient.service"

  # https://bugs.launchpad.net/ubuntu/+source/linux/+bug/759725
  sudo chmod +r "${linux_image}"

  # Generate image file from debootstrap directory.
  # Leave 1Gb extra empty space in the image.
  sudo virt-make-fs \
    --format qcow2 \
    --size +1G \
    --type ext2 \
    "$debootstrap_dir" \
    "$root_filesystem" \
  ;
  sudo chmod 666 "$root_filesystem"
fi

# 커널 컴파일.
linux_image="$(pwd)/linux/debian/build/build-generic/arch/arm64/boot/Image"
if [ ! -f "$linux_image" ]; then
  #git clone --branch Ubuntu-4.15.0-20.21 --depth 1 git://kernel.ubuntu.com/ubuntu/ubuntu-bionic.git linux
  cd linux
  cat << EOF | patch -p1
diff --git a/debian.master/config/config.common.ubuntu b/debian.master/config/config.common.ubuntu
index 5ff32cb997e9..8a190d3a0299 100644
--- a/debian.master/config/config.common.ubuntu
+++ b/debian.master/config/config.common.ubuntu
@@ -10153,7 +10153,7 @@ CONFIG_VIDEO_ZORAN_ZR36060=m
 CONFIG_VIPERBOARD_ADC=m
 CONFIG_VIRTIO=y
 CONFIG_VIRTIO_BALLOON=y
-CONFIG_VIRTIO_BLK=m
+CONFIG_VIRTIO_BLK=y
 CONFIG_VIRTIO_BLK_SCSI=y
 CONFIG_VIRTIO_CONSOLE=y
 CONFIG_VIRTIO_INPUT=m
EOF
  export ARCH=arm64
  export $(dpkg-architecture -aarm64)
  export CROSS_COMPILE=aarch64-linux-gnu-
  fakeroot debian/rules clean
  debian/rules updateconfigs
  fakeroot debian/rules DEB_BUILD_OPTIONS=parallel=`nproc` build-generic
  cd -
fi

#linux_image=/home/ciro/bak/git/linux-kernel-module-cheat/out/linux/default/aarch64/arch/arm64/boot/Image
#linux_image=/home/ciro/bak/git/linux-kernel-module-cheat/submodules/linux/debian/build/build-generic/arch/arm64/boot/Image
qemu-system-aarch64 \
  -append 'console=ttyAMA0 root=/dev/vda rootfstype=ext2' \
  -device rtl8139,netdev=net0 \
  -drive "file=${root_filesystem},format=qcow2" \
  -kernel "${linux_image}" \
  -m 2G \
  -netdev user,id=net0 \
  -serial mon:stdio \
  -M virt,highmem=off \
  -cpu cortex-a57 \
  -nographic \
;

Linux 커널 exec의 시스템 호출 ELF 방식에서 스크립트 언어 #! 인식 shebang 지정.

Linux 커널 exec의 시스템 호출 #! 인식 shebang 지정.
#! 사람이 읽기 편하도록 구성한다는 의미(스크립트 언어)

./something

리눅스 커널 소스
linux/fs/binfmt_script.c

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
바이트를 읽은  후 비교.

참이면 커널에서 파싱.
경로 /usr/bin/env python 첫 번째 인수 사용하여 또 다른 exec 호출 생성.
/usr/bin/env python /path/to/script.py

#주석 문자 사용하는 모든 스크립팅 언어에서 동작 함.

무한 루프도 만들 수 있음.
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

bash 오류 인식
-bash: /a: /a: bad interpreter: Too many levels of symbolic links

ELF 실행 파일
linux/fs/binfmt_elf.c
magic.elfmag[EI_MAG0] = ELFMAG0;
바이트 검사. 7f 45 4c 46, 사람이 읽을 수 있으나 이해 하려면 시간이 걸림.
EFL 형식의 파일을 읽고, 메모리에 정확하게 넣고, 새로운 프로세스 시작.

debootstrap이란?

debootstrap이란?

x86 시스템에서 임베디드 ARM 또는 PowerPC 시스템용 데비안/우분투를 설치를 의미, 조금더 큰 의미에서는 네트워 부팅도 여기에 속 할 수 있음, 요즘 클라우드 컴퓨팅 환경 구성이 과도기를 지나 완성도를 높이는 단계로 진입한 듯 함.

1. .deb 패키지 파일을 다운로드 받아 압축해제.
2. qemu-user-static 에물레이트 하기 위해 모든 패키지 구성 스크립트 실행

간단한 사용 예제.
우분투 18.04
sudo apt-get install \
  debootstrap \
  qemu-user-static \
;
debootstrap_dir=debootstrap
sudo debootstrap \
  --arch arm64 \
  --foreign \
  bionic \
  "$debootstrap_dir" \
  http://ports.ubuntu.com/ubuntu-ports \
;
sudo mkdir -p "${debootstrap_dir}/usr/bin"
sudo cp "$(which qemu-aarch64-static)" "${debootstrap_dir}/usr/bin"
sudo chroot "$debootstrap_dir" /debootstrap/debootstrap --second-stage
sudo rm -f "$root_filesystem"

리눅스 커널 컴파일 init/main.c 부팅시 메세지 출력

init/main.c

커널 소스 다운로드
git clone git://kernel.ubuntu.com/ubuntu/ubuntu-bionic.git
cd ubuntu-bionic

# 작업할 커널 소스버전 변경.
git checkout Ubuntu-4.15.0-20.21
fakeroot debian/rules clean
debian/rules updateconfigs
fakeroot debian/rules build-generic
linux_image="$(pwd)/debian/build/build-generic/arch/x86_64/boot/bzImage"

커널 정보 추출 확인.
https://nautiluslee.blogspot.com/2019/01/config.html

패치 적용
diff --git a/init/main.c b/init/main.c
index b8b121c17ff1..542229349efc 100644
--- a/init/main.c
+++ b/init/main.c
@@ -516,6 +516,8 @@ asmlinkage __visible void __init start_kernel(void)
        char *command_line;
        char *after_dashes;

+ pr_info("I'VE Hae Nam Korea Linux Love man!!!");
+
        set_task_stack_end_magic(&init_task);
        smp_setup_processor_id();
        debug_objects_early_init();

빌드
fakeroot debian/rules build-generic

부팅 메시지 출력
I'VE Hae Nam Korea Linux Love man

Kernel: arch/x86/boot/bzImage is ready  (#3)

우분투 커널 .config 환경 설정 부분 확인 및 추출 방법.

우분투 커널 .config 파일 관련

우분투 git 커널 저장소

debian/config 커널 트리 메타 데이터 git 저장소
https://kernel.ubuntu.com/git/ubuntu/ubuntu-bionic.git/

우분투 18.04 linux-image-4.15.0-36-generici 커널 패키지에 대한 태크 정보는 Ubuntu-4.15.0-36.39.

config 파일 저장소
https://kernel.ubuntu.com/git/ubuntu/ubuntu-bionic.git/tree/debian.master/config?h=Ubuntu-4.15.0-36.39

config.common.ubuntu, config.common.amd64, config.flavour.generic 병합 linux-image-4.15.0-36-generic 커널 패키지가 나옴.

병합하는 스크립트
https://kernel.ubuntu.com/git/ubuntu/ubuntu-bionic.git/tree/debian/scripts/misc/kernelconfig?h=Ubuntu-4.15.0-36.39

# Merge configs
# We merge config.common.ubuntu + config.common.<arch> +
# config.flavour.<flavour>

아키텍쳐 별 구성 파일.
https://kernel.ubuntu.com/git/ubuntu/ubuntu-bionic.git/tree/debian.master/config/annotations?h=Ubuntu-4.15.0-36.39

환경 설정없이 컴파일
git clone git://kernel.ubuntu.com/ubuntu/ubuntu-bionic.git linux
cd linux
git checkout Ubuntu-4.15.0-36.39
fakeroot debian/rules clean
debian/rules updateconfigs
fakeroot debian/rules build-generic

현재 커널 설정 내용과 차이점 비교.
diff debian/build/build-generic/.config /boot/config-4.15.0-36-generic

.deb 파일 구성
최종 커널 환경 설정 값
/boot/config-4.15.0-36-generic

커널 이미지
/boot/vmlinuz-4.15.0-36-generic

패키지 버전 확인
dpkg -S /boot/config-4.15.0-36-generic

패키지 파일은 다음 내용을 제공 함.
linux-modules-4.15.0-36-generic: /boot/config-4.15.0-36-generic

패키지 정보 목록 확인
https://packages.ubuntu.com/bionic-updates/linux-modules-4.15.0-36-generic

환경 구성 파일 추출
mkdir config
cd config
wget http://mirrors.kernel.org/ubuntu/pool/main/l/linux/linux-modules-4.15.0-36-generic_4.15.0-36.39_amd64.deb
ar x linux-modules-4.15.0-36-generic_4.15.0-36.39_amd64.deb
tar -xvf data.tar.xz
cat ./boot/config-4.15.0-36-generic

debootstrap amd64 전체 이미지 파일 구성 qemu

debootstrap amd64
모든 패키지 다운로드 구성
#!/usr/bin/env bash
# https://askubuntu.com/questions/281763/is-there-any-prebuilt-qemu-ubuntu-image32bit-online/1081171#1081171

set -eux

debootstrap_dir=debootstrap
root_filesystem=debootstrap.ext2.qcow2

sudo apt-get install \
  debootstrap \
  libguestfs-tools \
  qemu-system-x86 \
;

if [ ! -d "$debootstrap_dir" ]; then
  # Create 디렉토리 생성.
  # - linux-image-generic: /boot 사용할 커널 이미지 다운로드
  # - network-manager: 부팅시 네트워크 사용
  sudo debootstrap \
    --include linux-image-generic \
    bionic \
    "$debootstrap_dir" \
    http://archive.ubuntu.com/ubuntu \
  ;
  sudo rm -f "$root_filesystem"
fi

linux_image="$(printf "${debootstrap_dir}/boot/vmlinuz-"*)"

if [ ! -f "$root_filesystem" ]; then
  # Set root password.
  echo 'root:root' | sudo chroot "$debootstrap_dir"  chpasswd

  # 루투 파일시스템 rw 모드로 마운팅.
  cat << EOF | sudo tee "${debootstrap_dir}/etc/fstab"
/dev/sda / ext4 errors=remount-ro,acl 0 1
EOF

  # 네트워크 시작.
  # 네트워크 명령어 입력 실패시 :
  #    일시적 실패....
  # https://askubuntu.com/questions/1045278/ubuntu-server-18-04-temporary-failure-in-name-resolution/1080902#1080902
  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 "$debootstrap_dir/etc/systemd/system/dhclient.service" \
    "${debootstrap_dir}/etc/systemd/system/multi-user.target.wants/dhclient.service"

  # https://bugs.launchpad.net/ubuntu/+source/linux/+bug/759725
  sudo chmod +r "${linux_image}"

  # debootstrap 디렉토리에 이미지 파일 생성.
  # 1Gb 공간 남겨둔.
  sudo virt-make-fs \
    --format qcow2 \
    --size +1G \
    --type ext2 \
    "$debootstrap_dir" \
    "$root_filesystem" \
  ;
  sudo chmod 666 "$root_filesystem"
fi

qemu-system-x86_64 \
  -append 'console=ttyS0 root=/dev/sda' \
  -drive "file=${root_filesystem},format=qcow2" \
  -enable-kvm \
  -serial mon:stdio \
  -m 2G \
  -kernel "${linux_image}" \
  -device rtl8139,netdev=net0 \
  -netdev user,id=net0 \
;

login: root
pw: root

인터넷 동작 확인
wget그리고 curl기본적으로 설치되지 않기 때문에 다음 명령어로 인터넷 동작 확인
ping 또한 qemu에서 기본적으로 동작 하지 않음.

printf 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n' | nc example.com 80
apt-get update
apt-get install hello
hello

UEFI Cloud image arm64

UEFI Cloud image arm64
sudo apt-get install qemu-efi

자동 스크립트
vi uefi_cloud_image.sh

#!/usr/bin/env bash
set -eux

#sudo apt-get install cloud-image-utils qemu-system-arm qemu-efi

# 이미지 다운로드.
img=ubuntu-18.04-server-cloudimg-arm64.img
if [ ! -f "$img" ]; then
  wget "https://cloud-images.ubuntu.com/releases/18.04/release/${img}"
  qemu-img resize "$img" +60G
fi

# 암호 설정.
user_data=user-data.img
if [ ! -f "$user_data" ]; then
  cat >user-data <<EOF
#cloud-config
password: totoro
chpasswd: { expire: False }
ssh_pwauth: True
EOF
  cloud-localds "$user_data" user-data

  # EFI 사용:
  # https://wiki.ubuntu.com/ARM64/QEMU
  dd if=/dev/zero of=flash0.img bs=1M count=64
  dd if=/usr/share/qemu-efi/QEMU_EFI.fd of=flash0.img conv=notrunc
  dd if=/dev/zero of=flash1.img bs=1M count=64
fi

qemu-system-aarch64 \
  -M virt \
  -cpu cortex-a57 \
  -device rtl8139,netdev=net0 \
  -m 4096 \
  -netdev user,id=net0 \
  -nographic \
  -smp 4 \
  -drive "if=none,file=${img},id=hd0" \
  -device virtio-blk-device,drive=hd0 \
  -drive "file=${user_data},format=raw" \
  -pflash flash0.img \
  -pflash flash1.img \
;

login: ubuntu 
pw:totoro

ubuntu wayland manager qemu kvm 활성화

Unable to init server: Could not connect: Connection refused 

사용자 추가(sudo GUI + terminal)
xhost -si:localuser:root

$ xhost +si:localuser:root

GL에서 GPU 장치 선택

GL에서 GPU 장치 선택

OpenGL 자체가 렌더링 API임.
GLX, WGL, EGL과 같은 윈도우 시스템 바인딩 API는 수 많은 세월에 거쳐 만들어짐.
멀티 GPU 시스템이 찾기 어려웠던 시대...

멀티 GPU API는 제조사 마다 다르지만 MESA 솔루션의 DRI_PRIME를 통해 발전함.

DRI_PRIME란?
초창기의 DRI_PRIME는 2개의 GPU에서 동작 하도록 정의한 환경 변수.
응용 프로그램 호출하기 전에 1로 설정하면 GL 스택이 X서버로 쿼리하고 시스템에 있는 다른 GPU를 사용.

이러한 방법으르로 초기에 발전 함.
- 시스템에 GPU가 3개 이상 있을때?
- x 서버가 없는 시스템일 때?
- 응용 프로그램 개발시 사용할 GPU를 어떻게 선택해 사용할 것인가?

사용자 ID_PATH_TAG가 udev에서 제공 한대로 DRI_PRIME 장치를 나열하여 선택할 수 있다.
EGL의 확장 가능구조 덕분에 EGLDevice 계열의 확장을 통해 해결할 수 있음.

EGLDevice 입력
EGL_EXT_device_base 확장 측면에서 구현된 EGL_EXT_device_enumeration 및 EGL_EXT_device_query.

EGLDevice는 장치고유 속성을 나열해 질문하는 수단 인 EGLDevice의 개념 정의.
또 다른 두 개의 확장 EGL_EXT_device_drm 및 EGL_MESA_device_software은

각각의 하드웨어 DRM 장치 노드 및 소프트웨어와 백업 장치 정의
- 메사로 사용해 GL 구현.

사용 사례
확장 세트를 사용하려면 어떤 장치를 사용할지 명시 적으로 선택한다

그래픽 서버/윈도우 메이지먼트는 전력 소모가 적은 장치로 렌더링한다.
webGL 신뢰할 수 없는 장치로 분류 할 수 있고, 시간 기준으로 GPU 작업을 처리한다.

구현 상태

EGL_EXT_device_base- 구현 모두 EGL_EXT_device_enumeration와EGL_EXT_device_query
EGL_EXT_device_drm
EGL_MESA_device_software
EGL_EXT_platform_device

Cloud image amd64

1. Cloud image amd64
데스크탑 시스템 설치없이 직접 부팅 할 수있는 이미지임.
이게 가능한 이유는 https://help.ubuntu.com/community/CloudInit
여기 사이트에 설명 되어 있음.

즉 init 개념을 -> Cloudint 개념을 추가해 부팅 시퀀서를 만듬.

이미지 생성 스크립트
vi upstream.sh
#!/usr/bin/env bash

sudo apt-get install cloud-image-utils qemu qemu-system qemu-system-x86

# qcow2 형식.
img=ubuntu-18.04-server-cloudimg-amd64.img
if [ ! -f "$img" ]; then
  wget "https://cloud-images.ubuntu.com/releases/18.04/release/${img}"

  # sparse resize: 추가 공간을 사용하지 않고 나중 크기 변경 허용.
  # https://superuser.com/questions/1022019/how-to-increase-size-of-an-ubuntu-cloud-image
  qemu-img resize "$img" +128G
fi

user_data=user-data.img
if [ ! -f "$user_data" ]; then
  # 암호.
  # https://serverfault.com/questions/920117/how-do-i-set-a-password-on-an-ubuntu-cloud-image
  # https://askubuntu.com/questions/507345/how-to-set-a-password-for-ubuntu-cloud-images-ie-not-use-ssh
  cat >user-data <<EOF
#cloud-config
password: totoro
chpasswd: { expire: False }
ssh_pwauth: True
EOF
  cloud-localds "$user_data" user-data
fi

qemu-system-x86_64 \
  -drive "file=${img},format=qcow2" \
  -drive "file=${user_data},format=raw" \
  -device rtl8139,netdev=net0 \
  -enable-kvm \
  -m 2G \
  -netdev user,id=net0 \
  -serial mon:stdio \
  -smp 2 \
  -vga virtio \
;
:wq

QEMU 시작 후 부트 메뉴가 나타나면, 엔터 입력.

부트 메시지
error: no such device: root.

Press any key to continue...

특정 시간이 지나면 자동 부팅 됨.

사용자 이름: ubuntu
암호: totoro

인터넷 동작 확인.

callback test

/*
 * Callback.c - 연결 목록 콜백 구현
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct NODE {
struct NODE *link;
int data;
}Node;

Node **create_sll(const int);
void insert_data(Node **);
void show_list(Node **);
void sort_list(Node **);

int compare_ints(void const *, void const *); /* 프로토타입 함수 */
Node *search_list(Node *, void const *, int(void const *, void const *)); /* 프로토타입 */

int main(void){
int (*compare)(void const *, void const *) = compare_ints;

int value, val2find;
int nodes; /* 노트 카운트 */
Node **rootp; /* 루투 위치 */
Node *desired_node;

puts("\n**Program creates Singly Linked List**");
puts("**And allows users to perform various operations on the"
"list**\n");
puts("User, specify number of nodes in the list, in range 1"
" through some positive no.");
scanf("%d", &nodes);

rootp = create_sll(nodes);

printf("Les's insert %d integers in the list...\n", nodes);
insert_data(rootp);

puts("**Les's show up the list**");
show_list(rootp);

puts("Let's sort the list, in ascending order...");
sort_list(rootp);
puts("Let's show up the list**");
show_list(rootp);

puts("**Let's use Callback() function**");
printf("User, enter an integer you want to see into the "
"Singly Linked List...\n");
scanf("%d", &val2find);

/* 콜밸 함수 호출 */
desired_node = search_list(*rootp, &val2find, compare);

if(desired_node != NULL)
puts("Desired value is found.");
else
puts("Desired value NOT found.");
return 0;
}

Node *search_list(Node *node, void const *value, int compare(void const *, void const *)){
while(node != NULL){
if(compare(&node->data, value) == 0)
break;
node = node->link;
}

return node;
}

int compare_ints(void const *p2nv, void const *p2v){
if(*(int *)p2nv == *(int *)p2v)
return 0;
else
return 1;
}

Node **create_sll(const int nodes){
int i;
Node *current;
static Node *root;
Node **rootp = &root;

root = (Node *)malloc(nodes * sizeof(Node));

if(root == NULL){
puts("Error: Not Enough Memory!");
exit(1);
} else {
current = root;

for(i = 1; i <= nodes; i++){
if(i == nodes) {
current->link = NULL;
} else {
current->link = current + 1;
current++;
}
}
printf("List with %d nodes created successfully!\n", nodes);
puts("");
}
return rootp;
}

void insert_data(Node **linkp){
Node *next = *linkp;
Node *current;

do {
current = next;
scanf("%d", &(current->data));
next = current->link;
}while(current->link != NULL);
puts("");
}

void show_list(Node **linkp){
Node *next = *linkp;
Node *current;

do{
current = next;
printf("%d", current->data);
next = current->link;
}while(current->link != NULL);
puts("\n");
}

void sort_list(Node **linkp){
int temp;
Node *current = *linkp;
Node *next = current->link;

while(current->link != NULL){
while(next != NULL){
if(current->data > next->data){
temp = next->data;
next->data = current->data;
current->data = temp;
}
next = next->link;
}
current = current->link;
next = current->link;
}
}
/*
 * ./callback

**Program creates Singly Linked List**
**And allows users to perform various operations on thelist**

User, specify number of nodes in the list, in range 1 through some positive no.
5
List with 5 nodes created successfully!

Les's insert 5 integers in the list...
32
53
1
08
0556

**Les's show up the list**
325318556

Let's sort the list, in ascending order...
Let's show up the list**
183253556

**Let's use Callback() function**
User, enter an integer you want to see into the Singly Linked List...
53
Desired value is found */