Title: Implementing System Calls
1Implementing System Calls
2Steps in writing a system call
- Create an entry for the system call in the
kernels 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.
3Step 1 Create a sys_call_table entry
- arch/x86/kernel/syscall_table_32.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 /
- include/asm/unistd_32.h
- /
- This file contains the system call numbers.
- /
- define __NR_restart_syscall 0
- define __NR_exit 1
- define __NR_fork 2
- define __NR_read 3
- define __NR_write 4
-
- define __NR_foo 325
- define NR_syscalls 326
- / increment by one /
4Step 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-gtuid) - return current-gtuid
-
- One primitive argument
- asmlinkage int sys_foo(int arg)
- printk (KERN ALERT, This is foo. Argument is
d\n, arg) - return arg
5Step 2 Write the system call (2)
- Verifying argument passed by user space
- asmlinkage long sys_close(unsigned int fd)
-
- struct file filp
- struct files_struct files
current-gtfiles - struct fdtable fdt
- spin_lock(files-gtfile_lock)
- fdt files_fdtable(files)
- if (fd gt fdt-gtmax_fds)
- goto out_unlock
- filp fdt-gtfdfd
- if (!filp)
- goto out_unlock
-
- 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
-
6Example syscall implementation
- 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)
7Step 3 Generate user-level stub Using your new
system call - the new way
- old macros _syscall0, _syscall1, etc are now
obsolete in the new kernels. - The new way to invoke a system call is using the
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/
8Using your new system call - the new way(contd.)
- include ltstdio.hgt
- include lterrno.hgt
- include ltunistd.hgt
- include ltlinux/unistd.hgt
- // define the new syscall number. Standard
syscalls are defined in linux/unistd.h - define __NR_sys_foo 311
- 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)
9Using 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
10Using 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?
11Using your new system call - the old way(contd.)
- include ltstdio.hgt
- include lterrno.hgt
- include ltunistd.hgt
- include ltlinux/unistd.hgt
- // define the new syscall number. Standard
syscalls are defined in linux/unistd.h - define __NR_foo 311
- // 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)
12SYSENTER/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/aboutelfauxiliaryv
ectors
13Reference
- Kernel Projects Gary Nutt, Chapter 5, Part 2
- Tons of material online if you Google.