diff options
Diffstat (limited to 'tests/tst-pointer.c')
| -rw-r--r-- | tests/tst-pointer.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/tests/tst-pointer.c b/tests/tst-pointer.c new file mode 100644 index 0000000..ca0ff99 --- /dev/null +++ b/tests/tst-pointer.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <string.h> +#include <libmcpu.h> +#include "../utils/mcpu-asm.h" + +#define CHECK(c,m) do{if(!(c)){fprintf(stderr,"FAIL: %s\n",m);return 1;}}while(0) + +static const char src[]= +".data\n" +".align 8\n" +"global_value:\n" +" .integer 64, 41\n" +".text\n" +" LEA r64@0x00000, global_value\n" +" LOADP r64@0x00008, r64@0x00000\n" +" LDI r64@0x00010, 42\n" +" STOREP r64@0x00000, r64@0x00010\n" +" LOADP r64@0x00018, r64@0x00000\n" +" ADJSP -16\n" +" LDI r64@0x00020, 11\n" +" LDI r64@0x00028, 22\n" +" STSP 0, r64@0x00020\n" +" STSP 8, r64@0x00028\n" +" LEASP r64@0x00030, 0\n" +" LOADP r64@0x00038, r64@0x00030\n" +" LEASP r64@0x00040, 8\n" +" LOADP r64@0x00048, r64@0x00040\n" +" LDI r64@0x00050, 33\n" +" STOREP r64@0x00040, r64@0x00050\n" +" LDSP r64@0x00058, 8\n" +" ADJSP 16\n" +" HALT\n"; + +static int +eq64( unsigned address, const char *text ) +{ + mpu_int64_t x; + iatoi( ( mpu_int * ) x, (__mpu_char8_t *)text, NB_I64 ); + return( !memcmp( __cpu_reg_ptr( 64, address ), x, NB_I64 ) ); +} + +static __mpu_uint64_t +reg_u64( unsigned address ) +{ + __mpu_uint64_t v = 0; + memcpy( &v, __cpu_reg_ptr( 64, address ), 8 ); + return( v ); +} + +int +main( void ) +{ + cpu_asm_image im; + cpu_instruction i; + __mpu_uint64_t p; + __mpu_UNIT_t saved[8]; + char err[256]; + int rc; + + __cpu_init(); + + CHECK( CPU_PTR_SEG_SHIFT == 60U, "PTR64 segment shift" ); + CHECK( CPU_PTR_OFFSET_MASK == __mpu_UINT64_C( 0x0fffffffffffffff ), "PTR64 offset mask" ); + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 0x1234 ) == 0, "make DATA pointer" ); + CHECK( p == __mpu_UINT64_C( 0x0000000000001234 ), "DATA pointer encoding" ); + CHECK( __cpu_ptr_segment( p ) == CPU_PTR_SEG_DATA, "DATA pointer segment" ); + CHECK( __cpu_ptr_offset( p ) == 0x1234, "DATA pointer offset" ); + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_STACK, 0x1234 ) == 0, "make STACK pointer" ); + CHECK( p == __mpu_UINT64_C( 0x1000000000001234 ), "STACK pointer encoding" ); + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_PROGRAM, 0x1234 ) == 0, "make PROGRAM pointer" ); + CHECK( p == __mpu_UINT64_C( 0x2000000000001234 ), "PROGRAM pointer encoding" ); + CHECK( __cpu_ptr_make( &p, 0x10, 0 ) == -1, "reject segment wider than four bits" ); + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, CPU_PTR_OFFSET_MASK + 1 ) == -1, "reject offset wider than 60 bits" ); + + CHECK( cpu_assemble_text( src, &im, err, sizeof( err ) ) == 0, err ); + CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "program set" ); + CHECK( __cpu_data_set( im.data, im.data_size ) == 0, "data set" ); + CHECK( __cpu_stack_alloc( 128 ) == 0, "stack alloc" ); + __cpu_pc = 0; + CHECK( __cpu_run() == CPU_EXEC_SUCCESS, "PTR64 program run" ); + + p = reg_u64( 0x00000 ); + CHECK( __cpu_ptr_segment( p ) == CPU_PTR_SEG_DATA, "LEA creates DATA pointer" ); + CHECK( __cpu_ptr_offset( p ) == CPU_DATA_NULL_GUARD_SIZE, "LEA DATA label offset after NULL guard" ); + CHECK( eq64( 0x00008, "41" ), "LOADP reads DATA" ); + CHECK( eq64( 0x00018, "42" ), "STOREP writes DATA and LOADP reads it back" ); + CHECK( eq64( 0x00038, "11" ), "LEASP/LOADP first local object field" ); + CHECK( eq64( 0x00048, "22" ), "LEASP/LOADP second local object field" ); + CHECK( eq64( 0x00058, "33" ), "STOREP writes STACK through PTR64" ); + CHECK( __cpu_sp == 128, "stack frame released" ); + + p = reg_u64( 0x00030 ); + CHECK( __cpu_ptr_segment( p ) == CPU_PTR_SEG_STACK, "LEASP segment selector" ); + CHECK( __cpu_ptr_offset( p ) == 112, "LEASP absolute stack offset for SP+0" ); + + /* PROGRAM is readable through PTR64 but is not writable. */ + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_PROGRAM, 0 ) == 0, "make PROGRAM pointer for indirect access" ); + memcpy( __cpu_reg_ptr( 64, 0x00060 ), &p, 8 ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_LOADP; + i.operand[0].type = CPU_OPERAND_REGISTER; + i.operand[0].value.reg.bits = 16; + i.operand[0].value.reg.address = 0x00068; + i.operand[1].type = CPU_OPERAND_REGISTER; + i.operand[1].value.reg.bits = 64; + i.operand[1].value.reg.address = 0x00060; + CHECK( __cpu_exec( &i ) == CPU_EXEC_SUCCESS, "LOADP may read PROGRAM" ); + CHECK( !memcmp( __cpu_reg_ptr( 16, 0x00068 ), __cpu_program_ptr(), 2 ), "LOADP PROGRAM bytes" ); + + memcpy( saved, __cpu_program_ptr(), sizeof( saved ) ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_STOREP; + i.operand[0].type = CPU_OPERAND_REGISTER; + i.operand[0].value.reg.bits = 64; + i.operand[0].value.reg.address = 0x00060; + i.operand[1].type = CPU_OPERAND_REGISTER; + i.operand[1].value.reg.bits = 64; + i.operand[1].value.reg.address = 0x00010; + CHECK( __cpu_exec( &i ) == CPU_EXEC_MEMORY_FAULT, "STOREP rejects PROGRAM write" ); + CHECK( !memcmp( saved, __cpu_program_ptr(), sizeof( saved ) ), "PROGRAM write fault is atomic" ); + + + /* ABI NULL is all-zero PTR64 and is never dereferenceable. */ + p = CPU_NULL_PTR; + memcpy( __cpu_reg_ptr( 64, 0x00060 ), &p, 8 ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_LOADP; + i.operand[0].type = CPU_OPERAND_REGISTER; + i.operand[0].value.reg.bits = 8; + i.operand[0].value.reg.address = 0x00070; + i.operand[1].type = CPU_OPERAND_REGISTER; + i.operand[1].value.reg.bits = 64; + i.operand[1].value.reg.address = 0x00060; + CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "NULL PTR64 dereference faults" ); + + /* Reserved segment selectors decode but cannot currently be dereferenced. */ + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_FIRST_RESERVED, 0 ) == 0, "reserved segment fits PTR64" ); + memcpy( __cpu_reg_ptr( 64, 0x00060 ), &p, 8 ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_LOADP; + i.operand[0].type = CPU_OPERAND_REGISTER; + i.operand[0].value.reg.bits = 8; + i.operand[0].value.reg.address = 0x00070; + i.operand[1].type = CPU_OPERAND_REGISTER; + i.operand[1].value.reg.bits = 64; + i.operand[1].value.reg.address = 0x00060; + rc = __cpu_exec( &i ); + CHECK( rc == CPU_EXEC_POINTER_FAULT, "reserved PTR64 segment faults on dereference" ); + + cpu_asm_image_free( &im ); + __cpu_free_context(); + puts( "libcpu PTR64/indirect-addressing regression: PASS" ); + return( 0 ); +} |
