From 0def435e493fe6350c7a2e5dee26af7179b08634 Mon Sep 17 00:00:00 2001
From: Roberto Hexsel <roberto@inf.ufpr.br>
Date: Sun, 8 May 2016 22:59:08 -0300
Subject: [PATCH] handler for TLBload e TLBstore

---
 cMIPS/include/handlers.s | 48 +++++++++++++++++++++++--------------
 cMIPS/include/start.s    | 25 ++++++++++++-------
 cMIPS/tests/pt_walk.c    | 52 ++++++++++++++++++++++++----------------
 3 files changed, 78 insertions(+), 47 deletions(-)

diff --git a/cMIPS/include/handlers.s b/cMIPS/include/handlers.s
index f5f67a6..3fe1148 100644
--- a/cMIPS/include/handlers.s
+++ b/cMIPS/include/handlers.s
@@ -199,7 +199,12 @@ disableInterr:
 	
 
 	#================================================================
-	# handle TLB Modified exception (store to page with bit dirty=0)
+	# handle TLB Modified exception -- store to page with bit dirty=0
+	#
+	# (a) fix TLB entry, by setting dirty=1 ;
+	# (b) check permissions in PT entry and (maybe) kill the process
+	#     OR mark PT entry as Used and Modified, then
+	#     update TLB entry.
 	#
 	.global _excp_saves
 	.global _excp_0180ret
@@ -233,7 +238,7 @@ M_even: addi $a2, $a0, 4	# address for even entry
 
 M_test:	lw   $a1, 0($a2)	# read PT[badVAddr]
 	mfc0 $k0, c0_badvaddr	# get faulting address
-	andi $a0, $a1, 0x0003	# check if page is mapped
+	andi $a0, $a1, 0x0001	# check if page is mapped
 	beq  $a0, $zero, M_seg_fault	# no, abort simulation
 	nop
 
@@ -242,11 +247,11 @@ M_test:	lw   $a1, 0($a2)	# read PT[badVAddr]
 	nop
 
 	andi $a0, $a1, 0x0002	# check if page is in secondary memory
-	bne  $a0, $zero, M_sec_mem
+	bne  $a0, $zero, M_sec_mem	# yes, abort simulation
 	nop
 
 	mfc0 $a0, c0_epc	# check if fault is on an instruction
-	beq  $a0, $k0, M_prot_viol	# k0 is badVAddr
+	beq  $a0, $k0, M_prot_viol	# k0 is badVAddr, if so, abort
 	nop
 
 	ori  $a1, $a1, 0x0030	# mark PT entry as modified, used
@@ -277,7 +282,7 @@ M_prot_viol:	# print message and abort simulation
 	nop
 	nop
 	nop
-	wait 0x41
+	wait 0x42
 
 M_sec_mem:	# print message and abort simulation
 	la   $k1, x_IO_BASE_ADDR
@@ -287,7 +292,7 @@ M_sec_mem:	# print message and abort simulation
 	nop
 	nop
 	nop
-	wait 0x41
+	wait 0x43
 	
 	.end handle_Mod
 	#----------------------------------------------------------------
@@ -296,7 +301,10 @@ M_sec_mem:	# print message and abort simulation
 	#================================================================
 	# handle TLB Load exception: double-fault caused by a TLB miss
 	#   to the Page Table -- mapping pointing to PT is not on TLB
-	#   so, fix the TLB by storing mapping onto TLB[4]
+	#
+	# (a) fix the fault by (re)loading the mapping into TLB[4];
+	# (b) check permissions in PT entry and (maybe) kill the process.
+	#
 	.global _excp_saves
 	.global _excp_0180ret
 	.global handle_TLBL
@@ -305,7 +313,7 @@ M_sec_mem:	# print message and abort simulation
 
 	.ent handle_TLBL
 handle_TLBL:			# EntryHi points to offending TLB entry
-	tlbp			# what is the offender's index?
+	tlbp			# probe it to find the offender's index
 	lui  $k1, %hi(_excp_saves)
         ori  $k1, $k1, %lo(_excp_saves)
 	sw   $a0,  9*4($k1)
@@ -315,8 +323,8 @@ handle_TLBL:			# EntryHi points to offending TLB entry
 	mfc0 $a0, c0_badvaddr
 	la   $a1, (_PT + (x_INST_BASE_ADDR >>13)*16)
 
-	slt  $a2, $a0, $a1	# a2 <- badVAddr <= PageTable
-	bne  $a2, $zero, L_chks
+	slt  $a2, $a0, $a1	# a2 <- (badVAddr <= PageTable)
+	bne  $a2, $zero, L_chks	#   fault is not to PageTable
 	nop
 
 	# this is same code as in start.s
@@ -344,24 +352,27 @@ L_chks: andi $a0, $a0, 0x1000	# check if even or odd page
 	mfc0 $a0, c0_context
 
 L_odd:	j    L_test
-	addi $a2, $a0, 12	# address for odd entry
+	addi $a2, $a0, 12	# address for odd intLo1 entry
 	
-L_even: addi $a2, $a0, 4	# address for even entry
+L_even: addi $a2, $a0, 4	# address for even intLo0 entry
 
-L_test:	lw   $a1, 0($a2)
-	mfc0 $k0, c0_badvaddr	# get faulting address
-	andi $a0, $a1, 0x0003	# check if page is mapped
-	beq  $a0, $zero, M_seg_fault
+L_test:	lw   $a1, 0($a2)	# get intLo{0,1}
+	mfc0 $k0, c0_badvaddr	# get faulting address for printing
+	andi $a0, $a1, 0x0001	# check if page is mapped
+	beq  $a0, $zero, M_seg_fault	# no, abort simulation
 	nop
 
 	andi $a0, $a1, 0x0002	# check if page is in secondary memory
-	bne  $a0, $zero, M_sec_mem
+	bne  $a0, $zero, M_sec_mem	# yes, abort simulation
 	nop
 
 	ori  $a1, $a1, 0x0010	# mark PT entry as used
 	sw   $a1, 0($a2)
 
-L_ret:	lw   $a0,  9*4($k1)	# nothing else to do, return??
+	# if this were handler_TLBS, now is the time to also mark the
+	#    PT entry as Modified
+
+L_ret:	lw   $a0,  9*4($k1)	# nothing else to do, return
 	lw   $a1, 10*4($k1)
 	j    _excp_0180ret
 	lw   $a2, 11*4($k1)
@@ -407,6 +418,7 @@ TLB_purge:
 	move $v0, $zero		# V_addr was purged from TLB
 
 	tlbwi			# write invalid mappings to TLB
+	ehb
 	
 pu_miss: jr  $ra
 	nop
diff --git a/cMIPS/include/start.s b/cMIPS/include/start.s
index 1d96eb4..f9ba23a 100644
--- a/cMIPS/include/start.s
+++ b/cMIPS/include/start.s
@@ -100,14 +100,23 @@ _start:
 	mtc0  $a1, c0_entrylo0		# bottom page (even)
 
 	la    $a0, ( (MIDDLE_RAM + 1*4096) >>12 )<<6
-	ori   $a1, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1
-	mtc0  $a1, c0_entrylo1		# bottom page + 1 (odd)
+	ori   $a2, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1
+	mtc0  $a2, c0_entrylo1		# bottom page + 1 (odd)
 
 	# and write it to TLB[4]
 	li    $k0, 4
 	mtc0  $k0, c0_index
 	tlbwi 
 
+	# create a PT entry for the Page Table itself
+	#   in these simulations, only the first page is used
+	la    $a0, MIDDLE_RAM
+	srl   $a0, $a0, 9        # (_PT>>13)*16
+        la    $v0, PTbase
+        add   $a0, $v0, $a0
+	sw    $a1, 0($a0)        # write to PT[ _PTV ].entryLo0
+        sw    $a2, 8($a0)        # write to PT[ _PTV ].entryLo1
+
 	
 	# pin down first five TLB entries: ROM[0], I/O, RAM[0], stack, PgTbl
 	li   $k0, 5
@@ -233,8 +242,8 @@ excp_tbl: # see Table 8-25, pg 95,96
 	j handle_TLBL # 2
 	nop
 
-	j h_TLBS # 3
-	nop
+	j handle_TLBL # 3 == TLBS if miss on PT, on the TLB, on a store
+	nop		# should mark page as Modified on PT
 
 	wait 0x04  # 4 AdEL addr error     -- abort simulation
 	nop
@@ -449,15 +458,15 @@ PTbase:	.word  ( (x_INST_BASE_ADDR +  0*4096) >>6) | 0b000011
 	.word 0x00000006
 	
 	# PT[2] -- not mapped for simulation
-	.word  ( (x_INST_BASE_ADDR +  4*4096) >>6) | 0b000011  
+	.word  ( (x_INST_BASE_ADDR +  4*4096) >>6) | 0b000001  
 	.word 0x00000004
-	.word  ( (x_INST_BASE_ADDR +  5*4096) >>6) | 0b000011  
+	.word  ( (x_INST_BASE_ADDR +  5*4096) >>6) | 0b000001  
 	.word 0x00000004
 
 	# PT[3] -- not mapped for simulation
-	.word  ( (x_INST_BASE_ADDR +  6*4096) >>6) | 0b000011  
+	.word  ( (x_INST_BASE_ADDR +  6*4096) >>6) | 0b000001  
 	.word 0x00000004
-	.word  ( (x_INST_BASE_ADDR +  7*4096) >>6) | 0b000011  
+	.word  ( (x_INST_BASE_ADDR +  7*4096) >>6) | 0b000001  
 	.word 0x00000004
 	
 	# PT[4] -- not mapped for simulation
diff --git a/cMIPS/tests/pt_walk.c b/cMIPS/tests/pt_walk.c
index 69e5830..788516c 100644
--- a/cMIPS/tests/pt_walk.c
+++ b/cMIPS/tests/pt_walk.c
@@ -17,9 +17,9 @@
 
 //-----------------------------------------------------------------------
 // decide on the tests to run
-#define WALK_THE_PT  0
+#define WALK_THE_PT  1
 #define TLB_MODIFIED 1
-#define DOUBLE_FAULT 0
+#define DOUBLE_FAULT 1
 
 // these will abort the simulation when the fault is detected/handled
 #define PROT_VIOL 0
@@ -56,7 +56,7 @@ void main(void) {
   //-----------------------------------------------------------------
   walker = (int *)(x_DATA_BASE_ADDR + 1024);
 
-  for( i = 0 ; i < NUM_RAM_PAGES; i++){
+  for (i = 0 ; i < NUM_RAM_PAGES; i++) {
     *walker = i;
     walker = (int *)((int)walker + 4096);
   }
@@ -64,7 +64,7 @@ void main(void) {
   // and now read what was written
   walker = (int *)(x_DATA_BASE_ADDR + 1024);
 
-  for( i = 0 ; i < NUM_RAM_PAGES; i++){
+  for (i = 0 ; i < NUM_RAM_PAGES; i++) {
     print( *walker );
     walker = (int *)((int)walker + 4096);
   }
@@ -83,8 +83,8 @@ void main(void) {
   // let's change a mapping to cause a TLB-Modified exception
   //
   // in fact, there will be TWO exceptions: 
-  // (1) a TLB-Refill will copu the write-protected mapping from the PT
-  //     and retry the instruction;
+  // (1) a TLB-Refill will copy the mapping from the PT and retry the
+  //     instruction;
   // (2) when the sw is retried, it will cause a TLB-Modified
   //     exception, which checks PT's protection bits, then fixes the
   //     dirty bit in the TLB, and retries again, succeeding this time.
@@ -110,9 +110,9 @@ void main(void) {
 
   if ( *walker == 0x99 ) {     // this load is optimized away by gcc
     print( *walker );
-    print_str("\tMod ok\n");
+    print_str("\tMod ok\n\n");
   } else {
-    print_str("\tMod err\n");
+    print_str("\tMod err\n\n");
  }
 #endif
 
@@ -121,30 +121,41 @@ void main(void) {
 
 #if DOUBLE_FAULT
   //--------------------------------------------------------------------
-  // let's remove a PT's mapping from the TLB and cause a double-fault:
+  // let's remove from the TLB the mapping for the PT itself and cause
+  // a double-fault:
   //
   // (1) on the 1st reference, TLB-refill does not find a mapping for
   //     the PT on the TLB; this causes a TLBL (load) exception;
   // (2) routine handle_TLBL writes a new mapping on the PT, refills
-  //     the TLB, then retries the reference, which succeeds this time.
+  //     the TLB, then retries the reference;
+  // (3) the page referenced is not on the TLB, so there is another
+  //     TLB-refill, which loads the mapping, the store is retried
+  //     and succeeds.
   //--------------------------------------------------------------------
 
+  // remove the TLB entry for datum to be referenced
+  walker = (int *)(x_DATA_BASE_ADDR + PG_NUM*4096 + 1024);
+  if ( TLB_purge((void *)walker) == 0 ) {
+    print_str("\taddr purged from TLB\n");
+  } else {
+    print_str("\tTLB miss\n");
+  }
+
   // this is the base of the page table
   walker = (int *)(x_DATA_BASE_ADDR + (x_DATA_MEM_SZ/2));
 
   // remove the TLB entry which points to the PT
   if ( TLB_purge((void *)walker) == 0 ) {
-    print_str("\n\tPT purged from TLB\n");
+    print_str("\tPT purged from TLB\n");
   } else {
-    print_str("\n\twtf?\n");
+    print_str("\twtf?\n");
   }
 
   // now reference a mapped page, to cause the double fault
   walker = (int *)(x_DATA_BASE_ADDR + PG_NUM*4096 + 1024);
+  *walker = 0x88;              // cause a TLBrefill then a TLBload
 
-  *walker = 0x77;              // cause a TLBrefill then a TLBload
-
-  if ( *walker == 0x77 ) {     // this load is optimized away by gcc
+  if ( *walker == 0x88 ) {     // this load is optimized away by gcc
     print( *walker );
     print_str("\tdouble ok\n");
   } else {
@@ -176,10 +187,10 @@ void main(void) {
   new_value = 0x00000001;                          // NOT-writable, mapped
   PT_update( (int *)walker, 1, new_value);
 
-  *walker = 0x88;
+  *walker = 0x77;
 
   // will never get here -- protection violation on the store
-  if ( *walker == 0x88 ) {    // this load is optimized away by gcc
+  if ( *walker == 0x77 ) {    // this load is optimized away by gcc
     print( *walker );
     print_str("\tprot viol not ok\n");
   } else {
@@ -219,10 +230,10 @@ void main(void) {
   PT_update( (int *)walker, 2, new_value);
   PT_update( (int *)walker, 3, 0);              // mark as unmapped
 
-  *walker = 0x44;
+  *walker = 0x66;
 
   // will never get here -- seg fault on the store
-  if ( *walker == 0x44 ) {    // this load is optimized away by gcc
+  if ( *walker == 0x66 ) {    // this load is optimized away by gcc
     print( *walker );
     print_str("\tseg fault not ok\n");
   } else {
@@ -231,10 +242,9 @@ void main(void) {
 #endif
 
 
-
-
   to_stdout('\n');
 }
+//----------------------------------------------------------------------
 
 
 void print_str(char *s) {
-- 
GitLab