c - 我需要帮助来理解以下用 C 编写的内核模块

标签 c linux kernel

作为一项作业,我需要完成以下 C 代码,以便生成一个能够充当内存的内核模块,但从它的编写方式来看,我无法理解它是如何工作的,以及为什么不使用许多变量而只是使用它宣布。我已经尝试查看他们给我的教材,这更加令人困惑,而且我在网上找不到一个好的网站来查找有关这些功能的文档。

代码如下:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#define DEVICE_NAME             "my_device"
#define MAJOR_DEVICE_NUMBER     60
#define MINOR_DEVICE_NUMBER     0
#define BUF_LEN                 1024

static char msg[BUF_LEN];
static char *msg_ptr; // I'm pretty sure this should become msg_reading_offset
static int major;

MODULE_AUTHOR("<YOUR NAME>");
MODULE_LICENSE("GPL");

static ssize_t my_read (
    struct file *filp, char __user *buf,
    size_t length, loff_t *offset);
static ssize_t my_write (
    struct file *filp, const char __user *buf,
    size_t length, loff_t *offset);
static int my_open (struct inode *inode,
    struct file *filp);
static int my_close (struct inode *inode,
    struct file *filp);
static int __init my_init (void);
static void __exit my_cleanup (void);
static struct file_operations fops = {
    .read = my_read,
    .write = my_write,
    .open = my_open,
    .release = my_close,
};

// I need to implement this function
static int my_open (struct inode *inode,
   struct file *filp)
{
    return 0;
}
// and this function
static int my_close (struct inode *inode,
    struct file *filp)
{
    return 0;
}

static ssize_t my_read (
    struct file *filp, char __user *buf,
    size_t length, loff_t *offset)
{
   int nc = 0;
   // if no more "valid" bytes can be read, stop
   if (*msg_reading_offset == 0) return 0;
   // no-negative values allowed
   if (length < 0)
      return -EINVAL;
   // read the whole msg, nothing more
   if (length > strlen(msg)) {
       length = strlen(msg);
   }
   nc = copy_to_user(buf, msg_reading_offset, length);
   /*
   updates the current reading offset pointer so that a
   recursive call due to not original
   full length will get a 0 (nothing to read)
   */
   msg_reading_offset += sizeof(char) * (length-nc);
   // returns the number of REAL bytes read.
   return length - nc;
}

static ssize_t my_write (
    struct file *filp, const char __user *buf,
    size_t length, loff_t *offset)
{
   int nc = 0;
   if (length > BUF_LEN)
      return BUF_LEN-length;
   nc = copy_from_user(msg,buf,length);
   msg_ptr = msg;
   return length - nc;
}

static int __init my_init (void)
{
   register_chrdev (MAJOR_DEVICE_NUMBER,
      DEVICE_NAME,
      &fops);

}
module_init(my_init);
static void __exit my_cleanup (void)
{
   unregister_chrdev (major, DEVICE_NAME);
}
module_exit(my_cleanup);

目前这些是我最大的问题:

  • 所有 *inode、*filp 变量都去哪儿了?我应该使用它们吗?
  • 这个程序是如何运作的?我知道我需要用我提供的 makefile 来编译它,但是我应该如何访问这些函数呢?
  • 这应该是由内核执行的真实程序,还是只是我应该在另一个 C 程序中使用的函数集合?

如果这些问题看起来很愚蠢,我很抱歉,但我不知道该怎么解决这个问题。

最佳答案

你的问题有点宽泛,但我会尽力给你一些提示。

Where are all the *inode, *filp variables going? Am I supposed to use them?

首先阅读一个如何实现典型字符设备的示例,例如 here

How is this program even working? I know I need to compile it with a makefile I've been give, but then how am I supposed to access these functions?

Is this supposed to be a real program executed by the kernel or is it just a collections of functions I should use in another C program?

这不是一个正常的可执行程序。当您编写内核模块时,您正在扩展内核功能。您需要告诉内核这一点,通常是通过 insmod 调用。例如,

insmod chardev.ko

然后创建对应的字符设备:

mknod /dev/chardev c 60 0    # 60 being your MAJOR_DEVICE_NUMBER

然后您可以创建自己的程序来读取写入您的字符设备。或者,您可以使用现有的用户空间工具:

echo "12345678" > /dev/chardev    # write to the device

并且,

cat /dev/chardev    # read from the device

关于c - 我需要帮助来理解以下用 C 编写的内核模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34704739/

相关文章:

linux - 这个脚本有什么作用?

c# - 在 Windows 上监视文件读取 - C# 解决方案

kernel - 命令和程序如何与 Window OS 通信

c - 使用 goto 跳过变量声明?

c - 用户输入(字符串)写入文件,直到用户给出一个空行

c - 用 C 将字符数组写入文件

ruby-on-rails - 为什么 Rails 使用错误版本的 Ruby?

linux - 在 arch 中将 postgresql 语言设置为英语

linux - 访问/处理

c - 递增的错误类型参数