Operating Systems (234120) – Spring 2007 (Homework 1) Homework 1 Due date: Sunday 22.04.06, 12:30 noon Teaching assistant in charge: Alexander Landau E-mails regarding this exercise should be sent to cs234120@csl1.cs.technion.ac.il with the subject line: cs234120hw1. Note that this mail server will reject mails sent from non-Technion addresses (so send your mails from t2, tx, or cs only). Note 1: You must print your solution. Handwritten assignments will not be accepted. Note 2: In the dry part of this assignment you should assume that the fork() system call always succeeds. Question 1 (dry) 1. (8 points) What are all the possible outputs (i.e. text on the screen) of the following program? Explain your answer. int main() { int pid1 = fork(); int pid2 = fork(); int value = (pid1 != 0); if (pid2 != 0) { if (pid1 != 0) { wait(&value); value = WEXITSTATUS(value); } wait(&value); value = WEXITSTATUS(value); printf("%d ", value); } value *= 2; printf("%d ", value); return value; } 2. (4 points) How many processes (including the original process in which the function was called) are created during the execution of the following function? Explain your answer. void main() { for (int i = 1; i <= 10; i++) { 1 Operating Systems (234120) – Spring 2007 (Homework 1) fork(); if (i <= 6) fork(); } } Question 2 (dry) (8 points) Given the program below, draw the stack as it exists in memory when the execution is at the line (2). Suppose that the ESP register was equal to 0x1000 when the execution was at line (1). The figure you have to draw should look like the one on slide 5 of tutorial 2. For every element on the stack, you should write: Its address. Its contents (variable name, register name, parameter name, constant value, etc.). Be as specific as possible. For example, if some stack element contains a constant, write the constant. If it contains an address of some variable v, write “&v = 0xYYYY”, where YYYY (in hex) is its address (if it is known), or write “&v” if its address is unknown. Its size in bytes. int g(int x, char *s) { int a; a = x + s[0]; (2) return a; } void f(int x, int y) { int array[10]; char buffer[8]; array[0] = g(x+y, buffer); } void main() { (1) f(3, 5); } 2 Operating Systems (234120) – Spring 2007 (Homework 1) 3 Operating Systems (234120) – Spring 2007 (Homework 1) Question 3 (wet, 80 points) 1. Introducion In the preliminary assignment you learned the basic methods for changing and compiling the Linux kernel. In this assignment you will use this knowledge to make a more significant change to the functionality of the kernel. Your mission in this assignment is to enable processes to get some information about their relationships with other processes. You’ll add several new system calls to the interface of the Linux kernel. See the detailed description below. You should use VMware to simulate a virtual machine on which you compile and run your "modified" Linux. Of course, those of you who want to work directly on their computers and know how to do it are welcome to do so: you will submit only the changed source files of the Linux kernel! 2. Detailed Description You need to write code wrappers and internal system call implementations for the following system calls (see the slides from tutorial 2). The description below lists the wrappers as seen by the userspace code using them. The system calls should be written according to the rules learned in tutorial 2. int get_common_ancestor(int #243) p1, int p2) (system call Description: Returns the first common ancestor p of the processes p1 and p2. The process p has the following properties: p is an ancestor of p1 and of p2. None of p’s children are ancestors of p1 and p2 simultaneously. Note: “Ancestor” is a partial order relation, i.e. it is reflexive, antisymmetric and transitive. Specifically, a process is an ancestor of itself. Returns -1 on failure; the first common ancestor PID on success. On failure 'errno' should contain one of following values: 'ESRCH' (No such process): Either p1 or p2 are not valid PIDs. An integer is a valid PID if it is strictly positive and there is a process with that PID. 4 Operating Systems (234120) – Spring 2007 (Homework 1) int get_path(int p1, int p2, int *array, int size) (system call #244) Description: Fills array with PIDs of processes in the hierarchy, starting with p1, following with all processes up to and including the first common ancestor of p1 and p2 (as defined by the above system call), following with the path from that ancestor to p2. p1 is the first entry of the array, p2 is the last entry and the common ancestor is stored in the array only once (i.e. it is not doubled). p1 and p2 may be the same process or one may be the ancestor of the other. In the former case the array will contain just one element, and in the latter case the array will contain the path from p1 to p2 (be it “upwards” or “downwards” in the tree). size is the length of the array (in elements, not in bytes). You must not write more than size elements into it. Returns -1 on failure; the number of elements filled in the array on success. On failure 'errno' should contain one of following values: 'ESRCH' (No such process): Either p1 or p2 are not valid PIDs. 'EINVAL' (Invalid argument): size is 0 or negative. array is NULL. array can’t be written to (e.g. doesn’t belong to the calling process address space). ‘ENOMEM’ (Out of memory): array is not long enough. int are_brothers(int p1, int p2) (system call #245) Description: Returns 1 if p1 and p2 are brothers (they have the same direct parent process). Returns 0 if they are not. Returns -1 on failure. On failure 'errno' should contain one of following values: 'ESRCH' (No such process): Either p1 or p2 are not valid PIDs. If several errors occurred (e.g. for get_path, p2 is not a valid PID and size=0), you should return the error code listed first (i.e. ESRCH, for the above example). For each one of these code wrappers you should implement a system call with the appropriate name (e.g sys_get_path for get_path). The return value of the system call should be 0 for success, or the appropriate negative error code. For example, if it is said that get_path sets errno to EINVAL then sys_get_path should return –EINVAL. 5 Operating Systems (234120) – Spring 2007 (Homework 1) Here is an example of the code wrapper for get_path (see explanation on the next page). Follow this example to write the other code wrappers: int get_path(int p1, int p2, int *array, int size){ long __res; __asm__ volatile ( "movl $244, %%eax;" "movl %1, %%ebx;" "movl %2, %%ecx;" "movl %3, %%edx;" "movl %4, %%esi;" "int $0x80;" "movl %%eax,%0" : "=m" (__res) : "m" (p1), "m" (p2), "m" ((long)array), "m" (size) : "%eax","%ebx","%ecx","%edx","%esi" ); if ((unsigned long)(__res) >= (unsigned long)(-125)) { errno = -(__res); __res = -1; } return (int)(__res); } Explanation of inline assembler: 1) movl $244, %%eax – copy system call number to register eax. 2) movl %1, %%ebx - copy first parameter (p1) to register ebx. 3) movl %2, %%ecx - copy second parameter (p2) to register ecx. 3) movl %3, %%edx - copy third parameter (array) to register edx. 3) movl %3, %%esi - copy forth parameter (size) to register esi. 4) int $0x80 – system call invocation via interrupt 0x80. 5) movl %%eax,%0 – copy the value that was returned by the system call to %0 (which is the first output operand). 6) : "=m" (__res) – output operand. 7) : "m" (p1), "m" (p2), "m" ((long)array), "m" (size) – input operands. 8) : %eax,%ebx,%ecx,%edx,%esi – list of clobbered registers. Inform gcc that we use eax, ebx, ecx, edx, esi registers. You should read the following document for information about the commands used in the preceding code segment: http://www-106.ibm.com/developerworks/linux/library/l-ia.html 6 Operating Systems (234120) – Spring 2007 (Homework 1) The Test program: You must also write a test program called hw1_test.c that will verify the correct functionality of the new system calls. The program should test all system calls for both correctness and corner cases. Note that correctness includes the right behavior for bad arguments. Use VMware, like you learned in the preliminary assignment, in order to make the following changes in the Linux kernel: Put the implementation of the new system calls in the file kernel/hw1.c (you will need to create and add this file to the kernel). Update the makefile in that directory to compile your new file too. (Tip: add it to obj-y) Update entry.S (add the new system call table entries – use 243, 244 and 245). Recompile and run the new kernel like you did in the preliminary assignment. Boot with your new kernel, and try to compile and run the test program to make sure the new system calls work as expected. Did it all? Good work, submit your assignment! 4. Notes and Tips You are not allowed to use the syscall function to implement code wrappers, or to write the code wrappers for your system calls using the macro _syscall1. You should write the code wrappers according to the example of the code wrapper given above. You should use the functions copy_from_user, copy_to_user, etc. in order to copy data from user space to kernel space and vice versa. Use the course book, Google or the man pages to find information about these functions. '-EINVAL' stands for 'minus EINVAL' We will check your assignment with our own test program. Linux is case-sensitive. entry.S means entry.S, not Entry.s, Entry.S or entry.s. 7 Operating Systems (234120) – Spring 2007 (Homework 1) 5. Submission The submission of this assignment has two parts: An electronic submission – you should create a zip file (use zip only, not gzip, rar, 7z, …) containing the following files. Make sure your zip file contains only the files below without any directories in it. a. hw1.c – contains the kernel code you’ve written. b. entry.S – contains the syscall table. c. hw1.h – contains the implementation of the syscall wrappers. d. hw1_test.c - contains your test program (which, obviously, #include-s “hw1.h”) e. A file named submitters.txt which includes the ID and name of the participating students. The following format should be used: Bill Gates 123456789 Linus Torvalds 234567890 Steve Jobs 345678901 A printed submission: a. A printed solution of questions 1 and 2 (dry). b. A printout of the source code including your test program. For existing Linux files (such as entry.S), only the changes should be printed. We will not check assignments that have full printouts of kernel source files! c. The output of your test program. Good Luck, The course staff 8