1. How to build a linux kernel. The Linux kernel source Signature File Patch File Package Manager Steps To Build a Kernel Reduce Booting Time

Project 2 related Overview 1. 2. 3. 4. 5. How to build a linux kernel How to add a system call How to write a linux kernel module How to create an ...
10 downloads 0 Views 287KB Size
Project 2 related

Overview 1. 2. 3. 4. 5.

How to build a linux kernel How to add a system call How to write a linux kernel module How to create an entry in /proc How to use semaphore or mutex

1. How to build a linux kernel • • • • • •

The Linux kernel source Signature File Patch File Package Manager Steps To Build a Kernel Reduce Booting Time

The Linux kernel Source • Get the Linux kernel source code from www.kernel.org • The latest stable version of the Linux kernel is: 2.6.28.6 . (By Feb. 18, 2009) linux-2.6.28.tar.bz2 linux-2.6.28.tar.bz2.sign

Signature File • A .sign file is a signature file, which is used to verify the integerity of the source code via Gnu Privacy Guide (GPG) program. • Usage of gpg: % gpg --verify linux-2.3.9.tar.gz.sign linux-2.3.9.tar.gz gpg: Signature made Mon Oct 9 23:48:38 2000 PDT using DSA key ID 517D0F0E gpg: Good signature from "Linux Kernel Archives Verification Key “

• More information: http://www.kernel.org/signature.html

Patch File • patch file – Used by patch to apply a diff file to an original – Widely used in linux

• Usage of patch: diff file1 file2 > patch-f1-f2 # generate path file patch file1 patch-f1-f2 # apply patch to file1 patch –R file1 patch-f1-f2 # undo patch

• More information: – man patch – man diff

Package Manager • yum (Yellowdog Updater Modified) – Used in redhat, fedora core linux distribution – – – –

yum install [package1] [package2] […] # install package(s) yum remove [package1] [package2] […] # remove package(s) yum.conf # yum configuration file like apt-get in debain/ubuntu

• rpm (RPM Package manager) – Used in redhat, fedora core linux distribution

Steps To Build a Kernel(1) • Put the Linux kernel source code in /usr/src/ • Verify the source code signuature • Untar the source code: tar jxvf linux-2.6.28.tar.bz2

• Create a symbolic link ln –s

linux-2.6.28

linux

• Change current directory cd linux

Steps To Build a Kernel(2) • Remove junk from the old configuration make mrpr oper

• Customize the kernel configuration make menuconfig or make xconfig # Using a graphical UI

• Install modules make modules_install

• Install the Linux kernel make install

• Reboot machine reboot & select the newly added item in boot menu

Reduce Booting Time • Reduce the Linux kernel size – Remove unnecessary kernel features – Build kernel modules – Also reduce the kernel compiling time

• Turn off unnecessary system service – Run /usr/sbin/setup in Fedora Core

• Other reference – http://www.cs.fsu.edu/~baker/devices/assign/prog1.html

How to Add a System Call • • • • •

System Call Definition in Linux System Call Work Mechanism The Linux Kernel Support For System Call Steps to Add a System Call Source Code

System Call Definition • A system call (kernel call) is a request made via a software interrupt by an active process for a service performed by the kernel. • Software interrupt (exception) is an interrupt that is caused by software, usually by a program in user mode. • “int $0x80” to invoke the software interrupt in x86 machines

System Call Work Mechanism

http://www.ibm.com/developerworks/libr ary/l-system-calls/

The Linux Kernel Support for System Call start_kernel() # start_kernel defined in main.c, which is invoked during OS | # booting. | trap_init() # trap_init is defined in traps.c. | set_system_trap_gate(SYSCALL_VECTOR, &system_call) # SYSCALL_VECTOR is 0x80. # system_call is the entry point of generic system call handling, # which is defined in entry_32.S and written in assembly. ++!!! call *sys_call_table(,%eax,4)%e | | | | .long sys_fork

# sys_call_table is defined in syscall_table_32.S # This table contains all the system call in the form of # sys_[system call name]. # We will take system fork as an example.

sys_fork() | do_fork()

# The function sys_fork can be found in process_32.c. # sys_fork will eventually call do_fork to do the real job. # do_fork is defined in fork.c.

Steps To Add a System Call List of files to be modified and created.

Changes

Kernel Files: 1) /usr/src/linux/arch/x86/kernel/syscall_table_32.S

Kernel Files: Add #define .long sys_mycall /* 333 */

2)

/usr/src/linux/arch/x86/include/asm/unistd_32.h

Add #define __NR_mycall 333

3)

/usr/src/linux/Makefile

Change from core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ to core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ mycall/

4) 5) 6)

/usr/src/linux/mycall /usr/src/linux/mycall/mycall.c /usr/src/linux/mycall/Makefile

Create mycall directory in /usr/src/linux Create mycall.c the source code for custom system call Create a Makefile to comiple the custom system call code, which contains: core-y += mycall.o

User Space Files: 1) testmycall.c 2) testmycall.h

User Space Files: Create a test program to test new custom system call Create the header file for the test program

Source Code mycall.c -------------------------------------------#include #include

testmycall.h -------------------------------------------#include #define __NR_mycall 333

asmlinkage long sys_mycall(int i) { return i; }

testmycall.c --------------------------------------------

#include #include “testmycall.h” int main(void) { printf(“My system call return %d\n”, syscall(__NR_mycall)); return 0; } /* syscall() is used for invoking int 0x80 assembly instruction. */

3 How To Write A Linux Kernel Module • • • •

Overview Example1 Example2 Example3

Overview • An extension to the Linux kernel • Running in kernel mode • Can be loaded and removed dynamically insmod rmmod

module_name.ko module_name

# Load a module # Remove a module

Example1 /* * hello-1.c - The simplest kernel module. */ #include /* Needed by all modules */ #include /* 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"); }

Makefile for Example 1 #Makefile for a basic kernel module # -C will change the directory into the kernel source tree obj-m += hello-1.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

Example2 /* * hello-2.c - Demonstrating the module_init() and module_exit() macros. * This is preferred over using init_module() and cleanup_module(). */ #include /* Needed by all modules */ #include /* Needed for KERN_INFO */ #include /* 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);

Licensing and Module Documentaton • Warn people that code is not open source. • This license mechanism is defined and documented in linux/module.h. • http://lxr.linux.no/linux+v2.6.28.6/includ e/linux/module.h

Example3 #include ` /* Needed for KERN_INFO */ #include /* Needed for the macros */ #define DRIVER_AUTHOR "Peter Jay Salzman " #define DRIVER_DESC "A sample driver" 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); /* * You can use strings, like this: */ /* * Get rid of taint message by declaring code as GPL. */ MODULE_LICENSE("GPL"); /* * Or with defines, like this: */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC);

/* Who wrote this module? */ /* What does this module do */

/* * This module uses /dev/testdevice. The MODULE_SUPPORTED_DEVICE macro might * be used in the future to help automatic configuration of modules, but is * currently unused other than for documentation purposes. */ MODULE_SUPPORTED_DEVICE("testdevice");

How to create an entry in /proc filesystem • The /proc Filesystem • Manage /proc Filesystem • Communication Between User Space & Kernel Space • Examples

The /proc Filesystem • The /proc file system (procfs) is a virtual filesystem • It is not associated with a block device but only exists in memory • It allows user space programs to acess certain information from the Linux kernel

Manage /proc Filesystem • To use the procfs functions, you need to use the right header file • Most used functions – create_proc_entry() – proc_mkdir() – proc_symbolic()

Create and Remove an Entry • struct proc_dir_entry* create_proc_entry(const char* name, mode_t mode, struct proc_dir_entry* parent); – This function creates a regular file with the name name and mode in the directory parent. – To create a file in the root of the procfs, use NULL as parent parameter. – When successful, the function will return a pointer to the reated struct proc_dir_entry – foo_file = create_proc_entry(“foo”, 0644, example_dir);

• void remove_proc_entry(const char *name, struct proc_dir_entry *parent); – Removes the entry name in the directory parent from the procfs. – Be sure to free the data entry from the struct proc_dir_entry before remove_proc_entry is called

Create a Directory and a Symlink • struct proc_dir_entry* proc_mkdir(const char* name, struct proc_dir_entry* parent); – Create a directory name in the procfs directory parent.

• struct proc_dir_entry* proc_symlink(const char* name, struct proc_dir_entry* parent, const char* dest); – Create a symlink in the procfs directory parent that points from name to dest. This translates in userland to ln -s dest name.

Communication Between User Space & Kernel Space • Procfs works with callback functions for files. Whenever a procfs file is read or written callback functions will be invoked

.

• Callback functions are initialized by setting the pead_proc and/or write_proc fields in the struct proc_dir_entry* that the function create_proc_entry returned. struct proc_dir_entry * new_entry new_entry->read_proc = myread_proc new_entry->write_proc = mywrite_proc

Read Data from Kernel • int read_proc_t(char *page, char **start, off_t off, int count, int *eof, void *data); – This function write read information into the page. – The function start writing at an offset in page and write at most count bytes. – eof is used to signal that the end of the file has been reached by writing 1 to the memory location pointed by eof.

Write Data to Kernel • int write_func_t(struct file* file, const char* buffer, unsigned long count, void* data); – It reads count bytes at maximum from the buffer. – The buffer doesn't live in the kernel's memory space, and should first be copied to kernel space with copy_from_user. – The file parameter is usually ignored.

Example1 /* procfs1.c - create a "file" in /proc */ #include #include #include fs */ #include

/* Specifically, a module */ /* We're doing kernel work */ /* Necessary because we use the proc

int init_module() { Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL); if (Our_Proc_File == NULL) { remove_proc_entry(procfs_name, &proc_root); printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", procfs_name); return -ENOMEM; }

/* Time related */

#define procfs_name “current_time" struct proc_dir_entry *Our_Proc_File; int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data) { int ret; struct timespec now; printk(KERN_ALERT "procfile_read (/proc/%s) called\n", procfs_name); getnstimeofday(&now); ret = sprinft(buffer, “current seconds: %ld, current nanoseconds %ld\n”, now.tv_sec, now. tv_nsec); return ret; }

Our_Proc_File->read_proc = procfile_read; Our_Proc_File->owner = THIS_MODULE; Our_Proc_File->mode = S_IFREG | S_IRUGO; printk(KERN_ALERT "/proc/%s created\n", procfs_name); return 0; } void cleanup_module() { remove_proc_entry(procfs_name, &proc_root); printk(KERN_ALERT "/proc/%s removed\n", procfs_name); }

4. How to use semaphore • Semaphore or mutex is used for synchronizing acess to shared resources (critical section) among multiple processes/threads • Semaphores : an integer combined with P and V operations – Call P to enter a critical section • If semaphore value > 0, it is decremented • If semaphore value == 0, wait

– Call V to exit a critical section • Increments the value of the semaphore • Waits up processes that are waiting

– For mutual exclusions (mutex ), semaphore values are initialized to 1

• Linux offers two kinds of semaphores – Kernel semaphores, which are used by kernel control paths – System V IPC semaphores, which are used by User Mode processes

Kernel Semaphore 1 • Header file is . • To declare and initialize a semaphore, call – void sema_init(struct semaphore *sem, int val); – Can also call two macros • DECLARE_MUTEX(name); /* initialized to 1 */ • DECLARE_MUTEX_LOCKED(name); /* initialized to 0 */

• To initialize a dynamically allocated semaphore, call – void init_MUTEX(struct semaphore *sem); – void init_MUTEX_LOCKED(struct semaphore *sem);

Kernel Semaphore 2 •

For the P function, call – void down(struct semaphore *sem); – void down_interruptible(struct semaphore *sem); – void down_trylock(struct semaphore *sem);



down – Just waits for the critical section – Until the cows come home – A good way to create unkillable process



down_interruptible – Almost always the one to use – Allows a user-space process waiting on a semaphore to be interrupted by the user – Returns a nonzero value if the operation is interrupted •



No longer holds the semaphore

down_trylock – Never sleeps – Returns immediately with a nonzero value if the semaphore is not available



For the V function, call – void up(struct semaphore *sem);

System V Semaphore • #include • Create a semaphore set – int semget(key_t key, int nsems, int semflg) – key is s a unique identifier that is used by different processes to identify this semaphore set – key is generated by ftok() – nsems is the number of semaphores in this semaphore set. – semflg indicates permissions should be on the new semaphore set.

System V Semaphore • Operate on a semaphore set – – – –

int semop(int semid ,struct sembuf *sops, unsigned int nsops); semid is the number obtained from the call to semget(). struct sembuf is filled with semaphore commands. number of struct sembufs

• Destroy a semaphore – int semctl(int semid, int semnum, int cmd, ... /*arg*/); – cmd should be IPC_RMID

• ipcs is the command to view system IPC

User Space Mutex • Mutexes are used for threads. • #include • Mutex operations – pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; – int pthread_mutex_init (pthread_mutex_t *mutex, pthread_mutexattr_t *attr); – int pthread_mutex_destroy (pthread_mutex_t *mutex); – int pthread_mutex_lock (pthread_mutex_t *mutex); • Used to lock a mutex.

– int pthread_mutex_trylock (pthread_mutex_t *mutex); • It will return an error code if the mutex is already locked by another process. This function will not block.

– int pthread_mutex_unlock (pthread_mutex_t *mutex); • Used to unlock a mutex.

User Space Mutex • Condition Variables – It is used to convey information about the state of shared data which is associated with a mutex. – When a thread is waiting on a condition variable, it is in blocking mode.

• Operations on condition variables – pthread_cond_t cond=PTHREAD_COND_INITIALIZER; – int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *condattr); – int pthread_cond_destroy (pthread_cond_t *cond); – int pthread_cond_wait (pthread_cond_t *condition, pthread_mutex_t *mutex); – int pthread_cond_timedwait (pthread_cond_t *condition, pthread_mutex_t *mutex, struct timespec *expiration); – int pthread_cond_signal (pthread_cond_t *condition); – int pthread_cond_broadcast (pthread_cond_t *condition);

Threads in Linux • •

All threads within a process share the same address space. Threads in the same process share: – – – – – –



Each thread has a unique: – – – – – –



Process instructions Most data open files (descriptors) signals and signal handlers current working directory User and group id Thread ID set of registers, stack pointer stack for local variables, return addresses signal mask priority Return value: errno

pthread functions return "0" if OK.

Threads in Linux

Threads in Linux • int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg); • pthread_attr_init (attr) • pthread_attr_destroy (attr) • pthread_exit(status) • int pthread_join(pthread_t thread, void **value_ptr); • int pthread_detach(pthread_t thread);