Il file
mpx88.s fa parte dello strato più basso del kernel MINIX. In esso sono descritte ed implementate in assembly tutte le operazioni che consentono di cambiare lo stato di un processo(processing switching) e di gestire lo scambio di messaggi (message handling).
Questo file è utilizzato ogni qual volta si fà riferimento al kernel.
Es. per l’ invio e/o ricezione di messaggi e per la gestione delle interruzioni/trap.
Nei casi di eccezioni hardware, quali TRAP o interruzioni, prima di eseguire il relativo gestore viene chiamata la procedura save() per salvare lo stato della macchina nella tabella dei processi. Successivamente si passa a lavorare sullo stack del kernel e finalmente viene eseguita la reale trap o chiamato il reale gestore di interruzioni scritto in codice C. Al ritorno della chiamata di procedura relativa ai gestori, il numero di processo o task contenuto in ‘cur_proc’ viene messo in esecuzione.
I punti d’ingresso(entry points) definiti in questo file sono:
- minix: inizializza lo stack del kernel e chiama la procedura main(scritta in C )
- s_call: per un processo o task che vuole inviare o ricevere un messaggio
- tty_int: routine d’interruzioni per ogni tasto pressato e rilasciato
- lpr_int: routine d’interruzioni per ogni linea di stampata
- disk_int: routine d’interruzioni per il disco
- wini_int: routine d’interruzioni per Winchester
- clock_int: routine d’interruzioni per il clock (Hz)
- surprise : per altri interrupt(inaspettati)
- trp: per tutte le trap(esclusa trap su divisione)
- divide: per le trap del tipo divide overflow
- restart: per l’inizio dell’ esecuzione di un task o un processo
Queste entry point vengono chiamate prima di eseguire la relativa procedura in C
MINIXL’entry point per il kernel MINIX setta il DS e l’ SS del kernel all’indirizzo 4 e lo stack pointer sp del kernel viene inizializzato al valore #K_STACK_BYTES(256); infine viene chiamata la procedura main. Tutte queste operazioni vengono chiamate ad interruzioni disabilitate.
Ricordiamo che:
- DS : Data Segment è l’area che contiene i dati del programma
- CS : Code Segment è l’area di memoria che contiene le istruzioni(il testo) del programma
- SS : Stack Segment è l’area di memoria relativa allo stack del programma
- ES: Extra Segment è l’area di memoria per le informazioni extra relative al programma
|*===========================================================================* |* MINIX * |*===========================================================================* MINIX: | this is the entry point for the MINIX kernel. jmp M.0 | skip over the next few bytesM.0: cli | disable interrupts…mov ax,4 | build has loaded this word with ds value
mov ds,ax | ds now contains proper value mov ss,ax | ss now contains proper value
mov _scan_code,bx | save scan code for '=' key from bootstrap
mov sp,#_k_stack | set sp to point to the top of theadd sp,#K_STACK_BYTES | kernel stack call _main | start the main program of MINIXSystem CallQuesto entry point inserisce i parametri della funzione sys_call(function, caller, src_dest, m_ptr) nella stack del kernel prima della vera chiamata in codice C.
Al ritorno della procedura per la chiamata di sistema viene mandato un task o un processo in esecuzione(viene chiamata la procedura restart)
I parametri della sys_call vengono recuperati accendendo alla posizione della tabella dei processi relativa al processo o task in esecuzione.
|*===========================================================================* |* s_call * |*===========================================================================* _s_call: | System calls are vectored here.
call save | save the machine state mov bp,_proc_ptr | use bp to access sys call parameters
push 2(bp) | push(pointer to user message) (was bx)
push (bp) | push(src/dest) (was ax)push _cur_proc |push callerpush 4(bp) | push(SEND/RECEIVE/BOTH) (was cx)
call _sys_call | sys_call(function, caller, src_dest, m_ptr)
jmp _restart | jump to code to restart proc/task runningInterruzioni e trap.l’entry point per :
- interruzione da tastiera(tty_int) :
- interruzione stampa di una linea(lpr_int)
- una trap(trp)
- una trap di divisione(divide ,es. divisione per 0)
- altre interruzioni inaspettate(surprise)
si salva lo stato della macchina , si chiama il relativo gestore e si continua l’esecuzione

Es. routine per interruzione d'input da terminale
|*===========================================================================* |* tty_int * |*===========================================================================* _tty_int: | Interrupt routine for terminal input. call save | save the machine state
call _keyboard | process a keyboard interrupt
jmp _restart | continue executionI punti di ingresso alla chiamata delle routine di interruzione per :
- il floppy disk
- winchester disk
- clock
hanno un comportamento analogo; per chiamare la funzione interrupt(definita in codice C,proc.c) vengono copiati i parametri nello stack del kernel.
Es. Nella routine di interruzione per il floppy disk viene costruito il messaggio di interruzione da inviare; successivamente viene inpilato nello stack insieme all’argomento FLOPPY che identifica il destinatario.
Infine viene chiamata la funzione interrupt.
In questo caso gli argomenti passati alla funzione sono FLOPPY, &intmess.
Se la routine chiamata fosse stata di clock o winchester, i parametri passati alla funzione interrupt sarebbero rispettivamente [CLOCK, &intmess] o [WINI, &intmess]
|*===========================================================================* |* disk_int * |*===========================================================================* _disk_int: | Interrupt routine for the floppy disk.call save | save the machine state mov _int_mess+2,*DISKINT| build message for disk task mov ax,#_int_mess | prepare to call interrupt(FLOPPY, &intmess) push ax | push second parameter
mov ax,*FLOPPY | prepare to push first parameterpush ax | push first parameter
call _interrupt | this is the call
jmp _restart | continue execution
idlel’entry point idle fa attesa attiva aspettando un interruzione
idle: | executed when there is no work
sti | enable interruptsL3: wait | just idle while waiting for interrupt
jmp L3 | loop until interruptSaveQuesto è il punto di ingresso utilizzato per salvare lo stato del sistema, quindi le informazioni relative al processo in esecuzione, nella tabella dei processi.
Nel dettaglio, vengono recuperati dallo stack del programma attualmente in esecuzione i valori della program status word (psw), del segmento del codice(cs) e il program counter(pc) e salvati nella tabella dei processi.
Successivamente si salvano i registri relativi al processo, che in ordine di inserimento sono : sp,es,bp,di,si,dx,cx,bx,ax.
La procedura termina con un salto all’indirizzo del chiamante(indirizzo di ritorno della save)
Nota: _proc_ptr ritorna la posizione(indirizzo) nella tabella dei processi del processo in esecuzione.
|*===========================================================================* |* save * |*===========================================================================* save: | save the machine state in the proc table
. ..pop ds_save | stack: psw/cs/pc/ret addr
pop ret_save | stack: psw/cs/pc mov bx_save,bx | save bx for later ; we need a free register mov bx,_proc_ptr | start save set up; make bx point to save area add bx,*OFF | bx points to place to store cs pop PC-OFF(bx) | store pc in proc table pop csreg-OFF(bx) | store cs in proc table pop PSW-OFF(bx) | store psw mov ssreg-OFF(bx),ss | store ss
… push ds_save | start saving all the registers, sp first
push es | save es between sp and bp
mov es,bx | es now references kernel memory too push bp | save bp push di | save di
push si | save si push dx | save dx push cx | save cx push bx_save | save original bx
push ax | all registers now saved… mov ax,ret_save | ax = address to return to jmp (ax) | return to caller; Note: sp points to saved axRestart
Complementare a Save, questo entry point inizializza ed esegue un processo o un task.
Se il sistema è attivo, i valori psw, cs, sp e dei registri del processo da mandare in esecuzione, contenuti nella tabella dei processi, vengono ripristinati inserendoli nello stack.
|*===========================================================================* |* restart * |*===========================================================================* _restart: | This routine sets up and runs a proc or task.
cmp _cur_proc,#IDLE | restart user; if cur_proc = IDLE, go idle je idle | no user is runnable, jump to idle routine
cli | disable interrupts mov sp,_proc_ptr | return to user, fetch regs from proc table
pop ax | start restoring registers pop bx | restore bx pop cx | restore cx pop dx | restore dx
pop si | restore si pop di | restore di mov lds_low,bx | lds_low contains bx mov bx,sp | bx points to saved bp register mov bp,SPLIM-ROFF(bx) | splimit = p_splimit mov splimit,bp | ditto
mov bp,dsreg-ROFF(bx) | bp = ds mov lds_low+2,bp | lds_low+2 contains ds pop bp | restore bp pop es | restore es
mov sp,SP-ROFF(bx) | restore sp mov ss,ssreg-ROFF(bx) | restore ss using the value of ds push PSW-ROFF(bx) | push psw
push csreg-ROFF(bx) | push cs push PC-ROFF(bx) | push pc
lds bx,lds_low | restore ds and bx in one fell swoop
iret | return to user or taskle costanti utilizzate in mpx88.s e contenute in com.h sono:
K_STACK_BYTES = 256 | dimensione kernel stack
WINI = -6 |identificativo per task che si occupa del wininchester disk
FLOPPY = -5 |identificativo per il task floppy disk
CLOCK = -3 | identificativo per il task clock
IDLE = -999 | costante che identifica sistema inattivo
DISKINT = 1 | per identicare il tipo del mess. di interruzione disk
CLOCK_TICK = 2 | per identicare il tipo del mess. di interruzione clock