Skip to content

Latest commit

 

History

History
175 lines (148 loc) · 5.71 KB

File metadata and controls

175 lines (148 loc) · 5.71 KB

hello

Next, Module hello will be used to create a proc file named hello, which will send us 'Hello World' from Kernel space

Pre-requisites

Steps

  • Navigate to Project directory
cd hello
  • compile Module
sudo make
  • Look for hello in loaded Modules
sudo lsmod | grep hello

You will get no results

  • Look for file hello in porc fs
cat /proc/hello

you will see : cat: proc/hello: No such file or directory

  • Insert Module
sudo insmod hello.ko
  • Again check for simple in module list
sudo lsmod | grep hello

Now you will see the hello module listed image

  • Check the proc file again
cat /proc/hello

image

Now we can see Hello World !

  • Remove the Module and verify it's gone
sudo rmmod hello
sudo lsmod | grep hello

No output means module is removed

  • Check for proc file again
cat /proc/hello

image

Understanding the Code

  • Necessary Headers
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
  • Define macros
#define BUFFER_SIZE 128
#define PROC_NAME "hello"
  • Declare function to be called upon proc file read
static ssize_t proc_read(struct file *file, char __user *usr_buf,size_t count, loff_t *pos);

proc_read will be called whenver we read the created proc file

  • Set options for creating new proc file
static const struct proc_ops hello_ops= {
.proc_read = proc_read
};

proc_ops is struct which has options to be used while creating a proc file entry, here we only need to read proc file, hence, we only set the proc_read member, which is a function pointer.

  • This function is called when module is loaded
static int proc_init(void)
{
/* creates the /proc/hello entry */
proc_create(PROC_NAME, 0666, NULL, &hello_ops);
return 0;
}

proc_create function creates a new proc file entry with name as PROC_NAME. It returns a type called proc_dir_entry which is a struct representing a proc file.
Permissions of read and write are given by passing 0666 . Permissions : Numeric Notation
parent is set to NULL hence our file be directly inside /proc
lastly &hello_ops refers to options we defined above to be used while creating the proc file.

  • This function is called when module is removed
{
static void proc_exit(void)
{
/* removes the /proc/hello entry */
remove_proc_entry(PROC_NAME, NULL);
}
}

We remove the prof file using it's name PROC_NAME and passing parent as NULL, since it was created at top level.

  • This function is called each time /proc/hello is read
static ssize_t proc_read(struct file *file, char __user *usr_buf,size_t count, loff_t *pos)
{
int rv = 0;
char buffer[BUFFER_SIZE];
static int completed = 0;
if (completed) {
completed = 0;
return 0;
}
completed = 1;
rv = sprintf(buffer,"%s\n" ,"Hello World");
/* copies kernel space buffer to user space usr buf */
copy_to_user(usr_buf, buffer, rv);
return rv;
}

This function will be called each time we read a proc file. So function will be called from user space and function lives in kernel space
file is a file pointer, which refers to proc file, we are reading.
usr_buf is the buffer in user space which will be written into.
count refers to the max bytes of data that can written to usr_buf.
pos refers to positional offset while writting to usr_buf.

Note : in our case when we write cat /proc/hello, so the cat command calls the proc_read function with file pointer to our hello proc file, usr_buf as our terminal, and a significant count and generally zero pos.

But how would the proc_read function caller, here cat command know that no more data is to be received?

proc_read returns the number of bytes, which is equal to number of chars written, so proc_read is called repeteadly until it returns a 0 value, which means no more data is to be written, whereas a return value of -1 indicates failure!

So we initialize buffer and rv in Kernel space, referring to Kernel buffer and read-value which is returned by proc_read.
initially completed is made 0, to specify that data is still left to be written.
finally we count rv using sprintf, and copy the Kernel buffer : buffer to user buffer : usr_buf, and return rv.
In next call to proc_read, completed is 1 and hence function returns!

  • Macros for registering module entry and exit points
module_init(proc_init);
module_exit(proc_exit);
  • Defining additional module info
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hello Module");
MODULE_AUTHOR("SGG");

Note : We declare custom functions and variable as static, this is to limit their scope to current module,otherwise they would be accessible in whole of Kernel and pollute global namespace!

Next up : jiffies Module