Tema 9: Excepcions i interrupcions
27.1 Excepcions i interrupcions
Enunciat: Problema 18.1.
a) Una excepció és un esdeveniment causat per l’execució d’una instrucció (origen intern): per exemple, un accés a memòria amb adreça no alineada o una instrucció il·legal. Una interrupció és un esdeveniment causat per un dispositiu extern (origen extern): per exemple, un teclat que notifica que s’ha premut una tecla.
b) En cas d’excepció, mepc apunta a la instrucció causant (la que s’ha interromput sense completar-se). En cas d’interrupció, mepc apunta a la instrucció següent a la instrucció que s’estava executant (la instrucció en curs ha finalitzat completament i el PC ja s’ha incrementat).
c) Quan el processador detecta una excepció o interrupció, executa automàticament, per maquinari (Secció 9.3.1):
- Guarda el PC a
mepc. - Escriu el codi de causa a
mcause(bit 31 = 0 per a excepcions, bit 31 = 1 per a interrupcions). - Copia
MIEaMPIEi posaMIE = 0(deshabilita les interrupcions). - Guarda el mode de privilegi actual a
MPPi passa a mode M. - Salta a l’adreça de la rutina de servei d’excepcions (RSE) continguda a
mtvec.
d) L’RSE ha de desar tots els registres generals (x1–x31) sense excepció. A diferència d’una subrutina normal, el programa interromput no ha cedit el control voluntàriament i no pot saber quins registres modificarà l’RSE. Les convencions ABI (registres salvats vs. temporals) no s’apliquen.
Enunciat: Problema 18.3. Vegeu l’estructura general de l’RSE a Secció 9.4.
RV32IZicsr
rse:
# a) Reservar espai i desar tots els registres (x1-x31, excepte sp=x2)
addi sp, sp, -120
sw ra, 0(sp)
sw t0, 4(sp)
sw t1, 8(sp)
sw t2, 12(sp)
sw s0, 16(sp)
sw s1, 20(sp)
sw a0, 24(sp)
sw a1, 28(sp)
sw a2, 32(sp)
sw a3, 36(sp)
sw a4, 40(sp)
sw a5, 44(sp)
sw a6, 48(sp)
sw a7, 52(sp)
sw s2, 56(sp)
sw s3, 60(sp)
sw s4, 64(sp)
sw s5, 68(sp)
sw s6, 72(sp)
sw s7, 76(sp)
sw s8, 80(sp)
sw s9, 84(sp)
sw s10, 88(sp)
sw s11, 92(sp)
sw t3, 96(sp)
sw t4, 100(sp)
sw t5, 104(sp)
sw t6, 108(sp)
sw gp, 112(sp)
sw tp, 116(sp)
# b) Llegir mcause i comprovar si és ecall des de mode U (codi 8)
csrr t0, mcause
li t1, 8
beq t0, t1, handler_ecall
# Causa desconeguda: salt al gestor d'error genèric
j handler_error
handler_ecall:
# Tractament de la crida al sistema...
# Incrementar mepc en 4 per continuar a la instrucció següent
csrr t0, mepc
addi t0, t0, 4
csrw mepc, t0
j rse_ret
handler_error:
# Tractament d'error genèric...
j rse_ret
rse_ret:
# c) Restaurar tots els registres
lw ra, 0(sp)
lw t0, 4(sp)
lw t1, 8(sp)
lw t2, 12(sp)
lw s0, 16(sp)
lw s1, 20(sp)
lw a0, 24(sp)
lw a1, 28(sp)
lw a2, 32(sp)
lw a3, 36(sp)
lw a4, 40(sp)
lw a5, 44(sp)
lw a6, 48(sp)
lw a7, 52(sp)
lw s2, 56(sp)
lw s3, 60(sp)
lw s4, 64(sp)
lw s5, 68(sp)
lw s6, 72(sp)
lw s7, 76(sp)
lw s8, 80(sp)
lw s9, 84(sp)
lw s10, 88(sp)
lw s11, 92(sp)
lw t3, 96(sp)
lw t4, 100(sp)
lw t5, 104(sp)
lw t6, 108(sp)
lw gp, 112(sp)
lw tp, 116(sp)
addi sp, sp, 120
# Retornar: MIE←MPIE, mode←MPP, PC←mepc
mretObservacions:
- L’etiqueta
rseha de ser l’adreça que es configura amtvec(campBASE) durant la inicialització. - El salt
jés una pseudoinstrucció equivalent ajal x0, offset.
mepc, mtvec i ajust de retorn
Enunciat: Problema 18.4.
a) La instrucció lw t0, 0(t1) a 0x80001000 genera una excepció en executar-se (adreça no alineada). La instrucció s’avorta sense completar-se i el PC no s’incrementa. El maquinari guarda l’adreça de la instrucció causant:
\[\texttt{mepc} = \texttt{0x80001000}\]
b) La interrupció de temporitzador es detecta en acabar la instrucció lw t0, 0(a0) (el PC ja s’ha incrementat). El maquinari guarda l’adreça de la instrucció següent:
\[\texttt{mepc} = \texttt{0x80002008}\]
En retornar amb mret, el processador salta a mepc, és a dir, a 0x80002008: la instrucció que seguia el lw.
c) En mode directe (MODE = 0), totes les excepcions i interrupcions salten a BASE. L’RSE llegeix mcause per identificar la causa i derivar el control al gestor específic.
En mode vectoritzat (MODE = 1), les interrupcions salten a BASE + 4 × causa; les excepcions sempre salten a BASE.
Per a una interrupció de temporitzador en mode M (codi de causa 7):
\[\text{adreça} = \texttt{BASE} + 4 \times 7 = \texttt{BASE} + 28\]
d) Sense l’increment, mret retornaria a la mateixa instrucció ecall, que causaria una nova excepció indefinidament. L’RSE ha d’incrementar mepc perquè l’ecall ja ha estat atesa i el programa ha de continuar a la instrucció següent:
27.2 Crides al sistema
Enunciat: Problema 18.5. Els codis de servei de RARS són a RISC-V 9.13.
a) Imprimir l’enter de t0:
b) Llegir un enter i deixar el resultat a t1:
c) Imprimir la cadena de caràcters amb adreça base a t2:
d) Finalitzar el programa:
Nota: a EC la sortida es fa sempre amb exit2, no amb exit (codi 10) — vegeu RISC-V 2.19.
27.3 Entrada/sortida
Enunciat: Problema 18.8.
a) En la sincronització per enquesta (polling), el processador consulta repetidament el registre d’estat del dispositiu fins que l’operació acaba. És simple, però desaprofita el processador durant l’espera. En la sincronització per interrupcions, el dispositiu notifica el processador quan ha acabat, i el processador pot fer feina útil entremig. És més eficient, però requereix configurar els permisos d’interrupció i escriure una RSE.
b) Per habilitar les interrupcions en RISC-V cal:
- Habilitar el permís específic del tipus d’interrupció al registre
mie(per exemple,MEIE= bit 11 per a interrupcions externes). - Habilitar el permís global
MIE(bit 3 demstatus).
RV32IZicsr
c) El bit MIE (bit 3 de mstatus) és el permís global: si val 0, cap interrupció no s’atén, independentment de la resta de bits. El bit MTIE (bit 7 de mie) és la màscara específica de les interrupcions de temporitzador en mode M: si val 0, les interrupcions de temporitzador queden inhibides fins i tot quan MIE = 1. Cal que tots dos valguin 1 (i el bit corresponent de mip estigui actiu) perquè una interrupció de temporitzador sigui atesa.
Enunciat: Problema 18.10.
a) Cal activar MEIE (bit 11 de mie) i MIE (bit 3 de mstatus):
RV32IZicsr
b) RSE mínima per a la interrupció de teclat:
RV32IZicsr
.data
car: .word 0
.text
rse_teclat:
# Desar tots els registres generals (x1-x31, excepte sp=x2)
addi sp, sp, -120
sw ra, 0(sp)
sw t0, 4(sp)
sw t1, 8(sp)
sw t2, 12(sp)
sw s0, 16(sp)
sw s1, 20(sp)
sw a0, 24(sp)
sw a1, 28(sp)
sw a2, 32(sp)
sw a3, 36(sp)
sw a4, 40(sp)
sw a5, 44(sp)
sw a6, 48(sp)
sw a7, 52(sp)
sw s2, 56(sp)
sw s3, 60(sp)
sw s4, 64(sp)
sw s5, 68(sp)
sw s6, 72(sp)
sw s7, 76(sp)
sw s8, 80(sp)
sw s9, 84(sp)
sw s10, 88(sp)
sw s11, 92(sp)
sw t3, 96(sp)
sw t4, 100(sp)
sw t5, 104(sp)
sw t6, 108(sp)
sw gp, 112(sp)
sw tp, 116(sp)
# Comprovar que és una interrupció externa (bit 31 de mcause = 1, codi = 11)
csrr t0, mcause
li t1, 0x8000000B # bit31=1, codi=11 (interrupció externa mode M)
bne t0, t1, rse_ret_teclat
# Comprovar bit MEIP de mip (bit 11): petició externa pendent
csrr t0, mip
li t1, 0x800 # bit 11 (MEIP)
and t0, t0, t1
beqz t0, rse_ret_teclat
# Confirmar que la interrupció prové del teclat (registre d'estat, bit 0)
li t0, 0xF0001000 # adreça registre d'estat del teclat
lw t1, 0(t0)
andi t1, t1, 1 # bit 0: tecla disponible
beqz t1, rse_ret_teclat
# Llegir el caràcter del registre de dades i desar-lo a 'car'
li t0, 0xF0001004 # adreça registre de dades del teclat
lw t1, 0(t0) # llegir el caràcter
la t2, car
sw t1, 0(t2) # desar a la variable global
rse_ret_teclat:
# Restaurar tots els registres generals
lw ra, 0(sp)
lw t0, 4(sp)
lw t1, 8(sp)
lw t2, 12(sp)
lw s0, 16(sp)
lw s1, 20(sp)
lw a0, 24(sp)
lw a1, 28(sp)
lw a2, 32(sp)
lw a3, 36(sp)
lw a4, 40(sp)
lw a5, 44(sp)
lw a6, 48(sp)
lw a7, 52(sp)
lw s2, 56(sp)
lw s3, 60(sp)
lw s4, 64(sp)
lw s5, 68(sp)
lw s6, 72(sp)
lw s7, 76(sp)
lw s8, 80(sp)
lw s9, 84(sp)
lw s10, 88(sp)
lw s11, 92(sp)
lw t3, 96(sp)
lw t4, 100(sp)
lw t5, 104(sp)
lw t6, 108(sp)
lw gp, 112(sp)
lw tp, 116(sp)
addi sp, sp, 120
mretc) El codi de causa (mcause, codi 11) i el bit MEIP de mip indiquen que hi ha una interrupció externa pendent, però no quin dispositiu específic l’ha causada. Per identificar que la interrupció prové del teclat cal llegir directament el registre d’estat del dispositiu (0xF0001000, bit 0): és l’únic lloc on el controlador del teclat indica que té una dada disponible. En sistemes amb múltiples dispositius d’E/S, l’RSE ha d’interrogar cadascun per determinar quin ha generat la petició.
27.4 Fallada de pàgina
Enunciat: Problema 18.11, apartats a–b.
a) Una fallada de pàgina escriu a mcause (RISC-V 9.4):
- En lectura de dada:
mcause = 13(load page fault). - En escriptura:
mcause = 15(store/AMO page fault).
En tots dos casos, mtval conté l’adreça virtual que ha causat la fallada (Secció 9.7.2).
Cal recordar que, a RISC-V, la fallada de pàgina només es produeix quan la pàgina no és a la memòria física (bit V = 0 a la PTE): la fallada de TLB amb la pàgina present la resol el recorregut de la taula de pàgines (page-table walker) sense interrompre el programa (Essencial 9.9).
b) El flux que ha de seguir l’RSE (la rutina completa és a Secció 9.7.3.2):
- Llegir
mtvalper obtenir l’adreça virtual que ha causat la fallada. - Extreure’n el VPN (els bits per sobre del desplaçament de pàgina) i localitzar la PTE corresponent a la taula de pàgines del procés actiu (a partir del registre de taula de pàgines;
satpen mode S). - Si l’adreça no pertany a cap regió vàlida del procés, avortar el programa (segmentation fault).
- Si la pàgina és vàlida però no present (\(V = 0\)): copiar-la del disc a un marc lliure (reemplaçant-ne un si cal, i escrivint-lo prèviament al disc si té \(D = 1\)) i actualitzar la PTE (\(V \leftarrow 1\), \(PPN \leftarrow\) marc assignat, \(D \leftarrow 0\)).
- Executar
sfence.vmaperquè el TLB no conservi cap còpia obsoleta de la PTE i el recorregut de la taula de pàgines la torni a llegir. - No incrementar
mepc: la instrucció causant s’ha de reexecutar; en la reexecució, el recorregut de la taula de pàgines trobarà la PTE vàlida i l’accés es completarà.