summaryrefslogtreecommitdiff
path: root/tests/tst-pointer-policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-pointer-policy.c')
-rw-r--r--tests/tst-pointer-policy.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/tests/tst-pointer-policy.c b/tests/tst-pointer-policy.c
new file mode 100644
index 0000000..15d3b0f
--- /dev/null
+++ b/tests/tst-pointer-policy.c
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <string.h>
+#include <libmcpu.h>
+
+#define CHECK(c,m) do{if(!(c)){fprintf(stderr,"FAIL: %s\n",m);return 1;}}while(0)
+
+static void
+regop( cpu_operand *o, unsigned bits, unsigned address )
+{
+ memset( o, 0, sizeof( *o ) );
+ o->type = CPU_OPERAND_REGISTER;
+ o->value.reg.bits = bits;
+ o->value.reg.address = address;
+}
+
+static void
+set_u64( unsigned address, __mpu_uint64_t v )
+{
+ __cpu_data_put_u64( __cpu_reg_ptr( 64, address ), v );
+}
+
+static __mpu_uint64_t
+get_u64( unsigned address )
+{
+ return( __cpu_data_get_u64( __cpu_reg_ptr( 64, address ) ) );
+}
+
+static int
+exec2( cpu_opcode op, unsigned a, unsigned b )
+{
+ cpu_instruction i;
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = op;
+ regop( &i.operand[0], 64, a );
+ regop( &i.operand[1], 64, b );
+ return( __cpu_exec( &i ) );
+}
+
+static int
+exec3( cpu_opcode op, unsigned d, unsigned a, unsigned b )
+{
+ cpu_instruction i;
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = op;
+ regop( &i.operand[0], 64, d );
+ regop( &i.operand[1], 64, a );
+ regop( &i.operand[2], 64, b );
+ return( __cpu_exec( &i ) );
+}
+
+int
+main( void )
+{
+ __mpu_uint64_t p, q, saved;
+ __mpu_UNIT_t code[2] =
+ {
+ 0, 0
+ };
+ cpu_instruction i;
+
+ __cpu_init();
+ CHECK( CPU_ABI_STACK_RED_ZONE_SIZE == 0U, "ABI red zone is zero bytes" );
+ CHECK( __cpu_data_alloc( 128 ) == 0, "DATA alloc" );
+ CHECK( __cpu_stack_alloc( 128 ) == 0, "STACK alloc" );
+ CHECK( __cpu_program_set( code, sizeof( code ) ) == 0, "PROGRAM set" );
+
+ /* Pointer equality is full 64-bit equality and can be tested with ICMP/ZF. */
+ CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 32 ) == 0, "make DATA pointer p" );
+ CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_DATA, 32 ) == 0, "make equal DATA pointer q" );
+ set_u64( 0x100, p );
+ set_u64( 0x108, q );
+ CHECK( exec2( CPU_OP_ICMP, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "ICMP equal pointers" );
+ CHECK( ( __cpu_get_psw() & PSW_ZF_MASK ) != 0, "equal PTR64 sets ZF" );
+
+ CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_STACK, 32 ) == 0, "make STACK pointer q" );
+ set_u64( 0x108, q );
+ CHECK( exec2( CPU_OP_ICMP, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "ICMP cross-segment bit patterns" );
+ CHECK( ( __cpu_get_psw() & PSW_ZF_MASK ) == 0, "different segments are not equal" );
+
+ /* Pointer ordering is defined by PDIFF only inside one selector. */
+ CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 64 ) == 0, "make lower DATA pointer" );
+ CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_DATA, 96 ) == 0, "make upper DATA pointer" );
+ set_u64( 0x100, p );
+ set_u64( 0x108, q );
+ CHECK( exec3( CPU_OP_PDIFF, 0x110, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "same-segment PDIFF" );
+ CHECK( (__mpu_int64_t)get_u64( 0x110 ) == -32, "PDIFF gives signed byte difference" );
+ CHECK( exec2( CPU_OP_ITEST, 0x110, 0x110 ) == CPU_EXEC_SUCCESS, "ITEST pointer difference" );
+ CHECK( ( __cpu_get_psw() & PSW_SF_MASK ) != 0, "negative pointer difference sets SF" );
+
+ saved = __mpu_UINT64_C( 0x1122334455667788 );
+ set_u64( 0x110, saved );
+ CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_STACK, 96 ) == 0, "make cross-segment pointer" );
+ set_u64( 0x108, q );
+ CHECK( exec3( CPU_OP_PDIFF, 0x110, 0x100, 0x108 ) == CPU_EXEC_POINTER_FAULT, "PDIFF rejects cross-segment ordering" );
+ CHECK( get_u64( 0x110 ) == saved, "PDIFF cross-segment fault is atomic" );
+
+ /* Reserved selectors are structurally valid and support non-dereferencing arithmetic. */
+ CHECK( __cpu_ptr_make( &p, 0x0f, 123 ) == 0, "make reserved pointer p" );
+ CHECK( __cpu_ptr_make( &q, 0x0f, 100 ) == 0, "make reserved pointer q" );
+ set_u64( 0x100, p );
+ set_u64( 0x108, q );
+ CHECK( exec3( CPU_OP_PDIFF, 0x110, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "reserved same-selector PDIFF" );
+ CHECK( (__mpu_int64_t)get_u64( 0x110 ) == 23, "reserved PDIFF difference" );
+
+ /* A reserved PTR64 may be stored as data but may not be dereferenced. */
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = CPU_OP_STORE;
+ i.operand[0].type = CPU_OPERAND_ADDR64;
+ i.operand[0].value.addr64 = 16;
+ regop( &i.operand[1], 64, 0x100 );
+ CHECK( __cpu_exec( &i ) == CPU_EXEC_SUCCESS, "STORE preserves reserved PTR64 as ordinary data" );
+ CHECK( __cpu_data_get_u64( __cpu_data_ptr() + 16 ) == p, "stored reserved PTR64 bits" );
+
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = CPU_OP_LOADP;
+ regop( &i.operand[0], 64, 0x118 );
+ regop( &i.operand[1], 64, 0x100 );
+ CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "LOADP rejects reserved selector" );
+
+ /* Even a zero-length BMOVI requires semantically valid address-space selectors. */
+ CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_DATA, 16 ) == 0, "make valid DATA pointer" );
+ set_u64( 0x108, q );
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = CPU_OP_BMOVI;
+ regop( &i.operand[0], 64, 0x108 );
+ regop( &i.operand[1], 64, 0x100 );
+ i.operand[2].type = CPU_OPERAND_IMM64;
+ i.operand[2].value.imm64 = 0;
+ CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "zero-length BMOVI rejects reserved source" );
+
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = CPU_OP_JMPP;
+ regop( &i.operand[0], 64, 0x100 );
+ CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "JMPP rejects reserved selector" );
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = CPU_OP_CALLP;
+ regop( &i.operand[0], 64, 0x100 );
+ CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "CALLP rejects reserved selector" );
+ memset( &i, 0, sizeof( i ) );
+ i.opcode = CPU_OP_SETSP;
+ regop( &i.operand[0], 64, 0x100 );
+ CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "SETSP rejects reserved selector" );
+
+ /* DATA offsets 1..15 are ABI-reserved guard values, but only all-zero PTR64 is NULL. */
+ CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 1 ) == 0, "make DATA guard pointer" );
+ CHECK( p != CPU_NULL_PTR, "DATA:1 is not NULL" );
+ CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 0 ) == 0 && p == CPU_NULL_PTR, "DATA:0 is canonical NULL" );
+
+ __cpu_free_context();
+ puts( "libcpu pointer-comparison/red-zone/reserved-segment policy regression: PASS" );
+ return( 0 );
+}