2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
7 #ifndef NATIVE_CLIENT_TESTS_COMMON_REGISTER_SET_H_
8 #define NATIVE_CLIENT_TESTS_COMMON_REGISTER_SET_H_
10 #include "native_client/src/include/nacl/nacl_exception.h"
11 #include "native_client/src/include/nacl_macros.h"
12 #include "native_client/src/trusted/service_runtime/nacl_config.h"
13 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
16 * ASM_WITH_REGS(regs, asm_code) executes asm_code with most registers
17 * restored from regs, a pointer of type "struct NaClSignalContext *".
20 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
22 # define ASM_WITH_REGS(regs, asm_code) \
25 "movl 0x04(%%eax), %%ecx\n" \
26 "movl 0x08(%%eax), %%edx\n" \
27 "movl 0x0c(%%eax), %%ebx\n" \
28 "movl 0x10(%%eax), %%esp\n" \
29 "movl 0x14(%%eax), %%ebp\n" \
30 "movl 0x18(%%eax), %%esi\n" \
31 "movl 0x1c(%%eax), %%edi\n" \
32 "movl 0x00(%%eax), %%eax\n" \
35 : : "r"(regs) : "memory")
37 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
39 # define ASM_WITH_REGS(regs, asm_code) \
41 "naclrestbp %0, %%r15\n" \
42 "movq 0x00(%%rbp), %%rax\n" \
43 "movq 0x08(%%rbp), %%rbx\n" \
44 "movq 0x10(%%rbp), %%rcx\n" \
45 "movq 0x18(%%rbp), %%rdx\n" \
46 "movq 0x20(%%rbp), %%rsi\n" \
47 "movq 0x28(%%rbp), %%rdi\n" \
48 /* Handle %rbp (0x30) later */ \
49 "naclrestsp 0x38(%%rbp), %%r15\n" \
50 "movq 0x40(%%rbp), %%r8\n" \
51 "movq 0x48(%%rbp), %%r9\n" \
52 "movq 0x50(%%rbp), %%r10\n" \
53 "movq 0x58(%%rbp), %%r11\n" \
54 "movq 0x60(%%rbp), %%r12\n" \
55 "movq 0x68(%%rbp), %%r13\n" \
56 "movq 0x70(%%rbp), %%r14\n" \
57 "naclrestbp 0x30(%%rbp), %%r15\n" \
60 : : "r"(regs) : "memory")
62 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
65 * In principle we should be able to do just "ldmia r0, {r0-lr}", but:
66 * * We have to skip r9, since the validator currently makes it
67 * read-only (though service_runtime no longer trusts its
69 * * Oddly, PNaCl/Clang seems to have problems with '{' in inline
72 * Rather than debug Clang, I'm just writing out the register
73 * restoration in the long form.
75 # define REGS_MASK_R0 "bic r0, r0, #0xc0000000\n"
76 # define ASM_WITH_REGS(regs, asm_code) \
80 /* Set CPSR (flags) register, a.k.a. APSR for user mode */ \
81 REGS_MASK_R0 "ldr r1, [r0, #0x40]\n" \
82 "msr apsr_nzcvqg, r1\n" \
83 /* Set stack pointer */ \
84 REGS_MASK_R0 "ldr r1, [r0, #0x34]\n" \
85 "bic sp, r1, #0xc0000000\n" \
86 /* Ensure later superinstructions don't cross bundle boundaries */ \
88 /* Set general purpose registers */ \
89 REGS_MASK_R0 "ldr r1, [r0, #0x04]\n" \
90 REGS_MASK_R0 "ldr r2, [r0, #0x08]\n" \
91 REGS_MASK_R0 "ldr r3, [r0, #0x0c]\n" \
92 REGS_MASK_R0 "ldr r4, [r0, #0x10]\n" \
93 REGS_MASK_R0 "ldr r5, [r0, #0x14]\n" \
94 REGS_MASK_R0 "ldr r6, [r0, #0x18]\n" \
95 REGS_MASK_R0 "ldr r7, [r0, #0x1c]\n" \
96 REGS_MASK_R0 "ldr r8, [r0, #0x20]\n" \
97 /* Skip r9, which is not supposed to be settable or readable */ \
98 REGS_MASK_R0 "ldr r10, [r0, #0x28]\n" \
99 REGS_MASK_R0 "ldr r11, [r0, #0x2c]\n" \
100 REGS_MASK_R0 "ldr r12, [r0, #0x30]\n" \
101 REGS_MASK_R0 "ldr lr, [r0, #0x38]\n" \
102 /* Lastly, restore r0 */ \
103 REGS_MASK_R0 "ldr r0, [r0, #0x00]\n" \
104 ".p2align 4\n" /* Align for whatever comes after */ \
106 : : "r"(regs) : "memory")
108 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
110 # define REGS_MASK_A0 "and $a0, $a0, $t7\n"
111 # define ASM_WITH_REGS(regs, asm_code) \
116 /* We skip setting zero register because it's unsettable. */ \
117 REGS_MASK_A0 "lw $at, 4($a0)\n" \
118 REGS_MASK_A0 "lw $v0, 8($a0)\n" \
119 REGS_MASK_A0 "lw $v1, 12($a0)\n" \
120 REGS_MASK_A0 "lw $a1, 20($a0)\n" \
121 REGS_MASK_A0 "lw $a2, 24($a0)\n" \
122 REGS_MASK_A0 "lw $a3, 28($a0)\n" \
123 REGS_MASK_A0 "lw $t0, 32($a0)\n" \
124 REGS_MASK_A0 "lw $t1, 36($a0)\n" \
125 REGS_MASK_A0 "lw $t2, 40($a0)\n" \
126 REGS_MASK_A0 "lw $t3, 44($a0)\n" \
127 REGS_MASK_A0 "lw $t4, 48($a0)\n" \
128 REGS_MASK_A0 "lw $t5, 52($a0)\n" \
129 /* We skip setting t6 and t7 because those are mask registers. */ \
130 REGS_MASK_A0 "lw $s0, 64($a0)\n" \
131 REGS_MASK_A0 "lw $s1, 68($a0)\n" \
132 REGS_MASK_A0 "lw $s2, 72($a0)\n" \
133 REGS_MASK_A0 "lw $s3, 76($a0)\n" \
134 REGS_MASK_A0 "lw $s4, 80($a0)\n" \
135 REGS_MASK_A0 "lw $s5, 84($a0)\n" \
136 REGS_MASK_A0 "lw $s6, 88($a0)\n" \
137 REGS_MASK_A0 "lw $s7, 92($a0)\n" \
138 /* We skip setting t8 because that register hold TLS index. */ \
139 REGS_MASK_A0 "lw $t9, 100($a0)\n" \
140 /* We skip setting k0 and k1 registers, they are changed by kernel. */ \
141 REGS_MASK_A0 "lw $gp, 112($a0)\n" \
142 REGS_MASK_A0 "lw $sp, 116($a0)\n" \
143 /* Value change of sp requires masking instruction. */ \
144 "and $sp, $sp, $t7\n" \
146 REGS_MASK_A0 "lw $fp, 120($a0)\n" \
147 REGS_MASK_A0 "lw $ra, 124($a0)\n" \
148 REGS_MASK_A0 "lw $a0, 16($a0)\n" \
149 ".p2align 4\n" /* Align for whatever comes after. */ \
151 : : "r"(regs) : "memory")
154 # error Unsupported architecture
158 * JUMP_WITH_REGS(regs, dest) jumps to symbol |dest| with most
159 * registers restored from |regs|, a pointer of type "struct
160 * NaClSignalContext *".
162 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
163 # define JUMP_WITH_REGS(regs, dest) ASM_WITH_REGS(regs, "jmp " #dest)
164 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
165 # define JUMP_WITH_REGS(regs, dest) ASM_WITH_REGS(regs, "b " #dest)
166 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
167 # define JUMP_WITH_REGS(regs, dest) ASM_WITH_REGS(regs, \
171 # error Unsupported architecture
174 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
177 * Normally it is possible to save x86 flags using the 'pushf'
178 * instruction. However, 'pushf' is disallowed under NaCl. Instead,
179 * we can read a subset of the flags indirectly using conditional
183 * CF (carry), PF (parity), ZF (zero), SF (sign), OF (overflow)
185 * We don't attempt to check:
186 * AF (for BCD arithmetic only, which is not allowed by the validator)
187 * TF (trap flag: not settable or observable by untrusted code)
188 * DF (direction flag: indirectly observable, but it's a hassle to do so)
190 extern const uint8_t kX86FlagBits[5];
192 /* We use 'mov' and 'lea' because they do not modify the flags. */
193 # define SAVE_X86_FLAGS_INTO_REG(reg) \
195 "jnc 0f; lea 1<<0("reg"), "reg"; 0:\n" \
196 "jnp 0f; lea 1<<2("reg"), "reg"; 0:\n" \
197 "jnz 0f; lea 1<<6("reg"), "reg"; 0:\n" \
198 "jns 0f; lea 1<<7("reg"), "reg"; 0:\n" \
199 "jno 0f; lea 1<<11("reg"), "reg"; 0:\n"
201 /* Reset flags to RESET_X86_FLAGS_VALUE without modifying any registers. */
202 #define RESET_X86_FLAGS "testl $0, %%eax\n"
203 #define RESET_X86_FLAGS_VALUE ((1 << 2) | (1 << 6))
205 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
208 * These are the only ARM CPSR bits that user code and untrusted code
209 * can read and modify, excluding the IT bits which are for Thumb-2
210 * (for If-Then-Else instructions).
212 # define REGS_ARM_USER_CPSR_FLAGS_MASK \
218 (1<<19) | (1<<18) | (1<<17) | (1<<16) /* GE bits */)
223 * REGS_SAVER_FUNC(def_func, callee_func) defines a function named
224 * def_func which saves all registers on the stack and passes them to
225 * callee_func in the form of a "struct NaClSignalContext *".
228 #define REGS_SAVER_FUNC(def_func, callee_func) \
229 void def_func(void); \
230 REGS_SAVER_FUNC_NOPROTO(def_func, callee_func)
232 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
234 # define REGS_SAVER_FUNC_NOPROTO(def_func, callee_func) \
235 void callee_func(struct NaClSignalContext *regs); \
237 ".pushsection .text, \"ax\", @progbits\n" \
239 ".global " #def_func "\n"\
241 /* Push most of "struct NaClSignalContext" in reverse order. */ \
242 "push $0\n" /* Leave space for flags */ \
243 "push $0\n" /* Leave space for prog_ctr */ \
253 SAVE_X86_FLAGS_INTO_REG("%eax") \
254 "movl %eax, 0x24(%esp)\n" \
255 /* Obtain def_func from GOT to fill prog_ctr with known value. */ \
258 "1: addl $_GLOBAL_OFFSET_TABLE_ + (1b - 0b), %eax\n" \
259 "movl " #def_func "@GOT(%eax), %eax\n" \
260 "movl %eax, 0x20(%esp)\n" \
261 /* Adjust saved %esp value to account for preceding pushes. */ \
262 "addl $5 * 4, 0x10(%esp)\n" \
263 /* Save argument to callee_func() temporarily. */ \
265 /* Align the stack pointer and leave space for an argument. */ \
268 /* Set argument to callee_func(). */ \
269 "mov %eax, (%esp)\n" \
270 "call " #callee_func "\n" \
273 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
275 # define REGS_SAVER_FUNC_NOPROTO(def_func, callee_func) \
276 void callee_func(struct NaClSignalContext *regs); \
278 ".pushsection .text, \"ax\", @progbits\n" \
280 ".global " #def_func "\n"\
282 /* Push most of "struct NaClSignalContext" in reverse order. */ \
283 "push $0\n" /* Leave space for flags */ \
284 "push $0\n" /* Leave space for prog_ctr */ \
302 SAVE_X86_FLAGS_INTO_REG("%rax") \
303 "movl %eax, 0x88(%rsp)\n" \
304 /* Fill out prog_ctr with known value */ \
305 "leaq " #def_func "(%rip), %rax\n" \
306 "movq %rax, 0x80(%rsp)\n" \
307 /* Adjust saved %rsp value to account for preceding pushes. */ \
308 "addq $10 * 8, 0x38(%rsp)\n" \
309 /* Set argument to callee_func(). */ \
310 "movl %esp, %edi\n" \
311 /* Align the stack pointer */ \
313 "addq %r15, %rsp\n" \
314 "call " #callee_func "\n" \
317 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
320 * "push {sp}" is undefined ("unpredictable") on ARM, so we move sp to
321 * a temporary register to push its original value. (Indeed, whether
322 * sp is modified before or after being written differs between QEMU
323 * and the Panda boards.)
325 # define REGS_SAVER_FUNC_NOPROTO(def_func, callee_func) \
326 void callee_func(struct NaClSignalContext *regs); \
328 ".pushsection .text, \"ax\", %progbits\n" \
330 ".global " #def_func "\n"\
332 "push {r0}\n" /* Leave space for cpsr */ \
333 "push {r0}\n" /* Leave space for prog_ctr */ \
335 /* Save r0-r12 and sp; adjust sp for the pushes above */ \
336 "add r14, sp, #0xc\n" \
337 "push {r10-r12, r14}\n" \
338 /* Push a dummy value for r9, which the tests need not compare */ \
341 /* Save the rest of struct NaClSignalContext */ \
343 /* Now save a correct prog_ctr value */ \
344 "adr r0, " #def_func "\n" \
345 "str r0, [sp, #0x3c]\n" \
346 /* Save CPSR (flags) register, a.k.a. APSR for user mode */ \
348 "str r0, [sp, #0x40]\n" \
349 /* Set argument to callee_func() */ \
351 /* Align the stack pointer */ \
352 "bic sp, sp, #0xc000000f\n" \
353 "b " #callee_func "\n" \
356 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
358 # define REGS_SAVER_FUNC_NOPROTO(def_func, callee_func) \
359 void callee_func(struct NaClSignalContext *regs); \
361 ".pushsection .text, \"ax\", %progbits\n" \
364 ".global " #def_func "\n"\
366 /* Make space on stack for all registers. */ \
367 "add $sp, $sp, -132\n" \
368 "and $sp, $sp, $t7\n"\
369 "sw $zero, 0($sp)\n" \
372 "sw $v1, 12($sp)\n" \
373 "sw $a0, 16($sp)\n" \
374 "sw $a1, 20($sp)\n" \
375 "sw $a2, 24($sp)\n" \
376 "sw $a3, 28($sp)\n" \
377 "sw $t0, 32($sp)\n" \
378 "sw $t1, 36($sp)\n" \
379 "sw $t2, 40($sp)\n" \
380 "sw $t3, 44($sp)\n" \
381 "sw $t4, 48($sp)\n" \
382 "sw $t5, 52($sp)\n" \
383 "sw $t6, 56($sp)\n" \
384 "sw $t7, 60($sp)\n" \
385 "sw $s0, 64($sp)\n" \
386 "sw $s1, 68($sp)\n" \
387 "sw $s2, 72($sp)\n" \
388 "sw $s3, 76($sp)\n" \
389 "sw $s4, 80($sp)\n" \
390 "sw $s5, 84($sp)\n" \
391 "sw $s6, 88($sp)\n" \
392 "sw $s7, 92($sp)\n" \
393 "sw $t8, 96($sp)\n" \
394 "sw $t9, 100($sp)\n" \
395 /* We skip saving k0 and k1 registers, they are changed by kernel. */ \
396 "sw $gp, 112($sp)\n" \
397 /* Store the value stack_ptr had on entry of this function. */ \
398 "add $t1, $sp, 132\n" \
399 "sw $t1, 116($sp)\n" \
400 "sw $fp, 120($sp)\n" \
401 "sw $ra, 124($sp)\n" \
402 /* Save a correct prog_ctr value. */ \
403 "lui $t1, %hi(" #def_func ")\n" \
404 "addiu $t1, $t1, %lo(" #def_func ")\n" \
405 "sw $t1, 128($sp)\n" \
406 /* Prepare argument for callee_func. */ \
408 /* Align the stack pointer. */ \
409 "sll $t1, $t7, 3\n" \
410 "and $sp, $sp, $t1\n" \
411 "and $sp, $sp, $t7\n" \
412 /* Make space on stack for convention calling registers. */ \
413 "add $sp, $sp, -16\n" \
414 "and $sp, $sp, $t7\n" \
415 /* Set $t9 to callee_func as required by ABI for PIC code. */ \
416 "lui $t9, %hi(" #callee_func ")\n" \
417 "b " #callee_func "\n" \
418 "addiu $t9, $t9, %lo(" #callee_func ")\n" \
426 # error Unsupported architecture
429 /* Initialize the register set with arbitrary test data. */
430 void RegsFillTestValues(struct NaClSignalContext *regs, int seed);
432 /* Adjust registers to follow the sandbox's constraints. */
433 void RegsApplySandboxConstraints(struct NaClSignalContext *regs);
435 /* This compares for equality all registers saved by REGS_SAVER_FUNC. */
436 void RegsAssertEqual(const struct NaClSignalContext *actual,
437 const struct NaClSignalContext *expected);
440 * Copy a NaClUserRegisterState into a NaClSignalContext, leaving
441 * trusted registers in the NaClSignalContext with unspecified values.
443 void RegsCopyFromUserRegisterState(struct NaClSignalContext *dest,
444 const NaClUserRegisterState *src);
446 /* Zero out registers that are clobbered by function calls. */
447 void RegsUnsetNonCalleeSavedRegisters(struct NaClSignalContext *regs);
450 * For a function called with register state |regs|, extract the first
451 * argument. This is useful for a function entry point defined by
454 uintptr_t RegsGetArg1(const struct NaClSignalContext *regs);