summaryrefslogtreecommitdiff
path: root/tests/tst-pointer-policy.c
blob: 15d3b0f37416ae4c2a9146c1f90a155a50c72542 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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 );
}