
Operating Systems Practical Session 1 System Calls A few administrative notes… • Course homepage: • http://www.cs.bgu.ac.il/~os182/Main • Assignments: ❑ Extending xv6 (a pedagogical OS) ❑ Submission in pairs. ❑ Frontal checking: 1. Assume the grader may ask anything. 2. Must register to exactly one checking session. Operating System An operating system (OS) is system software that manages computer hardware and software resources and provides common services for computer programs. Main Components for today • Process – Describes an execution of a program and all of its requirements • Kernel – The Heart of the OS, manages processes and other resources • System Calls – Means of communications between the process and the kernel Process Process Kernel Space User Space Run Kernel code Run user code Has: Has: - Stack - Stack - Heap - Heap - System wide view - Direct Hardware access System calls System Calls • A System Call is an interface between a user application and a service provided by the operating system (or kernel). • These can be roughly grouped into five major categories: 1. Process control (e.g. create/terminate process) 2. File Management (e.g. read, write) 3. Device Management (e.g. logically attach a device) 4. Information Maintenance (e.g. set time or date) 5. Communications (e.g. send messages) System Calls - motivation • A process is not supposed to have a direct access the hardware/kernel. It can’t access the kernel memory or functions. • This is strictly enforced (‘protected mode’) for good reasons: • Can jeopardize other processes running. • Cause physical damage to devices. • Alter system behavior. • The system call mechanism provides a safe mechanism to request specific kernel operations. Jumping from user space to kernel space • A process running in user space cannot run code/access data structures in the kernel space • In x86 arch, in order to jump to kernel space, it is common that the process will use interrupts • When jumping to kernel space, the process (kernel) must store a “backup” for its current execution state (so that the kernel will be able to resume the execution later), this backup is referred to as a trapframe. System Calls - interface • Calls are usually made with C/C++ library functions: User Application C - Library Kernel System Call getpid() Load arguments, eax ← _NR_getpid, kernel mode (int 80) Call Sys_Call_table[eax] sys_getpid() syscall_exit return resume_userspace return User-Space Kernel-Space Remark: Invoking int 0x80 is common although newer techniques for “faster” control transfer (SYSCALL/SYSRET) are provided by both AMD’s and Intel’s architecture. XV6 CODE 10 System Calls - interface syscall.h // System call numbers #define • Calls are usually made with C/C++ librarySYS_fork functions: 1 #define SYS_exit 2 #define User Application C - Library KernelSYS_wait 3System #define Call SYS_pipe 4 #define SYS_read 5 #define getpid() Load arguments, eax ← _NR_getpid, SYS_kill 6 #define kernel mode (int 80) SYS_exec 7 #define SYS_fstatCall 8 #define Sys_Call_table[eax]SYS_chdir 9 #definesys_getpid() SYS_dup 10 #define SYS_getpid 11 #define return syscall_exit SYS_sbrk 12 #define SYS_sleep 13 #define resume_userspace SYS_uptime 14 #define SYS_open 15 #define return SYS_write 16 #define SYS_mknod 17 #define SYS_unlink 18 #define SYS_link 19 #define User-Space Kernel-SpaceSYS_mkdir 20 #define SYS_close 21 Remark: Invoking int 0x80 is common although newer techniques for “faster” control transfer are provided by both AMD’s and Intel’s architecture. usys.S #include "syscall.h" #include "traps.h" .globl fork; \ #defineSystem SYSCALL(name) Calls \ - interface fork : \ .globl name; \ name: \ movl $SYS_fork, %eax; \ movl $SYS_ ## name, %eax; \ int $T_SYSCALL; \ int• $T_SYSCALL;Calls are \usually made with C/C++ret library functions: ret User Application C - Library Kernel System Call SYSCALL(fork) SYSCALL(exit) SYSCALL(wait) getpid() Load arguments, ← SYSCALL(pipe) eax _NR_getpid, kernel mode (int 80) SYSCALL(read) Call SYSCALL(write) Sys_Call_table[eax] sys_getpid() SYSCALL(close) SYSCALL(kill) .globl fork; \ return SYSCALL(exec) syscall_exitfork : \ SYSCALL(open) movl $1, %eax; \ SYSCALL(mknod) resume_userspace SYSCALL unlink int $64; \ ( ) SYSCALL(fstat) ret return SYSCALL(link) SYSCALL(mkdir) SYSCALL (chdir) SYSCALL(dup) User-Space Kernel-Space SYSCALL(getpid) SYSCALLRemark:( Invokingsbrk) int 0x80 is common although newer techniques for “faster” control transfer are provided SYSCALLby both( AMD’ssleep and) Intel’s architecture. SYSCALL(uptime) System Calls - interface trapasm.S .globl alltraps •alltrapsCalls :are usually made with C/C++ library functions: # Build trap frame. pushl User%ds Application C - Library Kernel System Call pushl %es pushl %fs getpid() Load arguments, pushl %gs eax ← _NR_getpid, pushal kernel mode (int 80) Call . Sys_Call_table[eax] sys_getpid() . return syscall_exit # Call trap(tf), where tf=%esp pushl %esp resume_userspace call trap . return . User-Space Kernel-Space Remark: Invoking int 0x80 is common although newer techniques for “faster” control transfer are provided by both AMD’s and Intel’s architecture. System Calls - interface syscall.c trap.c static int (*syscalls[])(void) = { [•SYS_forkCalls] sys_forkare usually, made with C/C++ libraryVoid trap(struct functions: trapframe* tf) [SYS_exit] sys_exit, { . User Application C - Library Kernel System Call . [SYS_close] sys_close, . }; getpid() Load arguments, eax ← _NR_getpid, if(tf->trapno == T_SYSCALL){ if(myproc()->killed) void syscall(void) { kernel mode (int 80) int num; Call exit (); struct proc *curproc = myproc(); Sys_Call_table[eax] myproc()->tf =sys_getpid() tf; syscall(); num = curproc->tf->eax; if(myproc()->killed) exit(); if(num > 0 && num < NELEM(syscalls) && syscall_exit return syscalls[num]) { return; curproc->tf->eax = syscalls[num](); } } else { resume_userspace . cprintf("%d %s: unknown sys call %d\n", . curproc->pid, curproc->name, num); return curproc->tf->eax = -1; . } } User-Space Kernel-Space Remark: Invoking int 0x80 is common although newer techniques for “faster” control transfer are provided by both AMD’s and Intel’s architecture. System Calls - interface • Calls are usually made with C/C++ library functions: trapasm.S User Application C - Library Kernel System Call . getpid() Load arguments, . eax ← _NR_getpid, addl $4, %esp kernel mode (int 80) Call sys_getpid() # Return falls through to trapret... Sys_Call_table[eax] .globl trapret trapret: return popal syscall_exit popl %gs popl %fs resume_userspace popl %es popl %ds return addl $0x8, %esp # trapno and errcode iret User-Space Kernel-Space Remark: Invoking int 0x80 is common although newer techniques for “faster” control transfer are provided by both AMD’s and Intel’s architecture. System Calls – tips • Kernel behavior can be enhanced by altering the system calls themselves: imagine we wish to write a message (or add a log entry) whenever a specific user is opening a file. We can re-write the system call open with our new open function and load it to the kernel (need administrative rights). Now all “open” requests are passed through our function. • We can examine which system calls are made by a program by invoking strace<arguments>. Process Control Kernel Space Proc 1 Proc 2 Proc 3 Proc 4 (running) (sleep) (ready) (ready) Process Control Block proc.h enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; // Per-process state struct proc { uint sz; // Size of process memory (bytes) pde_t* pgdir; // Page table char *kstack; // Bottom of kernel stack for this process enum procstate state; // Process state int pid; // Process ID struct proc *parent; // Parent process struct trapframe *tf; // Trap frame for current syscall struct context *context; // swtch() here to run process void *chan; // If non-zero, sleeping on chan int killed; // If non-zero, have been killed struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) }; THE KILL SYSTEM CALL (XV6) /*** sysproc.c ***/ int sys_kill(void) { int pid; /*** syscall.c ***/ if(argint(0, &pid) < 0) return -1; static int (*syscalls[])(void) = { return kill(pid); [SYS_chdir] sys_chdir, } [SYS_close] sys_close, [SYS_dup] sys_dup, [SYS_exec] sys_exec, /*** proc.c ***/ [SYS_exit] sys_exit, [SYS_fork] sys_fork, // Kill the process with the given pid. [SYS_fstat] sys_fstat, // Process won't exit until it returns [SYS_getpid] sys_getpid, // to user space (see trap in trap.c). [SYS_kill] sys_kill, int [SYS_link] sys_link, kill(int pid) { [SYS_mkdir] sys_mkdir, struct proc *p; [SYS_mknod] sys_mknod, [SYS_open] sys_open, acquire(&ptable.lock); [SYS_pipe] sys_pipe, for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ [SYS_read] sys_read, if(p->pid == pid){ [SYS_sbrk] sys_sbrk, p->killed = 1; [SYS_sleep] sys_sleep, // Wake process from sleep if necessary. [SYS_unlink] sys_unlink, if(p->state == SLEEPING) [SYS_wait] sys_wait, p->state = RUNNABLE; [SYS_write] sys_write, release(&ptable.lock); [SYS_uptime] sys_uptime, return 0; }; } release(&ptable.lock); return -1; } 19 Fork • pid_t fork(void); • Fork is used to create a new process. It creates a duplicate of the original process (including all file descriptors, registers, instruction pointer, etc’). • Once the call is finished, the process and its copy go their separate ways. Subsequent changes to one should not effect the other. • The fork call returns a different value to the original process (parent) and its copy (child): in the child process this value is zero, and
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages42 Page
-
File Size-