# 2019q1 Homework2 (fibdrv)
contributed by < `yiwei01` >
###### tags: `sysprog2019`
## Linux 核心版本
```shell
$ uname -r
4.15.0-46-generic
```
## 自我檢查清單
- [ ] 檔案 fibdrv.c 裡頭的 MODULE_LICENSE, MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_VERSION 等巨集做了什麼事,可以讓核心知曉呢? insmod 這命令背後,對應 Linux 核心內部有什麼操作呢?請舉出相關 Linux 核心原始碼並解讀
在 [/linux/module.h](https://github.com/torvalds/linux/blob/master/include/linux/module.h) 可發現 ```MODULE_LICENSE``` , ```MODULE_AUTHOR``` , ```MODULE_DESCRIPTION``` 這些 Macro 又展開了 ```MODULE_INFO``` 這個 Macro
```clike
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
/*
* Author(s), use "Name <email>" or just "Name", for multiple
* authors use multiple MODULE_AUTHOR() statements/lines.
*/
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
/* What your module does. */
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
```
而 ```MODULE_INFO``` 的定義如下
```clike=
/* Generic info of form tag = "info" */
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
```
接著再到 [linux/moduleparam.h](https://github.com/torvalds/linux/blob/master/include/linux/moduleparam.h) 可發現 ```__MODULE_INFO``` 的定義
```clike=
#ifdef MODULE
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
__used __attribute__((section(".modinfo"), unused, aligned(1))) \
= __stringify(tag) "=" info
#else /* !MODULE */
/* This struct is here for syntactic coherency, it is not used */
#define __MODULE_INFO(tag, name, info) \
struct __UNIQUE_ID(name) {}
#endif
```
一一剖析程式碼:
#### static const char __UNIQUE_ID(name)[]
在 [include/linux/compiler-clang.h](https://github.com/torvalds/linux/blob/bb617b9b4519b0cef939c9c8e9c41470749f0d51/include/linux/compiler-clang.h) 中可找到 ```__UNIQUE_ID``` 的定義
```clike=
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
```
再到 [include/linux/compiler_types.h](https://github.com/torvalds/linux/blob/9105b8aa50c182371533fc97db64fc8f26f051b3/include/linux/compiler_types.h) 可知 ```__PASTE``` 可以 concatenate Macro 的兩個 arguments (詳見下方 ```__stringify```)
```clike=
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
```
#### __used \_\_attribute\_\_((section(".modinfo"), unused, aligned(1)))
參考 [Specifying Attributes of Variables](https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes) 可知,
#### __stringify(tag)
在 [linux/stringify.h](https://github.com/torvalds/linux/blob/master/tools/include/linux/stringify.h) 中可找到定義
```clike
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_STRINGIFY_H
#define __LINUX_STRINGIFY_H
/* Indirect stringification. Doing two levels allows the parameter to be a
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
* converts to "bar".
*/
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
#endif /* !__LINUX_STRINGIFY_H */
```
在分析 Linux 原始碼之前,先透過一些簡單的程式碼確認 ```#``` 和 ```##``` 的功能
程式碼一:
```clike
#include <stdio.h>
#define str(s) #s
#define concat(a,b) a##b
int main()
{
int apple = 5;
printf("Hello "str(World)"\n"); // 形同 printf("Hello ""World""\n");
printf("%d\n", concat(app,le)); // 形同 printf("%d\n",apple);
return 0;
}
```
功能:
1.使用 ```#``` 把 Macro 的 argument 變為一個字串
2.使用 ```##``` concatenate Macro 的兩個 arguments
程式碼二:
```clike=
#include<stdio.h>
#define five 5
#define _str(s) #s
#define str(s) _str(s)
int main()
{
printf("%d\n",five); // 5
printf(str(five)"\n"); // 5
printf(_str(five)"\n"); // five
return 0;
}
```
原理:
只要是 Macro 的定義裡有用 ```#``` 或 ```##``` , 則 Macro 的 auguments 並不會再展開,因此利用第一層的 Macro 先把 Arguments 展開,再展開第二個 Macro,便可以將 Macro 也作為 Arguments 。這也是為什麼在 [linux/stringify.h](https://github.com/torvalds/linux/blob/master/tools/include/linux/stringify.h) 中註解寫道 : " Doing two levels allows the parameter to be a macro itself. "
reference :
[MODULE_AUTHOR巨集(一)](https://www.itread01.com/content/1541866804.html)
- [ ] 當我們透過 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
- [ ] 查閱 ktime 相關的 API,並找出使用案例 (需要有核心模組和簡化的程式碼來解說)
- [ ] clock_gettime 和 High Resolution TImers (HRT) 的關聯為何?請參閱 POSIX 文件並搭配程式碼解說
- [ ] fibdrv 如何透過 Linux Virtual File System 介面,讓計算出來的 Fibonacci 數列得以讓 userspace (使用者層級) 程式 (本例就是 client.c 程式) 得以存取呢?解釋原理,並撰寫或找出相似的 Linux 核心模組範例
- [ ] 注意到 fibdrv.c 存在著 DEFINE_MUTEX, mutex_trylock, mutex_init, mutex_unlock, mutex_destroy 等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題
- [ ] 許多現代處理器提供了 clz / ctz 一類的指令,你知道如何透過演算法的調整,去加速 費氏數列 運算嗎?請列出關鍵程式碼並解說