[英]How can I Execute/Call a user-space defined function from Linux kernel space module?
我正在開發一個 Linux 模塊,我想用它來從 kernel 模式運行我的 C 程序。
我的問題在這里,在模塊的 function read()
中,我需要使用一個名為eval_keycode()
的 function ,它是在我的用戶空間程序中定義的。
當我嘗試編譯我的模塊時,會發生此錯誤:
錯誤:function 'eval_keycode' 的隱式聲明
這證實了我上面描述的問題。
這是我模塊的read()
function:
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
struct file *f = pfile->private_data;
enum { MAX_BUF_SIZE = 4096 };
size_t buf_size = 0;
char *buf = NULL;
ssize_t total = 0;
ssize_t rc = 0;
struct input_event *ev;
int yalv;
/* Allocate temporary buffer. */
if (length) {
buf_size = min_t(size_t, MAX_BUF_SIZE, length);
ev = kmalloc(buf_size, GFP_KERNEL);
if (ev == NULL) {
return -ENOMEM;
}
}
/* Read file to buffer in chunks. */
do {
size_t amount = min_t(size_t, length, buf_size);
rc = kernel_read(f, ev, amount, offset);
if (rc > 0) {
/* Have read some data from file. */
if (copy_to_user(buffer, ev, rc) != 0) {
/* Bad user memory! */
rc = -EFAULT;
} else {
/* Update totals. */
total += rc;
buffer += rc;
*offset += rc;
length -= rc;
for (yalv = 0; yalv < (int) (rc / sizeof(struct input_event)); yalv++) {
if (ev[yalv].type == EV_KEY) {
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
if (rc < amount) {
/* Didn't read the full amount, so terminate early. */
rc = 0;
}
}
}
}
while (rc > 0 && length > 0);
/* Free temporary buffer. */
kfree(buf);
if (total > 0) {
return total;
}
return rc;
}
這是我的用戶空間eval_keycode()
定義的 function:
void eval_keycode(int code)
{
static int red_state = 0;
static int green_state = 0;
switch (code) {
case 260:
printf("BTN left pressed\n");
/* figure out red state */
red_state = red_state ? 0 : 1;
change_led_state(LED_PATH "/" red "/brightness", red_state);
break;
case BTN_RIGHT:
printf("BTN right pressed\n");
/* figure out green state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
如何從用戶空間調用eval_keycode
function 來解決這個問題?
謝謝你。
你可以,但這是一個非常糟糕的主意。 您需要建立一個指向您的用戶模式 function 的指針,安排包含該 function 的進程在您調用它時運行(在內核中)。 這是一項繁重的工作,而且由於它造成的安全漏洞,基本上是惡意軟件。 此外,在 Spectre 等人的襲擊之后,為了鎖上現在空谷倉的門而瘋狂沖刺,新的黑客層被部署在更新的 CPU 中,使這變得更加困難。
另一種方法:
在您的原始查詢中,您將此驅動程序作為“三通”運行; 也就是說,您獲取從設備接收到的輸入,將副本提供給調用者,然后使用每個輸入調用 eval_keycode。 eval_keycode 不修改數據,之后 kernel 模塊將其丟棄。 所以 Eval_keycode 並不需要是 function; 或者更確切地說,可能有一個用戶 function:
void ProcessEvents(int fd) {
struct input_event ev;
while (read(fd, &ev, sizeof ev) == sizeof ev) {
eval_keycode(&ev);
}
}
如果您可以安排將所有事件輸入該 fd。 使用此設置,您的問題變得比 kernel 翻新更麻煩。 用戶創建一個管道/套接字/fifo/...並將寫入端傳遞給您的 kernel 模塊(更多的 ioctl()s)。 然后,您的 kernel 模塊可以小心地使用 kernel_write() (或 vfs_write 如果您過去遇到問題)使這些事件可用於用戶處理程序。 它想小心它的阻塞點在哪里。
您可以將其擴展為轉換; 那是您的驅動程序通過用戶模式處理程序轉換事件的地方; 但到那時,您可能真的認為 FUSE 是一個更好的解決方案。
沒有傳統的(以庫的工作方式)“調用”用戶空間“函數”的方式。
您的用戶空間代碼應該在其自己的進程(或另一個用戶空間進程)中運行,您將在其中實現通信(通過共享 memory、進程間調用 [IPC]、設備文件、中斷......),您可以在其中處理交換數據,並對數據采取行動(例如調用您的 eval_keycode 函數)。
你不能。
此時,您有兩個選擇:
在用戶空間中完成這一切,這將保持向后兼容性並變得更加穩定。
將您的用戶空間代碼復制到 kernel 代碼中並進行更改,例如從printf
移動到printk
以及從使用抽象切換到使用 kernel API。
做一些別的事情來分散自己的注意力,因為你需要做上述兩個中的一個來解決問題是徒勞的。
做出明智的選擇。
你基本上想要一個upcall。 你可以在這里找到一些解釋,但 Linux 似乎沒有官方的上調 API。
然而,正如其他人已經提到的那樣,這不是很好的設計。 Upcalls 對於在 kernel 中實現的服務器很有用。
如果您的exer_read()
僅針對您自己的代碼(在您正在為其實現驅動程序的文件上)調用,那么inotify可能是一個更好的設計。
如果您的exer_read()
可以為任何文件調用(例如,您希望在機器上寫入任何文件以更改 LED 狀態),那么您希望包含eval_keycode()
的用戶空間進程輪詢某些字符設備,並且您希望您的模塊將代碼寫入此字符設備,而不是調用eval_keycode()
。
但是,如果change_led_state()
是同步的,並且您實際上需要阻止讀取直到它返回,那么建議您重新考慮您的設計......但這是向上調用的有效用例。
在 linux 上,用戶空間代碼使用文件 API 與 kernel 代碼交互。 通常在不移動數據時使用 yocto 系統調用。
因此,您需要實現一個字符設備。 使用 shell 中的 mknod 添加新文件名,以將設備添加到 /dev 目錄。
然后,您的用戶代碼使用 open API 打開設備並使用 ioctl 調用進行交互。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.