130 likes | 294 Views
Implementing System Calls. CS552 Kartik Gopalan & Dennis Foreman. Steps in writing a system call. Create an entry for the system call in the kernel’s syscall_table User processes trapping to the kernel (through SYS_ENTER or int 0x80) find the syscall function through this table.
E N D
Implementing System Calls CS552 Kartik Gopalan & Dennis Foreman
Steps in writing a system call • Create an entry for the system call in the kernel’s syscall_table • User processes trapping to the kernel (through SYS_ENTER or int 0x80) find the syscall function through this table. • Write the system call code as a kernel function • Be careful when reading/writing to user-space • Use copy_to_user or copy_from_user routines • Generate/Use a user-level system call stub • Hides the complexity of making a system call from user applications.
/usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.s390x/arch/x86/kernel/syscall_table.S/usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.s390x/arch/x86/kernel/syscall_table.S ENTRY(sys_call_table) .long sys_restart_syscall /* 0 */ .long sys_exit .long sys_fork .long sys_read … .long sys_pselect6 .long sys_ppoll .long sys_unshare /* 310 */ .long sys_foo /* 311 */ /usr/include/asm/unistd.h /* * This file contains the system call numbers for aplications to use */ #define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 #define __NR_write 4 … #define __NR_foo 311 #define NR_syscalls 312 /* increment by one */ Step 1: Create a sys_call_table entry
Step 2: Write the system call (1) • No arguments, Integer return value asmlinkage int sys_foo(void) { printk (KERN_ALERT “I am foo. UID is %d\n”, current->uid); return current->uid; } • One primitive argument (in this case an int) asmlinkage int sys_foo(int arg) { printk (KERN_ALERT “This is foo. Argument is %d\n”, arg); return arg; } // Note, no comma after "KERN_ALERT"
Verifying argument passed by user space asmlinkage long sys_close(unsigned int fd) { struct file * filp; struct files_struct *files = current->files; struct fdtable *fdt; spin_lock(&files->file_lock); fdt = files_fdtable(files); if (fd >= fdt->max_fds) goto out_unlock; filp = fdt->fd[fd]; if (!filp) goto out_unlock; … out_unlock: spin_unlock(&files->file_lock); return -EBADF; } Call-by-reference argument User-space pointer sent as argument. Data to be copied back using the pointer. asmlinkage ssize_t sys_read ( unsigned int fd, char __user * buf, size_t count) { … if( !access_ok( VERIFY_WRITE, buf, count)) return –EFAULT; … } Step 2: Write the system call (2)
Example syscall implementation(code inside the kernel) asmlinkage int sys_foo(void) { static int count = 0; printk(KERN_ALERT "Hello World! %d\n", count++); //KERN_ALERT is a logging level return -EFAULT; // what happens to this return value? } EXPORT_SYMBOL(sys_foo);
Step 3: Generate user-level stubUsing your new system call - the new way • Old way macros _syscall0, _syscall1, etc are now obsolete in the new kernels. • New way to invoke a system call is using the syscall(...) library function. • Do a "man syscall" for details. • For instance, for a no-argument system call named foo(), you'll call • ret = syscall(__NR_sys_foo); // Assuming you've defined __NR_sys_foo earlier • For a 1 argument system call named foo(arg), you call • ret = syscall(__NR_sys_foo, arg); • and so on for 2, 3, 4 arguments etc. • For this method, check • http://www.ibm.com/developerworks/linux/library/l-system-calls/
Using your new system call - the new way (contd.) #include <stdio.h> #include <errno.h> #include <unistd.h> // --- note #include <linux/unistd.h> // --- note!!! // define the new syscall number. Standard syscalls are defined in linux/unistd.h int main(void) { int ret; while(1) {// making the system call ret = syscall(__NR_sys_foo); printf("ret = %d errno = %d\n", ret, errno); sleep(1); } return 0; }
Using your new system call - the old way • You can still replicate the old _syscall0, _syscall1 etc assembly code stubs in your user program, but this is really not necessary anymore. • These stubs use the old method of raising "int 0x80" software interrupts • which are found to be quite slow on newer Pentium machines. • But this technique still works for backward compatibility. • For this method, check http://www.linuxjournal.com/article/1145
Using your new system call - the old way(contd.) • _syscall0(type,name) • type : type of return value (e.g. void or int) • name : name of the system call (e.g. foo) • _syscall0(int,foo) • Defines syscall entry point for “asmlinkage int sys_foo(void)” • _syscall1(type,name,type1,arg1) • type and name same as before • type1 : type of first argument • name1 : name of first argument • _syscall1(void,foo,int,arg) • Defines syscall entry point for “asmlinkage void sys_foo(int arg)” • … and similarly for two arguments, three arguments and so on. • For definitions of _syscallN macros, check • include/asm/unistd.h • Also, pay attention to the usage and implementation of __syscall_return macro. What does it do?
Using your new system call - the old way(contd.) #include <stdio.h> #include <errno.h> #include <unistd.h> #include <linux/unistd.h> // define the new syscall number. Standard syscalls are defined in linux/unistd.h // generate a user-level stub _syscall0(int,foo) int main(void) { int ret; while(1) { // making the system call ret = foo(); printf("ret = %d errno = %d\n", ret, errno); sleep(1); } return 0; }
SYSENTER/SYSEXIT Method • This is the newest and fastest of all methods to make system calls in Pentium class machines. • Pentium machines have long supported these new instructions as a faster technique to enter and exit the kernel mode than the old technique based on raising the "int 0x80" software interrupt. Newer linux kernels have apparently adopted this technique. • The details of how this works is quite interesting and I may try to cover this briefly in the class. • Meanwhile you can read about the details in the following links and maybe even try it out using the example code. • http://manugarg.googlepages.com/systemcallinlinux2_6.html • http://www.win.tue.nl/~aeb/linux/lk/lk-4.html • http://manugarg.googlepages.com/aboutelfauxiliaryvectors
Kernel Projects: Gary Nutt, Chapter 5, Part 2 Tons of material online if you Google. Reference