0

我的目标是编写一个内核模块。我正在关注freesoftware 杂志的内存教程。

该教程工作正常。我能够编译代码。加载时insmod,内核<1>Inserting memory module按预期打印。当我使用移除模块时rmmod当我使用内核打印<1>Removing memory module

出于调试目的,我正在尝试添加printk()其他方法。但它们永远不会被打印出来。

所有消息的优先级为<1>

我通过以下方式写入设备:echo -n test1234 > /dev/memory 并使用cat /dev/memory取回数据。

cat /var/log/messages并且dmesg不再打印信息

[ 5550.651221] <1>Inserting memory module [ 5550.655396] <1>Inserting memory module !!!!!!!!!!!!!!! [12230.130847] <1>Removing memory module

cat /proc/sys/kernel/printk 7 4 1 7

uname- a Linux generic-armv7a-hf 3.14.0-163850-g775a3df-dirty #2 SMP Mon Jan 12 13:53:50 CET 2015 armv7l GNU/Linux

为什么printk()只在initandexit方法中起作用?

有没有(更好的)方法来打印变量值printk()

这里的代码:

/* Necessary includes for device drivers */
#include <linux/init.h>
//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */

MODULE_LICENSE("Dual BSD/GPL");

/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);

/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
  read: memory_read,
  write: memory_write,
  open: memory_open,
  release: memory_release
};

/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);

/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;


int memory_init(void) {
  int result;

  /* Registering device */
  result = register_chrdev(memory_major, "memory", &memory_fops);
  if (result < 0) {
    printk(
      "<1>memory: cannot obtain major number %d\n", memory_major);
    return result;
  }

  /* Allocating memory for the buffer */
  memory_buffer = kmalloc(1, GFP_KERNEL); 
  if (!memory_buffer) { 
    result = -ENOMEM;
    goto fail; 
  } 
  memset(memory_buffer, 0, 1);

  printk("<1>Inserting memory module\n"); ///this works fine
  printk("<1>Inserting memory module !!!!!!!!!!!!!!!\n"); ///this works fine too
  return 0;

  fail: 
    memory_exit(); 
    return result;
}


void memory_exit(void) {
  /* Freeing the major number */
  unregister_chrdev(memory_major, "memory");

  /* Freeing buffer memory */
  if (memory_buffer) {
    kfree(memory_buffer);
  }

  printk("<1>Removing memory module\n"); //never printed

}


int memory_open(struct inode *inode, struct file *filp) {

      printk("<1>memory open\n"); //never printed

  /* Success */
  return 0;
}

int memory_release(struct inode *inode, struct file *filp) {

  printk("<1>memory_release\n"); //never printed

  /* Success */
  return 0;
}


ssize_t memory_read(struct file *filp, char *buf, 
                    size_t count, loff_t *f_pos) { 


  printk("<1>mem read\n"); //never printed

  /* Transfering data to user space */ 
  copy_to_user(buf,memory_buffer,1);




  /* Changing reading position as best suits */ 
  if (*f_pos == 0) { 
    *f_pos+=1; 
    return 1; 
  } else { 
    return 0; 
  }
}

ssize_t memory_write( struct file *filp, char *buf,
                      size_t count, loff_t *f_pos) {

  printk("<1>mem write\n"); //never printed

  char *tmp;

  tmp=buf+count-1;
  copy_from_user(memory_buffer,tmp,1);
  return 1;
}
4

1 回答 1

1

您的驱动程序看起来不错,但您实际上并没有用您的测试命令与它交谈,因此没有调用带有 printks 的函数。加载模块后,它会注册一个主要和次要编号,在您的情况下为 60 和 0。(以后您应该更新模块以请求可用的主编号,而不是使用硬编码的主编号。)

您需要使用mknod创建文件系统节点才能实际使用驱动程序。这将创建 /dev/memory 节点并将其连接到您已加载的模块。然后当它被打开、关闭、读取或写入时,你的模块中的 file_operations 将被调用,并且 printks 将工作。

对于您的模块,您应该能够使用

mknod /dev/memory c 60 0

您还chmod 666 /dev/memory可以允许任何用户使用该设备,而不是一直以 root 身份运行。

这是一个基于我与我开发的模块一起使用的脚本:

#!/bin/sh
device="memory"
mode="666"
major=$(awk "\$2==\"$device\" {print \$1}" /proc/devices}
mknod /dev/${device} c $major 0
chmod $mode /dev/${device}

它将查找与您的模块关联的主要编号并自动为其创建一个文件系统节点。

加载模块并运行 mknod 或脚本后,您应该能够使用驱动程序。您将知道它正在工作,因为 cat 只会返回写入设备的最后一个字符 - 您的驱动程序只有一个字符缓冲区,并且每次进入新字符时都会自动覆盖它。然后 dmesg 应该显示与相关联的 printk模块中的功能。

您的驱动程序似乎工作的原因是因为您正在使用 echo 命令创建一个常规文件,cat 高兴地立即打印给您。如果您在主目录中的文件上运行这些命令,会发生同样的事情,您只是碰巧在 /dev 中。

于 2015-01-13T13:53:54.960 回答