mirror of
https://github.com/bashrc/LKMPG.git
synced 2018-06-11 03:06:54 +02:00
Kernel 4.9.11
Included updates syscall example which disables page protection on Intel chips
This commit is contained in:
4299
4.9.11/LKMPG-4.9.11.html
Normal file
4299
4.9.11/LKMPG-4.9.11.html
Normal file
File diff suppressed because it is too large
Load Diff
3194
4.9.11/LKMPG-4.9.11.org
Normal file
3194
4.9.11/LKMPG-4.9.11.org
Normal file
File diff suppressed because it is too large
Load Diff
26
4.9.11/examples/Makefile
Normal file
26
4.9.11/examples/Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
obj-m += hello-1.o
|
||||
obj-m += hello-2.o
|
||||
obj-m += hello-3.o
|
||||
obj-m += hello-4.o
|
||||
obj-m += hello-5.o
|
||||
obj-m += startstop.o
|
||||
startstop-objs := start.o stop.o
|
||||
obj-m += chardev.o
|
||||
obj-m += procfs1.o
|
||||
obj-m += procfs2.o
|
||||
obj-m += procfs3.o
|
||||
obj-m += procfs4.o
|
||||
obj-m += hello-sysfs.o
|
||||
obj-m += sleep.o
|
||||
obj-m += print_string.o
|
||||
obj-m += kbleds.o
|
||||
obj-m += file_sched.o
|
||||
obj-m += chardev2.o
|
||||
obj-m += syscall.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
rm other/ioctl other/cat_noblock
|
||||
166
4.9.11/examples/chardev.c
Normal file
166
4.9.11/examples/chardev.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* chardev.c: Creates a read-only char device that says how many times
|
||||
* you've read from the dev file
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/uaccess.h> /* for put_user */
|
||||
|
||||
/*
|
||||
* Prototypes - this would normally go in a .h file
|
||||
*/
|
||||
int init_module(void);
|
||||
void cleanup_module(void);
|
||||
static int device_open(struct inode *, struct file *);
|
||||
static int device_release(struct inode *, struct file *);
|
||||
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
|
||||
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
|
||||
|
||||
#define SUCCESS 0
|
||||
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
|
||||
#define BUF_LEN 80 /* Max length of the message from the device */
|
||||
|
||||
/*
|
||||
* Global variables are declared as static, so are global within the file.
|
||||
*/
|
||||
|
||||
static int Major; /* Major number assigned to our device driver */
|
||||
static int Device_Open = 0; /* Is device open?
|
||||
* Used to prevent multiple access to device */
|
||||
static char msg[BUF_LEN]; /* The msg the device will give when asked */
|
||||
static char *msg_Ptr;
|
||||
|
||||
static struct file_operations fops = {
|
||||
.read = device_read,
|
||||
.write = device_write,
|
||||
.open = device_open,
|
||||
.release = device_release
|
||||
};
|
||||
|
||||
/*
|
||||
* This function is called when the module is loaded
|
||||
*/
|
||||
int init_module(void)
|
||||
{
|
||||
Major = register_chrdev(0, DEVICE_NAME, &fops);
|
||||
|
||||
if (Major < 0) {
|
||||
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
|
||||
return Major;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
|
||||
printk(KERN_INFO "the driver, create a dev file with\n");
|
||||
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
|
||||
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
|
||||
printk(KERN_INFO "the device file.\n");
|
||||
printk(KERN_INFO "Remove the device file and module when done.\n");
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when the module is unloaded
|
||||
*/
|
||||
void cleanup_module(void)
|
||||
{
|
||||
/*
|
||||
* Unregister the device
|
||||
*/
|
||||
unregister_chrdev(Major, DEVICE_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* Called when a process tries to open the device file, like
|
||||
* "cat /dev/mycharfile"
|
||||
*/
|
||||
static int device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
static int counter = 0;
|
||||
|
||||
if (Device_Open)
|
||||
return -EBUSY;
|
||||
|
||||
Device_Open++;
|
||||
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
|
||||
msg_Ptr = msg;
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a process closes the device file.
|
||||
*/
|
||||
static int device_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
Device_Open--; /* We're now ready for our next caller */
|
||||
|
||||
/*
|
||||
* Decrement the usage count, or else once you opened the file, you'll
|
||||
* never get get rid of the module.
|
||||
*/
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a process, which already opened the dev file, attempts to
|
||||
* read from it.
|
||||
*/
|
||||
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
|
||||
char *buffer, /* buffer to fill with data */
|
||||
size_t length, /* length of the buffer */
|
||||
loff_t * offset)
|
||||
{
|
||||
/*
|
||||
* Number of bytes actually written to the buffer
|
||||
*/
|
||||
int bytes_read = 0;
|
||||
|
||||
/*
|
||||
* If we're at the end of the message,
|
||||
* return 0 signifying end of file
|
||||
*/
|
||||
if (*msg_Ptr == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Actually put the data into the buffer
|
||||
*/
|
||||
while (length && *msg_Ptr) {
|
||||
|
||||
/*
|
||||
* The buffer is in the user data segment, not the kernel
|
||||
* segment so "*" assignment won't work. We have to use
|
||||
* put_user which copies data from the kernel data segment to
|
||||
* the user data segment.
|
||||
*/
|
||||
put_user(*(msg_Ptr++), buffer++);
|
||||
|
||||
length--;
|
||||
bytes_read++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Most read functions return the number of bytes put into the buffer
|
||||
*/
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a process writes to dev file: echo "hi" > /dev/hello
|
||||
*/
|
||||
static ssize_t
|
||||
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
|
||||
{
|
||||
printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
66
4.9.11/examples/chardev.h
Normal file
66
4.9.11/examples/chardev.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* chardev2.h - the header file with the ioctl definitions.
|
||||
*
|
||||
* The declarations here have to be in a header file, because
|
||||
* they need to be known both to the kernel module
|
||||
* (in chardev.c) and the process calling ioctl (ioctl.c)
|
||||
*/
|
||||
|
||||
#ifndef CHARDEV_H
|
||||
#define CHARDEV_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/*
|
||||
* The major device number. We can't rely on dynamic
|
||||
* registration any more, because ioctls need to know
|
||||
* it.
|
||||
*/
|
||||
#define MAJOR_NUM 100
|
||||
|
||||
/*
|
||||
* Set the message of the device driver
|
||||
*/
|
||||
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
|
||||
/*
|
||||
* _IOR means that we're creating an ioctl command
|
||||
* number for passing information from a user process
|
||||
* to the kernel module.
|
||||
*
|
||||
* The first arguments, MAJOR_NUM, is the major device
|
||||
* number we're using.
|
||||
*
|
||||
* The second argument is the number of the command
|
||||
* (there could be several with different meanings).
|
||||
*
|
||||
* The third argument is the type we want to get from
|
||||
* the process to the kernel.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the message of the device driver
|
||||
*/
|
||||
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
|
||||
/*
|
||||
* This IOCTL is used for output, to get the message
|
||||
* of the device driver. However, we still need the
|
||||
* buffer to place the message in to be input,
|
||||
* as it is allocated by the process.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the n'th byte of the message
|
||||
*/
|
||||
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
|
||||
/*
|
||||
* The IOCTL is used for both input and output. It
|
||||
* receives from the user a number, n, and returns
|
||||
* Message[n].
|
||||
*/
|
||||
|
||||
/*
|
||||
* The name of the device file
|
||||
*/
|
||||
#define DEVICE_FILE_NAME "char_dev"
|
||||
|
||||
#endif
|
||||
276
4.9.11/examples/chardev2.c
Normal file
276
4.9.11/examples/chardev2.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* chardev2.c - Create an input/output character device
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/fs.h>
|
||||
#include <asm/uaccess.h> /* for get_user and put_user */
|
||||
|
||||
#include "chardev.h"
|
||||
#define SUCCESS 0
|
||||
#define DEVICE_NAME "char_dev"
|
||||
#define BUF_LEN 80
|
||||
|
||||
/*
|
||||
* Is the device open right now? Used to prevent
|
||||
* concurent access into the same device
|
||||
*/
|
||||
static int Device_Open = 0;
|
||||
|
||||
/*
|
||||
* The message the device will give when asked
|
||||
*/
|
||||
static char Message[BUF_LEN];
|
||||
|
||||
/*
|
||||
* How far did the process reading the message get?
|
||||
* Useful if the message is larger than the size of the
|
||||
* buffer we get to fill in device_read.
|
||||
*/
|
||||
static char *Message_Ptr;
|
||||
|
||||
/*
|
||||
* This is called whenever a process attempts to open the device file
|
||||
*/
|
||||
static int device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "device_open(%p)\n", file);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We don't want to talk to two processes at the same time
|
||||
*/
|
||||
if (Device_Open)
|
||||
return -EBUSY;
|
||||
|
||||
Device_Open++;
|
||||
/*
|
||||
* Initialize the message
|
||||
*/
|
||||
Message_Ptr = Message;
|
||||
try_module_get(THIS_MODULE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int device_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "device_release(%p,%p)\n", inode, file);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We're now ready for our next caller
|
||||
*/
|
||||
Device_Open--;
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called whenever a process which has already opened the
|
||||
* device file attempts to read from it.
|
||||
*/
|
||||
static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
|
||||
char __user * buffer, /* buffer to be
|
||||
* filled with data */
|
||||
size_t length, /* length of the buffer */
|
||||
loff_t * offset)
|
||||
{
|
||||
/*
|
||||
* Number of bytes actually written to the buffer
|
||||
*/
|
||||
int bytes_read = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we're at the end of the message, return 0
|
||||
* (which signifies end of file)
|
||||
*/
|
||||
if (*Message_Ptr == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Actually put the data into the buffer
|
||||
*/
|
||||
while (length && *Message_Ptr) {
|
||||
|
||||
/*
|
||||
* Because the buffer is in the user data segment,
|
||||
* not the kernel data segment, assignment wouldn't
|
||||
* work. Instead, we have to use put_user which
|
||||
* copies data from the kernel data segment to the
|
||||
* user data segment.
|
||||
*/
|
||||
put_user(*(Message_Ptr++), buffer++);
|
||||
length--;
|
||||
bytes_read++;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read functions are supposed to return the number
|
||||
* of bytes actually inserted into the buffer
|
||||
*/
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when somebody tries to
|
||||
* write into our device file.
|
||||
*/
|
||||
static ssize_t
|
||||
device_write(struct file *file,
|
||||
const char __user * buffer, size_t length, loff_t * offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < length && i < BUF_LEN; i++)
|
||||
get_user(Message[i], buffer + i);
|
||||
|
||||
Message_Ptr = Message;
|
||||
|
||||
/*
|
||||
* Again, return the number of input characters used
|
||||
*/
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called whenever a process tries to do an ioctl on our
|
||||
* device file. We get two extra parameters (additional to the inode and file
|
||||
* structures, which all device functions get): the number of the ioctl called
|
||||
* and the parameter given to the ioctl function.
|
||||
*
|
||||
* If the ioctl is write or read/write (meaning output is returned to the
|
||||
* calling process), the ioctl call returns the output of this function.
|
||||
*
|
||||
*/
|
||||
long device_ioctl(struct file *file, /* ditto */
|
||||
unsigned int ioctl_num, /* number and param for ioctl */
|
||||
unsigned long ioctl_param)
|
||||
{
|
||||
int i;
|
||||
char *temp;
|
||||
char ch;
|
||||
|
||||
/*
|
||||
* Switch according to the ioctl called
|
||||
*/
|
||||
switch (ioctl_num) {
|
||||
case IOCTL_SET_MSG:
|
||||
/*
|
||||
* Receive a pointer to a message (in user space) and set that
|
||||
* to be the device's message. Get the parameter given to
|
||||
* ioctl by the process.
|
||||
*/
|
||||
temp = (char *)ioctl_param;
|
||||
|
||||
/*
|
||||
* Find the length of the message
|
||||
*/
|
||||
get_user(ch, temp);
|
||||
for (i = 0; ch && i < BUF_LEN; i++, temp++)
|
||||
get_user(ch, temp);
|
||||
|
||||
device_write(file, (char *)ioctl_param, i, 0);
|
||||
break;
|
||||
|
||||
case IOCTL_GET_MSG:
|
||||
/*
|
||||
* Give the current message to the calling process -
|
||||
* the parameter we got is a pointer, fill it.
|
||||
*/
|
||||
i = device_read(file, (char *)ioctl_param, 99, 0);
|
||||
|
||||
/*
|
||||
* Put a zero at the end of the buffer, so it will be
|
||||
* properly terminated
|
||||
*/
|
||||
put_user('\0', (char *)ioctl_param + i);
|
||||
break;
|
||||
|
||||
case IOCTL_GET_NTH_BYTE:
|
||||
/*
|
||||
* This ioctl is both input (ioctl_param) and
|
||||
* output (the return value of this function)
|
||||
*/
|
||||
return Message[ioctl_param];
|
||||
break;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* Module Declarations */
|
||||
|
||||
/*
|
||||
* This structure will hold the functions to be called
|
||||
* when a process does something to the device we
|
||||
* created. Since a pointer to this structure is kept in
|
||||
* the devices table, it can't be local to
|
||||
* init_module. NULL is for unimplemented functions.
|
||||
*/
|
||||
struct file_operations Fops = {
|
||||
.read = device_read,
|
||||
.write = device_write,
|
||||
.unlocked_ioctl = device_ioctl,
|
||||
.open = device_open,
|
||||
.release = device_release, /* a.k.a. close */
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the module - Register the character device
|
||||
*/
|
||||
int init_module()
|
||||
{
|
||||
int ret_val;
|
||||
/*
|
||||
* Register the character device (atleast try)
|
||||
*/
|
||||
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
|
||||
|
||||
/*
|
||||
* Negative values signify an error
|
||||
*/
|
||||
if (ret_val < 0) {
|
||||
printk(KERN_ALERT "%s failed with %d\n",
|
||||
"Sorry, registering the character device ", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s The major device number is %d.\n",
|
||||
"Registeration is a success", MAJOR_NUM);
|
||||
printk(KERN_INFO "If you want to talk to the device driver,\n");
|
||||
printk(KERN_INFO "you'll have to create a device file. \n");
|
||||
printk(KERN_INFO "We suggest you use:\n");
|
||||
printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
|
||||
printk(KERN_INFO "The device file name is important, because\n");
|
||||
printk(KERN_INFO "the ioctl program assumes that's the\n");
|
||||
printk(KERN_INFO "file you'll use.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup - unregister the appropriate file from /proc
|
||||
*/
|
||||
void cleanup_module()
|
||||
{
|
||||
/*
|
||||
* Unregister the device
|
||||
*/
|
||||
unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
|
||||
}
|
||||
164
4.9.11/examples/file_sched.c
Normal file
164
4.9.11/examples/file_sched.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* sched.c - scheduale a function to be called on every timer interrupt.
|
||||
*
|
||||
* Copyright (C) 2001 by Peter Jay Salzman
|
||||
*/
|
||||
|
||||
/*
|
||||
* The necessary header files
|
||||
*/
|
||||
|
||||
/*
|
||||
* Standard in kernel modules
|
||||
*/
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
|
||||
#include <linux/workqueue.h> /* We scheduale tasks here */
|
||||
#include <linux/sched.h> /* We need to put ourselves to sleep
|
||||
and wake up later */
|
||||
#include <linux/init.h> /* For __init and __exit */
|
||||
#include <linux/interrupt.h> /* For irqreturn_t */
|
||||
|
||||
struct proc_dir_entry *Our_Proc_File;
|
||||
#define PROC_ENTRY_FILENAME "sched"
|
||||
#define MY_WORK_QUEUE_NAME "WQsched.c"
|
||||
|
||||
/*
|
||||
* some work_queue related functions
|
||||
* are just available to GPL licensed Modules
|
||||
*/
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* The number of times the timer interrupt has been called so far
|
||||
*/
|
||||
static int TimerIntrpt = 0;
|
||||
|
||||
static void intrpt_routine(struct work_struct *work);
|
||||
|
||||
static int die = 0; /* set this to 1 for shutdown */
|
||||
|
||||
/*
|
||||
* The work queue structure for this task, from workqueue.h
|
||||
*/
|
||||
static struct workqueue_struct *my_workqueue;
|
||||
|
||||
static struct delayed_work Task;
|
||||
static DECLARE_DELAYED_WORK(Task, intrpt_routine);
|
||||
|
||||
/*
|
||||
* This function will be called on every timer interrupt. Notice the void*
|
||||
* pointer - task functions can be used for more than one purpose, each time
|
||||
* getting a different parameter.
|
||||
*/
|
||||
static void intrpt_routine(struct work_struct *work)
|
||||
{
|
||||
/*
|
||||
* Increment the counter
|
||||
*/
|
||||
TimerIntrpt++;
|
||||
|
||||
/*
|
||||
* If cleanup wants us to die
|
||||
*/
|
||||
if (die == 0)
|
||||
queue_delayed_work(my_workqueue, &Task, 100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put data into the proc fs file.
|
||||
*/
|
||||
int
|
||||
procfile_read(char *buffer,
|
||||
char **buffer_location,
|
||||
off_t offset, int buffer_length, int *eof, void *data)
|
||||
{
|
||||
int len; /* The number of bytes actually used */
|
||||
|
||||
/*
|
||||
* It's static so it will still be in memory
|
||||
* when we leave this function
|
||||
*/
|
||||
static char my_buffer[80];
|
||||
|
||||
/*
|
||||
* We give all of our information in one go, so if anybody asks us
|
||||
* if we have more information the answer should always be no.
|
||||
*/
|
||||
if (offset > 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Fill the buffer and get its length
|
||||
*/
|
||||
len = sprintf(my_buffer, "Timer called %d times so far\n", TimerIntrpt);
|
||||
|
||||
/*
|
||||
* Tell the function which called us where the buffer is
|
||||
*/
|
||||
*buffer_location = my_buffer;
|
||||
|
||||
/*
|
||||
* Return the length
|
||||
*/
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the module - register the proc file
|
||||
*/
|
||||
int __init init_module()
|
||||
{
|
||||
/*
|
||||
* Create our /proc file
|
||||
*/
|
||||
Our_Proc_File = proc_create(PROC_ENTRY_FILENAME, 0644, NULL, NULL);
|
||||
|
||||
if (Our_Proc_File == NULL) {
|
||||
remove_proc_entry(PROC_ENTRY_FILENAME, NULL);
|
||||
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
|
||||
PROC_ENTRY_FILENAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
proc_set_size(Our_Proc_File, 80);
|
||||
proc_set_user(Our_Proc_File, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);
|
||||
|
||||
/*
|
||||
* Put the task in the work_timer task queue, so it will be executed at
|
||||
* next timer interrupt
|
||||
*/
|
||||
my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
|
||||
queue_delayed_work(my_workqueue, &Task, 100);
|
||||
|
||||
printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
void __exit cleanup_module()
|
||||
{
|
||||
/*
|
||||
* Unregister our /proc file
|
||||
*/
|
||||
remove_proc_entry(PROC_ENTRY_FILENAME, NULL);
|
||||
printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_FILENAME);
|
||||
|
||||
die = 1; /* keep intrp_routine from queueing itself */
|
||||
cancel_delayed_work(&Task); /* no "new ones" */
|
||||
flush_workqueue(my_workqueue); /* wait till all "old ones" finished */
|
||||
destroy_workqueue(my_workqueue);
|
||||
|
||||
/*
|
||||
* Sleep until intrpt_routine is called one last time. This is
|
||||
* necessary, because otherwise we'll deallocate the memory holding
|
||||
* intrpt_routine and Task while work_timer still references them.
|
||||
* Notice that here we don't allow signals to interrupt us.
|
||||
*
|
||||
* Since WaitQ is now not NULL, this automatically tells the interrupt
|
||||
* routine it's time to die.
|
||||
*/
|
||||
}
|
||||
14
4.9.11/examples/flycheck_syscall.plist
Normal file
14
4.9.11/examples/flycheck_syscall.plist
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>clang_version</key>
|
||||
<string>clang version 3.9.1 (tags/RELEASE_391/final)</string>
|
||||
<key>files</key>
|
||||
<array>
|
||||
</array>
|
||||
<key>diagnostics</key>
|
||||
<array>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
20
4.9.11/examples/hello-1.c
Normal file
20
4.9.11/examples/hello-1.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* hello-1.c - The simplest kernel module.
|
||||
*/
|
||||
#include <linux/module.h> /* Needed by all modules */
|
||||
#include <linux/kernel.h> /* Needed for KERN_INFO */
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello world 1.\n");
|
||||
|
||||
/*
|
||||
* A non 0 return means init_module failed; module can't be loaded.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye world 1.\n");
|
||||
}
|
||||
21
4.9.11/examples/hello-2.c
Normal file
21
4.9.11/examples/hello-2.c
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* hello-2.c - Demonstrating the module_init() and module_exit() macros.
|
||||
* This is preferred over using init_module() and cleanup_module().
|
||||
*/
|
||||
#include <linux/module.h> /* Needed by all modules */
|
||||
#include <linux/kernel.h> /* Needed for KERN_INFO */
|
||||
#include <linux/init.h> /* Needed for the macros */
|
||||
|
||||
static int __init hello_2_init(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello, world 2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit hello_2_exit(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye, world 2\n");
|
||||
}
|
||||
|
||||
module_init(hello_2_init);
|
||||
module_exit(hello_2_exit);
|
||||
22
4.9.11/examples/hello-3.c
Normal file
22
4.9.11/examples/hello-3.c
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* hello-3.c - Illustrating the __init, __initdata and __exit macros.
|
||||
*/
|
||||
#include <linux/module.h> /* Needed by all modules */
|
||||
#include <linux/kernel.h> /* Needed for KERN_INFO */
|
||||
#include <linux/init.h> /* Needed for the macros */
|
||||
|
||||
static int hello3_data __initdata = 3;
|
||||
|
||||
static int __init hello_3_init(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello, world %d\n", hello3_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit hello_3_exit(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye, world 3\n");
|
||||
}
|
||||
|
||||
module_init(hello_3_init);
|
||||
module_exit(hello_3_exit);
|
||||
25
4.9.11/examples/hello-4.c
Normal file
25
4.9.11/examples/hello-4.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* hello-4.c - Demonstrates module documentation.
|
||||
*/
|
||||
#include <linux/module.h> /* Needed by all modules */
|
||||
#include <linux/kernel.h> /* Needed for KERN_INFO */
|
||||
#include <linux/init.h> /* Needed for the macros */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Bob Mottram");
|
||||
MODULE_DESCRIPTION("A sample driver");
|
||||
MODULE_SUPPORTED_DEVICE("testdevice");
|
||||
|
||||
static int __init init_hello_4(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello, world 4\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_hello_4(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye, world 4\n");
|
||||
}
|
||||
|
||||
module_init(init_hello_4);
|
||||
module_exit(cleanup_hello_4);
|
||||
70
4.9.11/examples/hello-5.c
Normal file
70
4.9.11/examples/hello-5.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* hello-5.c - Demonstrates command line argument passing to a module.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Peter Jay Salzman");
|
||||
|
||||
static short int myshort = 1;
|
||||
static int myint = 420;
|
||||
static long int mylong = 9999;
|
||||
static char *mystring = "blah";
|
||||
static int myintArray[2] = { -1, -1 };
|
||||
static int arr_argc = 0;
|
||||
|
||||
/*
|
||||
* module_param(foo, int, 0000)
|
||||
* The first param is the parameters name
|
||||
* The second param is it's data type
|
||||
* The final argument is the permissions bits,
|
||||
* for exposing parameters in sysfs (if non-zero) at a later stage.
|
||||
*/
|
||||
|
||||
module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
MODULE_PARM_DESC(myshort, "A short integer");
|
||||
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
MODULE_PARM_DESC(myint, "An integer");
|
||||
module_param(mylong, long, S_IRUSR);
|
||||
MODULE_PARM_DESC(mylong, "A long integer");
|
||||
module_param(mystring, charp, 0000);
|
||||
MODULE_PARM_DESC(mystring, "A character string");
|
||||
|
||||
/*
|
||||
* module_param_array(name, type, num, perm);
|
||||
* The first param is the parameter's (in this case the array's) name
|
||||
* The second param is the data type of the elements of the array
|
||||
* The third argument is a pointer to the variable that will store the number
|
||||
* of elements of the array initialized by the user at module loading time
|
||||
* The fourth argument is the permission bits
|
||||
*/
|
||||
module_param_array(myintArray, int, &arr_argc, 0000);
|
||||
MODULE_PARM_DESC(myintArray, "An array of integers");
|
||||
|
||||
static int __init hello_5_init(void)
|
||||
{
|
||||
int i;
|
||||
printk(KERN_INFO "Hello, world 5\n=============\n");
|
||||
printk(KERN_INFO "myshort is a short integer: %hd\n", myshort);
|
||||
printk(KERN_INFO "myint is an integer: %d\n", myint);
|
||||
printk(KERN_INFO "mylong is a long integer: %ld\n", mylong);
|
||||
printk(KERN_INFO "mystring is a string: %s\n", mystring);
|
||||
for (i = 0; i < (sizeof myintArray / sizeof (int)); i++)
|
||||
{
|
||||
printk(KERN_INFO "myintArray[%d] = %d\n", i, myintArray[i]);
|
||||
}
|
||||
printk(KERN_INFO "got %d arguments for myintArray.\n", arr_argc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit hello_5_exit(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye, world 5\n");
|
||||
}
|
||||
|
||||
module_init(hello_5_init);
|
||||
module_exit(hello_5_exit);
|
||||
68
4.9.11/examples/hello-sysfs.c
Normal file
68
4.9.11/examples/hello-sysfs.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* hello-sysfs.c sysfs example
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Bob Mottram");
|
||||
|
||||
static struct kobject *mymodule;
|
||||
|
||||
/* the variable you want to be able to change */
|
||||
static int myvariable = 0;
|
||||
|
||||
static ssize_t myvariable_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", myvariable);
|
||||
}
|
||||
|
||||
static ssize_t myvariable_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf, size_t count)
|
||||
{
|
||||
sscanf(buf, "%du", &myvariable);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static struct kobj_attribute myvariable_attribute =
|
||||
__ATTR(myvariable, 0660, myvariable_show,
|
||||
(void*)myvariable_store);
|
||||
|
||||
static int __init mymodule_init (void)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
printk(KERN_INFO "mymodule: initialised\n");
|
||||
|
||||
mymodule =
|
||||
kobject_create_and_add("mymodule", kernel_kobj);
|
||||
if (!mymodule)
|
||||
return -ENOMEM;
|
||||
|
||||
error = sysfs_create_file(mymodule, &myvariable_attribute.attr);
|
||||
if (error) {
|
||||
printk(KERN_INFO "failed to create the myvariable file " \
|
||||
"in /sys/kernel/mymodule\n");
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit mymodule_exit (void)
|
||||
{
|
||||
printk(KERN_INFO "mymodule: Exit success\n");
|
||||
kobject_put(mymodule);
|
||||
}
|
||||
|
||||
module_init(mymodule_init);
|
||||
module_exit(mymodule_exit);
|
||||
95
4.9.11/examples/kbleds.c
Normal file
95
4.9.11/examples/kbleds.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* kbleds.c - Blink keyboard leds until the module is unloaded.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/vt_kern.h> /* for fg_console */
|
||||
#include <linux/tty.h> /* For fg_console, MAX_NR_CONSOLES */
|
||||
#include <linux/kd.h> /* For KDSETLED */
|
||||
#include <linux/vt.h>
|
||||
#include <linux/console_struct.h> /* For vc_cons */
|
||||
|
||||
MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");
|
||||
MODULE_AUTHOR("Daniele Paolo Scarpazza");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct timer_list my_timer;
|
||||
struct tty_driver *my_driver;
|
||||
char kbledstatus = 0;
|
||||
|
||||
#define BLINK_DELAY HZ/5
|
||||
#define ALL_LEDS_ON 0x07
|
||||
#define RESTORE_LEDS 0xFF
|
||||
|
||||
/*
|
||||
* Function my_timer_func blinks the keyboard LEDs periodically by invoking
|
||||
* command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual
|
||||
* terminal ioctl operations, please see file:
|
||||
* /usr/src/linux/drivers/char/vt_ioctl.c, function vt_ioctl().
|
||||
*
|
||||
* The argument to KDSETLED is alternatively set to 7 (thus causing the led
|
||||
* mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF
|
||||
* (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus
|
||||
* the LEDs reflect the actual keyboard status). To learn more on this,
|
||||
* please see file:
|
||||
* /usr/src/linux/drivers/char/keyboard.c, function setledstate().
|
||||
*
|
||||
*/
|
||||
|
||||
static void my_timer_func(unsigned long ptr)
|
||||
{
|
||||
unsigned long *pstatus = (unsigned long *)ptr;
|
||||
struct tty_struct* t = vc_cons[fg_console].d->port.tty;
|
||||
|
||||
if (*pstatus == ALL_LEDS_ON)
|
||||
*pstatus = RESTORE_LEDS;
|
||||
else
|
||||
*pstatus = ALL_LEDS_ON;
|
||||
|
||||
(my_driver->ops->ioctl) (t, KDSETLED, *pstatus);
|
||||
|
||||
my_timer.expires = jiffies + BLINK_DELAY;
|
||||
add_timer(&my_timer);
|
||||
}
|
||||
|
||||
static int __init kbleds_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO "kbleds: loading\n");
|
||||
printk(KERN_INFO "kbleds: fgconsole is %x\n", fg_console);
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (!vc_cons[i].d)
|
||||
break;
|
||||
printk(KERN_INFO "poet_atkm: console[%i/%i] #%i, tty %lx\n", i,
|
||||
MAX_NR_CONSOLES, vc_cons[i].d->vc_num,
|
||||
(unsigned long)vc_cons[i].d->port.tty);
|
||||
}
|
||||
printk(KERN_INFO "kbleds: finished scanning consoles\n");
|
||||
|
||||
my_driver = vc_cons[fg_console].d->port.tty->driver;
|
||||
printk(KERN_INFO "kbleds: tty driver magic %x\n", my_driver->magic);
|
||||
|
||||
/*
|
||||
* Set up the LED blink timer the first time
|
||||
*/
|
||||
init_timer(&my_timer);
|
||||
my_timer.function = my_timer_func;
|
||||
my_timer.data = (unsigned long)&kbledstatus;
|
||||
my_timer.expires = jiffies + BLINK_DELAY;
|
||||
add_timer(&my_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit kbleds_cleanup(void)
|
||||
{
|
||||
printk(KERN_INFO "kbleds: unloading...\n");
|
||||
del_timer(&my_timer);
|
||||
(my_driver->ops->ioctl) (vc_cons[fg_console].d->port.tty,
|
||||
KDSETLED, RESTORE_LEDS);
|
||||
}
|
||||
|
||||
module_init(kbleds_init);
|
||||
module_exit(kbleds_cleanup);
|
||||
6
4.9.11/examples/other/Makefile
Normal file
6
4.9.11/examples/other/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
all:
|
||||
gcc -o cat_noblock cat_noblock.c
|
||||
gcc -o ioctl ioctl.c
|
||||
|
||||
clean:
|
||||
rm ioctl cat_noblock *.plist
|
||||
65
4.9.11/examples/other/cat_noblock.c
Normal file
65
4.9.11/examples/other/cat_noblock.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/* cat_noblock.c - open a file and display its contents, but exit rather than
|
||||
* wait for input */
|
||||
/* Copyright (C) 1998 by Ori Pomerantz */
|
||||
|
||||
#include <stdio.h> /* standard I/O */
|
||||
#include <fcntl.h> /* for open */
|
||||
#include <unistd.h> /* for read */
|
||||
#include <stdlib.h> /* for exit */
|
||||
#include <errno.h> /* for errno */
|
||||
|
||||
#define MAX_BYTES 1024*4
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd; /* The file descriptor for the file to read */
|
||||
size_t bytes; /* The number of bytes read */
|
||||
char buffer[MAX_BYTES]; /* The buffer for the bytes */
|
||||
|
||||
|
||||
/* Usage */
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <filename>\n", argv[0]);
|
||||
puts("Reads the content of a file, but doesn't wait for input");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Open the file for reading in non blocking mode */
|
||||
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
|
||||
|
||||
/* If open failed */
|
||||
if (fd == -1) {
|
||||
if (errno = EAGAIN)
|
||||
puts("Open would block");
|
||||
else
|
||||
puts("Open failed");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Read the file and output its contents */
|
||||
do {
|
||||
int i;
|
||||
|
||||
/* Read characters from the file */
|
||||
bytes = read(fd, buffer, MAX_BYTES);
|
||||
|
||||
/* If there's an error, report it and die */
|
||||
if (bytes == -1) {
|
||||
if (errno = EAGAIN)
|
||||
puts("Normally I'd block, but you told me not to");
|
||||
else
|
||||
puts("Another read error");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Print the characters */
|
||||
if (bytes > 0) {
|
||||
for(i=0; i<bytes; i++)
|
||||
putchar(buffer[i]);
|
||||
}
|
||||
|
||||
/* While there are no errors and the file isn't over */
|
||||
} while (bytes > 0);
|
||||
return 0;
|
||||
}
|
||||
104
4.9.11/examples/other/ioctl.c
Normal file
104
4.9.11/examples/other/ioctl.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* ioctl.c - the process to use ioctl's to control the kernel module
|
||||
*
|
||||
* Until now we could have used cat for input and output. But now
|
||||
* we need to do ioctl's, which require writing our own process.
|
||||
*/
|
||||
|
||||
/*
|
||||
* device specifics, such as ioctl numbers and the
|
||||
* major device file.
|
||||
*/
|
||||
#include "../chardev.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h> /* open */
|
||||
#include <unistd.h> /* exit */
|
||||
#include <sys/ioctl.h> /* ioctl */
|
||||
|
||||
/*
|
||||
* Functions for the ioctl calls
|
||||
*/
|
||||
|
||||
int ioctl_set_msg(int file_desc, char *message)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);
|
||||
|
||||
if (ret_val < 0) {
|
||||
printf("ioctl_set_msg failed:%d\n", ret_val);
|
||||
exit(-1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ioctl_get_msg(int file_desc)
|
||||
{
|
||||
int ret_val;
|
||||
char message[100];
|
||||
|
||||
/*
|
||||
* Warning - this is dangerous because we don't tell
|
||||
* the kernel how far it's allowed to write, so it
|
||||
* might overflow the buffer. In a real production
|
||||
* program, we would have used two ioctls - one to tell
|
||||
* the kernel the buffer length and another to give
|
||||
* it the buffer to fill
|
||||
*/
|
||||
ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);
|
||||
|
||||
if (ret_val < 0) {
|
||||
printf("ioctl_get_msg failed:%d\n", ret_val);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("get_msg message:%s\n", message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ioctl_get_nth_byte(int file_desc)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
|
||||
printf("get_nth_byte message:");
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);
|
||||
|
||||
if (c < 0) {
|
||||
printf("ioctl_get_nth_byte failed at the %d'th byte:\n",
|
||||
i);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
putchar(c);
|
||||
} while (c != 0);
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main - Call the ioctl functions
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
int file_desc, ret_val;
|
||||
char *msg = "Message passed by ioctl\n";
|
||||
|
||||
file_desc = open(DEVICE_FILE_NAME, 0);
|
||||
if (file_desc < 0) {
|
||||
printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ioctl_get_nth_byte(file_desc);
|
||||
ioctl_get_msg(file_desc);
|
||||
ioctl_set_msg(file_desc, msg);
|
||||
|
||||
close(file_desc);
|
||||
return 0;
|
||||
}
|
||||
108
4.9.11/examples/print_string.c
Normal file
108
4.9.11/examples/print_string.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* print_string.c - Send output to the tty we're running on, regardless if it's
|
||||
* through X11, telnet, etc. We do this by printing the string to the tty
|
||||
* associated with the current task.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h> /* For current */
|
||||
#include <linux/tty.h> /* For the tty declarations */
|
||||
#include <linux/version.h> /* For LINUX_VERSION_CODE */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Peter Jay Salzman");
|
||||
|
||||
static void print_string(char *str)
|
||||
{
|
||||
struct tty_struct *my_tty;
|
||||
const struct tty_operations *ttyops;
|
||||
|
||||
/*
|
||||
* tty struct went into signal struct in 2.6.6
|
||||
*/
|
||||
#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,5) )
|
||||
/*
|
||||
* The tty for the current task
|
||||
*/
|
||||
my_tty = current->tty;
|
||||
#else
|
||||
/*
|
||||
* The tty for the current task, for 2.6.6+ kernels
|
||||
*/
|
||||
my_tty = current->signal->tty;
|
||||
#endif
|
||||
ttyops = my_tty->driver->ops;
|
||||
|
||||
/*
|
||||
* If my_tty is NULL, the current task has no tty you can print to
|
||||
* (ie, if it's a daemon). If so, there's nothing we can do.
|
||||
*/
|
||||
if (my_tty != NULL) {
|
||||
|
||||
/*
|
||||
* my_tty->driver is a struct which holds the tty's functions,
|
||||
* one of which (write) is used to write strings to the tty.
|
||||
* It can be used to take a string either from the user's or
|
||||
* kernel's memory segment.
|
||||
*
|
||||
* The function's 1st parameter is the tty to write to,
|
||||
* because the same function would normally be used for all
|
||||
* tty's of a certain type. The 2nd parameter controls
|
||||
* whether the function receives a string from kernel
|
||||
* memory (false, 0) or from user memory (true, non zero).
|
||||
* BTW: this param has been removed in Kernels > 2.6.9
|
||||
* The (2nd) 3rd parameter is a pointer to a string.
|
||||
* The (3rd) 4th parameter is the length of the string.
|
||||
*
|
||||
* As you will see below, sometimes it's necessary to use
|
||||
* preprocessor stuff to create code that works for different
|
||||
* kernel versions. The (naive) approach we've taken here
|
||||
* does not scale well. The right way to deal with this
|
||||
* is described in section 2 of
|
||||
* linux/Documentation/SubmittingPatches
|
||||
*/
|
||||
(ttyops->write) (my_tty, /* The tty itself */
|
||||
#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,9) )
|
||||
0, /* Don't take the string
|
||||
from user space */
|
||||
#endif
|
||||
str, /* String */
|
||||
strlen(str)); /* Length */
|
||||
|
||||
/*
|
||||
* ttys were originally hardware devices, which (usually)
|
||||
* strictly followed the ASCII standard. In ASCII, to move to
|
||||
* a new line you need two characters, a carriage return and a
|
||||
* line feed. On Unix, the ASCII line feed is used for both
|
||||
* purposes - so we can't just use \n, because it wouldn't have
|
||||
* a carriage return and the next line will start at the
|
||||
* column right after the line feed.
|
||||
*
|
||||
* This is why text files are different between Unix and
|
||||
* MS Windows. In CP/M and derivatives, like MS-DOS and
|
||||
* MS Windows, the ASCII standard was strictly adhered to,
|
||||
* and therefore a newline requirs both a LF and a CR.
|
||||
*/
|
||||
|
||||
#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,9) )
|
||||
(ttyops->write) (my_tty, 0, "\015\012", 2);
|
||||
#else
|
||||
(ttyops->write) (my_tty, "\015\012", 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int __init print_string_init(void)
|
||||
{
|
||||
print_string("The module has been inserted. Hello world!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit print_string_exit(void)
|
||||
{
|
||||
print_string("The module has been removed. Farewell world!");
|
||||
}
|
||||
|
||||
module_init(print_string_init);
|
||||
module_exit(print_string_exit);
|
||||
50
4.9.11/examples/procfs1.c
Normal file
50
4.9.11/examples/procfs1.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
procfs1.c
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define procfs_name "helloworld"
|
||||
|
||||
struct proc_dir_entry *Our_Proc_File;
|
||||
|
||||
|
||||
ssize_t procfile_read(struct file *filePointer,char *buffer,
|
||||
size_t buffer_length, loff_t * offset)
|
||||
{
|
||||
int ret=0;
|
||||
if(strlen(buffer) ==0) {
|
||||
printk(KERN_INFO "procfile read %s\n",filePointer->f_path.dentry->d_name.name);
|
||||
ret=copy_to_user(buffer,"HelloWorld!\n",sizeof("HelloWorld!\n"));
|
||||
ret=sizeof("HelloWorld!\n");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static const struct file_operations proc_file_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = procfile_read,
|
||||
};
|
||||
|
||||
int init_module()
|
||||
{
|
||||
Our_Proc_File = proc_create(procfs_name,0644,NULL,&proc_file_fops);
|
||||
if(NULL==Our_Proc_File) {
|
||||
proc_remove(Our_Proc_File);
|
||||
printk(KERN_ALERT "Error:Could not initialize /proc/%s\n",procfs_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "/proc/%s created\n", procfs_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module()
|
||||
{
|
||||
proc_remove(Our_Proc_File);
|
||||
printk(KERN_INFO "/proc/%s removed\n", procfs_name);
|
||||
}
|
||||
98
4.9.11/examples/procfs2.c
Normal file
98
4.9.11/examples/procfs2.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* procfs2.c - create a "file" in /proc
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
|
||||
#include <asm/uaccess.h> /* for copy_from_user */
|
||||
|
||||
#define PROCFS_MAX_SIZE 1024
|
||||
#define PROCFS_NAME "buffer1k"
|
||||
|
||||
/**
|
||||
* This structure hold information about the /proc file
|
||||
*
|
||||
*/
|
||||
static struct proc_dir_entry *Our_Proc_File;
|
||||
|
||||
/**
|
||||
* The buffer used to store character for this module
|
||||
*
|
||||
*/
|
||||
static char procfs_buffer[PROCFS_MAX_SIZE];
|
||||
|
||||
/**
|
||||
* The size of the buffer
|
||||
*
|
||||
*/
|
||||
static unsigned long procfs_buffer_size = 0;
|
||||
|
||||
/**
|
||||
* This function is called then the /proc file is read
|
||||
*
|
||||
*/
|
||||
ssize_t procfile_read(struct file *filePointer,char *buffer,
|
||||
size_t buffer_length, loff_t * offset)
|
||||
{
|
||||
int ret=0;
|
||||
if(strlen(buffer) ==0) {
|
||||
printk(KERN_INFO "procfile read %s\n",filePointer->f_path.dentry->d_name.name);
|
||||
ret=copy_to_user(buffer,"HelloWorld!\n",sizeof("HelloWorld!\n"));
|
||||
ret=sizeof("HelloWorld!\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is called with the /proc file is written
|
||||
*
|
||||
*/
|
||||
static ssize_t procfile_write(struct file *file, const char *buff,
|
||||
size_t len, loff_t *off)
|
||||
{
|
||||
procfs_buffer_size = len;
|
||||
if (procfs_buffer_size > PROCFS_MAX_SIZE)
|
||||
procfs_buffer_size = PROCFS_MAX_SIZE;
|
||||
|
||||
if (copy_from_user(procfs_buffer, buff, procfs_buffer_size))
|
||||
return -EFAULT;
|
||||
|
||||
procfs_buffer[procfs_buffer_size] = '\0';
|
||||
return procfs_buffer_size;
|
||||
}
|
||||
|
||||
static const struct file_operations proc_file_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = procfile_read,
|
||||
.write = procfile_write,
|
||||
};
|
||||
|
||||
/**
|
||||
*This function is called when the module is loaded
|
||||
*
|
||||
*/
|
||||
int init_module()
|
||||
{
|
||||
Our_Proc_File = proc_create(PROCFS_NAME,0644,NULL,&proc_file_fops);
|
||||
if(NULL==Our_Proc_File) {
|
||||
proc_remove(Our_Proc_File);
|
||||
printk(KERN_ALERT "Error:Could not initialize /proc/%s\n",PROCFS_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*This function is called when the module is unloaded
|
||||
*
|
||||
*/
|
||||
void cleanup_module()
|
||||
{
|
||||
proc_remove(Our_Proc_File);
|
||||
printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME);
|
||||
}
|
||||
83
4.9.11/examples/procfs3.c
Normal file
83
4.9.11/examples/procfs3.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
procfs3.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define PROCFS_MAX_SIZE 2048
|
||||
#define PROCFS_ENTRY_FILENAME "buffer2k"
|
||||
|
||||
struct proc_dir_entry *Our_Proc_File;
|
||||
static char procfs_buffer[PROCFS_MAX_SIZE];
|
||||
static unsigned long procfs_buffer_size = 0;
|
||||
|
||||
static ssize_t procfs_read(struct file *filp, char *buffer,
|
||||
size_t length, loff_t *offset)
|
||||
{
|
||||
static int finished = 0;
|
||||
if(finished)
|
||||
{
|
||||
printk(KERN_DEBUG "procfs_read: END\n");
|
||||
finished = 0;
|
||||
return 0;
|
||||
}
|
||||
finished = 1;
|
||||
if(copy_to_user(buffer, procfs_buffer, procfs_buffer_size))
|
||||
return -EFAULT;
|
||||
printk(KERN_DEBUG "procfs_read: read %lu bytes\n", procfs_buffer_size);
|
||||
return procfs_buffer_size;
|
||||
}
|
||||
static ssize_t procfs_write(struct file *file, const char *buffer,
|
||||
size_t len, loff_t *off)
|
||||
{
|
||||
if(len>PROCFS_MAX_SIZE)
|
||||
procfs_buffer_size = PROCFS_MAX_SIZE;
|
||||
else
|
||||
procfs_buffer_size = len;
|
||||
if(copy_from_user(procfs_buffer, buffer, procfs_buffer_size))
|
||||
return -EFAULT;
|
||||
printk(KERN_DEBUG "procfs_write: write %lu bytes\n", procfs_buffer_size);
|
||||
return procfs_buffer_size;
|
||||
}
|
||||
int procfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
try_module_get(THIS_MODULE);
|
||||
return 0;
|
||||
}
|
||||
int procfs_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
module_put(THIS_MODULE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations File_Ops_4_Our_Proc_File = {
|
||||
.read = procfs_read,
|
||||
.write = procfs_write,
|
||||
.open = procfs_open,
|
||||
.release = procfs_close,
|
||||
};
|
||||
|
||||
int init_module()
|
||||
{
|
||||
Our_Proc_File = proc_create(PROCFS_ENTRY_FILENAME, 0644, NULL,&File_Ops_4_Our_Proc_File);
|
||||
if(Our_Proc_File == NULL)
|
||||
{
|
||||
remove_proc_entry(PROCFS_ENTRY_FILENAME, NULL);
|
||||
printk(KERN_DEBUG "Error: Could not initialize /proc/%s\n", PROCFS_ENTRY_FILENAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
proc_set_size(Our_Proc_File, 80);
|
||||
proc_set_user(Our_Proc_File, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);
|
||||
|
||||
printk(KERN_DEBUG "/proc/%s created\n", PROCFS_ENTRY_FILENAME);
|
||||
return 0;
|
||||
}
|
||||
void cleanup_module()
|
||||
{
|
||||
remove_proc_entry(PROCFS_ENTRY_FILENAME, NULL);
|
||||
printk(KERN_DEBUG "/proc/%s removed\n", PROCFS_ENTRY_FILENAME);
|
||||
}
|
||||
134
4.9.11/examples/procfs4.c
Normal file
134
4.9.11/examples/procfs4.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* procfs4.c - create a "file" in /proc
|
||||
* This program uses the seq_file library to manage the /proc file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/proc_fs.h> /* Necessary because we use proc fs */
|
||||
#include <linux/seq_file.h> /* for seq_file */
|
||||
|
||||
#define PROC_NAME "iter"
|
||||
|
||||
MODULE_AUTHOR("Philippe Reynes");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/**
|
||||
* This function is called at the beginning of a sequence.
|
||||
* ie, when:
|
||||
* - the /proc file is read (first time)
|
||||
* - after the function stop (end of sequence)
|
||||
*
|
||||
*/
|
||||
static void *my_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
static unsigned long counter = 0;
|
||||
|
||||
/* beginning a new sequence ? */
|
||||
if ( *pos == 0 ) {
|
||||
/* yes => return a non null value to begin the sequence */
|
||||
return &counter;
|
||||
}
|
||||
else {
|
||||
/* no => it's the end of the sequence, return end to stop reading */
|
||||
*pos = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called after the beginning of a sequence.
|
||||
* It's called untill the return is NULL (this ends the sequence).
|
||||
*
|
||||
*/
|
||||
static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
unsigned long *tmp_v = (unsigned long *)v;
|
||||
(*tmp_v)++;
|
||||
(*pos)++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called at the end of a sequence
|
||||
*
|
||||
*/
|
||||
static void my_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
/* nothing to do, we use a static value in start() */
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called for each "step" of a sequence
|
||||
*
|
||||
*/
|
||||
static int my_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
loff_t *spos = (loff_t *) v;
|
||||
|
||||
seq_printf(s, "%Ld\n", *spos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This structure gather "function" to manage the sequence
|
||||
*
|
||||
*/
|
||||
static struct seq_operations my_seq_ops = {
|
||||
.start = my_seq_start,
|
||||
.next = my_seq_next,
|
||||
.stop = my_seq_stop,
|
||||
.show = my_seq_show
|
||||
};
|
||||
|
||||
/**
|
||||
* This function is called when the /proc file is open.
|
||||
*
|
||||
*/
|
||||
static int my_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &my_seq_ops);
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure gather "function" that manage the /proc file
|
||||
*
|
||||
*/
|
||||
static struct file_operations my_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = my_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This function is called when the module is loaded
|
||||
*
|
||||
*/
|
||||
int init_module(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
entry = proc_create(PROC_NAME, 0, NULL, &my_file_ops);
|
||||
if(entry == NULL)
|
||||
{
|
||||
remove_proc_entry(PROC_NAME, NULL);
|
||||
printk(KERN_DEBUG "Error: Could not initialize /proc/%s\n", PROC_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when the module is unloaded.
|
||||
*
|
||||
*/
|
||||
void cleanup_module(void)
|
||||
{
|
||||
remove_proc_entry(PROC_NAME, NULL);
|
||||
printk(KERN_DEBUG "/proc/%s removed\n", PROC_NAME);
|
||||
}
|
||||
265
4.9.11/examples/sleep.c
Normal file
265
4.9.11/examples/sleep.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* sleep.c - create a /proc file, and if several processes try to open it at
|
||||
* the same time, put all but one to sleep
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
#include <linux/proc_fs.h> /* Necessary because we use proc fs */
|
||||
#include <linux/sched.h> /* For putting processes to sleep and
|
||||
waking them up */
|
||||
#include <asm/uaccess.h> /* for get_user and put_user */
|
||||
|
||||
/*
|
||||
* The module's file functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Here we keep the last message received, to prove that we can process our
|
||||
* input
|
||||
*/
|
||||
#define MESSAGE_LENGTH 80
|
||||
static char Message[MESSAGE_LENGTH];
|
||||
|
||||
static struct proc_dir_entry *Our_Proc_File;
|
||||
#define PROC_ENTRY_FILENAME "sleep"
|
||||
|
||||
/*
|
||||
* Since we use the file operations struct, we can't use the special proc
|
||||
* output provisions - we have to use a standard read function, which is this
|
||||
* function
|
||||
*/
|
||||
static ssize_t module_output(struct file *file, /* see include/linux/fs.h */
|
||||
char *buf, /* The buffer to put data to
|
||||
(in the user segment) */
|
||||
size_t len, /* The length of the buffer */
|
||||
loff_t * offset)
|
||||
{
|
||||
static int finished = 0;
|
||||
int i;
|
||||
char message[MESSAGE_LENGTH + 30];
|
||||
|
||||
/*
|
||||
* Return 0 to signify end of file - that we have nothing
|
||||
* more to say at this point.
|
||||
*/
|
||||
if (finished) {
|
||||
finished = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If you don't understand this by now, you're hopeless as a kernel
|
||||
* programmer.
|
||||
*/
|
||||
sprintf(message, "Last input:%s\n", Message);
|
||||
for (i = 0; i < len && message[i]; i++)
|
||||
put_user(message[i], buf + i);
|
||||
|
||||
finished = 1;
|
||||
return i; /* Return the number of bytes "read" */
|
||||
}
|
||||
|
||||
/*
|
||||
* This function receives input from the user when the user writes to the /proc
|
||||
* file.
|
||||
*/
|
||||
static ssize_t module_input(struct file *file, /* The file itself */
|
||||
const char *buf, /* The buffer with input */
|
||||
size_t length, /* The buffer's length */
|
||||
loff_t * offset) /* offset to file - ignore */
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Put the input into Message, where module_output will later be
|
||||
* able to use it
|
||||
*/
|
||||
for (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++)
|
||||
get_user(Message[i], buf + i);
|
||||
/*
|
||||
* we want a standard, zero terminated string
|
||||
*/
|
||||
Message[i] = '\0';
|
||||
|
||||
/*
|
||||
* We need to return the number of input characters used
|
||||
*/
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 if the file is currently open by somebody
|
||||
*/
|
||||
int Already_Open = 0;
|
||||
|
||||
/*
|
||||
* Queue of processes who want our file
|
||||
*/
|
||||
DECLARE_WAIT_QUEUE_HEAD(WaitQ);
|
||||
/*
|
||||
* Called when the /proc file is opened
|
||||
*/
|
||||
static int module_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
* If the file's flags include O_NONBLOCK, it means the process doesn't
|
||||
* want to wait for the file. In this case, if the file is already
|
||||
* open, we should fail with -EAGAIN, meaning "you'll have to try
|
||||
* again", instead of blocking a process which would rather stay awake.
|
||||
*/
|
||||
if ((file->f_flags & O_NONBLOCK) && Already_Open)
|
||||
return -EAGAIN;
|
||||
|
||||
/*
|
||||
* This is the correct place for try_module_get(THIS_MODULE) because
|
||||
* if a process is in the loop, which is within the kernel module,
|
||||
* the kernel module must not be removed.
|
||||
*/
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
/*
|
||||
* If the file is already open, wait until it isn't
|
||||
*/
|
||||
|
||||
while (Already_Open) {
|
||||
int i, is_sig = 0;
|
||||
|
||||
/*
|
||||
* This function puts the current process, including any system
|
||||
* calls, such as us, to sleep. Execution will be resumed right
|
||||
* after the function call, either because somebody called
|
||||
* wake_up(&WaitQ) (only module_close does that, when the file
|
||||
* is closed) or when a signal, such as Ctrl-C, is sent
|
||||
* to the process
|
||||
*/
|
||||
wait_event_interruptible(WaitQ, !Already_Open);
|
||||
|
||||
/*
|
||||
* If we woke up because we got a signal we're not blocking,
|
||||
* return -EINTR (fail the system call). This allows processes
|
||||
* to be killed or stopped.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Emmanuel Papirakis:
|
||||
*
|
||||
* This is a little update to work with 2.2.*. Signals now are contained in
|
||||
* two words (64 bits) and are stored in a structure that contains an array of
|
||||
* two unsigned longs. We now have to make 2 checks in our if.
|
||||
*
|
||||
* Ori Pomerantz:
|
||||
*
|
||||
* Nobody promised me they'll never use more than 64 bits, or that this book
|
||||
* won't be used for a version of Linux with a word size of 16 bits. This code
|
||||
* would work in any case.
|
||||
*/
|
||||
for (i = 0; i < _NSIG_WORDS && !is_sig; i++)
|
||||
is_sig =
|
||||
current->pending.signal.sig[i] & ~current->
|
||||
blocked.sig[i];
|
||||
|
||||
if (is_sig) {
|
||||
/*
|
||||
* It's important to put module_put(THIS_MODULE) here,
|
||||
* because for processes where the open is interrupted
|
||||
* there will never be a corresponding close. If we
|
||||
* don't decrement the usage count here, we will be
|
||||
* left with a positive usage count which we'll have no
|
||||
* way to bring down to zero, giving us an immortal
|
||||
* module, which can only be killed by rebooting
|
||||
* the machine.
|
||||
*/
|
||||
module_put(THIS_MODULE);
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got here, Already_Open must be zero
|
||||
*/
|
||||
|
||||
/*
|
||||
* Open the file
|
||||
*/
|
||||
Already_Open = 1;
|
||||
return 0; /* Allow the access */
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the /proc file is closed
|
||||
*/
|
||||
int module_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
* Set Already_Open to zero, so one of the processes in the WaitQ will
|
||||
* be able to set Already_Open back to one and to open the file. All
|
||||
* the other processes will be called when Already_Open is back to one,
|
||||
* so they'll go back to sleep.
|
||||
*/
|
||||
Already_Open = 0;
|
||||
|
||||
/*
|
||||
* Wake up all the processes in WaitQ, so if anybody is waiting for the
|
||||
* file, they can have it.
|
||||
*/
|
||||
wake_up(&WaitQ);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
/*
|
||||
* Structures to register as the /proc file, with pointers to all the relevant
|
||||
* functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File operations for our proc file. This is where we place pointers to all
|
||||
* the functions called when somebody tries to do something to our file. NULL
|
||||
* means we don't want to deal with something.
|
||||
*/
|
||||
static struct file_operations File_Ops_4_Our_Proc_File = {
|
||||
.read = module_output, /* "read" from the file */
|
||||
.write = module_input, /* "write" to the file */
|
||||
.open = module_open, /* called when the /proc file is opened */
|
||||
.release = module_close, /* called when it's closed */
|
||||
};
|
||||
|
||||
/*
|
||||
* Module initialization and cleanup
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize the module - register the proc file
|
||||
*/
|
||||
|
||||
int init_module()
|
||||
{
|
||||
Our_Proc_File = proc_create(PROC_ENTRY_FILENAME, 0644, NULL, &File_Ops_4_Our_Proc_File);
|
||||
if(Our_Proc_File == NULL)
|
||||
{
|
||||
remove_proc_entry(PROC_ENTRY_FILENAME, NULL);
|
||||
printk(KERN_DEBUG "Error: Could not initialize /proc/%s\n", PROC_ENTRY_FILENAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
proc_set_size(Our_Proc_File, 80);
|
||||
proc_set_user(Our_Proc_File, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);
|
||||
|
||||
printk(KERN_INFO "/proc/test created\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup - unregister our file from /proc. This could get dangerous if
|
||||
* there are still processes waiting in WaitQ, because they are inside our
|
||||
* open function, which will get unloaded. I'll explain how to avoid removal
|
||||
* of a kernel module in such a case in chapter 10.
|
||||
*/
|
||||
void cleanup_module()
|
||||
{
|
||||
remove_proc_entry(PROC_ENTRY_FILENAME, NULL);
|
||||
printk(KERN_DEBUG "/proc/%s removed\n", PROC_ENTRY_FILENAME);
|
||||
}
|
||||
12
4.9.11/examples/start.c
Normal file
12
4.9.11/examples/start.c
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* start.c - Illustration of multi filed modules
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello, world - this is the kernel speaking\n");
|
||||
return 0;
|
||||
}
|
||||
11
4.9.11/examples/stop.c
Normal file
11
4.9.11/examples/stop.c
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* stop.c - Illustration of multi filed modules
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* We're doing kernel work */
|
||||
#include <linux/module.h> /* Specifically, a module */
|
||||
|
||||
void cleanup_module()
|
||||
{
|
||||
printk(KERN_INFO "Short is the life of a kernel module\n");
|
||||
}
|
||||
155
4.9.11/examples/syscall.c
Normal file
155
4.9.11/examples/syscall.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* syscall.c
|
||||
*
|
||||
* System call "stealing" sample.
|
||||
*
|
||||
* Disables page protection at a processor level by
|
||||
* changing the 16th bit in the cr0 register (could be Intel specific)
|
||||
*
|
||||
* Based on example by Peter Jay Salzman and
|
||||
* https://bbs.archlinux.org/viewtopic.php?id=139406
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/paravirt.h>
|
||||
#include <linux/moduleparam.h> /* which will have params */
|
||||
#include <linux/unistd.h> /* The list of system calls */
|
||||
|
||||
/*
|
||||
* For the current (process) structure, we need
|
||||
* this to know who the current user is.
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
unsigned long **sys_call_table;
|
||||
unsigned long original_cr0;
|
||||
|
||||
/*
|
||||
* UID we want to spy on - will be filled from the
|
||||
* command line
|
||||
*/
|
||||
static int uid;
|
||||
module_param(uid, int, 0644);
|
||||
|
||||
/*
|
||||
* A pointer to the original system call. The reason
|
||||
* we keep this, rather than call the original function
|
||||
* (sys_open), is because somebody else might have
|
||||
* replaced the system call before us. Note that this
|
||||
* is not 100% safe, because if another module
|
||||
* replaced sys_open before us, then when we're inserted
|
||||
* we'll call the function in that module - and it
|
||||
* might be removed before we are.
|
||||
*
|
||||
* Another reason for this is that we can't get sys_open.
|
||||
* It's a static variable, so it is not exported.
|
||||
*/
|
||||
asmlinkage int (*original_call) (const char *, int, int);
|
||||
|
||||
/*
|
||||
* The function we'll replace sys_open (the function
|
||||
* called when you call the open system call) with. To
|
||||
* find the exact prototype, with the number and type
|
||||
* of arguments, we find the original function first
|
||||
* (it's at fs/open.c).
|
||||
*
|
||||
* In theory, this means that we're tied to the
|
||||
* current version of the kernel. In practice, the
|
||||
* system calls almost never change (it would wreck havoc
|
||||
* and require programs to be recompiled, since the system
|
||||
* calls are the interface between the kernel and the
|
||||
* processes).
|
||||
*/
|
||||
asmlinkage int our_sys_open(const char *filename, int flags, int mode)
|
||||
{
|
||||
int i = 0;
|
||||
char ch;
|
||||
|
||||
/*
|
||||
* Report the file, if relevant
|
||||
*/
|
||||
printk("Opened file by %d: ", uid);
|
||||
do {
|
||||
get_user(ch, filename + i);
|
||||
i++;
|
||||
printk("%c", ch);
|
||||
} while (ch != 0);
|
||||
printk("\n");
|
||||
|
||||
/*
|
||||
* Call the original sys_open - otherwise, we lose
|
||||
* the ability to open files
|
||||
*/
|
||||
return original_call(filename, flags, mode);
|
||||
}
|
||||
|
||||
static unsigned long **aquire_sys_call_table(void)
|
||||
{
|
||||
unsigned long int offset = PAGE_OFFSET;
|
||||
unsigned long **sct;
|
||||
|
||||
while (offset < ULLONG_MAX) {
|
||||
sct = (unsigned long **)offset;
|
||||
|
||||
if (sct[__NR_close] == (unsigned long *) sys_close)
|
||||
return sct;
|
||||
|
||||
offset += sizeof(void *);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __init syscall_start(void)
|
||||
{
|
||||
if(!(sys_call_table = aquire_sys_call_table()))
|
||||
return -1;
|
||||
|
||||
original_cr0 = read_cr0();
|
||||
|
||||
write_cr0(original_cr0 & ~0x00010000);
|
||||
|
||||
/* keep track of the original open function */
|
||||
original_call = (void*)sys_call_table[__NR_open];
|
||||
|
||||
/* use our open function instead */
|
||||
sys_call_table[__NR_open] = (unsigned long *)our_sys_open;
|
||||
|
||||
write_cr0(original_cr0);
|
||||
|
||||
printk(KERN_INFO "Spying on UID:%d\n", uid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit syscall_end(void)
|
||||
{
|
||||
if(!sys_call_table) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the system call back to normal
|
||||
*/
|
||||
if (sys_call_table[__NR_open] != (unsigned long *)our_sys_open) {
|
||||
printk(KERN_ALERT "Somebody else also played with the ");
|
||||
printk(KERN_ALERT "open system call\n");
|
||||
printk(KERN_ALERT "The system may be left in ");
|
||||
printk(KERN_ALERT "an unstable state.\n");
|
||||
}
|
||||
|
||||
write_cr0(original_cr0 & ~0x00010000);
|
||||
sys_call_table[__NR_open] = (unsigned long *)original_call;
|
||||
write_cr0(original_cr0);
|
||||
|
||||
msleep(2000);
|
||||
}
|
||||
|
||||
module_init(syscall_start);
|
||||
module_exit(syscall_end);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
BIN
4.9.11/img/seq_file.png
Normal file
BIN
4.9.11/img/seq_file.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Reference in New Issue
Block a user