Transcript Document

Implementing System Calls
CS552
Kartik Gopalan
Steps in writing a system call
1.
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.
2. 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
3. Generate/Use a user-level system call stub
 Hides the complexity of making a system call from user
applications.
CS552/BU/Spring2008
Step 1: Create a sys_call_table entry
 /usr/src/redhat/BUILD/kernel2.6.18/linux2.6.18.s390x/arch/s390/kernel/syscalls.S
// for a z/390 kernel)
#define NI_SYSCALL SYSCALL(…)
syscall (sys_fork, sys_fork, sys_fork)
●●●
syscall(sys_mysvc, sys_mysvc, sys_mysvc)
 arch/x86/kernel/syscall_table_32.S
//for a PC kernel
ENTRY(sys_call_table)
.long sys_restart_syscall
/* 0 */
.long sys_exit
.long sys_fork
.long sys_read
●●●
.long sys_unshare
/* 310 */
.long sys_foo
/* 311 */
CS552/BU/Spring2008
 include/asm/unistd_32.h
/*
* This file contains the system call
numbers.
*/
#define __NR_restart_syscall
#define __NR_exit
1
#define __NR_fork
2
#define __NR_read
3
#define __NR_write
4
…
#define __NR_foo
0
325
#define NR_syscalls 326
/* increment by one
*/
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;
}
 Note: no comma after KERN ALERT
 One primitive argument
asmlinkage int sys_foo(int arg) {
printk (KERN ALERT “This is foo. Argument is %d\n”, arg);
return arg;
}
CS552/BU/Spring2008
Step 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>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;
}
CS552/BU/Spring2008
 Call-by-reference argument
o
o
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;
…
}
Example syscall implementation
asmlinkage int sys_foo(void) {
static int count = 0;
printk(KERN_ALERT "Hello World! %d\n", count++);
return -EFAULT; // what happens to this return value?
}
EXPORT_SYMBOL(sys_foo);
CS552/BU/Spring2008
Step 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/
CS552/BU/Spring2008
Using your new system call - the new way (contd.)
#include
#include
#include
#include
<stdio.h>
<errno.h>
<unistd.h>
<linux/unistd.h>
// define the new syscall number. Standard syscalls are defined in
linux/unistd.h
#define
__NR_sys_foo
311 // or add this to 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;
CS552/BU/Spring2008
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
CS552/BU/Spring2008
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?
CS552/BU/Spring2008
Using your new system call - the old way
(contd.)
#include
#include
#include
#include
<stdio.h>
<errno.h>
<unistd.h>
<linux/unistd.h>
// 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);
sleep(1);
}
}
return 0;
CS552/BU/Spring2008
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
CS552/BU/Spring2008
Files to change in Redhat Linux
 /usr/src/redhat/BUILD/kernel-2.6.18/linux2.6.18.s390x/arch/s390/mm/fault.c
o Your kernel function implementation goes here (actual function code)
 /usr/src/redhat/BUILD/kernel-2.6.18/linux2.6.18.s390x/arch/s390/kernel/syscalls.S
o SYSCALL(sys_mysvc, sys_mysvc, sys_mysvc); // typical entry
 /usr/src/redhat/BUILD/kernel-2.6.18/linux2.6.18.s390x/include/asm-s390/unistd.h
o #define __NR_mysvc n and #define __NR_syscalls
n+1
 /usr/src/kernels/2.6.18-92.el5-s390x/include/asm-s390/unistd.h
o Same as the BUILD UNISTD.H
-------- following are for a PC build, not S390 --------- /usr/include/asm/unistd.h
 /usr/src/redhat/BUILD/kernel-2.6.18/linux2.6.18.s390x/arch/i386/kernel/syscall_table.S
o .long sys_mysvc
CS552/BU/Spring2008