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