diff --git a/cMIPS/include/handlers.s b/cMIPS/include/handlers.s index ebb702a1cd4f10fb413507147a97da07a11324ad..f5f67a6b33f98b80c7341da4e4db0cbe8a89e194 100644 --- a/cMIPS/include/handlers.s +++ b/cMIPS/include/handlers.s @@ -1,18 +1,18 @@ # interrupt handlers .include "cMIPS.s" .text - .set noreorder + .set noreorder # do not reorder instructions + .set noat # do not use register $1 as $at .align 2 .set M_StatusIEn,0x0000ff11 # STATUS.intEn=1, user mode - - #---------------------------------------------------------------- + + #================================================================ # interrupt handler for external counter attached to IP5=HW3 # for extCounter address see vhdl/packageMemory.vhd .bss .align 2 - .set noreorder .global _counter_val # accumulate number of interrupts .comm _counter_val 4 .comm _counter_saves 8*4 # area to save up to 8 registers @@ -67,12 +67,11 @@ extCounter: #---------------------------------------------------------------- - #---------------------------------------------------------------- + #================================================================ # interrupt handler for UART attached to IP6=HW4 .bss .align 2 - .set noreorder .global Ud Ud: .comm rx_queue 16 # reception queue and pointers .comm rx_hd 4 @@ -138,15 +137,16 @@ UARTret: #---------------------------------------------------------------- - #---------------------------------------------------------------- + #================================================================ # handler for COUNT-COMPARE registers -- IP7=HW5 .text .set noreorder + .equ num_cycles, 64 .global countCompare .ent countCompare countCompare: mfc0 $k1,c0_count # read COMPARE and clear IRQ - addiu $k1,$k1,64 # set next interrupt in 64 ticks + addiu $k1,$k1,num_cycles # set next interrupt in so many ticks mtc0 $k1,c0_compare mfc0 $k0, c0_status # Read STATUS register @@ -160,7 +160,7 @@ countCompare: #---------------------------------------------------------------- - #---------------------------------------------------------------- + #================================================================ # functions to enable and disable interrupts, both return STATUS .text .set noreorder @@ -188,7 +188,234 @@ disableInterr: #---------------------------------------------------------------- - #---------------------------------------------------------------- + #================================================================ + ## TLB handlers + ## page table entry is { EntryLo0 int0 EntryLo1 int1 } + ## int{0,1} is + ## { fill_31..6, Modified_5, Used_4, Writable_3, eXecutable_2, + ## Status_10 }, + ## Status is 00=unmapped, 01=mapped, 10=secondary_storage + #================================================================ + + + #================================================================ + # handle TLB Modified exception (store to page with bit dirty=0) + # + .global _excp_saves + .global _excp_0180ret + .global handle_Mod + .set noreorder + + .ent handle_Mod +handle_Mod: # EntryHi points to offending TLB entry + tlbp # what is the offender's index? + lui $k1, %hi(_excp_saves) + ori $k1, $k1, %lo(_excp_saves) + sw $a0, 9*4($k1) # save registers + sw $a1, 10*4($k1) + sw $a2, 11*4($k1) + + mfc0 $a0, c0_badvaddr + andi $a0, $a0, 0x1000 # check if even or odd page + beq $a0, $zero, M_even + mfc0 $a0, c0_context + +M_odd: addi $a2, $a0, 12 # address for odd entry + mfc0 $k0, c0_entrylo1 + ori $k0, $k0, 0x0004 # mark TLB entry as dirty/writable + j M_test + mtc0 $k0, c0_entrylo1 + +M_even: addi $a2, $a0, 4 # address for even entry + mfc0 $k0, c0_entrylo0 + ori $k0, $k0, 0x0004 # mark TLB entry as dirty/writable + mtc0 $k0, c0_entrylo0 + +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 + beq $a0, $zero, M_seg_fault # no, abort simulation + nop + + andi $a0, $a1, 0x0008 # check if page is writable + beq $a0, $zero, M_prot_viol # no, abort simulation + nop + + andi $a0, $a1, 0x0002 # check if page is in secondary memory + bne $a0, $zero, M_sec_mem + nop + + mfc0 $a0, c0_epc # check if fault is on an instruction + beq $a0, $k0, M_prot_viol # k0 is badVAddr + nop + + ori $a1, $a1, 0x0030 # mark PT entry as modified, used + sw $a1, 0($a2) + + tlbwi # write entry with dirty bit=1 back to TLB + + lw $a0, 9*4($k1) # restore saved registers and return + lw $a1, 10*4($k1) + j _excp_0180ret + lw $a2, 11*4($k1) + +M_seg_fault: # print message and abort simulation + la $k1, x_IO_BASE_ADDR + sw $k0, 0($k1) + jal cmips_kmsg + la $k1, 3 # segmentation fault + nop + nop + nop + wait 0x41 + +M_prot_viol: # print message and abort simulation + la $k1, x_IO_BASE_ADDR + sw $k0, 0($k1) + jal cmips_kmsg + la $k1, 2 # protection violation + nop + nop + nop + wait 0x41 + +M_sec_mem: # print message and abort simulation + la $k1, x_IO_BASE_ADDR + sw $k0, 0($k1) + jal cmips_kmsg + la $k1, 4 # secondary memory + nop + nop + nop + wait 0x41 + + .end handle_Mod + #---------------------------------------------------------------- + + + #================================================================ + # 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] + .global _excp_saves + .global _excp_0180ret + .global handle_TLBL + .global _PT + .set MIDDLE_RAM, (x_DATA_BASE_ADDR + (x_DATA_MEM_SZ/2)) + + .ent handle_TLBL +handle_TLBL: # EntryHi points to offending TLB entry + tlbp # what is the offender's index? + lui $k1, %hi(_excp_saves) + ori $k1, $k1, %lo(_excp_saves) + sw $a0, 9*4($k1) + sw $a1, 10*4($k1) + sw $a2, 11*4($k1) + + 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 + nop + + # this is same code as in start.s + # get physical page number for two pages at the bottom of PageTable + la $a0, ( MIDDLE_RAM >>13 )<<13 + mtc0 $a0, c0_entryhi # tag for bottom double-page + + la $a0, ( (MIDDLE_RAM + 0*4096) >>12 )<<6 + ori $a1, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1 + 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) + + # and write it to TLB[4] + li $k0, 4 + mtc0 $k0, c0_index + tlbwi + j L_ret # all work done, return + nop + +L_chks: andi $a0, $a0, 0x1000 # check if even or odd page + beq $a0, $zero, L_even + mfc0 $a0, c0_context + +L_odd: j L_test + addi $a2, $a0, 12 # address for odd entry + +L_even: addi $a2, $a0, 4 # address for even 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 + nop + + andi $a0, $a1, 0x0002 # check if page is in secondary memory + bne $a0, $zero, M_sec_mem + 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?? + lw $a1, 10*4($k1) + j _excp_0180ret + lw $a2, 11*4($k1) + + .end handle_TLBL + #---------------------------------------------------------------- + + + #================================================================ + # purge an entry from the TLB + # int TLB_purge(void *V_addr) + # returns 0 if V_addr purged, 1 if V_addr not in TLB (probe failure) + # + .text + .global TLB_purge + + .set noreorder + .ent TLB_purge +TLB_purge: + srl $a0, $a0, 13 # clear out in-page address bits + sll $a0, $a0, 13 # + mtc0 $a0, c0_entryhi + nop + tlbp # probe the TLB + nop + mfc0 $a0, c0_index # check for hit + srl $a0, $a0, 31 # keeo only MSbit + bne $a0, $zero, pu_miss # address not in TLB + move $v0, $a0 # V_addr not in TLB + + tlbr # read the entry + li $a0, -8192 # -8192 = 0xffff.e000 + mtc0 $a0, c0_entryhi # and write an un-mapped address to tag + + addi $v0, $zero, -3 # -3 = 0xffff.fffd to clear valid bit + mfc0 $a0, c0_entrylo0 # invalidate the mappings + and $a0, $v0, $a0 + mtc0 $a0, c0_entrylo0 + + mfc0 $a0, c0_entrylo1 + and $a0, $v0, $a0 + mtc0 $a0, c0_entrylo1 + move $v0, $zero # V_addr was purged from TLB + + tlbwi # write invalid mappings to TLB + +pu_miss: jr $ra + nop + .end TLB_purge + ##--------------------------------------------------------------- + + + + #================================================================ # delays processing by approx 4*$a0 processor cycles .text .set noreorder @@ -205,7 +432,7 @@ cmips_delay: #---------------------------------------------------------------- - #---------------------------------------------------------------- + #================================================================ # print a message from within "the kernel" # void cmips_kmsg( $k1 ) # this function preserves registers other than k0,k1 @@ -219,10 +446,10 @@ cmips_delay: .align 2 .set noreorder .set noat - .global cmips_kmsg - .ent cmips_kmsg .equ stdout,(x_IO_BASE_ADDR + 1*x_IO_ADDR_RANGE); + .global cmips_kmsg + .ent cmips_kmsg cmips_kmsg: lui $k0, %hi(_kmsg_saves) ori $k0, $k0, %lo(_kmsg_saves) @@ -257,13 +484,18 @@ k_for: lbu $a0, 0($a1) .data .align 2 -_kmsg_interr: .asciiz "\n\tinterrupt\n\n" -_kmsg_excep: .asciiz "\n\texception\n\n" +_kmsg_interr: .asciiz "\n\t00 - interrupt\n\n" +_kmsg_excep: .asciiz "\n\t01 - exception\n\n" +_kmsg_prot_viol: .asciiz "\n\t02 - protection violation\n\n" +_kmsg_seg_fault: .asciiz "\n\t03 - segmentation fault\n\n" +_kmsg_sec_mem: .asciiz "\n\t04 - in secondary memory\n\n" .global _kmsg_list .data - .align 2 -_kmsg_list: .word _kmsg_interr,_kmsg_excep + .align 2 +_kmsg_list: + .word _kmsg_interr,_kmsg_excep, _kmsg_prot_viol, _kmsg_seg_fault + .word _kmsg_sec_mem #---------------------------------------------------------------- diff --git a/cMIPS/include/start.s b/cMIPS/include/start.s index 9652e4e38efce0ce15d93c5068ff19bb0cf4117c..1d96eb4fa880ad140d71275ba5dd076f98d1d7fd 100644 --- a/cMIPS/include/start.s +++ b/cMIPS/include/start.s @@ -155,12 +155,13 @@ _excp_0000: .set noat mfc0 $k1, c0_context - lw $k0, 0($k1) # k0 <- TP[context.lo] - lw $k1, 8($k1) # k1 <- TP[context.hi] - mtc0 $k0, c0_entrylo0 # EntryLo0 <- k0 = even element - mtc0 $k1, c0_entrylo1 # EntryLo1 <- k1 = odd element + lw $k0, 0($k1) # k0 <- TP[context.lo] + lw $k1, 8($k1) # k1 <- TP[context.hi] + mtc0 $k0, c0_entrylo0 # EntryLo0 <- k0 = even element + mtc0 $k1, c0_entrylo1 # EntryLo1 <- k1 = odd element ehb - tlbwr # update TLB + tlbwr # update TLB + mfc0 $zero, c0_cause # clear excCode in Cause eret .end _excp_0000 @@ -201,6 +202,9 @@ _excp_0100: .text .set noreorder .set noat + .global _excp_saves, _excp_0180ret + .global handle_Mod, handle_TLBL, handle_TLBS + .org x_EXCEPTION_0180,0 # exception vector_180 .ent _excp_0180 _excp_0180: @@ -223,10 +227,10 @@ excp_tbl: # see Table 8-25, pg 95,96 wait 0x02 # interrupt, should never get here, abort simulation nop - j h_Mod # 1 + j handle_Mod # 1 nop - j h_TLBL # 2 + j handle_TLBL # 2 nop j h_TLBS # 3 @@ -266,8 +270,6 @@ excp_tbl: # see Table 8-25, pg 95,96 nop -h_Mod: -h_TLBL: h_TLBS: h_syscall: h_breakpoint: @@ -275,7 +277,7 @@ h_RI: h_CpU: h_Ov: -excp_0180ret: +_excp_0180ret: lui $k1, %hi(_excp_saves) # Read previous contents of STATUS ori $k1, $k1, %lo(_excp_saves) lw $k0, 1*4($k1) @@ -390,75 +392,103 @@ _excp_BFC0: ##--------------------------------------------------------------- - ## + #================================================================ + # modify the page table: + # void PT_update(void *V_addr, int component, int new_value) + # component is in {0=entrylo0, 1-int0, 2=entrylo1, 3=int1} + .text + .global PT_update + + .set noreorder + .ent PT_update +PT_update: + srl $a0, $a0, 9 # (_PT + (V_addr >>13)*16) + la $v0, PTbase + add $a0, $v0, $a0 + andi $a1, $a1, 0x0003 # make sure component is in range + sll $a1, $a1, 2 # component * 4 + add $a0, $a0, $a1 # (_PT + (V_addr >>13)*16).component + jr $ra + sw $a2, 0($a0) # write to PT[V_addr].component + .end PT_update + ##--------------------------------------------------------------- + + + + + ##=============================================================== ## Page Table ## ## See EntryLo, pg 63 ## + ## intLo0 and intLo1 are: + ## nil_31..6 Modified_5 Used_4 Writable_3 eXecutable_2 Status_1,0 + ## Status: 00=unmapped, 01=mapped, 10=in_secondary_storage, 11=undef + ## .section .PT,"aw",@progbits - + .global _PT + ## ( ( (x_INST_BASE_ADDR + n*4096) >>12 )<<6 ) || 0b000011 d,v,g - _PT: ## - ## ROM mappings + ## ROM mappings, intLo{01} = U=M=W=0, X=1, S=10 (or 00) = 6 (or 4) ## .org (_PT + (x_INST_BASE_ADDR >>13)*16) # PT[0], ROM - .word ( (x_INST_BASE_ADDR + 0*4096) >>6) | 0b000011 - .word 0 +PTbase: .word ( (x_INST_BASE_ADDR + 0*4096) >>6) | 0b000011 + .word 0x00000006 .word ( (x_INST_BASE_ADDR + 1*4096) >>6) | 0b000011 - .word 0 + .word 0x00000006 # PT[1] .word ( (x_INST_BASE_ADDR + 2*4096) >>6) | 0b000011 - .word 0 + .word 0x00000006 .word ( (x_INST_BASE_ADDR + 3*4096) >>6) | 0b000011 - .word 0 + .word 0x00000006 - # PT[2] + # PT[2] -- not mapped for simulation .word ( (x_INST_BASE_ADDR + 4*4096) >>6) | 0b000011 - .word 0 + .word 0x00000004 .word ( (x_INST_BASE_ADDR + 5*4096) >>6) | 0b000011 - .word 0 + .word 0x00000004 - # PT[3] + # PT[3] -- not mapped for simulation .word ( (x_INST_BASE_ADDR + 6*4096) >>6) | 0b000011 - .word 0 + .word 0x00000004 .word ( (x_INST_BASE_ADDR + 7*4096) >>6) | 0b000011 - .word 0 + .word 0x00000004 # PT[4] -- not mapped for simulation .word ( (x_INST_BASE_ADDR + 8*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 .word ( (x_INST_BASE_ADDR + 9*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 # PT[5] -- not mapped for simulation .word ( (x_INST_BASE_ADDR + 10*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 .word ( (x_INST_BASE_ADDR + 11*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 # PT[6] -- not mapped for simulation .word ( (x_INST_BASE_ADDR + 12*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 .word ( (x_INST_BASE_ADDR + 13*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 # PT[7] -- not mapped for simulation .word ( (x_INST_BASE_ADDR + 14*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 .word ( (x_INST_BASE_ADDR + 15*4096) >>6) | 0b000001 - .word 0 + .word 0x00000004 - ## all remaining ROM entries are invalid + ## all remaining ROM entries are invalid and unmapped ## - ## RAM mappings + ## RAM mappings, intLo{01} = U=M=0, W=1, X=0, S=10 (or 00) = a (or 8) ## .org (_PT + (x_DATA_BASE_ADDR >>13)*16) @@ -466,54 +496,54 @@ _PT: # PT[ram+0], RAM .word ( (x_DATA_BASE_ADDR + 0*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 1*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+1] .word ( (x_DATA_BASE_ADDR + 2*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 3*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+2] .word ( (x_DATA_BASE_ADDR + 4*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 5*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+3] .word ( (x_DATA_BASE_ADDR + 6*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 7*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+4] .word ( (x_DATA_BASE_ADDR + 8*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 9*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+5] .word ( (x_DATA_BASE_ADDR + 10*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 11*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+6] .word ( (x_DATA_BASE_ADDR + 12*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 13*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a # PT[ram+7] .word ( (x_DATA_BASE_ADDR + 14*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a .word ( (x_DATA_BASE_ADDR + 15*4096) >>6) | 0b000111 - .word 0 + .word 0x0000000a - ## all remaining RAM entries are invalid + ## all remaining RAM entries are invalid and unmapped _endPT: diff --git a/cMIPS/tests/pt_walk.c b/cMIPS/tests/pt_walk.c index 3a24e13fc811888f127dbfa515703dba0c222fe6..69e583052220e3e27371b67bad53ce67208aaa0f 100644 --- a/cMIPS/tests/pt_walk.c +++ b/cMIPS/tests/pt_walk.c @@ -15,8 +15,24 @@ // With this much memory, simulations run slowly. No free lunch. +//----------------------------------------------------------------------- +// decide on the tests to run +#define WALK_THE_PT 0 +#define TLB_MODIFIED 1 +#define DOUBLE_FAULT 0 + +// these will abort the simulation when the fault is detected/handled +#define PROT_VIOL 0 +#define SEG_FAULT 0 +//----------------------------------------------------------------------- + + #include "cMIPS.h" +extern void PT_update(void *V_addr, int component, int new_value); +extern int TLB_purge(void *V_addr); +static void print_str(char *); + #define FALSE (0==1) #define TRUE !FALSE @@ -25,11 +41,19 @@ #define NUM_RAM_PAGES ( (x_DATA_MEM_SZ / 2) / 4096 ) + + void main(void) { - int i; + int i, rsp, new_value; int *walker; - // write to the middle of all pages + +#if WALK_THE_PT + //----------------------------------------------------------------- + // write to the middle of all datapages + // this will cause some TLB refill exceptions, which should be + // handled smoothly by the handler at excp_0000 (include/start/s) + //----------------------------------------------------------------- walker = (int *)(x_DATA_BASE_ADDR + 1024); for( i = 0 ; i < NUM_RAM_PAGES; i++){ @@ -44,11 +68,180 @@ void main(void) { print( *walker ); walker = (int *)((int)walker + 4096); } - - to_stdout('\n'); - to_stdout('o'); - to_stdout('k'); - to_stdout('\n'); + print_str("\twalked\n"); +#endif + + + +#define PG_NUM 10 + + + +#if TLB_MODIFIED + //------------------------------------------------------------------- + // 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; + // (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. + //------------------------------------------------------------------- + // ( ( (x_DATA_BASE_ADDR + n*4096) >>12 )<<6 ) || 0b000111 d,v,g + + walker = (int *)(x_DATA_BASE_ADDR + PG_NUM*4096); + + // first, remove V_addr from the TLB, to ensure the PT is searched + if ( TLB_purge((void *)walker) == 0 ) { + print_str("\n\tTLB entry purged\n"); + } else { + print_str("\n\tTLB miss\n"); + } + + new_value = ( ((x_DATA_BASE_ADDR + PG_NUM*4096)>>12) <<6) | 0b000011; // d=0 + PT_update( (int *)walker, 0, new_value); + + new_value = 0x00000009; // writable, mapped + PT_update( (int *)walker, 1, new_value); + + *walker = 0x99; // cause a TLBrefill, then a TLBmod + + if ( *walker == 0x99 ) { // this load is optimized away by gcc + print( *walker ); + print_str("\tMod ok\n"); + } else { + print_str("\tMod err\n"); + } +#endif + + + + +#if DOUBLE_FAULT + //-------------------------------------------------------------------- + // let's remove a PT's mapping from the TLB 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. + //-------------------------------------------------------------------- + + // 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"); + } else { + print_str("\n\twtf?\n"); + } + + // now reference a mapped page, to cause the double fault + walker = (int *)(x_DATA_BASE_ADDR + PG_NUM*4096 + 1024); + + *walker = 0x77; // cause a TLBrefill then a TLBload + + if ( *walker == 0x77 ) { // this load is optimized away by gcc + print( *walker ); + print_str("\tdouble ok\n"); + } else { + print_str("\tdouble err\n"); + } +#endif + + + + +#if PROT_VIOL + //---------------------------------------------------------------------- + // let's cause a protection violation -- write to a write-protected page + // this will abort the simulation + //---------------------------------------------------------------------- + + walker = (int *)(x_DATA_BASE_ADDR + PG_NUM*4096); + + // first, remove V_addr from the TLB, to ensure the PT is searched + if ( TLB_purge((void *)walker) == 0 ) { + print_str("\n\tpurged\n"); + } else { + print_str("\t\tTLB miss\n"); + } + + // change a PT element so it is data, NON-writable, page is mapped in PT + new_value = ( ((x_DATA_BASE_ADDR + PG_NUM*4096)>>12) <<6) | 0b000011; // d=0 + PT_update( (int *)walker, 0, new_value); + new_value = 0x00000001; // NOT-writable, mapped + PT_update( (int *)walker, 1, new_value); + + *walker = 0x88; + + // will never get here -- protection violation on the store + if ( *walker == 0x88 ) { // this load is optimized away by gcc + print( *walker ); + print_str("\tprot viol not ok\n"); + } else { + print_str("\tprot viol err\n"); + } +#endif + + + + +#if SEG_FAULT + //----------------------------------------------------------------- + // let's cause a segmentation fault -- reference to page not mapped + // this will abort the simulation + //----------------------------------------------------------------- + +#define PG_UNMAPPED 20 + + // pick a page that is not mapped + walker = (int *)(x_DATA_BASE_ADDR + PG_UNMAPPED*4096); // page not mapped + + // first, remove V_addr from the TLB, to ensure the PT will be searched + if ( TLB_purge((void *)walker) == 0 ) { + print_str("\n\tpurged\n"); + } else { + print_str("\n\tTLB miss\n"); + } + + // add a new PT element for an address range with RAM but UN-mapped + // this address is above the page table + new_value = + (((x_DATA_BASE_ADDR + PG_UNMAPPED*4096)>>12) <<6) | 0b000011; // d=0 + PT_update( (int *)walker, 0, new_value); + PT_update( (int *)walker, 1, 0); // mark as unmapped + new_value = + (((x_DATA_BASE_ADDR + (PG_UNMAPPED+1)*4096)>>12) <<6) | 0b000011; // d=0 + PT_update( (int *)walker, 2, new_value); + PT_update( (int *)walker, 3, 0); // mark as unmapped + + *walker = 0x44; + + // will never get here -- seg fault on the store + if ( *walker == 0x44 ) { // this load is optimized away by gcc + print( *walker ); + print_str("\tseg fault not ok\n"); + } else { + print_str("\tseg fault err\n"); + } +#endif + + + + + to_stdout('\n'); } + +void print_str(char *s) { + int i; + i = 0; + while (s[i] != '\0') { + to_stdout(s[i]); + i = i + 1; + } +}