关于操作系统例程

 把自己认为有保留价值的几个代码片断给放在这里,以供参考!

 1.进行proc文件系统编程,在内核中维护一张表格(表格记录了学生的姓名和学号),可以向表格添加记录,显示记录和删除记录,并编写一个用户程序进行测试

 老师给的答案(好像有问题):

 /*
 * a mini module do nothing
 *   test passed on linux redhat 9 'kernel 2.4.20-8'
 * Compile:
 * gcc -c -I/usr/src/linux/include -Wall procf.c
 */


//#define __NO_VERSION__
#define LINUX
#define __KERNEL__
#define MODULE

#include <linux/kernel.h> /* program in kernel */
#include <linux/module.h> /* program as module */
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

#define KBUILD_MODNAME procf

char content[100] = "this my file content";
int  len = 20;

int my_read_proc(char *buf, char **start, off_t offset, int xlen, int *eof, void *data)
{
// copy_to_user(buf, content, len);
    int i;
 for(i=0; i<len+1; i++) buf[i] = content[i];
 return len;
}

int my_write_proc(struct file *file, const char *buf,
     unsigned long count, void *data)
{
 int i;
 if( count > 99 ) count = 99;
// copy_from_user(content, buf, count);
 for(i=0; i<count; i++) content[i] = buf[i];
 len = i;
 content[i] = '/0';
 
 return len;
}

struct proc_dir_entry my_entry = {
   0,
   6,                      /* unsigned short namelen */
   "myname",                /* const char *name */
   S_IFREG | S_IRUGO,      /* mode_t mode */
   1,                      /* nlink_t nlink */
   0,                      /* uid_t uid */
   0,                      /* gid_t gid */
   2,                      /* unsigned long size */
   NULL,                   /* struct inode_operations *ops */
   NULL,
   NULL,
   NULL, NULL, NULL,
   NULL,
   my_read_proc,
   my_write_proc,
   NULL,
   0,
   0
 };


int init_module()
{
    int i;
 for(i=49, len =0; i<59; i++){
   content[i-49] = i;
   len ++;
 }
 content[i] = '/0';
 proc_register(&proc_root, &my_entry);
 printk("Hello world/n");
 return 0;
}

void cleanup_module()
{
 proc_unregister(&proc_root, my_entry.low_ino);
 printk("bye/n");
}

MODULE_LICENSE("GPL");

自己改造过的答案:

#define LINUX
#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
//#include <string.h>
//#include <stdio.h>

#define NAMELEN 10
#define IDLEN   10
#define STRINGLEN 100
struct person_information{
 char name[NAMELEN];
 char id[IDLEN];
};

char global_buffer[1024];

struct person_information global_buffer_student[STRINGLEN];
//struct proc_dir_entry student_file = {
// 0,
// strlen("student_file"),  /*unsigned short namelen*/
// "student_file",  /*const char* name*/
// S_IFREG|S_IRUGO, /*mode_t mode*/
// 1,   /*nlink_t nlink*/
// 0,   /*uid_t uid*/
// 0,   /*gid_t gid*/
// 2,   /*unsigned long size*/
// NULL,   /*struct inode_operation *pos*/
// NULL,
// NULL,
// NULL,NULL,NULL,
// NULL,
// proc_read_student,
// proc_write_student,
// NULL,
// 0,
// 0
//};

struct proc_dir_entry *student_file;
struct proc_dir_entry *example_dir;
struct proc_dir_entry *current_file;
struct proc_dir_entry *hello_file;
struct proc_dir_entry *symlink;

int proc_read_student(char* page,char** start,off_t off,int count,int* eof,void* data);
int proc_write_student(struct file *file,const char *buffer,unsigned long count,void* data);

int proc_read_current(char* page,char** start,off_t off,int count,int *eof,void* data);

int proc_read_hello(char* page,char** start,off_t off,int count,int* eof,void* data);
int proc_write_hello(struct file *file,const char *buffer,unsigned long count,void* data);


void init_student(){
 int i=0;
 for(i;i<STRINGLEN;++i){
  memset(global_buffer_student[i].name,'0'+i,NAMELEN);
  memset(global_buffer_student[i].id,i,IDLEN);
 }
}

int proc_read_student(char* page,char** start,off_t off,int count,int* eof,void* data){
 int len;
 MOD_INC_USE_COUNT;
len = sprintf(page,"golbal_buffer==%s/n",global_buffer);
 int i;
 //init_student();
 i=0;
// for(i=0;i<STRINGLEN;++i){
printk("name==%s,id==%s/n",global_buffer_student[i].name,global_buffer_student[i].id);
// }
 MOD_DEC_USE_COUNT; 
 return len;
}

int proc_write_student(struct file *file,const char *buffer,unsigned long count,void* data){
 int len;
 MOD_INC_USE_COUNT;
 if(count>=STRINGLEN)
  len = STRINGLEN-1;
 else
  len = count;
 copy_from_user(global_buffer_student,buffer,len);
 global_buffer[len]='/0';
 MOD_DEC_USE_COUNT; 
 return 0;
}

int init_module(){
 example_dir = proc_mkdir("proc_test",NULL);
 example_dir->owner = THIS_MODULE;
 

 current_file = create_proc_read_entry("current",666,example_dir,proc_read_current,NULL);
 current_file->owner = THIS_MODULE;

 hello_file = create_proc_entry("hello",666,example_dir);
 strcpy(global_buffer,"this is a global_buffer/n");
 hello_file->read_proc = proc_read_hello;
 hello_file->write_proc = proc_write_hello;
 hello_file->owner = THIS_MODULE;

 student_file = create_proc_entry("student",666,example_dir);
 student_file->read_proc = proc_read_student;
 student_file->write_proc = proc_write_student;
 student_file->owner = THIS_MODULE;

 symlink = proc_symlink("current_symlink",example_dir,"current");
 symlink->owner = THIS_MODULE;
 init_student();
 //proc_register(&proc_root,&proc_read_student);
 //int i=0;
        //for(i;i<STRINGLEN;++i){
 // memset(global_buffer_student[i].name,0,NAMELEN);
 // memset(global_buffer_student[i].id,0,IDLEN);
 //}
 printk("init_module msg form tested_proc.c/n"); 
 return 0;
}

int proc_read_current(char* page,char** start,off_t off,int count,int *eof,void* data){
 int len;
 MOD_INC_USE_COUNT;
 len = sprintf(page,"current process usages:/nname:%s/ngid:%d/npid:%d/n",current->comm,current->pgrp,current->pid);
 MOD_DEC_USE_COUNT;
 return len;
}

//void proc_write_information(){

//}

int proc_read_hello(char* page,char** start,off_t off,int count,int* eof,void* data){
 int len;
 MOD_INC_USE_COUNT;
 len = sprintf(page,"hello message:/n %s write: %s /n",current->comm,global_buffer);
 MOD_DEC_USE_COUNT;
 return len;
}

int proc_write_hello(struct file *file,const char *buffer,unsigned long count,void* data){     int len;
 MOD_INC_USE_COUNT;
 if(count >= 1024)
  len = 1024-1;
 else
  len = count;
 copy_from_user(global_buffer,buffer,len);
 global_buffer[len]='/0';
 MOD_DEC_USE_COUNT;
 return len;
}


void cleanup_module(){
 remove_proc_entry("current_symlink",example_dir); 
 remove_proc_entry("hello",example_dir); 
 remove_proc_entry("student",example_dir); 
 remove_proc_entry("current",example_dir); 
 remove_proc_entry("proc_test",NULL); 
 //proc_unregister(&proc_root,proc_read_student.low_ino);
 printk("cleanup_module msg form tested_proc.c/n"); 
}

MODULE_LICENSE("GPL");


2.示例如何使用模块

/* rwbuf: read/write a buffer
 *        a demo on how to build a device in a kernel module
 * test pass with Mandrake 7(Kernel 2.2.14) in vmare, 2005/12
 * test pass with RedHat 9(Kernel 2.4.20-8) in vmware, 2005/12
 *
 * how to test ?
 * so :
 *
 * $ first you must be ROOT
 compile in Kernel 2.4
 * #  gcc -I/usr/src/linux/include/ -D KERNEL2_4 -c rwbuf.c
 compile in Kernel 2.2
 * #  gcc -I/usr/src/linux/include/  -c rwbuf.c
 * # insmod rwbuf.o          // you should see that 'rwbuf' in there
 * # lsmod
 * # mknod /dev/rwbuf c 60 0 // this can do only once
 * #                         // now you can use /dev/rwbuf
 */


#define LINUX
#define __KERNEL__
#define MODULE

#define KBUILD_MODNAME rwbuf

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>

#ifdef KERNEL2_4
#define HAVE_MEMCPY    /* no export 'memcpy' in kernel 2.2 */
#define HAVE_MOD_LIC   /* no Module License in kernel 2.2 */
#endif


#ifndef HAVE_MEMCPY
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
#endif

#define RWBUF_prefix   rwbuf  // not used yet
#define RWBUF_NAME     "rwbuf"      // device's symbol name
#define RWBUF_ID       60   // device's major no
#define RW_CLEAR       0x909090     // IO ctl command

#define rwbuf_size 1000  // 1k enough
static unsigned char rwbuf[rwbuf_size+1];  //
static int rwlen=0;   // how many bytes used in <rwbuf>
static int inuse=0;   // only one process permited at the same time

static int rwbuf_open(struct inode *inode,struct file * filep)
{
 if (inuse==1) // the buf is used by another process, so fail to open
  return -1;
 inuse=1;

 MOD_INC_USE_COUNT; // don't ask what this means
 return 0;
}

static int rwbuf_close(struct inode *inode,struct file * filep)
{
 inuse=0;

 MOD_DEC_USE_COUNT;
 return 0;
}

static ssize_t rwbuf_write(struct file * filep,
  const char *buf, size_t count, loff_t * ppos)
{
 if (count>rwbuf_size)
  count = rwbuf_size;
#ifndef HAVE_MEMCPY /* no export 'memcpy' in kernel 2.2 */
    copy_from_user(rwbuf, buf, count);
#else
 memcpy(rwbuf, buf, count);  // as you see
#endif
 rwlen = count;
 printk("user-to-kernel: %s/n", rwbuf);
 return count;
}

static ssize_t rwbuf_read(struct file* filep,
   char * buf, size_t count, loff_t* ppos)
{
 if (count>rwlen)
  count = rwlen;
#ifndef HAVE_MEMCPY /* no export 'memcpy' in kernel 2.2 */
    copy_to_user(buf, rwbuf, count);
#else
 memcpy(buf, rwbuf, count);
#endif
 printk("kernel-to-user: %s/n", buf);
 return count;
}

static int rwbuf_ioctl(struct inode *inode,struct file * filep,
  unsigned int cmd,unsigned long arg)
{
 switch (cmd)
 {
 case RW_CLEAR:
  rwlen = 0; // clear buf by set its len to zero
  printk("rwbuf in kernel zero-ed/n");
  break;

 default:
  break;
 };

 return 0;
}


static struct file_operations rwbuf_fops =
{
 open:    rwbuf_open,
 release: rwbuf_close,
 read:    rwbuf_read,
 write:   rwbuf_write,
 ioctl:   rwbuf_ioctl,
};

int init_module()
{
 printk("Hello world/n");
 if (register_chrdev(RWBUF_ID, RWBUF_NAME, &rwbuf_fops))
  printk("register error/n");
 else
  printk("register ok/n");
 return 0;
}

void cleanup_module()
{
 if (unregister_chrdev(RWBUF_ID, RWBUF_NAME)!=0)
  printk("unreg err/n");
 else
  printk("unreg ok/n");
 printk("bye/n");
}

#ifdef HAVE_MOD_LIC
MODULE_LICENSE("GPL");
#endif

3.了解和熟悉Linux中设备驱动程序的概念和设计,能独立编写一个简单的字符型或是块型设备驱动程序

------------------------radimo.h---------------------------------------
#define RADIMO_MAJOR  42

#define RADIMO_TIMER_DELAY 60*HZ

/* msg masks */
#define RADIMO_OPEN  1
#define RADIMO_IOCTL  2
#define RADIMO_INFO  4
#define RADIMO_REQUEST  8
#define RADIMO_TIMER  16
#define RADIMO_ERROR  32

#ifndef MSG_MASK
#define MSG_MASK ( RADIMO_IOCTL | RADIMO_INFO | RADIMO_ERROR | RADIMO_REQUEST | RADIMO_OPEN)
#endif

#define MSG(mask, string, args...) /
 if (MSG_MASK & mask) printk(KERN_DEBUG "radimo: " string, ##args)

 

------------------------radimo.c---------------------------------------
/*
 * Sample Ram DIsk Module, Radimo
 *
 */

#include <linux/module.h>

#if defined(CONFIG_SMP)
#define __SMP__
#endif

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>

#include <asm/uaccess.h>

#include "radimo.h"

/*以上定义了一些常用的头文件*/

#define MAJOR_NR  RADIMO_MAJOR  // 定义了RADIMO的主设备号
#define DEVICE_NAME  "radimo"  // 定义了RADIMO的设备名
#define DEVICE_NR(device) (MINOR(device))  
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#define DEVICE_NO_RANDOM

#include <linux/blk.h>

#define RADIMO_HARDS_BITS 9 /* 2**9 byte hardware sector */
#define RADIMO_BLOCK_SIZE 1024 /* block size */
//定义了一个块的大小,以字节为单位
#define RADIMO_TOTAL_SIZE 2048 /* size in blocks */
//定义了这个虚拟盘的容量,以块为单位

/* the storage pool */
static char *radimo_storage;  //这个指针是全局变量,指向用于虚拟盘的内存

static int radimo_hard = 1 << RADIMO_HARDS_BITS;
static int radimo_soft = RADIMO_BLOCK_SIZE;
static int radimo_size = RADIMO_TOTAL_SIZE;

static int radimo_readahead = 4;

struct timer_list radimo_timer;  
//定义了一个定时器,这个程序中我们并没有用到。这里作为一个使用定时器的例子

/* forward declarations for _fops */
static int radimo_open(struct inode *inode, struct file *file);  
static int radimo_release(struct inode *inode, struct file *file);
static int radimo_ioctl(struct inode *inode, struct file *file,
   unsigned int cmd, unsigned long arg);
 //定义了三个常用的接口函数

static struct block_device_operations radimo_fops = {
 open:  radimo_open,
 release: radimo_release,
 ioctl:  radimo_ioctl,
};     
//用一个结构把三个接口函数组装起来,以便通知操作系统


static int radimo_request(request_queue_t *request_queue, int rw, struct buffer_head *sbh)
{ //【重要】这是块设备驱动程序处理读写请求的函数,是本程序中最重要的部分
 unsigned long offset, total;
 //int *make_oops = NULL;    // CR: access to this pointer will cause Oops, for debug only. 

 MSG(RADIMO_REQUEST, "%s sector rsector = %lu, blocknr = %lu/n",
    rw == READ ? "read" : "write",
    sbh->b_rsector,
    sbh->b_blocknr); 
//MSG宏的定义在radimo.h中,相当于printk,
       
//用于在log文件中打印一行,以便调试
 
 offset = sbh->b_rsector * radimo_hard;  
 total = (unsigned long)sbh->b_size;  
//计算需要访问的地址和大小
 
 /* access beyond end of the device */
 if (total+offset > radimo_size * (radimo_hard << 1)) {
  MSG(RADIMO_REQUEST, "Error: access beyond end of the device");
  /* error in request  */
  buffer_IO_error(sbh);
  return 0;
 } 
//判断访问地址是否越界

 MSG(RADIMO_REQUEST, "offset = %lu, total = %lu/n", offset, total);
 
 if (rw == READ || rw==READA) { //如果是读操作,从虚拟盘的内存中复制数据到缓冲区中
  memcpy(bh_kmap(sbh), radimo_storage+offset, total);
 } else if (rw == WRITE) { //如果是写操作,从缓冲区中复制数据到虚拟盘的内存中
  memcpy(radimo_storage+offset, bh_kmap(sbh), total);
 } else { /* can't happen */
  MSG(RADIMO_ERROR, "cmd == %d is invalid/n", rw);
 }
 /* successful */
 
 sbh->b_end_io(sbh,1); //结束读写操作
 
 return 0;
}

void radimo_timer_fn(unsigned long data)
{ //这是用于定时器处理的函数,本程序中没有用到,但是可以作为使用定时器的框架
 /* set it up again */
 radimo_timer.expires = RADIMO_TIMER_DELAY + jiffies;
 add_timer(&radimo_timer);
}

static int radimo_release(struct inode *inode, struct file *file)
{ //关闭设备时调用
 MSG(RADIMO_OPEN, "closed/n");
 MOD_DEC_USE_COUNT; //减少引用计数
 return 0;
}

static int radimo_open(struct inode *inode, struct file *file)
{ //打开设备时调用
 MSG(RADIMO_OPEN, "opened/n");
 MOD_INC_USE_COUNT; //增加引用计数

 /* timer function needs device to invalidate buffers. pass it as
    data. */
 radimo_timer.data = inode->i_rdev;
 radimo_timer.expires = RADIMO_TIMER_DELAY + jiffies;
 radimo_timer.function = &radimo_timer_fn;

 if (!timer_pending(&radimo_timer))
  add_timer(&radimo_timer);
 //以上几行是设置定时器,本程序中没有用到定时器

 return 0;
}

static int radimo_ioctl(struct inode *inode, struct file *file,
   unsigned int cmd, unsigned long arg)
{ //响应一些特殊的操作,这些操作可以自己定义
 unsigned int minor;
 
 if (!inode || !inode->i_rdev)  
  return -EINVAL;

 minor = MINOR(inode->i_rdev);

 switch (cmd) {

  case BLKFLSBUF: { //将缓冲写回存储区的操作
   /* flush buffers */
   MSG(RADIMO_IOCTL, "ioctl: BLKFLSBUF/n");
   /* deny all but root */
   if (!capable(CAP_SYS_ADMIN))
    return -EACCES;
   fsync_dev(inode->i_rdev);
   invalidate_buffers(inode->i_rdev);
   break;
  }

          case BLKGETSIZE: { //得到设备容量的操作
   /* return device size */
   MSG(RADIMO_IOCTL, "ioctl: BLKGETSIZE/n");
   if (!arg)
    return -EINVAL;
   return put_user(radimo_size*2, (long *) arg);
  }
  
  case BLKRASET: { //设置设备预读值的操作
   /* set read ahead value */
   int tmp;
   MSG(RADIMO_IOCTL, "ioctl: BLKRASET/n");
   if (get_user(tmp, (long *)arg))
    return -EINVAL;
   if (tmp > 0xff)
    return -EINVAL;
   read_ahead[RADIMO_MAJOR] = tmp;
   return 0;
  }

  case BLKRAGET: { //得到设备预读值的操作
   /* return read ahead value */
   MSG(RADIMO_IOCTL, "ioctl: BLKRAGET/n");
   if (!arg)
    return -EINVAL;
   return put_user(read_ahead[RADIMO_MAJOR], (long *)arg);
  }

  case BLKSSZGET: { //得到设备块大小的操作
   /* return block size */
   MSG(RADIMO_IOCTL, "ioctl: BLKSSZGET/n");
   if (!arg)
    return -EINVAL;
   return put_user(radimo_soft, (long *)arg);
  }

  default: {  //其他操作
   MSG(RADIMO_ERROR, "ioctl wanted %u/n", cmd);
   return -ENOTTY;
  }
 }
 return 0;
}
 
int init_module(void)
{ //在模块被加载的时候调用
 int res;
 
 /* 块大小必须是扇区大小的整数倍 */
 if (radimo_soft & ((1 << RADIMO_HARDS_BITS)-1)) {
  MSG(RADIMO_ERROR, "Block size not a multiple of sector size/n");
  return -EINVAL;
 }
 
 /* 分配存储空间 */
 radimo_storage = (char *) vmalloc(1024*radimo_size);
 if (radimo_storage == NULL) {
  MSG(RADIMO_ERROR, "Not enough memory. Try a smaller size./n");
  return -ENOMEM;
 }
 memset(radimo_storage, 0, 1024*radimo_size);
 
 /* 【重要】向系统注册块设备 */
 res = register_blkdev(RADIMO_MAJOR, "radimo", &radimo_fops);
 if (res) {
  MSG(RADIMO_ERROR, "couldn't register block device/n");
  return res;
 }
 
 init_timer(&radimo_timer);
 
 /* 在系统中注册块的大小、存储容量等参数 */
 hardsect_size[RADIMO_MAJOR] = &radimo_hard;
 blksize_size[RADIMO_MAJOR] = &radimo_soft;
 blk_size[RADIMO_MAJOR] = &radimo_size;
 
 /* 在系统中注册响应读写请求的函数 */
 blk_queue_make_request(BLK_DEFAULT_QUEUE(RADIMO_MAJOR), &radimo_request);
 read_ahead[RADIMO_MAJOR] = radimo_readahead;
 
 MSG(RADIMO_INFO, "loaded/n");
 MSG(RADIMO_INFO, "sector size of %d, block size of %d, total size = %dKb/n",
     radimo_hard, radimo_soft, radimo_size);
 
 printk("init_module from radimo.c ");
 return 0;
}

void cleanup_module(void)
{ //在模块被卸载的时候调用
 unregister_blkdev(RADIMO_MAJOR, "radimo");
 del_timer(&radimo_timer);

 invalidate_buffers(MKDEV(RADIMO_MAJOR,0));

 /* remove our request function */
 blk_dev[RADIMO_MAJOR].request_queue.request_fn = 0;
 
 vfree(radimo_storage);

 MSG(RADIMO_INFO, "unloaded/n");
 printk("cleanup_module from radimo.c ");
}
MODULE_LICENSE("GPL"); 


------------------------Makefile---------------------------------------
# standards
INCLUDE  = /usr/src/linux-2.4/include
CC   = gcc
CFLAGS   = -D__KERNEL__ -I$(INCLUDE) -DMODULE -Wall -O2

TARGET = radimo
SRC = radimo.c 

all: $(TARGET).o

clean:
 rm -f *.o *~ core

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值