Le syscall in Minix - homes.di.unimi.ithomes.di.unimi.it/sisop/lucidi0607/Solez11.pdf · loro volta...

Post on 03-Feb-2018

220 views 1 download

Transcript of Le syscall in Minix - homes.di.unimi.ithomes.di.unimi.it/sisop/lucidi0607/Solez11.pdf · loro volta...

Le syscall in Minix

Sistemi OperativiLez. 11

System Call

• Interfaccia tra le applicazioni ed il sistema operativo, per lo svolgimento di operazioni che coinvolgono dispositivi o strutture di memoria gestite dal sistema operativo• Rendono la programmazione più semplice• Incrementano la sicurezza del sistema• Facilitano la portabilità del codice

Posix (Portable Operating system Interface)

• Standard che definisce l’interfaccia utente e software verso applicazioni del sistema operativo• Kernel API• Comandi e utility

• L’aderenza allo standard Posix è spesso garantita da librerie C che provvedono poi alla effettiva chiamata della syscall

• POSIX compliant = un sistema che offre le API di Posix

Architettura di un SO: minix

Minix • Al fine di mantenere aderenza con l’idea di microkernel

le syscall in Minix sono eseguite principalmente dai server (PM e FS) che operano a livello utente, che a loro volta richiamano il kernel per le sole operazioni che coinvolgono strutture dati manipolabili dal solo kenel• System call tutte le chiamate di sistema POSIX effettuate a

livello applicazione• Kernel Call le chiamate fatte al SYSTEM_TASK

esclusivamente dai server, per lo la realizzazione delle System call

• IPC call le chiamate che il SYSTEM_TASK inoltra effettivamente al kernel per l’esecuzione delle syscall

priv

Syscall nr.

Kernel call

Overview of System Task (2)

sys_task

La chiamata di una syscall

• if (fork() != 0)• Viene tradotta dal compilatore in una

chiamata alla procedura di libreria lib/syscall/fork.s (nel caso di eventuali parametri gli stessi sono passati via stack)

• sys/src/lib/syscall/fork.s: .sect .text .extern __fork .define _fork .align 2

_fork: jmp __fork

• Che a sua volta richiama la procedura fork(), che è definita nel file sys/src/lib/posix/fork.c

• sys/src/lib/posix/fork.c

#include < lib.h> #define fork _fork #include < unistd.h>

PUBLIC pid_t fork() message m; return(_syscall(PM, FORK, &m));

• Che richiama la funzione _syscall, indicando come destinatario dell’attività richiesta il processo PM

_syscall

#include < lib.h> PUBLIC int _syscall(who, syscallnr, msgptr) int who; int syscallnr; register message *msgptr; int status; msgptr->m_type = syscallnr; status = _sendrec(who, msgptr); if (status != 0) { /* 'sendrec' itself failed. */ /* XXX - strerror doesn't know all the codes */

msgptr->m_type = status; } if (msgptr->m_type < 0) { errno = -msgptr->m_type; return(-1); } return(msgptr->m_type);

_sendrec

+++++++++++++++++++++++++++++++++ lib/i386/rts/_sendrec.

+++++++++++++++++++++++++++++++++300 .sect .text; .sect .rom; .sect .data; .sect .bss 301 .define __send, __receive, __sendrec 302 ! See ../h/com.h for C definitions 303 SEND = 1 304 RECEIVE = 2 305 BOTH = 3 306 SYSVEC = 33 307 SRCDEST = 8 308 MESSAGE = 12

_sendrec

/sys/src/lib/i386/rts/_sendrec.c __sendrec: push ebp

mov ebp, esp push ebx mov eax, SRCDEST(ebp) ! eax = dest-src mov ebx, MESSAGE(ebp) ! ebx = message pointer mov ecx, BOTH ! _sendrec(srcdest, ptr) int SYSVEC ! trap to the kernel pop ebx pop ebp ret

Vettore Syscall

_s_call: _p_s_call:

cld ! set direction flag to a known value sub esp, 6*4 ! skip RETADR, eax, ecx, edx, ebx, est push ebp

! stack already points into proc table push esi push edi

o16 push ds o16 push es o16 push fs o16 push gs

mov dx, ss mov ds, dx mov es, dx incb (_k_reenter) mov esi, esp ! assumes P_STACKBASE == 0 mov esp, k_stktop xor ebp, ebp ! for stacktrace ! end of inline save

! now set up parameters for sys_call() push ebx ! pointer to user message push eax ! src/dest push ecx ! SEND/RECEIVE/BOTH call _sys_call ! sys_call(function, src_dest, m_ptr)

minisend

• Prepara il per PM, che prima o poi lo preleverà attraverso una receive

• Nel file include/minix/callnr.h, alla fork() è assegnato il numero 2 : • #define FORK 2

• Nel file pm/table.c, la struttura dati call_vec associa alla syscall fork() la procedura:• do_fork, /* 2 = fork */

Richiama pm/do_fork()

do_fork

• Verifica se esiste spazio nella tabella dei processi mproc che contiene la mappa di memoria per ogni processo

• Verifica la quantità di memoria necessaria per allocare il nuovo processo (è uguale a quella del padre) e la sua disponibilità

• Crea una copia delle porzioni di memoria occupate dal processo padre

• Inidivuda una slot libero in mproc e copia il contenuto dello slot del processo padre

• Assegna un PID all’interno di mproc ,che sarà poi lo stesso usato per la tabella dei processi

• Chiama la kernel call sys_fork (kernel) per aggiornare la process table

• Chiama tell_fs (FS)

sys_forkPUBLIC int sys_fork(parent, child, pid, child_base_or_shadow)

int parent; /* process doing the fork */ int child; /* which proc has been created by the fork */ int pid; /* process id assigned by PM */ phys_clicks child_base_or_shadow; /* position for child [VM386] */

/* A process has forked. Tell the kernel. */ message m; m.m1_i1 = parent; m.m1_i2 = child; m.m1_i3 = pid; m.m1_p1 = (char *) child_base_or_shadow; return(_taskcall(SYSTASK, SYS_FORK, &m));

_taskcallsys/src/lib/syslib/taskcall.c:

#include < lib.h> #include < minix/syslib.h>PUBLIC int _taskcall(who, syscallnr, msgptr) int who; int syscallnr; register message *msgptr; int status;

msgptr->m_type = syscallnr;status = _sendrec(who, msgptr); if (status != 0) return(status);return(msgptr->m_type);

system task

system task

• Now we're at the point of doing whatever else needs to be done to complete the fork (also in system.c).

• The message sent via the taskcall contains a pointer to the parent (PROC1) and the child (PROC2).

• The MM has completed all the work for the fork that pertains to memory (the copy, setting the mproc table (mm/mproc.h), and now the system needs to update the process table entry and do the bookkeeping:

PRIVATE int do_fork(m_ptr)

register message *m_ptr; /* pointer to request message */

/* Handle sys_fork(). m_ptr->PROC1 has forked. The child is m_ptr->PROC2. */

rpp = proc_addr(m_ptr->PROC1);

rpc = proc_addr(m_ptr->PROC2);

/* Copy parent 'proc' struct to child. */

#if (CHIP == INTEL)

old_ldt_sel = rpc->p_ldt_sel; /* stop this being obliterated by copy */

#endif

*rpc = *rpp; /* copy 'proc' struct */

• Then we reply to the child and the parent, both of which are waiting for the completion of the fork system call.

• The child is responded to with reply (mm/main.c) and then do_fork returns to mm/main, where it does a reply to the initiating process (the parent process).

• Reply (in mm/main.c) just does a send (again out of the lib/i386/rts/_sendrec.c):