Interaction with Kernels
January 28, 2002
Yongguang Zhang
Today's Lecture
- Q&A
- Using Modules in UML
- Kernel/User Interaction
- Implementing System Calls
Q&A
- Are we going too fast or too slow in this class?
Using Modules in UML
- Same as using modules in other Linux kernel
- insmod, lsmod, rmmod, modprobe, depmod
- When do you need to recompile kernel?
- You want to change how some existing kernel modules are compiled
- Statically linked? Loadable modules? No included?
- You want to make your new module part of the kernel source tree (for other to use)
- Project 2: you don’t need to recompile kernel
- Future projects: implemented as modules if possible (first, outside the kernel source tree)
Compiling UML with Modules
- Following the normal procedure
- Select what parts you want as loadable modules
- During make xconfig ARCH=um,
- Each module can be compiled as: statically linked (y), loadable module (m), not included (n)
- Be careful of what you choose!
- c.f.: /projects/cs378.ygz/src/uml.config-2.4.9-modules
- Compilation steps
- make dep ARCH=um
- make linux ARCH=um
- make modules ARCH=um (this is new!)
Installing UML Modules
- Run a working version of UML (not the one you just compile!):
/projects/cs378.ygz/bin/linux-uml ubd0=../root_fs_utcs
- In side the above UML run,
- cd to the directory of your UML build directory
- make modules_install ARCH=um
- Halt
- Now you have installed the modules to your root file system.
User/Kernel Interactions
- Transfer of Control between User and Kernel Mode
- System Calls
- Interrupts (timer or device)
- Transfer of Data between User and Kernel Space
- Memory copy
- /proc file system
System Calls
- Process in User Mode make a system call (a special function call) to obtain kernel service
- Some takes one or more arguments (words)
- Returns an integer value
- If failed: return -1 and set errno (see include/asm-i386/errno.h)
- In User Space, a system call is implemented as a wrapper function in libc.
System Call Wrapper Function
- Define system calls using macros: _syscall0 ... _syscall5 (see include/asm-i386/unistd.h)
- For example:
- pid_t getpid()
- unsigned int alarm(unsigned int seconds)
- _syscall1(unsigned int,alarm,unsigned int,seconds)
- int write(int fd,const char * buf,unsigned int count)
- _syscall3(int,write,int,fd,const char *,buf,unsigned int, count)
After the Macro Expansion
unsigned int alarm(unsigned int seconds)
{
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (__NR_alarm),"b" ((long)(seconds)));
do {
if ((unsigned long)(__res) >= (unsigned long)(-125)) {
errno = -(__res);
__res = -1;
}
return (unsigned int) (__res);
} while (0);
}
Return Value
- Long integer (in 32-bit architecture)
- (unsigned long)0 ... (unsigned long)(-126)
- (unsigned long)(-125) ... (unsigned long)(-1)
- System call failed
- Set errno.
Transfer of Control
- By special programmed exception (int $0x80)
- Exception vector 128 defined as system call
- The system call handler in kernel
- system_call(): written in assembly code
- Dispatch to the corresponding system call service routine (e.g., sys_alarm()), according to the system call number (e.g, __NR_alarm)
- System call dispatch table
System Call Dispatch Table
See arch/i386/kernel/entry.S:
.data
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* 0 */
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork)
.long SYMBOL_NAME(sys_read)
.long SYMBOL_NAME(sys_write)
.long SYMBOL_NAME(sys_open) /* 5 */
.long SYMBOL_NAME(sys_close)
...
System Call Service Routine
Corresponding to each system call, e.g.:
asmlinkage unsigned long sys_alarm(unsigned int seconds)
{
struct itimerval it_new, it_old;
unsigned int oldalarm;
it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
it_new.it_value.tv_sec = seconds;
it_new.it_value.tv_usec = 0;
do_setitimer(ITIMER_REAL, &it_new, &it_old);
oldalarm = it_old.it_value.tv_sec;
/* ehhh.. We can't return 0 if we have an alarm pending.. */
/* And we'd better return too much than too little anyway */
if (it_old.it_value.tv_usec)
oldalarm++;
return oldalarm;
}
Parameter Passing
- Through CPU Registers
- Each parameter is a word (32bit)
- Parameters limited by register number
- What about complex data (e.g., pointer to a buffer, such as in write() system call)
- Parameter: memory address
- Kernel will copy data from/to process' user-mode memory space
- Verifying the system call parameters
User Space Memory Access
- Two service routines: get_user() and put_user()
- They are macros, see include/asm-i386/uaccess.h
- They in turn call __get_user_x() and __put_user_x() (both written in assembly)
- Example
- System call: int stime(time_t *t);
- Purpose: set the system time to value pointed by t
- Parameter: is a memory address
Service Routine for stime()
asmlinkage long sys_stime(int * tptr)
{
int value;
if (!capable(CAP_SYS_TIME))
return -EPERM;
if (get_user(value, tptr))
return -EFAULT;
write_lock_irq(&xtime_lock);
xtime.tv_sec = value;
xtime.tv_usec = 0;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
write_unlock_irq(&xtime_lock);
return 0;
}
Parameter Checking
- Check if each parameter is valid
- Check address
- Illegitimate address? (e.g., reversed to kernel only)
- Page fault and Fixup Code
- Wait until we cover the memory access
Steps for Adding New System Calls
- Add a wrapper function in user-space code
- Include <linux/unistd.h>
- Use _syscall0() ... _syscall5()
- Include a macro definition for NR_XYZ
- In include/asm-i386/unistd.h
- Write the corresponding service routine in kernel source tree
(e.g., sys_XYZ())
- Add an entry to system call dispatch table
- In arch/i386/kernel/entry.S
Not Quite Right Yet
- UML needs extra steps
- We will discuss this later
Homework
- Explore module configuration
- Read Chapter 8 (Understanding Linux Kernel)
- Do project 2
© 2002 Yongguang Zhang