# 2019q1 Homework2 (fibdrv)
> contributed by < ```shihyuuuuuuu``` >
> [作業要求](https://hackmd.io/s/SJ2DKLZ8E)
## 實驗環境
```
$ uname -a
Linux shihyu 4.18.0-16-generic #17~18.04.1-Ubuntu SMP Tue Feb 12 13:35:51 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
```
## 核心模組相關
- 副檔名為 .ko
- insmod: 將模組載入到核心中
- rmmod: 將模組從核心移除
- modinfo: 列出該模組的相關資訊(例如: license, description, author...)
- lsmod: 列出已經載入到核心中的模組,會顯示模組名稱( Module )、模組的大小( size )、相依性( Used by )
參考:[鳥哥](http://linux.vbird.org/linux_basic/0510osloader.php#kernel)
## 自我檢查清單
- **檔案 `fibdrv.c` 裡頭的 `MODULE_LICENSE`, `MODULE_AUTHOR`, `MODULE_DESCRIPTION`, `MODULE_VERSION` 等巨集做了什麼事,可以讓核心知曉呢?**
在 linux 原始碼 [/include/linux/module.h](https://elixir.bootlin.com/linux/v4.18/source/include/linux/module.h) 中搜尋`MODULE_LICENSE` 、`MODULE_AUTHOR` 、 `MODULE_DESCRIPTION` 、 `MODULE_VERSION` 等巨集,可以找到以下四巨集:
```clike=199
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
```
```clike=205
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
```
```clike==208
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
```
```clike=237
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
```
可以發現這些巨集的參數都被傳到[同檔案](https://elixir.bootlin.com/linux/v4.18/source/include/linux/module.h)中的一個 `MODULE_INFO` 巨集:
```clike=161
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
```
再繼續找下去,可以在 [/include/linux/moduleparam.h](https://elixir.bootlin.com/linux/v4.18/source/include/linux/moduleparam.h#L21) 中找到巨集 ```__MODULE_INFO``` 的定義:
```clike=21
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
__used __attribute__((section(".modinfo"), unused, aligned(1))) \
= __stringify(tag) "=" info
```
一開始看不太懂這段在做什麼,參閱一些資料後才了解,在 .ko 檔案中有一個 '.modinfo' 區段是用來存放模組的資訊(也就是使用 ```modinfo``` 指令會顯示的資訊),而在程式碼中,我們就可以透過 '```MODULE_INFO```' 來加入這些資訊。
'```MODULE_INFO```' 會定義一個像是字典的 key-value 資料在 '.modinfo' 中,猜測是透過程式碼中的 ```__stringify(tag) "=" info``` 來達到。
**參考自:[Anatomy of the Linux loadable kernel module](http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2018/06/02/linux-loadable-module)**
原文:*".ko file will also contain a ‘.modinfo’ section which stores some of the module information. modinfo program can show these info. In the source code, one can **use ‘MODULE_INFO’ to add this information**."
"MODULE_INFO just **define a key-value data in ‘.modinfo’ section** once the MODULE is defined."*
:::info
**```__attribute__``` 用法:**
```__attribute__``` 可以對變量或結構等設定一些特別屬性,依據設定的對象可以分為三類:
1. 函數屬性( Function Attributes )
2. 變量屬性( Variable Attributes )
3. 類型屬性( Type Attributes )
語法:```__attribute__ ((attribute-list))```
若 attribute-list 有多個屬性則以逗號分隔。
而我認為在這邊是變量屬性,也就是對 ```__UNIQUE_ID(name) ``` 這個字元陣列做設定。
這邊設了三個屬性:
1. section(".modinfo"): 將此變量設定在特定區間中(在這邊為 ".modinfo" )
2. unused: 表示該變量可能未被使用
3. aligned(1): 設定變量的最小對齊格式為1 byte
**參考資料**
[5.31 Specifying Attributes of Variables](https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes)
[[轉]GNU C __attribute__ 機制簡介](http://huenlil.pixnet.net/blog/post/26078382-%5B%E8%BD%89%5Dgnu-c-__attribute__-%E6%A9%9F%E5%88%B6%E7%B0%A1%E4%BB%8B)
[Setting the license for modules in the linux kernel](https://stackoverflow.com/questions/11927590/setting-the-license-for-modules-in-the-linux-kernel)
:::
- **`insmod` 這命令背後,對應 Linux 核心內部有什麼操作呢?請舉出相關 Linux 核心原始碼並解讀**
[insmod(8) - Linux man page](https://linux.die.net/man/8/insmod): simple program to insert a module into the Linux Kernel
```insmod``` 這支程式功能是將一個模組嵌入 Linux 核心中,而在[這篇討論](https://www.quora.com/What-does-insmod-internally-do)中,有人說到 insmod 會調用 ```init_module``` 這個系統呼叫。
實際查看 [init_module 的 Man Page](https://linux.die.net/man/2/init_module),內有 ```init_module``` 和 ```finit_module```,兩者的功能都是 load a kernel module ,差別在於前者的參數是指向 "a buffer containing the binary image to be loaded", 而後者是指向一個 file descriptor 。
接著進入 Linux 原始碼中找到在 [kernel/module.c](https://elixir.bootlin.com/linux/v4.18/source/kernel/module.c#L3835) 中 ```init_module``` 的實做:
```clike=3835
SYSCALL_DEFINE3(init_module, void __user *, umod,
unsigned long, len, const char __user *, uargs)
{
int err;
...
return load_module(&info, uargs, 0);
}
```
再追蹤最後 return 的 ```load_module```,在 [/kernel/module.c](https://elixir.bootlin.com/linux/v4.18/source/kernel/module.c#L3654) 中,註解顯示它的功能大致上是為模組分配空間並載入:
```cpp=
/* Allocate and load the module: note that size of section 0 is always
zero, and we rely on this for optional sections. */
static int load_module(struct load_info *info, const char __user *uargs,
int flags){ ... }
```
:::success
**補充1**
在 [`johnnylord`](https://hackmd.io/s/rkLAuRs8V) 同學的開發紀錄中看到,使用 `strace` 可以紀錄某個process在執行時所產生的系統呼叫。實際執行結果如下:
```shell=
$ sudo strace insmod fibdrv.ko
[sudo] password for shihyu:
execve("/sbin/insmod", ["insmod", "fibdrv.ko"], 0x7ffcc5ede198 /* 27 vars */) = 0
brk(NULL) = 0x564e6e73e000
...
mmap(NULL, 8288, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f22ead02000
finit_module(3, "", 0) = 0
munmap(0x7f22ead02000, 8288) = 0
close(3) = 0
exit_group(0) = ?
+++ exited with 0 +++
```
確實看到了它有執行 `finit_module` 這個 system call 。
**補充2**
在 Github 上查看 `insmod` 的 [原始碼](https://github.com/vadmium/module-init-tools/blob/master/insmod.c),在第159行有看到 init_module 被呼叫。
```clike=159
ret = init_module(file, len, options);
```
:::
---
- **當我們透過 insmod 去載入一個核心模組時,為何 module_init 所設定的函式得以執行呢?Linux 核心做了什麼事呢?**
---
- **試著執行 `$ readelf -a fibdrv.ko`, 觀察裡頭的資訊和原始程式碼及 `modinfo` 的關聯,搭配上述提問,解釋像 `fibdrv.ko` 這樣的 ELF 執行檔案是如何「植入」到 Linux 核心**
---
- **這個 `fibdrv` 名稱取自 Fibonacci driver 的簡稱,儘管在這裡顯然是為了展示和教學用途而存在,但針對若干關鍵的應用場景,特別去撰寫 Linux 核心模組,仍有其意義,請找出 Linux 核心的案例並解讀。提示: 可參閱 [Random numbers from CPU execution time jitter](https://lwn.net/Articles/642166/)**
---
- **查閱 [ktime 相關的 API](https://www.kernel.org/doc/html/latest/core-api/timekeeping.html),並找出使用案例 (需要有核心模組和簡化的程式碼來解說)**
---
- **[clock_gettime](https://linux.die.net/man/2/clock_gettime) 和 [High Resolution TImers (HRT)](https://elinux.org/High_Resolution_Timers) 的關聯為何?請參閱 POSIX 文件並搭配程式碼解說**
- **`fibdrv` 如何透過 [Linux Virtual File System](https://www.win.tue.nl/~aeb/linux/lk/lk-8.html) 介面,讓計算出來的 Fibonacci 數列得以讓 userspace (使用者層級) 程式 (本例就是 `client.c` 程式) 得以存取呢?解釋原理,並撰寫或找出相似的 Linux 核心模組範例**
- **注意到 `fibdrv.c` 存在著 `DEFINE_MUTEX`, `mutex_trylock`, `mutex_init`, `mutex_unlock`, `mutex_destroy` 等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題**
- **許多現代處理器提供了 [clz / ctz](v) 一類的指令,你知道如何透過演算法的調整,去加速 [費氏數列](https://hackmd.io/s/BJPZlyDSV) 運算嗎?請列出關鍵程式碼並解說**