COL788: Embedded Computing
Lab Assignment – 1
Due Date: 2nd Sep, 2016. 5pm.
Objective:
Getting Linux kernel build for ARM setup on your system.
Understand how system calls are implemented.
Implement your own system call and user program to test it.
Procedure:
Get Linux kernel setup working as per instructions at https://balau82.wordpress.com/2012/03/31/compile-linux-kernel-3-2-for-arm-and-emulate-with-qemu/
Ubuntu systems can use sudo apt-get install gcc-arm-linux-gnueabi to install the cross compiler and skip the corresponding instructions in the web link.
Once you have the kernel built and booting over qemu, proceed with the next assignment to implement system calls.
Understand the system call implementation in Linux.
Implement a new system call named getprocinfo with the following features. Once the system call implementation is done, write a user program which makes use of this system call to test the system call.
It takes two arguments: a process identifier value; and a reference to a process information struct that you need to define in a new header file.
getprocinfo fills in the field values of the second argument with information about the specified process. If the pid argument is 0, then getprocinfo should "return" information about the calling process, otherwise it should "return" information about the process with a matching pid value. The system call returns 0 on success, and one of the following error values otherwise (feel free to add additional error return values):
ESRCH if a process with the given pid does not exist
EINVAL if there are errors with the arguments
EFAULT if there is an error writing to user space
(ESRCH, EINVAL, ... , are defined in linux/errno.h). Take a look at how other system calls return error values to figure out how your code should do this.
Start by defining a the proc_info_struct in a new header file that you create in include/linux/. The struct should have the following fields:
pid_t pid; /* pid of process */
pid_t parn_pid; /* pid of its parent process */
pid_t gid; /* group id */
unsigned long user_time; /* total CPU time in user mode*/
unsigned long sys_time; /* total CPU time in system mode*/
long state; /* its current state */
unsigned long long sched_avg_running; /* its scheduled ave running time */
unsigned int time_slice; /* its scheduling time slice */
unsigned int policy; /* its scheduling policy */
unsigned long num_cxs; /* number of context switches it has had
(sum of voluntary and involuntary cxs) */
int num_children; /* the number of child processes it has */
char prog[16]; /* its exec'ed file name (e.g. a.out) */
You can fill in these values by accessing a process' task_struct that is defined in include/linux/sched.h. Field values in the proc_info_struct that correspond to null pointer values in the process' task_struct should be set to -1. Not all field values in your struct match the names of fields in the task_struct, so you may need to read through some code and/or try some things out before you get the right values for these fields. Additionally, some values may need to be obtain indirectly via task_struct fields. Types are defined in types.h files in architecture neutral and architecture specific subdirectories of include. For example: linux-source-<version>/include/linux/types.h. Errors are defined in linux-source-<version>/linux/asm-generic/errno.h
When dealing with pointer parameters, you need to make sure that your system call doesn't dereference bad addresses: the kernel should never crash when the user passing in a bad address value to a system call. Also, remember that you need to explicitly copy values passed-by-reference to/from kernel space from/to user space. Use the functions access_ok, copy_from_user, and copy_to_user. Look at other system calls to see how these are used. A few things to help you determine what to do and if your system call returns correct information:
The macro find_task_by_vpid might be useful.
get_current() returns the task_struct of the calling process.
Looking at the list interface defined in include/linux/list.h might be useful. Also, look at some examples of kernel code that uses these macros to figure out how to use them.
sched.h and types.h contain may type defs.
u64 is unsigned long long, u32 is unsigned int
top, ps, and cat'ing out files in /proc may give you some information about running processes that can help you check to see if you are getting the right values for some of the fields. In /proc are subdirectories for each running process in the system (the directory name is its pid value), with files you can cat out to get information about the process. Here is some more information about /proc:
tools for examining system state
/proc file system
Look at other kernel code that accesses task_struct structs.
Submission Instructions:
Please create a tarball containing the below files and submit on moodle before the deadline.
The files which have been modified compared to the base source code (for implementing the system call).
Source code for user program(s) created to test the implemented syscall.
A short report containing:
Your approach to implementing the system call.
What features have been tested using the user program (e.g. normal functionality, error handling, etc.).
Any limitations/caveats in your implementation.
3 key learnings from this exercise.