---
# System prepended metadata

title: Firmadyne MIPS kernel-v2.6.32 procfs_stubs.c
tags: [firmadyne]

---

---
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` 的目錄
