310 likes | 501 Views
MINIX3 LLAMADAS AL SISTEMA Cátedra: Diseño e Implementación de Sistemas Operativos UTN-FRSF Tomado de: Operating Systems Design and Implementation, Third Edition. Generalidades. Las interfaces entre los programas de usuario y el sistema operativo son los system calls o llamadas al sistema.
E N D
MINIX3LLAMADAS AL SISTEMACátedra: Diseño e Implementación de Sistemas Operativos UTN-FRSFTomado de: Operating Systems Design and Implementation, Third Edition
Generalidades • Las interfaces entre los programas de usuario y el sistema operativo son los system calls o llamadas al sistema. • En el caso de MINIX estas llamadas se implementan a través de las 4 únicas primitivas que ofrece el sistema operativo. • send() • receive() • sendrec() • notify()
Invocando un System Call user process getpid() src/lib/syscall getpid.s getpid: jmp _getpid src/lib/posix _getpid.c getpid(){ _syscall() } src/lib/other syscall.c _syscall(){ _sendrec() } src/lib/i386/rts/ _ipc.s _sendrec: int SYSVEC
Atendiendo un System Call src/kernel protect.c int_gate{ s_call() } SYSVEC s_call src/kernel src/kernel src/kernel proc.c sys_call(){ mini_send() mini_rec() } mpx386.s s_call: call _sys_call() _proc.c mini_send() {.....} mini_rec() {.....}
src/lib/i386/rts/_ipc.s .define __echo, __notify, __send, __receive, __sendrec ! See src/kernel/ipc.h for C definitions SEND = 1 RECEIVE = 2 SENDREC = 3 NOTIFY = 4 ECHO = 8 SYSVEC = 33 ! trap to kernel SRC_DST = 8 ! source/ destination process ECHO_MESS = 8 ! echo doesn't have SRC_DST MESSAGE = 12 ! message pointer
src/lib/i386/rts/_sendrec.s !*============================================================* ! IPC assembly routines * !*============================================================* ! all message passing routines save ebp, but destroy eax and ecx. .define __echo, __notify, __send, __receive, __sendrec .sect .text __send: push ebp mov ebp, esp push ebx mov eax, SRC_DST(ebp) ! eax = dest-src mov ebx, MESSAGE(ebp) ! ebx = message pointer mov ecx, SEND ! _send(dest, ptr) int SYSVEC ! trap to the kernel pop ebx pop ebp ret
src/lib/i386/rts/_sendrec.s __receive: push ebp mov ebp, esp push ebx mov eax, SRC_DST(ebp) ! eax = dest-src mov ebx, MESSAGE(ebp) ! ebx = message pointer mov ecx, RECEIVE ! _receive(src, ptr) int SYSVEC ! trap to the kernel pop ebx pop ebp ret __sendrec: push ebp mov ebp, esp push ebx mov eax, SRC_DST(ebp) ! eax = dest-src mov ebx, MESSAGE(ebp) ! ebx = message pointer mov ecx, SENDREC ! _sendrec(srcdest, ptr) int SYSVEC ! trap to the kernel pop ebx pop ebp ret
src/kernel/mpx386.s 06645 !*===========================================================================* 06646 !* _s_call * 06647 !*===========================================================================* 06648 .align 16 06649 _s_call: 06650 _p_s_call: 06651 cld ! set direction flag to a known value 06652 sub esp, 6*4 ! skip RETADR, eax, ecx, edx, ebx, est 06653 push ebp ! stack already points into proc table 06654 push esi 06655 push edi 06656 o16 push ds 06657 o16 push es 06658 o16 push fs 06659 o16 push gs 06660 mov dx, ss 06661 mov ds, dx 06662 mov es, dx 06663 incb (_k_reenter) 06664 mov esi, esp ! assumes P_STACKBASE == 0 06665 mov esp, k_stktop 06666 xor ebp, ebp ! for stacktrace 06667 ! end of inline save 06668 ! now set up parameters for sys_call() 06669 push ebx ! pointer to user message 06670 push eax ! src/dest 06671 push ecx ! SEND/RECEIVE/BOTH 06672 call _sys_call ! sys_call(function, src_dest, m_ptr) 06673 ! caller is now explicitly in proc_ptr 06674 mov AXREG(esi), eax ! sys_call MUST PRESERVE si 06675 06676 ! Fall into code to restart proc/task running.
src/kernel/proc.c 07477 /*===========================================================================* 07478 * sys_call * 07479 *===========================================================================*/ 07480 PUBLIC int sys_call(call_nr, src_dst, m_ptr) 07481 int call_nr; /* system call number and flags */ 07482 int src_dst; /* src to receive from or dst to send to */ 07483 message *m_ptr; /* pointer to message in the caller's space */ 07484 { 07485 /* System calls are done by trapping to the kernel with an INT instruction. 07486 * The trap is caught and sys_call() is called to send or receive a message 07487 * (or both). The caller is always given by 'proc_ptr'. 07488 */ 07489 register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */ 07490 int function = call_nr & SYSCALL_FUNC; /* get system call function */ 07491 unsigned flags = call_nr & SYSCALL_FLAGS; /* get flags */ 07492 int mask_entry; /* bit to check in send mask */ 07493 int result; /* the system call's result */ 07494 vir_clicks vlo, vhi; /* virtual clicks containing message to send */
src/kernel/proc.c 07496 /* Check if the process has privileges for the requested call. Calls to the 07497 * kernel may only be SENDREC, because tasks always reply and may not block 07498 * if the caller doesn't do receive(). 07499 */ 07500 if (! (priv(caller_ptr)->s_trap_mask & (1 << function)) || 07501 (iskerneln(src_dst) && function != SENDREC 07502 && function != RECEIVE)) { 07503 kprintf("sys_call: trap %d not allowed, caller %d, src_dst %d\n", 07504 function, proc_nr(caller_ptr), src_dst); 07505 return(ECALLDENIED); /* trap denied by mask or kernel */ 07506 } 07507 07508 /* Require a valid source and/ or destination process, unless echoing. */ 07509 if (! (isokprocn(src_dst) || src_dst == ANY || function == ECHO)) { 07510 kprintf("sys_call: invalid src_dst, src_dst %d, caller %d\n", 07511 src_dst, proc_nr(caller_ptr)); 07512 return(EBADSRCDST); /* invalid process number */ 07513 }
src/kernel/proc.c 07515 /* If the call involves a message buffer, i.e., for SEND, RECEIVE, SENDREC, 07516 * or ECHO, check the message pointer. This check allows a message to be 07517 * anywhere in data or stack or gap. It will have to be made more elaborate 07518 * for machines which don't have the gap mapped. 07519 */ 07520 if (function & CHECK_PTR) { 07521 vlo = (vir_bytes) m_ptr >> CLICK_SHIFT; 07522 vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT; 07523 if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi || 07524 vhi >= caller_ptr->p_memmap[S].mem_vir + 07525 caller_ptr->p_memmap[S].mem_len) { 07526 kprintf("sys_call: invalid message pointer, trap %d, caller %d\n", 07527 function, proc_nr(caller_ptr)); 07528 return(EFAULT); /* invalid message pointer */ 07529 } 07530 }
src/kernel/proc.c 07532 /* If the call is to send to a process, i.e., for SEND, SENDREC or NOTIFY, 07533 * verify that the caller is allowed to send to the given destination and 07534 * that the destination is still alive. 07535 */ 07536 if (function & CHECK_DST) { 07537 if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) { 07538 kprintf("sys_call: ipc mask denied %d sending to %d\n", 07539 proc_nr(caller_ptr), src_dst); 07540 return(ECALLDENIED); /* call denied by ipc mask */ 07541 } 07542 07543 if (isemptyn(src_dst) && !shutdown_started) { 07544 kprintf("sys_call: dead dest; %d, %d, %d\n", 07545 function, proc_nr(caller_ptr), src_dst); 07546 return(EDEADDST); /* cannot send to the dead */ 07547 } 07548 }
src/kernel/proc.c 07550 /* Now check if the call is known and try to perform the request. The only 07551 * system calls that exist in MINIX are sending and receiving messages. 07552 * - SENDREC: combines SEND and RECEIVE in a single system call 07553 * - SEND: sender blocks until its message has been delivered 07554 * - RECEIVE: receiver blocks until an acceptable message has arrived 07555 * - NOTIFY: nonblocking call; deliver notification or mark pending 07556 * - ECHO: nonblocking call; directly echo back the message 07557 */ 07558 switch(function) { 07559 case SENDREC: 07560 /* A flag is set so that notifications cannot interrupt SENDREC. */ 07561 priv(caller_ptr)->s_flags |= SENDREC_BUSY; 07562 /* fall through */ 07563 case SEND: 07564 result = mini_send(caller_ptr, src_dst, m_ptr, flags); 07565 if (function == SEND || result != OK) { 07566 break; /* done, or SEND failed */ 07567 } /* fall through for SENDREC */ 07568 case RECEIVE: 07569 if (function == RECEIVE) 07570 priv(caller_ptr)->s_flags &= ~SENDREC_BUSY; 07571 result = mini_receive(caller_ptr, src_dst, m_ptr, flags); 07572 break;
src/kernel/proc.c 07573 case NOTIFY: 07574 result = mini_notify(caller_ptr, src_dst); 07575 break; 07576 case ECHO: 07577 CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, caller_ptr, m_ptr); 07578 result = OK; 07579 break; 07580 default: 07581 result = EBADCALL; /* illegal system call */ 07582 } 07583 07584 /* Now, return the result of the system call to the caller. */ 07585 return(result); 07586 }
Implementando un System Call User Process System Call FS/PM Task Call TASK Kernel call SYSTEM TASK
Implementando un System Call • src/lib/syscall:Crear el archivo newcall.s • src/lib/syscall:Modificar el Makefile para que incluya su compilación. • src/lib/posix:Crear el archivo _newcall.c • src/lib/posix:Modificar el Makefile para que incluya su compilación. • include/unistd.h: Prototipo del System Call newcall • include/minix/callnr.h: Asignarle el número de System Call e incrementar la Cantidad de System Calls NCALLS si fuese necesario. ATENCION: esto afecta a src/pm/table.c y src/fs/table.c que utilizan NCALLS para sus vectores!!!!
Implementando un System Call • src/servers/pm/proto.h o src/servers/pm/proto.h : Agregar el prototipo de la función que invocará el PM/FS con nombre do_newcall. • src/servers/pm/table.c o src/servers/fs/table.c: insertar un elemento en la Tabla de funciones de atención de System Calls del PM/FS con nombre do_newcall.. • src/servers/pm/newcall.c: Crear este archivo con el código de la nueva System Call. • src/servers/pm/Makefile: Editar este archivo para que incluya la compilación de newcall.c.
Syscalls que usan SYSTASK • src/lib/syslib: Crear un archivo sys_newcall.c con el cual se invocara a la SYSTASK utilizando mini_send(), mini_rec() o directamente taskcall(). • src/lib/Makefile: Editar este archivo para que incluya la compilación de sys_newcall.c. • include/minix/syslib.h: Agregar el prototipo de la función sys_newcall(). • include/minix/com.h: Agregar el tipo de mensaje que que se envía a SYSTASK solicitando realizar tarea para newcall. • src/kernel/system.c: Modificar el código de la SYSTASK para que atienda el nuevo tipo de mensajes.
Comunicación con las Tareas Las interfaces entre los servidores PM y FS y las tareas se puede llevar a de 2 formas • Utilizando sendrec() • Utilizando taskcall() # ls sys* sys_abort.c sys_irqctl.c sys_setalarm.c sys_vircopy.c sys_endsig.c sys_kill.c sys_sigreturn.c sys_vm_map.c sys_eniop.c sys_memset.c sys_sigsend.c sys_vm_setbuf.c sys_exec.c sys_newmap.c sys_svrctl.c sys_voutb.c sys_exit.c sys_nice.c sys_times.c sys_voutl.c sys_fork.c sys_out.c sys_trace.c sys_voutw.c sys_getinfo.c sys_physcopy.c sys_umap.c syslib.h sys_getsig.c sys_privctl.c sys_vinb.c sys_in.c sys_sdevio.c sys_vinl.c sys_int86.c sys_segctl.c sys_vinw.c
src/lib/syslib/taskcall.c # cat sys_out.c #include "syslib.h" /*=================================================================* * sys_out * =================================================================*/ PUBLIC int sys_out(port, value, type) int port; /* port address to write to */ unsigned long value; /* value to write */ int type; /* byte, word, long */ { message m_io; m_io.DIO_TYPE = type; m_io.DIO_REQUEST = DIO_OUTPUT; m_io.DIO_PORT = port; m_io.DIO_VALUE = value; return _taskcall(SYSTASK, SYS_DEVIO, &m_io); }
Compilación Total # cd /usr/src/tools # make Master Makefile to create new MINIX configuration. Root privileges are required. Usage: make includes # Install include files make depend # Generate dependency files make libraries # Make system libraries make services # Compile and install all services make fresh # Make clean, libraries, and services make image # Make needed services and create boot image make install # Make image, and install to hard disk make hdboot # Make image, and install to hard disk make fdboot # Make image, and install to floppy disk make bootable # Make hard disk bootable make clean # Remove all compiler results, except libs To create a fresh MINIX configuration, try: make clean install # new boot image make fresh install # new everything #