# Linux Kernel 5.5.1 Build
###### tags: `Linux`
## Development environment
* Host
* Ubuntu 18.04.1 x86_64
* Linux ubuntu 5.3.0-46-generic
* Guest
* Linux-5.5.1
* busybox-1.31.0
* QEMU emulator version 2.11.1
* Directory Hierarchy:
~/tmp
|--linux-5.5.1
|--busybox-1.31.0
---
## Prerequisites
```bash=
$ sudo apt-get install qemu qemu-system -y
$ sudo apt-get install libncurses5-dev build-essential -y
$ sudo apt-get install flex bison -y
$ sudo apt-get install bridge-utils -y
```
* `qemu` : 是一個免費的虛擬機軟體,QEMU的架構由純軟體實現,並在Guest與Host中間,來處理Guest的硬體請求,並由其轉譯給真正的硬體。
* `libncurses5-dev` : 是一個`ncurses`開發函式庫,可以允許程式設計師編寫獨立於終端的基於文字的使用者介面。
* `build-essential` : 提供必要的編譯環境。
* `flex` : 提供語意分析(編譯會用到)。
## Linux kernel (x86_64)
### Linux kernel source code (v5.5.1)
```bash=
$ wget https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.5.1.tar.gz
$ tar -xvf linux-linux-5.5.1.tar.gz
```
### Configuration
> 在編譯你的kernel前,可以先選擇哪些功能你需要或者不需要,以下是兩種方法的範例。
```bash=
$ cd linux-5.5.1/
# method 1
$ make menuconfig # GUI
# method 2
$ vim .config
```
* Method1
```bash=
KernelHacking -->
[*]Compile the kernel with debug info
[*]Compile the kernel with frame pointers
[ ]Write protect kernel read-only data structures
Processor type and features-->
[ ]Paravirtualized guest support
# This make debugging easier
[ ] Randomize the address of the kernel image (KASLR)
[ ] Compile also drivers which will not load
[x] Optimize for size (-Os)
```
* Method2
> 選這個的目的是為了後面的網路功能,要先給他配一張網卡。
```bash=
CONFIG_PCI=y # by default
CONFIG_E1000=y
```
### Compile kernel
```bash=
$ make -j8 ARCH=x86_64
```
> 如果編譯成功在這個目錄下會有這個檔案`arch/x86_64/boot/bzImage`
## Root File system
### Busybox source code
```bash=
$ wget https://busybox.net/downloads/busybox-1.31.0.tar.bz2
$ tar -xvf busybox-1.31.0.tar.bz2
```
### Compile Busybox
```bash=
$ cd busybox-1.31.0/
$ make menuconfig
Settings -> Build Options -->
[*] Build Busybox as a static binary
$ make -j8 install
```
> 當你編譯完成,會出現一個 **_install**。
### Setting file system
```bash=
$ cd _install
$ mkdir proc sys dev etc etc/init.d
$ vim etc/init.d/rcS # write a script
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
$ chmod +x etc/init.d/rcS
```
* `/proc` : 在`/proc`底下會有很多`process`的資訊,還有`memory`、`disk`等等資訊。
* `sys` : 在`/sys`底下則放一些`HW device`的驅動資訊
* `etc/init.d/rcS` : 這個`rcS`當做是`file system`剛啟動時的`init script`
* `/sbin/mdev -s` : mdev(Busybox簡化版的udev),`udev`是linux的裝置管理器。它主要的功能是管理/dev目錄底下的裝置節點。(若無這個會發生**can't open /dev/tty2,3,4**的bug)
### Pack
```bash=
$ find . | cpio -o --format=newc > ../rootfs.img
```
* `cpio` : 用於將files打包成一個package,這邊我們用來打包我們的檔案系統。(newc 是支援大於`65536 inode`的文件系統格式)
## Start up~
```bash=
$ cd linux-linux-5.5.1/
$ qemu-system-x86_64 -m 1024 -kernel arch/x86_64/boot/bzImage -initrd ../busybox-1.31.0/rootfs.img -append "root=/dev/ram rdinit=/sbin/init"
```
* `vmlinux` : 編譯出來的kernel,沒壓縮(debug時會用到)
* `bzImage` : 由`vmlinux`用gzip壓縮後
* `initrd` : 又稱`initrd ramdisk`是一個臨時檔案系統,掛載在/dev/ram,它在啟動階段被Linux kernel呼叫,initrd主要用於當`root file system`被掛載之前,進行準備工作
* `append` : 附加kerenl啟動參數
* `root` : 用哪個目錄當作`root file system`
* `rdinit` : kernel載入後,用`initrd`指定的路徑,創造第一個process
* `nographic` : 不使用GUI介面,使用tty介面(terminal)
* `-s -S` : 給gdb remote用,綁在port 1234

## Run a process on your kernel with QEMU
* C code
```c=
#include <stdio.h>
int main()
{
printf("hello QEMU\n");
return 0;
}
```
* Method1
> 使用`-static`編譯,原因是剛剛製作的`file system`不帶任何`library`所以直接用`靜態編譯`。
```bash=
$ gcc hello.c -o hello -static
```
* Method2
> 將他所需要的`library`複製過來即可。
```bash=
$ gcc hello.c -o hello
$ ldd hello
linux-vdso.so.1 (0x00007ffecb0ef000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff3d40d1000) # library
/lib64/ld-linux-x86-64.so.2 (0x00007ff3d46c4000) # linker
$ mkdir -p ./lib/x86_64-linux-gnu/ ./lib64
$ cp /lib/x86_64-linux-gnu/libc.so.6 ./lib/x86_64-linux-gnu/
$ cp /lib64/ld-linux-x86-64.so.2 ./lib64
```
## Network (bridge)
* Add a bridge
```bash=
$ sudo brctl addbr br0
$ sudo brctl addif br0 ens33
$ sudo ifconfig br0 up
$ sudo ifconfig br0 <IP>
```
* Setting a qemu bridge helper
```bash=
$ mkdir /etc/qemu
$ vim /etc/qemu/bridge.conf
allow br0
```
* Enable IPv4 forwarding
```script=
$ sudo -i
# echo 1 > /proc/sys/net/ipv4/ip_forward
```
## Start up with QEMU network parameters
```bash=
$ sudo qemu-system-x86_64 -m 1024 -kernel arch/x86_64/boot/bzImage -initrd ../busybox-1.31.0/rootfs.img -append "root=/dev/ram rdinit=/sbin/init" -net nic -net bridge,br=br0
```
### Setting Network in QEMU
* 檢查網卡是否存在

* 給網卡一個IP

* Ping主機,檢查是否有通

* 設定路由,並且檢查是否有通到WAN

## Reference
* http://pwn4.fun/2017/04/17/Linux%E5%86%85%E6%A0%B8%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%EF%BC%88%E4%B8%80%EF%BC%89%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/
* https://www.cnblogs.com/hac425/p/9416886.html
* https://blog.csdn.net/ytusdc/article/details/77980915
* https://jacobpan3g.github.io/cn/2017/09/01/solve-kernel2.6.36-build-error-in-ubuntu16.04/
* https://zhuanlan.zhihu.com/p/105069730
* https://www.cnblogs.com/senix/archive/2013/02/21/2921221.html
* https://zh.wikipedia.org/wiki/Initrd
* https://github.com/OP-TEE/build/issues/103
* https://www.cnblogs.com/pengdonglin137/p/3328889.html
* https://wiki.qemu.org/Documentation/Networking
* [kernel debug](https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-debugging.html)