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
MINIX
L’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
jmp M.0 | skip over the next few bytes
M.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 the
add sp,#K_STACK_BYTES | kernel stack
call _main | start the main program of MINIX
System Call
Questo 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 caller
push 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 running
Interruzioni 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 execution
I punti di ingresso alla chiamata delle routine di interruzione per :
- il floppy disk
- winchester disk
- clock
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 parameter
push ax | push first parameter
call _interrupt | this is the call
jmp _restart | continue execution
idle
l’entry point idle fa attesa attiva aspettando un interruzione
idle: | executed when there is no work
sti | enable interrupts
L3: wait | just idle while waiting for interrupt
jmp L3 | loop until interrupt
Save
Questo è 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 ax
Restart
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 task
le 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