From a1d83ba91a17e2812e8f3d99e01df9ca05deb414 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 31 Jan 2026 16:08:22 +1100 Subject: [PATCH] tests/mmu: Add a test for a faulting load near the end of a page This tests for the bug where a load near the end of a page, if the load faults and the following page isn't mapped, could cause a DSI followed incorrectly by an ISI shortly afterwards. Signed-off-by: Paul Mackerras --- tests/mmu/head.S | 76 +++++++++++++++++++++---------- tests/mmu/mmu.c | 91 ++++++++++++++++++++++--------------- tests/test_mmu.bin | Bin 24608 -> 24608 bytes tests/test_mmu.console_out | 1 + 4 files changed, 109 insertions(+), 59 deletions(-) diff --git a/tests/mmu/head.S b/tests/mmu/head.S index 824ad67..c2b5731 100644 --- a/tests/mmu/head.S +++ b/tests/mmu/head.S @@ -23,6 +23,7 @@ ori r,r, (e)@l; .section ".head","ax" + .machine "power10" /* * Microwatt currently enters in LE mode at 0x0, so we don't need to @@ -45,82 +46,97 @@ _start: 2: LOAD_IMM64(%r1,__stack_top) li %r0,0 stdu %r0,-16(%r1) + pla %r9,3f-. + mtsprg1 %r9 LOAD_IMM64(%r12, main) mtctr %r12 bctrl - attn // terminate on exit +3: attn // terminate on exit b . /* Read a location with translation on */ .globl test_read test_read: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mfmsr %r9 ori %r8,%r9,0x10 /* set MSR_DR */ mtmsrd %r8,0 mr %r6,%r3 li %r3,0 ld %r5,0(%r6) - li %r3,1 - /* land here if DSI occurred */ mtmsrd %r9,0 +1: /* land here if DSI occurred */ std %r5,0(%r4) + mtsprg1 %r10 blr /* Write a location with translation on */ .globl test_write test_write: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mfmsr %r9 ori %r8,%r9,0x10 /* set MSR_DR */ mtmsrd %r8,0 mr %r6,%r3 li %r3,0 std %r4,0(%r6) - li %r3,1 - /* land here if DSI occurred */ mtmsrd %r9,0 +1: /* land here if DSI occurred */ + mtsprg1 %r10 blr /* Do a dcbz with translation on */ .globl test_dcbz test_dcbz: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mfmsr %r9 ori %r8,%r9,0x10 /* set MSR_DR */ mtmsrd %r8,0 mr %r6,%r3 li %r3,0 dcbz 0,%r6 - li %r3,1 - /* land here if DSI occurred */ mtmsrd %r9,0 +1: /* land here if DSI occurred */ + mtsprg1 %r10 blr .globl test_exec test_exec: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mtsrr0 %r4 mtsrr1 %r5 rfid +1: /* land here if an interrupt occurred */ + mtsprg1 %r10 + blr #define EXCEPTION(nr) \ .= nr ;\ attn - /* DSI vector - skip the failing instruction + the next one */ + /* DSI vector - set r3 to 0x300, jump to addr in SPRG1 */ . = 0x300 - mtsprg0 %r10 - mfsrr0 %r10 - addi %r10,%r10,8 - mtsrr0 %r10 - rfid + li %r3,0x300 + mfsprg1 %r9 + mtctr %r9 + bctr EXCEPTION(0x380) - /* - * ISI vector - jump to LR to return from the test, - * with r3 cleared - */ + /* ISI vector - set r3 to 0x400, jump to addr in SPRG1 */ . = 0x400 - li %r3,0 - blr + li %r3,0x400 + mfsprg1 %r9 + mtctr %r9 + bctr /* More exception stubs */ EXCEPTION(0x480) @@ -138,7 +154,9 @@ test_exec: * may have been set. */ . = 0xc00 - blr + mfsprg1 %r9 + mtctr %r9 + bctr EXCEPTION(0xd00) EXCEPTION(0xe00) @@ -162,12 +180,13 @@ test_exec: test_start: nop nop - cmpdi %r3,1 + mr %r6,%r3 + li %r3,0 + cmpdi %r6,1 beq test_1 - cmpdi %r3,2 + cmpdi %r6,2 beq test_2 test_return: - li %r3,1 sc . = 0x1ff8 @@ -177,3 +196,14 @@ test_1: b test_return /* test flowing from one page to the next */ test_2: nop b test_return + + . = 0x2fe8 + /* test generating an interrupt just before an instruction page fault */ + .globl test_2_faults +test_2_faults: + nop + nop + mr %r6,%r3 + li %r3,0 + lwz %r7,0(%r6) + ld %r7,0(%r7) diff --git a/tests/mmu/mmu.c b/tests/mmu/mmu.c index ff6a582..749c121 100644 --- a/tests/mmu/mmu.c +++ b/tests/mmu/mmu.c @@ -192,7 +192,7 @@ int mmu_test_1(void) long val; /* this should fail */ - if (test_read(ptr, &val, 0xdeadbeefd00d)) + if (!test_read(ptr, &val, 0xdeadbeefd00d)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadbeefd00d) @@ -215,7 +215,7 @@ int mmu_test_2(void) /* initialize the memory content */ mem[33] = 0xbadc0ffee; /* this should succeed and be a cache miss */ - if (!test_read(&ptr[33], &val, 0xdeadbeefd00d)) + if (test_read(&ptr[33], &val, 0xdeadbeefd00d)) return 1; /* dest reg of load should have the value written */ if (val != 0xbadc0ffee) @@ -223,13 +223,13 @@ int mmu_test_2(void) /* load a second TLB entry in the same set as the first */ map(ptr2, mem, DFLT_PERM); /* this should succeed and be a cache hit */ - if (!test_read(&ptr2[33], &val, 0xdeadbeefd00d)) + if (test_read(&ptr2[33], &val, 0xdeadbeefd00d)) return 3; /* dest reg of load should have the value written */ if (val != 0xbadc0ffee) return 4; /* check that the first entry still works */ - if (!test_read(&ptr[33], &val, 0xdeadbeefd00d)) + if (test_read(&ptr[33], &val, 0xdeadbeefd00d)) return 5; if (val != 0xbadc0ffee) return 6; @@ -247,7 +247,7 @@ int mmu_test_3(void) /* initialize the memory content */ mem[45] = 0xfee1800d4ea; /* this should succeed and be a cache miss */ - if (!test_read(&ptr[45], &val, 0xdeadbeefd0d0)) + if (test_read(&ptr[45], &val, 0xdeadbeefd0d0)) return 1; /* dest reg of load should have the value written */ if (val != 0xfee1800d4ea) @@ -255,7 +255,7 @@ int mmu_test_3(void) /* remove the PTE */ unmap(ptr); /* this should fail */ - if (test_read(&ptr[45], &val, 0xdeadbeefd0d0)) + if (!test_read(&ptr[45], &val, 0xdeadbeefd0d0)) return 3; /* dest reg of load should be unchanged */ if (val != 0xdeadbeefd0d0) @@ -278,7 +278,7 @@ int mmu_test_4(void) /* initialize the memory content */ mem[27] = 0xf00f00f00f00; /* this should succeed and be a cache miss */ - if (!test_write(&ptr[27], 0xe44badc0ffee)) + if (test_write(&ptr[27], 0xe44badc0ffee)) return 1; /* memory should now have the value written */ if (mem[27] != 0xe44badc0ffee) @@ -286,14 +286,14 @@ int mmu_test_4(void) /* load a second TLB entry in the same set as the first */ map(ptr2, mem, DFLT_PERM); /* this should succeed and be a cache hit */ - if (!test_write(&ptr2[27], 0x6e11ae)) + if (test_write(&ptr2[27], 0x6e11ae)) return 3; /* memory should have the value written */ if (mem[27] != 0x6e11ae) return 4; /* check that the first entry still exists */ /* (assumes TLB is 2-way associative or more) */ - if (!test_read(&ptr[27], &val, 0xdeadbeefd00d)) + if (test_read(&ptr[27], &val, 0xdeadbeefd00d)) return 5; if (val != 0x6e11ae) return 6; @@ -309,7 +309,7 @@ int mmu_test_5(void) /* create PTE */ map(ptr, mem, DFLT_PERM); /* this should fail */ - if (test_read(ptr, &val, 0xdeadbeef0dd0)) + if (!test_read(ptr, &val, 0xdeadbeef0dd0)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadbeef0dd0) @@ -330,7 +330,7 @@ int mmu_test_6(void) /* initialize memory */ *mem = 0x123456789abcdef0; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd0)) + if (!test_write(ptr, 0xdeadbeef0dd0)) return 1; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(DSISR) != 0x42000000) @@ -348,7 +348,7 @@ int mmu_test_7(void) /* create PTE without R or C */ map(ptr, mem, PERM_RD | PERM_WR); /* this should fail */ - if (test_read(ptr, &val, 0xdeadd00dbeef)) + if (!test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadd00dbeef) @@ -357,7 +357,7 @@ int mmu_test_7(void) if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x00040000) return 3; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd0)) + if (!test_write(ptr, 0xdeadbeef0dd0)) return 4; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000) @@ -378,10 +378,10 @@ int mmu_test_8(void) /* create PTE with R but not C */ map(ptr, mem, REF | PERM_RD | PERM_WR); /* this should succeed */ - if (!test_read(ptr, &val, 0xdeadd00dbeef)) + if (test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 2; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000) @@ -402,7 +402,7 @@ int mmu_test_9(void) /* create PTE without read or write permission */ map(ptr, mem, REF); /* this should fail */ - if (test_read(ptr, &val, 0xdeadd00dbeef)) + if (!test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadd00dbeef) @@ -411,7 +411,7 @@ int mmu_test_9(void) if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x08000000) return 3; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 4; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) @@ -432,10 +432,10 @@ int mmu_test_10(void) /* create PTE with read but not write permission */ map(ptr, mem, REF | PERM_RD); /* this should succeed */ - if (!test_read(ptr, &val, 0xdeadd00dbeef)) + if (test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 2; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) @@ -451,7 +451,7 @@ int mmu_test_11(void) unsigned long ptr = 0x523000; /* this should fail */ - if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != (long) ptr || @@ -469,12 +469,12 @@ int mmu_test_12(void) /* create PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should succeed and be a cache miss */ - if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* create a second PTE */ map((void *)ptr2, (void *)mem, PERM_EX | REF); /* this should succeed and be a cache hit */ - if (!test_exec(0, ptr2, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(0, ptr2, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 2; return 0; } @@ -488,14 +488,14 @@ int mmu_test_13(void) /* create a PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should succeed */ - if (!test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* invalidate the PTE */ unmap((void *)ptr); /* install a second PTE */ map((void *)ptr2, (void *)mem, PERM_EX | REF); /* this should fail */ - if (test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 2; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != (long) ptr || @@ -514,7 +514,7 @@ int mmu_test_14(void) /* create a PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should fail due to second page not being mapped */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != ptr2 || @@ -523,7 +523,7 @@ int mmu_test_14(void) /* create a PTE for the second page */ map((void *)ptr2, (void *)mem2, PERM_EX | REF); /* this should succeed */ - if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 3; return 0; } @@ -536,7 +536,7 @@ int mmu_test_15(void) /* create a PTE without execute permission */ map((void *)ptr, (void *)mem, DFLT_PERM); /* this should fail */ - if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != ptr || @@ -557,7 +557,7 @@ int mmu_test_16(void) /* create a PTE for the second page without execute permission */ map((void *)ptr2, (void *)mem2, PERM_RD | REF); /* this should fail due to second page being no-execute */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != ptr2 || @@ -566,7 +566,7 @@ int mmu_test_16(void) /* create a PTE for the second page with execute permission */ map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF); /* this should succeed */ - if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 3; return 0; } @@ -579,7 +579,7 @@ int mmu_test_17(void) /* create a PTE without the ref bit set */ map((void *)ptr, (void *)mem, PERM_EX); /* this should fail */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != (long) ptr || @@ -589,7 +589,7 @@ int mmu_test_17(void) unmap((void *)ptr); map((void *)ptr, (void *)mem, 0); /* this should fail */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ /* RC update fail bit should not be set */ @@ -608,12 +608,12 @@ int mmu_test_18(void) /* create PTE */ map(ptr, mem, DFLT_PERM); /* this should succeed and be a cache miss */ - if (!test_dcbz(&ptr[129])) + if (test_dcbz(&ptr[129])) return 1; /* create a second PTE */ map(ptr2, mem, DFLT_PERM); /* this should succeed and be a cache hit */ - if (!test_dcbz(&ptr2[130])) + if (test_dcbz(&ptr2[130])) return 2; return 0; } @@ -627,7 +627,7 @@ int mmu_test_19(void) /* create PTE with read but not write permission */ map(ptr, mem, REF | PERM_RD); /* this should fail and create a TLB entry */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 1; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) @@ -635,11 +635,26 @@ int mmu_test_19(void) /* Update the PTE to have write permission */ map(ptr, mem, REF | CHG | PERM_RD | PERM_WR); /* this should succeed */ - if (!test_write(ptr, 0xdeadbeef0dd1)) + if (test_write(ptr, 0xdeadbeef0dd1)) return 3; return 0; } +int mmu_test_20(void) +{ + unsigned long mem = 0x2000; + unsigned long ptr = 0x324000; + unsigned long ret; + + /* create a PTE with execute permission */ + map((void *)ptr, (void *)mem, PERM_EX | PERM_PRIV | REF); + ret = test_exec(0x124000, ptr + 0xfe8, MSR_SF | MSR_HV | MSR_IR | MSR_DR | MSR_LE); + /* Should see a 300 from the load, not a 400 from the page crossing */ + if (ret != 0x300) + return ret + 1; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -656,7 +671,10 @@ void do_test(int num, int (*test)(void)) } else { fail = 1; print_string("FAIL "); - putchar(ret + '0'); + if (ret < 10) + putchar(ret + '0'); + else + print_hex(ret); if (num <= 10 || num == 19) { print_string(" DAR="); print_hex(mfspr(DAR)); @@ -696,6 +714,7 @@ int main(void) do_test(17, mmu_test_17); do_test(18, mmu_test_18); do_test(19, mmu_test_19); + do_test(20, mmu_test_20); return fail; } diff --git a/tests/test_mmu.bin b/tests/test_mmu.bin index 6e352a773ba39b843f5e1bc1aaa9abb2beaa0d21..1c4f87692c501636e8c8401cf41255f246c12b70 100755 GIT binary patch literal 24608 zcmeHPeQZ?Ml|OIB*kc36fOprFraZ^aYQ}Y?A&a^**oHT@N$dd<12)h!G|w4RnXf9@ zkkt&lml?a03M8T>tNf8xVnnK}V+Ms$Oxt6G0eXXE8in4M2P=kH}qSR1_B!ljmbgE&EE>q%;>l^ozG>^NHF&F=yw8_SlSvIBIPiiUm z&$LRSRW@H?iSy6b9|5--NYyXaQ*NIwvk(5IKc>(BrKM)%<^4amf4cF{%*6COIrdKv z?q3(F&iqgBOiVZa(=C5`(I;!qIo(=JoBV0r`%IhFS%Mw^&jMqT$Eoo7bN5f8(pTE_ z=hpwr^8ZSWos^l1R@FXNOZ2zZgLAq=E|deJq{c}{IgJhi4gwAW4gwAW4gwAW4gwAW z4gwAW4gwAW4gz0$1iYihN+_wyX8E<(*HO?xz(K%4z(K%4z(K%4z(K%4z(K%4z(K%4 zz(L@;5Kuui{yRU>Zxckn8X>s zQkAz%w9V5=!FvZSUd@9#%T%a5&{I$mgPft1+oSQ{^OO0J5-79vT;S>ntffS)Yv6E{ z{7IGH2Vni)g?^hS=vB+_D!A?vIw}dJ-#;i26Rdr?~WP9do`@bS?D2Ad>`X73$py+Gx!Z^I{P=&1XI*OLtuwTk`hv` zZKKBNG3FIr_>hK)8Rz%i%WuS&75Lf;sj%8hUCIXX1!by;T{euGn8o+9v8cM=Fy-9` zd4ABS`4zFZvgP6LQL?ejmS-6E))ql#-?oUrlkK<#WB+^X^SGblfg&;%ohXQCg_gXQ z(YWTPNPycu`D@d*rI?Fh>zVByS|Hj@Tg|_PfxlE%%hbKPj~eh!N%;OHz-T#DdaGeq z_u0MC=)$ddpTd{(eo4o7eX$mKuT~n4XuZ%$X{pqr6?@@7T}pIavo6sv-U(5HDfh6} zZz%Q8uW_R-9Q-(AJL_XhT>Rx}XpAu*Vmq#Lb`D^1OpSeXxFT_h5rB<~oy%RxUcVJNoUUW*AD)b;cJf z9&L=3UhsiO0`K3Ds=|(B;^r=inu8|_e0t>~Uo4rZf0X<7B@`NJltG~+4OD_T^nNE+0oRnUs9YKAbq}H=RW4i zvY3W>GJoc~!{W<%jN@7reBT|( za+UTB?7(|nff5T>TaU$%`y=FOZhwAmQf1zoEPghQonovp@*}*5##lZ-7y7kKjwkDB z&k6H-^9@tC8^QDLzsice3AvYT2wGTPc{!@)i7x&DGZ0M=jARuO~awyxEw zKD^^kU2m7nlk1}E%{@v!^@uobo=;6DpBz|j7`-*@_oL^Hh@5wRLoqFnML+s^oapnh z1D_cyXZM-=9M<{LONjL>zv5gJ{q`wM|3$7Hk6Zg2VZ%_Bwg-Nja{YVUwg0)@JcrFx z<=rXT=IMF-P9^N@K%H^6@nO6fqv*)L#oH|YB7Yzs1O!g&bOLXVf3MBUW%6SGAo{^D z=LpUh9#J>*go=Gr=e#Vxo+M8&UcA;bK8zb<#P~2aj1gmykDSOk<20}ncmWH>Y|E!p zW48LWT)ehVu>CA-H*v0vF~)5cy}%RpoBK5E75AHaMaJ`57(_qI?9-N(_}X~y$QWpI zvoM&j&&l=|f}O0x0?<$8FFVpx+s^*7`qf47zMeJvQKl1c0&DFCd>Ox+h>GpXy!iJP< zp><9gs5Q??!%=GT;%w5b2;1aDp!pgy-aKPsVy@3yIcJ63;LYc%69o-;r+ezN9?t{s z)h5ove|Ls9$S@d5f22MUH*YTcs$vmabFa~O(>%;A%VqemXHO>%gTu#m!8;o;o z^WOL2-}C-1vsO=BuMWSQYfq<$mj^W0{;h}?bNz1>@q)VzD+hB9V4I_mBU5|295PT2 zO_akqeuc%~-piV?V&04JIpCS1tXwr=-^wvkX!}=It~&l9e86qyDxMdF=cF$bxuw1+}c{zQiwCDSDfj+tvE;G3>i4p*~;feK64D_ zMWR*BO?t;S6kX2T>wrb>d4~6|rO;Ev`+n$&JoaFrc`n4+YPm$cHGO@jB5&evRz8>` z*D)=XnP)&g8+IOws29$eXT#1%eeFcUIM>^I(>mY=7Q)JGwYF~Mi@H5s~$uP6H>s+4s<^y(!u-j~>U9{5Sf^KDuB zCWU=*Z3*Ls@pU-&^7A-P*sNcJ&+IHd=3aFv?$ms-W~>vq%YmK9r)+1|eVT2v8+x+M zE|h%#aiZY8__=~>`?H8)){FP`y#7L0&M|x+^Y#Z<+sW(Mj+2>rW!%|zmeo@biFQI( z%Jo^?)ib=C^__)z;4uThoAt(?>MFelaE}%pdoRA=3iCDf;QA&@KF2i26Z84-XBpXh z3|>c<>g-QXfk(*akHaTa z^E*(JOq{9Nlla#fqGer_F2vcfD@5>f?pI(l?qwd`h;fyRhIdP3)KoR;+8Uf+`?BS@ zb7L?29+2;vn4gV#%6%*Te~iD=@5lJ)N3X=+7y)kX;dmK^($TSt@pAmX8F(Jz+*Jwe z`5v(!cZiHXukqkLf;k=Gd);#vz++)tGuLNQnRWoQ3F!P&^cB*g>W#3+553t>4!DG$ zs73TG+@*FY^HFkM<#9t8_b|q!Tn}ikqU5$wwB0Y-{y{r#wRyHj0y|lE%-;dDoxn5G zra`+x(C*Th54RC$7mK#t;+_$h@<&Qc*dN+!-VC>?-*I4K7~Sw$H9#%Nz%j%Y*V#X| zw{cl_KIjBGOgJj@8tvc>x0=4%f1E;L|T-5h;z<#Tabtm9eVZT+Mk9sfak63l& z*T9SIupf0^dw{jtjk`?tn=kqufazXH+`N~|Be-uQ+>84W*F;srrMSC2nn&7mcgVP> z_1%9FF-f#_NVI)R)t2Q)TFrH+3U|FG?S%}j!n7XTYcu@?&}YRB#AV_Jk5}nXJ&6wT zxDHjrLWet5Z8G_|b7ozYW%*lL@qaN1+6x=xFI+P@S90v;{`T zHvLVAA+t7$HuVW0C zbUS#5#_2=FEv|-Qs>gu*5bJRtXa;^~7%fcOEO2QoZUJXkJ(CHZjPK*<_YC6(5YNDu z@xRB$m-}Bt{}J?GH2WF@pBP3bo~a?n zFG9u2${e{o=W-sA26{j9wBvJy;C&~E8}ku%%$spo1=_?P3?nIM#az0O6hMQxLO*}9 z^9;9@;oJ8|jNwjvxQ+Ex(wX>WJrsP8qD@69^f)LzjmWYy3cxb+1drd2?*M3d9Dlei zf$zs?6Y*fRaW0tknS}+OosWZngMfp8gMfp8gMfp8gMfp8gMfp8gMfp;v?8GJff^ri M2uCSfbu!EU15lie&j0`b literal 24608 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 diff --git a/tests/test_mmu.console_out b/tests/test_mmu.console_out index cb4ad85..aea206f 100644 --- a/tests/test_mmu.console_out +++ b/tests/test_mmu.console_out @@ -17,3 +17,4 @@ test 16:PASS test 17:PASS test 18:PASS test 19:PASS +test 20:PASS