nkeynes@976: #include "utlb.h" nkeynes@976: #include "../lib.h" nkeynes@976: nkeynes@976: struct utlb_test_case { nkeynes@976: const char *name; nkeynes@976: uint32_t vma; nkeynes@976: uint32_t pma; nkeynes@976: int read_exc; nkeynes@976: int write_exc; nkeynes@976: }; nkeynes@976: nkeynes@976: #define OK 0 nkeynes@976: nkeynes@976: #define MAX_BATCH_ENTRIES 4 nkeynes@976: #define MAX_BATCH_TESTS 8 nkeynes@976: nkeynes@976: uint32_t dummy; nkeynes@976: nkeynes@976: #define LOAD(ent,asid,vpn,ppn,mode) load_utlb_entry( ent, vpn, ppn, asid, mode ) nkeynes@976: #define TEST(name,asid,vma,pma,sr,sw,ur,uw) run_utlb_test_case(name,asid,vma,pma,sr,sw,ur,uw) nkeynes@976: nkeynes@976: int run_utlb_priv_test( struct utlb_test_case *test ); nkeynes@976: int run_utlb_user_test( struct utlb_test_case *test ); nkeynes@976: nkeynes@976: int cases_failed; nkeynes@976: int cases_run; nkeynes@976: int tests_failed; nkeynes@976: int tests_run; nkeynes@976: int tests_skipped; nkeynes@976: nkeynes@976: int run_utlb_test_case( const char *name, int asid, unsigned int vma, unsigned int pma, nkeynes@976: int sr, int sw, int ur, int uw ) nkeynes@976: { nkeynes@976: char tmp[64]; nkeynes@976: struct utlb_test_case test = { tmp, vma, pma, sr, sw }; nkeynes@976: int fails = 0; nkeynes@976: nkeynes@976: cases_run++; nkeynes@976: nkeynes@976: set_asid( asid ); nkeynes@976: if( sr == OTLBMULTIHIT || sw == OTLBMULTIHIT ) { nkeynes@976: fprintf( stderr, "%s: Skipping system test (multihit)\n", name ); nkeynes@976: tests_skipped += 2; nkeynes@976: } else { nkeynes@976: snprintf(tmp,sizeof(tmp), "%s (System)", name ); nkeynes@976: tests_run += 2; nkeynes@976: fails += run_utlb_priv_test( &test ); nkeynes@976: } nkeynes@976: nkeynes@976: if( ur == OTLBMULTIHIT || uw == OTLBMULTIHIT ) { nkeynes@976: fprintf( stderr, "%s: Skipping user test '%s' (multihit)\n", name ); nkeynes@976: tests_skipped += 2; nkeynes@976: } else { nkeynes@976: snprintf(tmp,sizeof(tmp), "%s (User)", name ); nkeynes@976: test.read_exc = ur; nkeynes@976: test.write_exc = uw; nkeynes@976: tests_run += 2; nkeynes@976: fails += run_utlb_user_test( &test ); nkeynes@976: } nkeynes@976: if( fails != 0 ) { nkeynes@976: cases_failed++; nkeynes@976: tests_failed += fails; nkeynes@976: } nkeynes@976: return fails; nkeynes@976: } nkeynes@976: nkeynes@976: int main() nkeynes@976: { nkeynes@976: /* Non-TLB behaviour tests */ nkeynes@976: nkeynes@1090: install_utlb_test_handler(); nkeynes@976: nkeynes@1090: /* TLB off tests (make sure the MMU _stays_ off) */ nkeynes@1090: LOAD( 62, 0, 0x0C000000, 0x0CFFFC00, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); nkeynes@1090: TEST( "TLB OFF", 0, 0x0C000018, 0x0C000018, OK, OK, OK, OK ); nkeynes@1090: TEST( "TLB OFF", 1, 0x0C000018, 0x0C000018, OK, OK, OK, OK ); nkeynes@1090: nkeynes@976: /* TLB tests */ nkeynes@976: invalidate_tlb(); nkeynes@976: /* Permanently map the first and last MB of RAM into userspace - without nkeynes@976: * this it's a bit hard to actually run any user-mode tests. nkeynes@976: */ nkeynes@976: LOAD(62, 0, 0x0C000000, 0x0C000000, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1M|TLB_CACHEABLE|TLB_DIRTY|TLB_SHARE); nkeynes@976: LOAD(63, 0, 0x0CF00000, 0x0CF00000, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1M|TLB_CACHEABLE|TLB_DIRTY|TLB_SHARE); nkeynes@976: set_tlb_enabled(1); nkeynes@976: nkeynes@976: /* Test miss */ nkeynes@976: TEST( "U0", 0, 0x12345008, 0x0c000018, RTLBMISS, WTLBMISS, RTLBMISS, WTLBMISS ); nkeynes@976: TEST( "P1", 0, 0x8c000018, 0x0c000018, OK, OK, RADDERR, WADDERR ); nkeynes@976: TEST( "P1", 0, 0xac000018, 0x0c000018, OK, OK, RADDERR, WADDERR ); nkeynes@976: TEST( "P3", 0, 0xC4345008, 0x0c000018, RTLBMISS, WTLBMISS, RADDERR, WADDERR ); nkeynes@976: nkeynes@976: /* Test flags with 1K pages */ nkeynes@976: LOAD( 0, 0, 0x12345C00, 0x0C000000, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); nkeynes@976: LOAD( 1, 1, 0x12345C00, 0x0CFFFC00, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); nkeynes@976: LOAD( 2, 0, 0x12345800, 0x0C000800, TLB_VALID|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); nkeynes@976: LOAD( 3, 0, 0x12345400, 0x0C000400, TLB_VALID|TLB_USERMODE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); nkeynes@976: LOAD( 4, 0, 0x12345000, 0x0C000000, TLB_VALID|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); nkeynes@976: LOAD( 5, 1, 0x12345800, 0x0CF01800, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE ); nkeynes@976: LOAD( 6, 1, 0x12346000, 0x0C000000, TLB_VALID|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE ); nkeynes@976: LOAD( 7, 2, 0x12346800, 0x0C000400, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_SHARE|TLB_DIRTY ); nkeynes@976: TEST( "1K ASID 0", 0, 0x12345C18, 0x0C000018, OK, OK, OK, OK ); nkeynes@976: TEST( "1K ASID 1", 1, 0x12345C18, 0x0CFFFC18, OK, OK, OK, OK ); nkeynes@976: TEST( "1K ASID 2", 2, 0x12345C18, 0x0C000018, RTLBMISS, WTLBMISS, RTLBMISS, WTLBMISS ); nkeynes@976: TEST( "1K PRIV", 0, 0x12345818, 0x0C000818, OK, OK, READPROT, WRITEPROT ); nkeynes@976: TEST( "1K READONLY", 0, 0x12345418, 0x0C000418, OK, WRITEPROT, OK, WRITEPROT ); nkeynes@976: TEST( "1K PRIVREAD", 0, 0x12345018, 0x0C000018, OK, WRITEPROT, READPROT, WRITEPROT ); nkeynes@976: TEST( "1K FIRSTWR", 1, 0x12345818, 0x0CF01818, OK, FIRSTWRITE, OK, FIRSTWRITE ); nkeynes@976: TEST( "1K PRIVFWR", 1, 0x12346018, 0x0C000018, OK, FIRSTWRITE, READPROT, WRITEPROT ); nkeynes@976: TEST( "1K MISS", 1, 0x12346418, 0x0C000018, RTLBMISS, WTLBMISS, RTLBMISS, WTLBMISS ); nkeynes@976: TEST( "1K SHARED 0", 0, 0x12346818, 0x0C000418, OK, OK, OK, OK ); nkeynes@976: TEST( "1K SHARED 2", 2, 0x12346818, 0x0C000418, OK, OK, OK, OK ); nkeynes@976: nkeynes@976: nkeynes@976: uninstall_utlb_test_handler(); nkeynes@976: nkeynes@976: nkeynes@976: printf( "--> %d/%d Test cases passed (%d%%)\n", cases_run-cases_failed, cases_run, ( (cases_run-cases_failed)*100/cases_run) ); nkeynes@976: printf( "--> %d/%d Tests passed (%d%%)\n", tests_run-tests_failed, tests_run, ( (tests_run-tests_failed)*100/tests_run) ); nkeynes@976: nkeynes@976: return cases_failed == 0 ? 0 : 1; nkeynes@976: }