---
title: Firmadyne MIPS kernel-v2.6.32 procfs_stubs.c
tags: firmadyne
lang: zh_tw
---
---
# Firmadyne MIPS kernel-v2.6.32 procfs_stubs.c
Source Code: https://github.com/firmadyne/kernel-v2.6.32/blob/firmadyne-v2.6.32.70/drivers/firmadyne/procfs_stubs.c
紀錄追 Code 過程
---
**目錄:**
[TOC]
## procfs vs initramfs
參考: [procfs wiki](https://zh.wikipedia.org/wiki/Procfs)
> 在許多類 Unix 電腦系統中, procfs 是 行程 (process) 檔案系統 (file system) 的縮寫,包含一個偽檔案系統(啟動時動態生成的檔案系統),用於通過核心存取行程資訊。這個檔案系統通常被掛載到 /proc 目錄。由於 /proc 不是一個真正的檔案系統,它也就不占用儲存空間,只是占用有限的記憶體。
procfs 是種存在於 RAM 的虛擬檔案系統。
參考: [鳥哥的 Linux 私房菜 -- 第十九章、開機流程、模組管理與 Loader](http://linux.vbird.org/linux_basic/0510osloader.php#startup_loader)
在 `載入核心偵測硬體與 initramfs 的功能` 一節中提到
> 一般來說,非必要的功能且可以編譯成為模組的核心功能,目前的 Linux distributions 都會將他編譯成為模組。 因此 USB, SATA, SCSI... 等磁碟裝置的驅動程式通常都是以模組的方式來存在的。
> 問題是,核心根本不認識 SATA 磁碟,所以需要載入 SATA 磁碟的驅動程式, 否則根本就無法掛載根目錄。但是 SATA 的驅動程式在 /lib/modules 內,你根本無法掛載根目錄又怎麼讀取到 /lib/modules/ 內的驅動程式
> 虛擬檔案系統 (Initial RAM Disk 或 Initial RAM Filesystem) 一般使用的檔名為 /boot/initrd 或 /boot/initramfs ,這個檔案的特色是,他也能夠透過 boot loader 來載入到記憶體中,然後這個檔案會被解壓縮並且在記憶體當中模擬成一個根目錄, 且此模擬在記憶體當中的檔案系統能夠提供一支可執行的程式,透過該程式來載入開機過程中所最需要的核心模組, 通常這些模組就是 USB, RAID, LVM, SCSI 等檔案系統與磁碟介面的驅動程式啦!等載入完成後, 會幫助核心重新呼叫 systemd 來開始後續的正常開機流程。
我在想或許 procfs 的機制跟這幾段話有關。
所以小小姑狗了一下,兩者是否不同
參考: [ramfs, tmpfs, rootfs, initramfs的区别](https://woshijpf.github.io/%E5%86%85%E6%A0%B8/2017/06/14/ramfs-rootfs-initramfs%E7%9A%84%E5%8C%BA%E5%88%AB.html)
發現不一樣
procfs 是用來取得跟 process 有關的資訊 e.g. fd
也可以反過來輸入資訊給 process by 改掉裡面的檔案 e.g. [關閉 ASLR](https://askubuntu.com/questions/318315/how-can-i-temporarily-disable-aslr-address-space-layout-randomization)
而鳥哥寫的是 initramfs
> initramfs 是一种以 cpio 格式压缩后的 rootfs 文件系统
> 并启动内核之后,内核接着就对 cpio 格式的 initramfs 进行解压,并将解压后得到的 rootfs 加载进内存 ....
從這段話可以說明,initramfs 本身是 rootfs,且會被 kernel load 到 ram 中
兩者都是存在於 ram,但本質和目的不一樣
| | procfs | initramfs |
| -------- | -------- | -------- |
| 存在於 | ram | ram |
| 本質 | procfs | 壓縮過的 rootfs |
| 目的 | 與 processes 溝通 | 開機流程一環 |
## procfs_stubs.c
Line 9 定義了 Macro STUB_ENTRIES
裡頭有 Macro DIR、FILE
```c=9
#define STUB_ENTRIES \
FILE(blankstatus, read, write, NULL) \
FILE(btnCnt, read, write, NULL) \
FILE(br_igmpProxy, read, write, NULL) \
FILE(BtnMode, read, write, NULL) \
FILE(gpio, read, write, NULL) \
FILE(led, read, write, NULL) \
/* Used by "Firmware_TEW-435BRM_0121e.zip" (12973) */ \
FILE(push_button, read, write, NULL) \
FILE(rtk_promiscuous, read, write, NULL) \
FILE(rtk_vlan_support, read, write, NULL) \
FILE(RstBtnCnt, read, write, NULL) \
FILE(sw_nat, read, write, NULL) \
DIR(simple_config, NULL) \
FILE(reset_button_s, read, write, simple_config_dir) \
DIR(quantum, NULL) \
FILE(drv_ctl, read, write, quantum_dir) \
DIR(rt3052, NULL) \
DIR(mii, rt3052_dir) \
FILE(ctrl, read, write, mii_dir) \
FILE(data, read, write, mii_dir)
```
---
在 Line 59 ~ 70 展開 Macro
```c=59
#define DIR(a, b) \
static struct proc_dir_entry *a##_dir;
#define FILE(a, b, c, d) \
static const struct file_operations a##_fops = { \
.read = b, \
.write = c, \
};
STUB_ENTRIES
#undef FILE
#undef DIR
```
以 `DIR(mii, rt3052_dir)` 來說,會被展開為
```c
static struct proc_dir_entry *mii_dir;
```
以 `FILE(ctrl, read, write, mii_dir)` 來說,會被展開為
```c
static const struct file_operations ctrl_fops = {
.read = read,
.write = write,
};
```
---
在 Line 72 的 `register_procfs_stubs()` 中
```c=75
if (!procfs) {
return -EINVAL;
}
```
extern 變數 procfs 初始化於 [firmadyne.c](https://github.com/firmadyne/kernel-v2.6.32/blob/firmadyne-v2.6.32.70/drivers/firmadyne/firmadyne.c) 中,為 1
Line 79 ~ 94 展開 Macro
```c=79
#define DIR(a, b) \
if (!(a##_dir = proc_mkdir(#a, b))) { \
printk(KERN_WARNING MODULE_NAME": Cannot register procfs directory: %s!\n", #a); \
ret = -1; \
}
#define FILE(a, b, c, d) \
if (!proc_create_data(#a, 0666, d, &a##_fops, NULL)) { \
printk(KERN_WARNING MODULE_NAME": Cannot register procfs file: %s!\n", #a); \
ret = -1; \
}
STUB_ENTRIES
#undef FILE
#undef DIR
```
以 `DIR(mii, rt3052_dir)` 來說,會被展開為
```c
if (!(mii_dir = proc_mkdir("mii", rt3052_dir))) {
printk(KERN_WARNING MODULE_NAME": Cannot register procfs directory: %s!\n", "mii");
ret = -1;
}
```
在變數 rt3052_dir 所代表的目錄底下創立名為 `mii` 的目錄
並用變數 mii_dir 存著,代表著這個目錄
若失敗才會進 if
以 `FILE(ctrl, read, write, mii_dir)` 來說,會被展開為
```c
if (!proc_create_data("ctrl", 0666, mii_dir, &ctrl_fops, NULL)) {
printk(KERN_WARNING MODULE_NAME": Cannot register procfs file: %s!\n", "ctrl");
ret = -1;
}
```
在變數 mii_dir 所代表著的目錄底下創立檔名為 ctrl 的檔案,權限為 0666,相關 file operations 位置在 ctrl_fops
參考 [Linux内核中的proc文件系统](http://www.embeddedlinux.org.cn/emb-linux/file-system/201703/27-6340.html)
```
struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
struct proc_dir_entry *parent,
const struct file_operations *proc_fops,
void *data)
```
- name
你要创建的文件名。
- mode
为创建的文件指定权限
- parent
为你要在哪个文件夹下建立名字为name的文件,如:init_net.proc_net是要在/proc/net/下建立文件。
- proc_fops
为 struct file_operations
- data
保存私有数据的指针,如不要为NULL。
而 Line 99 的 `unregister_procfs_stubs()` 只是在做相反的事情
有創就有刪
## 總結
這份 Code 主要拿來創 procfs
`FILE(filename, read, write, dir)`
會在 `dir` 底下創檔名為 `filename` 的檔案
`DIR(subdir, rootdir)`
會在 `/proc/${rootdir}` 底下創名為 `subdir` 的目錄