VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/cpu/cidet-app.cpp@ 98006

Last change on this file since 98006 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.1 KB
Line 
1/* $Id: cidet-app.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * CPU Instruction Decoding & Execution Tests - Ring-3 Driver Application.
4 */
5
6/*
7 * Copyright (C) 2014-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "cidet.h"
42
43#include <iprt/asm-amd64-x86.h>
44#include <iprt/buildconfig.h>
45#include <iprt/err.h>
46#include <iprt/getopt.h>
47#include <iprt/initterm.h>
48#include <iprt/mem.h>
49#include <iprt/param.h>
50#include <iprt/rand.h>
51#include <iprt/stream.h>
52#include <iprt/string.h>
53#include <iprt/test.h>
54
55#ifdef RT_OS_WINDOWS
56# include <iprt/win/windows.h>
57#else
58# define USE_SIGNALS
59# include <signal.h>
60# include <unistd.h>
61# include <sys/ucontext.h>
62#endif
63
64
65/*********************************************************************************************************************************
66* Defined Constants And Macros *
67*********************************************************************************************************************************/
68/** @def CIDET_LEAVE_GS_ALONE
69 * Leave GS alone on 64-bit darwin (gs is 0, no ldt or gdt entry to load that'll
70 * restore the lower 32-bits of the base when saving and restoring the register).
71 */
72#if (defined(RT_OS_DARWIN) && defined(RT_ARCH_AMD64)) || defined(DOXYGEN_RUNNING)
73# define CIDET_LEAVE_GS_ALONE
74#endif
75
76
77/*********************************************************************************************************************************
78* Structures and Typedefs *
79*********************************************************************************************************************************/
80/**
81 * CIDET driver app buffer.
82 */
83typedef struct CIDETAPPBUF
84{
85 /** The buffer size. */
86 size_t cb;
87 /** The normal allocation.
88 * There is a fence page before this as well as at pbNormal+cb. */
89 uint8_t *pbNormal;
90 /** The low memory allocation (32-bit addressable if 64-bit host, 16-bit
91 * addressable if 32-bit host). */
92 uint8_t *pbLow;
93 /** Set if we're using the normal buffer, clear if it's the low one. */
94 bool fUsingNormal : 1;
95 /** Set if the buffer is armed, clear if mostly accessible. */
96 bool fArmed : 1;
97 /** Set if this is a code buffer. */
98 bool fIsCode : 1;
99 /** The memory protection for the pages (RTMEM_PROT_XXX). */
100 uint8_t fDefaultProt : 3;
101 /** The memory protection for the last page (RTMEM_PROT_XXX). */
102 uint8_t fLastPageProt : 3;
103 /** The buffer index. */
104 uint16_t idxCfg;
105} CIDETAPPBUF;
106/** Pointer to a CIDET driver app buffer. */
107typedef CIDETAPPBUF *PCIDETAPPBUF;
108
109/** Number of code buffers. */
110#define CIDETAPP_CODE_BUF_COUNT 1
111/** Number of data buffers. */
112#define CIDETAPP_DATA_BUF_COUNT 1
113
114
115/**
116 * CIDET driver app instance.
117 */
118typedef struct CIDETAPP
119{
120 /** The core structure. */
121 CIDETCORE Core;
122 /** The execute return context. */
123 CIDETCPUCTX ExecuteCtx;
124 /** Code buffers (runs parallel to g_aCodeBufCfgs). */
125 CIDETAPPBUF aCodeBuffers[CIDETAPP_CODE_BUF_COUNT];
126 /** Data buffers (runs parallel to g_aDataBufCfgs). */
127 CIDETAPPBUF aDataBuffers[CIDETAPP_DATA_BUF_COUNT];
128
129 /** The lowest stack address. */
130 uint8_t *pbStackLow;
131 /** The end of the stack allocation (highest address). */
132 uint8_t *pbStackEnd;
133 /** Stack size (= pbStackEnd - pbStackLow). */
134 uint32_t cbStack;
135 /** Whether we're currently using the 'lock int3' to deal with tricky stack. */
136 bool fUsingLockedInt3;
137} CIDETAPP;
138/** Pointer to a CIDET driver app instance. */
139typedef CIDETAPP *PCIDETAPP;
140/** Pointer to a pointer to a CIDET driver app instance. */
141typedef PCIDETAPP *PPCIDETAPP;
142
143
144/*********************************************************************************************************************************
145* Global Variables *
146*********************************************************************************************************************************/
147/** The test instance handle. */
148static RTTEST g_hTest;
149/** Points to the instance data while executing, NULL if not executing or if
150 * we've already handled the first exception while executing. */
151static PCIDETAPP volatile g_pExecutingThis;
152#ifdef USE_SIGNALS
153/** The default signal mask. */
154static sigset_t g_ProcSigMask;
155/** The alternative signal stack. */
156static stack_t g_AltStack;
157#endif
158
159
160/** Code buffer configurations (parallel to CIDETAPP::aCodeBuffers). */
161static CIDETBUFCFG g_aCodeBufCfgs[CIDETAPP_CODE_BUF_COUNT] =
162{
163 {
164 "Normal",
165 CIDETBUF_PROT_RWX | CIDETBUF_DPL_3 | CIDETBUF_DPL_SAME | CIDETBUF_SEG_ER | CIDETBUF_KIND_CODE,
166 },
167};
168
169/** Data buffer configurations (parallel to CIDETAPP::aDataBuffers). */
170static CIDETBUFCFG g_aDataBufCfgs[CIDETAPP_DATA_BUF_COUNT] =
171{
172 {
173 "Normal",
174 CIDETBUF_PROT_RWX | CIDETBUF_DPL_3 | CIDETBUF_DPL_SAME | CIDETBUF_SEG_RW | CIDETBUF_KIND_DATA,
175 },
176};
177
178
179/*********************************************************************************************************************************
180* Internal Functions *
181*********************************************************************************************************************************/
182DECLASM(void) CidetAppSaveAndRestoreCtx(void);
183DECLASM(void) CidetAppRestoreCtx(PCCIDETCPUCTX pRestoreCtx);
184DECLASM(void) CidetAppExecute(PCIDETCPUCTX pSaveCtx, PCCIDETCPUCTX pRestoreCtx);
185
186
187/*
188 *
189 *
190 * Exception and signal handling.
191 * Exception and signal handling.
192 * Exception and signal handling.
193 *
194 *
195 */
196
197#ifdef RT_OS_WINDOWS
198static int CidetAppXcptFilter(EXCEPTION_POINTERS *pXcptPtrs) RT_NOTHROW_DEF
199{
200 /*
201 * Grab the this point. We expect at most one signal.
202 */
203 PCIDETAPP pThis = g_pExecutingThis;
204 g_pExecutingThis = NULL;
205 if (pThis == NULL)
206 {
207 /* we're up the infamous creek... */
208 for (;;) ExitProcess(2);
209 }
210
211 /*
212 * Gather CPU state information from the context structure.
213 */
214 CONTEXT *pSrcCtx = pXcptPtrs->ContextRecord;
215# ifdef RT_ARCH_AMD64
216 if ( (pSrcCtx->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
217 != (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
218 __debugbreak();
219 pThis->Core.ActualCtx.rip = pSrcCtx->Rip;
220 pThis->Core.ActualCtx.rfl = pSrcCtx->EFlags;
221 pThis->Core.ActualCtx.aGRegs[X86_GREG_xAX] = pSrcCtx->Rax;
222 pThis->Core.ActualCtx.aGRegs[X86_GREG_xCX] = pSrcCtx->Rcx;
223 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDX] = pSrcCtx->Rdx;
224 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBX] = pSrcCtx->Rbx;
225 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSP] = pSrcCtx->Rsp;
226 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBP] = pSrcCtx->Rbp;
227 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSI] = pSrcCtx->Rsi;
228 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDI] = pSrcCtx->Rdi;
229 pThis->Core.ActualCtx.aGRegs[X86_GREG_x8] = pSrcCtx->R8;
230 pThis->Core.ActualCtx.aGRegs[X86_GREG_x9] = pSrcCtx->R9;
231 pThis->Core.ActualCtx.aGRegs[X86_GREG_x10] = pSrcCtx->R10;
232 pThis->Core.ActualCtx.aGRegs[X86_GREG_x11] = pSrcCtx->R11;
233 pThis->Core.ActualCtx.aGRegs[X86_GREG_x12] = pSrcCtx->R12;
234 pThis->Core.ActualCtx.aGRegs[X86_GREG_x13] = pSrcCtx->R13;
235 pThis->Core.ActualCtx.aGRegs[X86_GREG_x14] = pSrcCtx->R14;
236 pThis->Core.ActualCtx.aGRegs[X86_GREG_x15] = pSrcCtx->R15;
237 pThis->Core.ActualCtx.aSRegs[X86_SREG_ES] = pSrcCtx->SegEs;
238 pThis->Core.ActualCtx.aSRegs[X86_SREG_CS] = pSrcCtx->SegCs;
239 pThis->Core.ActualCtx.aSRegs[X86_SREG_SS] = pSrcCtx->SegSs;
240 pThis->Core.ActualCtx.aSRegs[X86_SREG_DS] = pSrcCtx->SegDs;
241 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = pSrcCtx->SegFs;
242 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = pSrcCtx->SegGs;
243 if (pSrcCtx->ContextFlags & CONTEXT_FLOATING_POINT)
244 {
245 /* ... */
246 }
247 if (pSrcCtx->ContextFlags & CONTEXT_DEBUG_REGISTERS)
248 {
249 /* ... */
250 }
251
252# elif defined(RT_ARCH_X86)
253 if ( (pSrcCtx->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
254 != (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
255 __debugbreak();
256 pThis->Core.ActualCtx.rip = pSrcCtx->Eip;
257 pThis->Core.ActualCtx.rfl = pSrcCtx->EFlags;
258 pThis->Core.ActualCtx.aGRegs[X86_GREG_xAX] = pSrcCtx->Eax;
259 pThis->Core.ActualCtx.aGRegs[X86_GREG_xCX] = pSrcCtx->Ecx;
260 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDX] = pSrcCtx->Edx;
261 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBX] = pSrcCtx->Ebx;
262 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSP] = pSrcCtx->Esp;
263 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBP] = pSrcCtx->Ebp;
264 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSI] = pSrcCtx->Esi;
265 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDI] = pSrcCtx->Edi;
266 pThis->Core.ActualCtx.aGRegs[X86_GREG_x8] = 0;
267 pThis->Core.ActualCtx.aGRegs[X86_GREG_x9] = 0;
268 pThis->Core.ActualCtx.aGRegs[X86_GREG_x10] = 0;
269 pThis->Core.ActualCtx.aGRegs[X86_GREG_x11] = 0;
270 pThis->Core.ActualCtx.aGRegs[X86_GREG_x12] = 0;
271 pThis->Core.ActualCtx.aGRegs[X86_GREG_x13] = 0;
272 pThis->Core.ActualCtx.aGRegs[X86_GREG_x14] = 0;
273 pThis->Core.ActualCtx.aGRegs[X86_GREG_x15] = 0;
274 pThis->Core.ActualCtx.aSRegs[X86_SREG_ES] = pSrcCtx->SegEs;
275 pThis->Core.ActualCtx.aSRegs[X86_SREG_CS] = pSrcCtx->SegCs;
276 pThis->Core.ActualCtx.aSRegs[X86_SREG_SS] = pSrcCtx->SegSs;
277 pThis->Core.ActualCtx.aSRegs[X86_SREG_DS] = pSrcCtx->SegDs;
278 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = pSrcCtx->SegFs;
279 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = pSrcCtx->SegGs;
280 if (pSrcCtx->ContextFlags & CONTEXT_FLOATING_POINT)
281 {
282 /* ... */
283 }
284 if (pSrcCtx->ContextFlags & CONTEXT_EXTENDED_REGISTERS)
285 {
286 /* ... */
287 }
288 if (pSrcCtx->ContextFlags & CONTEXT_DEBUG_REGISTERS)
289 {
290 /* ... */
291 }
292# else
293# error "Not supported"
294# endif
295
296 /*
297 * Add/Adjust CPU state information according to the exception code.
298 */
299 pThis->Core.ActualCtx.uErr = UINT64_MAX;
300 switch (pXcptPtrs->ExceptionRecord->ExceptionCode)
301 {
302 case EXCEPTION_INT_DIVIDE_BY_ZERO:
303 pThis->Core.ActualCtx.uXcpt = X86_XCPT_DE;
304 break;
305 case EXCEPTION_SINGLE_STEP:
306 pThis->Core.ActualCtx.uXcpt = X86_XCPT_DB;
307 break;
308 case EXCEPTION_BREAKPOINT:
309 pThis->Core.ActualCtx.uXcpt = X86_XCPT_BP;
310 break;
311 case EXCEPTION_INT_OVERFLOW:
312 pThis->Core.ActualCtx.uXcpt = X86_XCPT_OF;
313 break;
314 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
315 pThis->Core.ActualCtx.uXcpt = X86_XCPT_BR;
316 break;
317 case EXCEPTION_ILLEGAL_INSTRUCTION:
318 pThis->Core.ActualCtx.uXcpt = X86_XCPT_UD;
319 break;
320
321 case EXCEPTION_PRIV_INSTRUCTION:
322 pThis->Core.ActualCtx.uXcpt = X86_XCPT_GP;
323 pThis->Core.ActualCtx.uErr = 0;
324 break;
325
326 case EXCEPTION_ACCESS_VIOLATION:
327 {
328 pThis->Core.ActualCtx.uXcpt = X86_XCPT_PF;
329 pThis->Core.ActualCtx.cr2 = pXcptPtrs->ExceptionRecord->ExceptionInformation[1];
330 pThis->Core.ActualCtx.uErr = 0;
331 if (pXcptPtrs->ExceptionRecord->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT)
332 pThis->Core.ActualCtx.uErr = X86_TRAP_PF_RW;
333 else if (pXcptPtrs->ExceptionRecord->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
334 pThis->Core.ActualCtx.uErr = X86_TRAP_PF_ID;
335 else if (pXcptPtrs->ExceptionRecord->ExceptionInformation[0] != EXCEPTION_READ_FAULT)
336 AssertFatalFailed();
337
338 MEMORY_BASIC_INFORMATION MemInfo = {0};
339 if (VirtualQuery((PVOID)pXcptPtrs->ExceptionRecord->ExceptionInformation[1], &MemInfo, sizeof(MemInfo)) > 0)
340 switch (MemInfo.Protect & 0xff)
341 {
342 case PAGE_NOACCESS:
343 break;
344 case PAGE_READONLY:
345 case PAGE_READWRITE:
346 case PAGE_WRITECOPY:
347 case PAGE_EXECUTE:
348 case PAGE_EXECUTE_READ:
349 case PAGE_EXECUTE_READWRITE:
350 case PAGE_EXECUTE_WRITECOPY:
351 pThis->Core.ActualCtx.uErr |= X86_TRAP_PF_P;
352 break;
353 default:
354 AssertFatalFailed();
355 }
356 break;
357 }
358
359 case EXCEPTION_FLT_DENORMAL_OPERAND:
360 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
361 case EXCEPTION_FLT_INEXACT_RESULT:
362 case EXCEPTION_FLT_INVALID_OPERATION:
363 case EXCEPTION_FLT_OVERFLOW:
364 case EXCEPTION_FLT_STACK_CHECK:
365 case EXCEPTION_FLT_UNDERFLOW:
366 pThis->Core.ActualCtx.uXcpt = X86_XCPT_MF;
367 break;
368
369 case EXCEPTION_DATATYPE_MISALIGNMENT:
370 pThis->Core.ActualCtx.uXcpt = X86_XCPT_AC;
371 break;
372
373 default:
374 pThis->Core.ActualCtx.uXcpt = pXcptPtrs->ExceptionRecord->ExceptionCode;
375 break;
376 }
377
378 /*
379 * Our own personal long jump implementation.
380 */
381 CidetAppRestoreCtx(&pThis->ExecuteCtx);
382
383 /* Won't return...*/
384 return EXCEPTION_EXECUTE_HANDLER;
385}
386
387
388/**
389 * Vectored exception handler.
390 *
391 * @returns Long jumps or terminates the process.
392 * @param pXcptPtrs The exception record.
393 */
394static LONG CALLBACK CidetAppVectoredXcptHandler(EXCEPTION_POINTERS *pXcptPtrs) RT_NOTHROW_DEF
395{
396 RTStrmPrintf(g_pStdErr, "CidetAppVectoredXcptHandler!\n");
397 CidetAppXcptFilter(pXcptPtrs);
398
399 /* won't get here. */
400 return EXCEPTION_CONTINUE_SEARCH;
401}
402
403
404/**
405 * Unhandled exception filter.
406 *
407 * @returns Long jumps or terminates the process.
408 * @param pXcptPtrs The exception record.
409 */
410static LONG CALLBACK CidetAppUnhandledXcptFilter(EXCEPTION_POINTERS *pXcptPtrs) RT_NOTHROW_DEF
411{
412 RTStrmPrintf(g_pStdErr, "CidetAppUnhandledXcptFilter!\n");
413 CidetAppXcptFilter(pXcptPtrs);
414
415 /* won't get here. */
416 return EXCEPTION_CONTINUE_SEARCH;
417}
418
419
420#elif defined(USE_SIGNALS)
421/**
422 * Signal handler.
423 */
424static void CidetAppSigHandler(int iSignal, siginfo_t *pSigInfo, void *pvCtx)
425{
426# if 1
427 if ( !g_pExecutingThis
428 || !g_pExecutingThis->fUsingLockedInt3
429 || iSignal != SIGILL)
430 {
431 RTStrmPrintf(g_pStdErr, "signal %d pSigInfo=%p pvCtx=%p", iSignal, pSigInfo, pvCtx);
432 if (pSigInfo)
433 RTStrmPrintf(g_pStdErr, " si_addr=%p si_code=%#x sival_ptr=%p sival_int=%d",
434 pSigInfo->si_addr, pSigInfo->si_code, pSigInfo->si_value.sival_ptr, pSigInfo->si_value.sival_int);
435 RTStrmPrintf(g_pStdErr, "\n");
436 }
437# endif
438
439 /*
440 * Grab the this point. We expect at most one signal.
441 */
442 PCIDETAPP pThis = g_pExecutingThis;
443 g_pExecutingThis = NULL;
444 if (pThis == NULL)
445 {
446 /* we're up the infamous creek... */
447 RTStrmPrintf(g_pStdErr, "Creek time!\n");
448 for (;;) _exit(2);
449 }
450
451 /*
452 * Gather all the CPU state information available.
453 */
454# ifdef RT_OS_LINUX
455 ucontext_t const *pCtx = (ucontext_t const *)pvCtx;
456# ifdef RT_ARCH_AMD64
457
458 pThis->Core.ActualCtx.aGRegs[X86_GREG_xAX] = pCtx->uc_mcontext.gregs[REG_RAX];
459 pThis->Core.ActualCtx.aGRegs[X86_GREG_xCX] = pCtx->uc_mcontext.gregs[REG_RCX];
460 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDX] = pCtx->uc_mcontext.gregs[REG_RDX];
461 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBX] = pCtx->uc_mcontext.gregs[REG_RBX];
462 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSP] = pCtx->uc_mcontext.gregs[REG_RSP];
463 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBP] = pCtx->uc_mcontext.gregs[REG_RBP];
464 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSI] = pCtx->uc_mcontext.gregs[REG_RSI];
465 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDI] = pCtx->uc_mcontext.gregs[REG_RDI];
466 pThis->Core.ActualCtx.aGRegs[X86_GREG_x8 ] = pCtx->uc_mcontext.gregs[REG_R8];
467 pThis->Core.ActualCtx.aGRegs[X86_GREG_x9 ] = pCtx->uc_mcontext.gregs[REG_R9];
468 pThis->Core.ActualCtx.aGRegs[X86_GREG_x10] = pCtx->uc_mcontext.gregs[REG_R10];
469 pThis->Core.ActualCtx.aGRegs[X86_GREG_x11] = pCtx->uc_mcontext.gregs[REG_R11];
470 pThis->Core.ActualCtx.aGRegs[X86_GREG_x12] = pCtx->uc_mcontext.gregs[REG_R12];
471 pThis->Core.ActualCtx.aGRegs[X86_GREG_x13] = pCtx->uc_mcontext.gregs[REG_R13];
472 pThis->Core.ActualCtx.aGRegs[X86_GREG_x14] = pCtx->uc_mcontext.gregs[REG_R14];
473 pThis->Core.ActualCtx.aGRegs[X86_GREG_x15] = pCtx->uc_mcontext.gregs[REG_R15];
474 pThis->Core.ActualCtx.aSRegs[X86_SREG_CS] = RT_LO_U16((uint32_t)pCtx->uc_mcontext.gregs[REG_CSGSFS]);
475 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = RT_HI_U16((uint32_t)pCtx->uc_mcontext.gregs[REG_CSGSFS]);
476 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = (uint16_t)RT_HI_U32(pCtx->uc_mcontext.gregs[REG_CSGSFS]);
477 pThis->Core.ActualCtx.aSRegs[X86_SREG_DS] = ASMGetDS();
478 pThis->Core.ActualCtx.aSRegs[X86_SREG_ES] = ASMGetES();
479 pThis->Core.ActualCtx.aSRegs[X86_SREG_SS] = ASMGetSS();
480 pThis->Core.ActualCtx.rip = pCtx->uc_mcontext.gregs[REG_RIP];
481 pThis->Core.ActualCtx.rfl = pCtx->uc_mcontext.gregs[REG_EFL];
482 pThis->Core.ActualCtx.cr2 = pCtx->uc_mcontext.gregs[REG_CR2];
483 pThis->Core.ActualCtx.uXcpt = pCtx->uc_mcontext.gregs[REG_TRAPNO];
484 pThis->Core.ActualCtx.uErr = pCtx->uc_mcontext.gregs[REG_ERR];
485
486 /* Fudge the FS and GS registers as setup_sigcontext returns 0. */
487 if (pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] == 0)
488 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = pThis->Core.ExpectedCtx.aSRegs[X86_SREG_FS];
489 if (pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] == 0)
490 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = pThis->Core.ExpectedCtx.aSRegs[X86_SREG_GS];
491
492# elif defined(RT_ARCH_X86)
493 pThis->Core.ActualCtx.aGRegs[X86_GREG_xAX] = pCtx->uc_mcontext.gregs[REG_EAX];
494 pThis->Core.ActualCtx.aGRegs[X86_GREG_xCX] = pCtx->uc_mcontext.gregs[REG_ECX];
495 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDX] = pCtx->uc_mcontext.gregs[REG_EDX];
496 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBX] = pCtx->uc_mcontext.gregs[REG_EBX];
497 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSP] = pCtx->uc_mcontext.gregs[REG_ESP];
498 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBP] = pCtx->uc_mcontext.gregs[REG_EBP];
499 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSI] = pCtx->uc_mcontext.gregs[REG_ESI];
500 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDI] = pCtx->uc_mcontext.gregs[REG_EDI];
501 pThis->Core.ActualCtx.aSRegs[X86_SREG_CS] = pCtx->uc_mcontext.gregs[REG_CS];
502 pThis->Core.ActualCtx.aSRegs[X86_SREG_DS] = pCtx->uc_mcontext.gregs[REG_DS];
503 pThis->Core.ActualCtx.aSRegs[X86_SREG_ES] = pCtx->uc_mcontext.gregs[REG_ES];
504 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = pCtx->uc_mcontext.gregs[REG_FS];
505 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = pCtx->uc_mcontext.gregs[REG_GS];
506 pThis->Core.ActualCtx.aSRegs[X86_SREG_SS] = pCtx->uc_mcontext.gregs[REG_SS];
507 pThis->Core.ActualCtx.rip = pCtx->uc_mcontext.gregs[REG_EIP];
508 pThis->Core.ActualCtx.rfl = pCtx->uc_mcontext.gregs[REG_EFL];
509 pThis->Core.ActualCtx.cr2 = pCtx->uc_mcontext.cr2;
510 pThis->Core.ActualCtx.uXcpt = pCtx->uc_mcontext.gregs[REG_TRAPNO];
511 pThis->Core.ActualCtx.uErr = pCtx->uc_mcontext.gregs[REG_ERR];
512
513# else
514# error "Unsupported arch."
515# endif
516
517 /* Adjust uErr. */
518 switch (pThis->Core.ActualCtx.uXcpt)
519 {
520 case X86_XCPT_TS:
521 case X86_XCPT_NP:
522 case X86_XCPT_SS:
523 case X86_XCPT_GP:
524 case X86_XCPT_PF:
525 case X86_XCPT_AC:
526 case X86_XCPT_DF:
527 break;
528 default:
529 pThis->Core.ActualCtx.uErr = UINT64_MAX;
530 break;
531 }
532
533# if 0
534 /* Fudge the resume flag (it's probably always set here). */
535 if ( (pThis->Core.ActualCtx.rfl & X86_EFL_RF)
536 && !(pThis->Core.ExpectedCtx.rfl & X86_EFL_RF))
537 pThis->Core.ActualCtx.rfl &= ~X86_EFL_RF;
538# endif
539
540# else
541 /** @todo */
542# endif
543
544
545 /*
546 * Check for the 'lock int3' instruction used for tricky stacks.
547 */
548 if ( pThis->fUsingLockedInt3
549 && pThis->Core.ActualCtx.uXcpt == X86_XCPT_UD
550 && pThis->Core.ActualCtx.rip == pThis->Core.CodeBuf.uEffBufAddr - pThis->Core.CodeBuf.offSegBase
551 + pThis->Core.CodeBuf.offActive + pThis->Core.CodeBuf.cbActive )
552 {
553 pThis->Core.ActualCtx.uXcpt = UINT32_MAX;
554 Assert(pThis->Core.ActualCtx.uErr == UINT64_MAX);
555 pThis->Core.ActualCtx.rfl &= ~X86_EFL_RF;
556 }
557
558 /*
559 * Jump back to CidetAppCbExecute.
560 */
561 CidetAppRestoreCtx(&pThis->ExecuteCtx);
562}
563#endif
564
565
566
567/*
568 *
569 * Buffer handling
570 * Buffer handling
571 * Buffer handling
572 *
573 *
574 */
575
576static int cidetAppAllocateAndConfigureOneBuffer(PCIDETAPP pThis, PCIDETAPPBUF pBuf, uint16_t idxBuf, bool fIsCode,
577 uint32_t fFlags)
578{
579 RT_NOREF_PV(pThis);
580 static uint8_t const s_afBufProtToDefaultMemProt[] =
581 {
582 /* [0] = */ RTMEM_PROT_NONE,
583 /* [1] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
584 /* [2] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
585 /* [3] = */ RTMEM_PROT_READ | RTMEM_PROT_EXEC,
586 /* [4] = */ RTMEM_PROT_READ,
587 /* [5] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
588 /* [6] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
589 /* [7] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
590 /* [8] = */ RTMEM_PROT_NONE,
591 /* [9] = */ RTMEM_PROT_NONE,
592 /* [10] = */ RTMEM_PROT_NONE,
593 /* [11] = */ RTMEM_PROT_NONE,
594 /* [12] = */ RTMEM_PROT_NONE,
595 /* [13] = */ RTMEM_PROT_NONE,
596 /* [14] = */ RTMEM_PROT_NONE,
597 /* [15] = */ RTMEM_PROT_NONE,
598 };
599 static uint8_t const s_afBufProtToLastPageMemProt[] =
600 {
601 /* [0] = */ RTMEM_PROT_NONE,
602 /* [1] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
603 /* [2] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
604 /* [3] = */ RTMEM_PROT_READ | RTMEM_PROT_EXEC,
605 /* [4] = */ RTMEM_PROT_READ,
606 /* [5] = */ RTMEM_PROT_NONE,
607 /* [6] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
608 /* [7] = */ RTMEM_PROT_READ,
609 /* [8] = */ RTMEM_PROT_NONE,
610 /* [9] = */ RTMEM_PROT_NONE,
611 /* [10] = */ RTMEM_PROT_NONE,
612 /* [11] = */ RTMEM_PROT_NONE,
613 /* [12] = */ RTMEM_PROT_NONE,
614 /* [13] = */ RTMEM_PROT_NONE,
615 /* [14] = */ RTMEM_PROT_NONE,
616 /* [15] = */ RTMEM_PROT_NONE,
617 };
618
619 int rc;
620 Assert(CIDETBUF_IS_CODE(fFlags) == fIsCode);
621 pBuf->fIsCode = fIsCode;
622 pBuf->idxCfg = idxBuf;
623 pBuf->fUsingNormal = true;
624 pBuf->fDefaultProt = s_afBufProtToDefaultMemProt[fFlags & CIDETBUF_PROT_MASK];
625 pBuf->fLastPageProt = s_afBufProtToLastPageMemProt[fFlags & CIDETBUF_PROT_MASK];
626 if (pBuf->fDefaultProt != RTMEM_PROT_NONE)
627 {
628 /*
629 * Allocate a 3 page buffer plus two fence pages.
630 */
631 pBuf->cb = fIsCode ? CIDET_CODE_BUF_SIZE : CIDET_DATA_BUF_SIZE;
632 pBuf->pbNormal = (uint8_t *)RTMemPageAlloc(PAGE_SIZE + pBuf->cb + PAGE_SIZE);
633 if (pBuf->pbNormal)
634 {
635 memset(pBuf->pbNormal, 0x55, PAGE_SIZE);
636 memset(pBuf->pbNormal + PAGE_SIZE, 0xcc, pBuf->cb);
637 memset(pBuf->pbNormal + PAGE_SIZE + pBuf->cb, 0x77, PAGE_SIZE);
638
639 /* Set up fence pages. */
640 rc = RTMemProtect(pBuf->pbNormal, PAGE_SIZE, RTMEM_PROT_NONE); /* fence */
641 if (RT_SUCCESS(rc))
642 rc = RTMemProtect(pBuf->pbNormal + PAGE_SIZE + pBuf->cb, PAGE_SIZE, RTMEM_PROT_NONE); /* fence */
643 pBuf->pbNormal += PAGE_SIZE;
644
645 /* Default protection + read + write. */
646 if (RT_SUCCESS(rc))
647 rc = RTMemProtect(pBuf->pbNormal, pBuf->cb, pBuf->fDefaultProt | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
648
649 /*
650 * Allocate a low memory buffer or LDT if necessary.
651 */
652 if ( RT_SUCCESS(rc)
653 && (uintptr_t)pBuf->pbNormal + pBuf->cb > RT_BIT_64(sizeof(uintptr_t) / 2 * 8))
654 {
655 /** @todo Buffers for the other addressing mode. */
656 pBuf->pbLow = NULL;
657 }
658 else
659 pBuf->pbLow = pBuf->pbNormal;
660 if (RT_SUCCESS(rc))
661 return VINF_SUCCESS;
662
663 }
664 else
665 rc = RTTestIFailedRc(VERR_NO_PAGE_MEMORY, "Error allocating three pages.");
666 }
667 else
668 rc = RTTestIFailedRc(VERR_NO_PAGE_MEMORY, "Unsupported buffer config: fFlags=%#x, idxBuf=%u", fFlags, idxBuf);
669 return rc;
670}
671
672
673static void CidetAppDeleteBuffer(PCIDETAPPBUF pBuf)
674{
675 RTMemProtect(pBuf->pbNormal - PAGE_SIZE, PAGE_SIZE + pBuf->cb + PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
676 RTMemPageFree(pBuf->pbNormal - PAGE_SIZE, PAGE_SIZE + pBuf->cb + PAGE_SIZE);
677 if (pBuf->pbLow != pBuf->pbNormal && pBuf->pbLow)
678 {
679 RTMemProtect(pBuf->pbLow, pBuf->cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
680 RTMemFreeEx(pBuf->pbLow, pBuf->cb);
681 }
682}
683
684
685static bool CidetAppArmBuf(PCIDETAPP pThis, PCIDETAPPBUF pAppBuf)
686{
687 RT_NOREF_PV(pThis);
688 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
689 if (pAppBuf->fLastPageProt == pAppBuf->fDefaultProt)
690 {
691 if ((pAppBuf->fDefaultProt & (RTMEM_PROT_READ | RTMEM_PROT_WRITE)) != (RTMEM_PROT_READ | RTMEM_PROT_WRITE))
692 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf, pAppBuf->cb, pAppBuf->fDefaultProt), VINF_SUCCESS, false);
693 }
694 else
695 {
696 if ((pAppBuf->fDefaultProt & (RTMEM_PROT_READ | RTMEM_PROT_WRITE)) != (RTMEM_PROT_READ | RTMEM_PROT_WRITE))
697 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf, pAppBuf->cb - PAGE_SIZE, pAppBuf->fDefaultProt), VINF_SUCCESS, false);
698 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf + pAppBuf->cb - PAGE_SIZE, PAGE_SIZE, pAppBuf->fLastPageProt),
699 VINF_SUCCESS, false);
700 }
701 pAppBuf->fArmed = true;
702 return true;
703}
704
705
706static bool CidetAppDearmBuf(PCIDETAPP pThis, PCIDETAPPBUF pAppBuf)
707{
708 RT_NOREF_PV(pThis);
709 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
710 int rc = RTMemProtect(pbUsingBuf, pAppBuf->cb, pAppBuf->fDefaultProt | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
711 if (RT_FAILURE(rc))
712 {
713 RTTestIFailed("RTMemProtect failed on %s buf #%u: %Rrc", pAppBuf->fIsCode ? "code" : "data", pAppBuf->idxCfg, rc);
714 return false;
715 }
716 pAppBuf->fArmed = false;
717 return true;
718}
719
720
721/**
722 * @interface_method_impl{CIDETCORE,pfnReInitDataBuf}
723 */
724static DECLCALLBACK(bool) CidetAppCbReInitDataBuf(PCIDETCORE pThis, PCIDETBUF pBuf)
725{
726 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
727 PCIDETAPPBUF pAppBuf = &pThisApp->aDataBuffers[pBuf->idxCfg];
728 Assert(CIDETBUF_IS_DATA(pBuf->pCfg->fFlags));
729
730 /*
731 * De-arm the buffer.
732 */
733 if (pAppBuf->fArmed)
734 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
735 return false;
736
737 /*
738 * Check the allocation requirements.
739 */
740 if (RT_UNLIKELY((size_t)pBuf->off + pBuf->cb > pAppBuf->cb))
741 {
742 RTTestIFailed("Buffer too small; off=%#x cb=%#x pAppBuf->cb=%#x (%s)",
743 pBuf->off, pBuf->cb, pAppBuf->cb, pBuf->pCfg->pszName);
744 return false;
745 }
746
747 /*
748 * Do we need to use the low buffer? Check that we have one, if we need it.
749 */
750 bool fUseNormal = pThis->cbAddrMode == ARCH_BITS / 8;
751 if (!fUseNormal && !pAppBuf->pbLow)
752 return false;
753
754 /*
755 * Update the state.
756 */
757 pAppBuf->fUsingNormal = fUseNormal;
758
759 pBuf->offActive = pBuf->off;
760 pBuf->cbActive = pBuf->cb;
761 pBuf->cbPrologue = 0;
762 pBuf->cbEpilogue = 0;
763 pBuf->uSeg = UINT32_MAX;
764 pBuf->cbActiveSegLimit = UINT64_MAX;
765 pBuf->uSegBase = 0;
766 if (fUseNormal)
767 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbNormal;
768 else
769 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbLow;
770
771 return true;
772}
773
774
775/**
776 * @interface_method_impl{CIDETCORE,pfnSetupDataBuf}
777 */
778static DECLCALLBACK(bool) CidetAppCbSetupDataBuf(PCIDETCORE pThis, PCIDETBUF pBuf, void const *pvSrc)
779{
780 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
781 PCIDETAPPBUF pAppBuf = &pThisApp->aDataBuffers[pBuf->idxCfg];
782 Assert(CIDETBUF_IS_DATA(pBuf->pCfg->fFlags));
783 Assert(!pAppBuf->fArmed);
784
785
786 /*
787 * Copy over the data.
788 */
789 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
790 memcpy(pbUsingBuf + pBuf->offActive, pvSrc, pBuf->cbActive);
791
792 /*
793 * Arm the buffer.
794 */
795 return CidetAppArmBuf(pThisApp, pAppBuf);
796}
797
798
799/**
800 * @interface_method_impl{CIDETCORE,pfnIsBufEqual}
801 */
802static DECLCALLBACK(bool) CidetAppCbIsBufEqual(PCIDETCORE pThis, struct CIDETBUF *pBuf, void const *pvExpected)
803{
804 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
805 PCIDETAPPBUF pAppBuf = CIDETBUF_IS_CODE(pBuf->pCfg->fFlags)
806 ? &pThisApp->aCodeBuffers[pBuf->idxCfg]
807 : &pThisApp->aDataBuffers[pBuf->idxCfg];
808
809 /*
810 * Disarm the buffer if we can't read it all.
811 */
812 if ( pAppBuf->fArmed
813 && ( !(pAppBuf->fLastPageProt & RTMEM_PROT_READ)
814 || !(pAppBuf->fDefaultProt & RTMEM_PROT_READ)) )
815 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
816 return false;
817
818 /*
819 * Do the comparing.
820 */
821 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
822 if (memcmp(pbUsingBuf + pBuf->offActive, pvExpected, pBuf->cbActive) != 0)
823 {
824 /** @todo RTMEM_PROT_NONE may kill content on some hosts... */
825 return false;
826 }
827
828 /** @todo check padding. */
829 return true;
830}
831
832
833/*
834 *
835 * Code buffer, prologue, epilogue, and execution.
836 * Code buffer, prologue, epilogue, and execution.
837 * Code buffer, prologue, epilogue, and execution.
838 *
839 *
840 */
841
842
843/**
844 * @interface_method_impl{CIDETCORE,pfnReInitCodeBuf}
845 */
846static DECLCALLBACK(bool) CidetAppCbReInitCodeBuf(PCIDETCORE pThis, PCIDETBUF pBuf)
847{
848 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
849 PCIDETAPPBUF pAppBuf = &pThisApp->aCodeBuffers[pBuf->idxCfg];
850 Assert(CIDETBUF_IS_CODE(pBuf->pCfg->fFlags));
851 Assert(pAppBuf->fUsingNormal);
852
853 /*
854 * De-arm the buffer.
855 */
856 if (pAppBuf->fArmed)
857 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
858 return false;
859
860 /*
861 * Determin the prologue and epilogue sizes.
862 */
863 uint16_t cbPrologue = 0;
864 uint16_t cbEpilogue = ARCH_BITS == 64 ? 0x56 : 0x4e;
865 if (pThis->InCtx.fTrickyStack)
866 cbEpilogue = 16;
867
868 /*
869 * Check the allocation requirements.
870 */
871 if (RT_UNLIKELY( cbPrologue > pBuf->off
872 || (size_t)pBuf->off + pBuf->cb + cbEpilogue > pAppBuf->cb))
873 {
874 RTTestIFailed("Buffer too small; off=%#x cb=%#x cbPro=%#x cbEpi=%#x pAppBuf->cb=%#x (%s)",
875 pBuf->off, pBuf->cb, cbPrologue, cbEpilogue, pAppBuf->cb, pBuf->pCfg->pszName);
876 return false;
877 }
878
879 /*
880 * Update the state.
881 */
882 pAppBuf->fUsingNormal = true;
883
884 pBuf->cbActive = pBuf->cb;
885 pBuf->offActive = pBuf->off;
886 pBuf->cbPrologue = cbPrologue;
887 pBuf->cbEpilogue = cbEpilogue;
888 pBuf->uSeg = UINT32_MAX;
889 pBuf->cbActiveSegLimit = UINT64_MAX;
890 pBuf->uSegBase = 0;
891 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbNormal;
892
893 return true;
894}
895
896
897/**
898 * @interface_method_impl{CIDETCORE,pfnSetupCodeBuf}
899 */
900static DECLCALLBACK(bool) CidetAppCbSetupCodeBuf(PCIDETCORE pThis, PCIDETBUF pBuf, void const *pvInstr)
901{
902 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
903 PCIDETAPPBUF pAppBuf =&pThisApp->aCodeBuffers[pBuf->idxCfg];
904 Assert(CIDETBUF_IS_CODE(pBuf->pCfg->fFlags));
905 Assert(pAppBuf->fUsingNormal);
906 Assert(!pAppBuf->fArmed);
907
908 /*
909 * Emit prologue code.
910 */
911 uint8_t *pbDst = pAppBuf->pbNormal + pBuf->offActive - pBuf->cbPrologue;
912
913 /*
914 * Copy over the code.
915 */
916 Assert(pbDst == &pAppBuf->pbNormal[pBuf->offActive]);
917 memcpy(pbDst, pvInstr, pBuf->cbActive);
918 pbDst += pBuf->cbActive;
919
920 /*
921 * Emit epilogue code.
922 */
923 if (!pThis->InCtx.fTrickyStack)
924 {
925 /*
926 * The stack is reasonably good, do minimal work.
927 *
928 * Note! Ideally, we would just fill in 16 int3s here and check that
929 * we hit the first right one. However, if we wish to run this
930 * code with IEM, we better skip unnecessary trips to ring-0.
931 */
932 uint8_t * const pbStartEpilogue = pbDst;
933
934 /* jmp $+6 */
935 *pbDst++ = 0xeb;
936 *pbDst++ = 0x06; /* This is a push es, so if the decoder is one off, we'll hit the int 3 below. */
937
938 /* Six int3s for trapping incorrectly decoded instructions. */
939 *pbDst++ = 0xcc;
940 *pbDst++ = 0xcc;
941 *pbDst++ = 0xcc;
942 *pbDst++ = 0xcc;
943 *pbDst++ = 0xcc;
944 *pbDst++ = 0xcc;
945
946 /* push rip / call $+0 */
947 *pbDst++ = 0xe8;
948 *pbDst++ = 0x00;
949 *pbDst++ = 0x00;
950 *pbDst++ = 0x00;
951 *pbDst++ = 0x00;
952 uint8_t offRipAdjust = (uint8_t)(uintptr_t)(pbStartEpilogue - pbDst);
953
954 /* push xCX */
955 *pbDst++ = 0x51;
956
957 /* mov xCX, [xSP + xCB] */
958 *pbDst++ = 0x48;
959 *pbDst++ = 0x8b;
960 *pbDst++ = 0x4c;
961 *pbDst++ = 0x24;
962 *pbDst++ = sizeof(uintptr_t);
963
964 /* lea xCX, [xCX - 24] */
965 *pbDst++ = 0x48;
966 *pbDst++ = 0x8d;
967 *pbDst++ = 0x49;
968 *pbDst++ = offRipAdjust;
969
970 /* mov xCX, [xSP + xCB] */
971 *pbDst++ = 0x48;
972 *pbDst++ = 0x89;
973 *pbDst++ = 0x4c;
974 *pbDst++ = 0x24;
975 *pbDst++ = sizeof(uintptr_t);
976
977 /* mov xCX, &pThis->ActualCtx */
978#ifdef RT_ARCH_AMD64
979 *pbDst++ = 0x48;
980#endif
981 *pbDst++ = 0xb9;
982 *(uintptr_t *)pbDst = (uintptr_t)&pThisApp->Core.ActualCtx;
983 pbDst += sizeof(uintptr_t);
984
985 /* pop [ss:rcx + ActualCtx.aGRegs[X86_GREG_xCX]] */
986 *pbDst++ = 0x36;
987 *pbDst++ = 0x8f;
988 *pbDst++ = 0x41;
989 *pbDst++ = RT_UOFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xCX]);
990 Assert(RT_UOFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xCX]) < 0x7f);
991
992 /* mov [ss:rcx + ActualCtx.aGRegs[X86_GREG_xDX]], rdx */
993 *pbDst++ = 0x36;
994#ifdef RT_ARCH_AMD64
995 *pbDst++ = 0x48;
996#endif
997 *pbDst++ = 0x89;
998 *pbDst++ = 0x51;
999 *pbDst++ = RT_UOFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xDX]);
1000 Assert(RT_UOFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xDX]) < 0x7f);
1001
1002 /* mov [ss:rcx + ActualCtx.aSRegs[X86_GREG_DS]], ds */
1003 *pbDst++ = 0x36;
1004 *pbDst++ = 0x8c;
1005 *pbDst++ = 0x99;
1006 *(uint32_t *)pbDst = RT_UOFFSETOF(CIDETCPUCTX, aSRegs[X86_SREG_DS]);
1007 pbDst += sizeof(uint32_t);
1008
1009 /* mov edx, 0XXYYh */
1010 *pbDst++ = 0xba;
1011 *(uint32_t *)pbDst = pThisApp->Core.InTemplateCtx.aSRegs[X86_SREG_DS];
1012 pbDst += sizeof(uint32_t);
1013
1014 /* mov ds, dx */
1015 *pbDst++ = 0x8e;
1016 *pbDst++ = 0xda;
1017
1018 /* mov xDX, &pThisApp->ExecuteCtx */
1019#ifdef RT_ARCH_AMD64
1020 *pbDst++ = 0x48;
1021#endif
1022 *pbDst++ = 0xba;
1023 *(uintptr_t *)pbDst = (uintptr_t)&pThisApp->ExecuteCtx;
1024 pbDst += sizeof(uintptr_t);
1025
1026#ifdef RT_ARCH_AMD64
1027 /* jmp [cs:$ wrt rip] */
1028 *pbDst++ = 0xff;
1029 *pbDst++ = 0x25;
1030 *(uint32_t *)pbDst = 0;
1031 pbDst += sizeof(uint32_t);
1032#else
1033 /* jmp NAME(CidetAppSaveAndRestoreCtx) */
1034 *pbDst++ = 0xb9;
1035#endif
1036 *(uintptr_t *)pbDst = (uintptr_t)CidetAppSaveAndRestoreCtx;
1037 pbDst += sizeof(uintptr_t);
1038
1039 /* int3 */
1040 *pbDst++ = 0xcc;
1041
1042 pThisApp->fUsingLockedInt3 = false;
1043
1044 }
1045 else
1046 {
1047 /*
1048 * Tricky stack, so just make it raise #UD after a successful run.
1049 */
1050 *pbDst++ = 0xf0; /* lock prefix */
1051 memset(pbDst, 0xcc, 15); /* int3 */
1052 pbDst += 15;
1053
1054 pThisApp->fUsingLockedInt3 = true;
1055 }
1056
1057 AssertMsg(pbDst == &pAppBuf->pbNormal[pBuf->offActive + pBuf->cb + pBuf->cbEpilogue],
1058 ("cbEpilogue=%#x, actual %#x\n", pBuf->cbEpilogue, pbDst - &pAppBuf->pbNormal[pBuf->offActive + pBuf->cb]));
1059
1060 /*
1061 * Arm the buffer.
1062 */
1063 return CidetAppArmBuf(pThisApp, pAppBuf);
1064}
1065
1066
1067/**
1068 * @interface_method_impl{CIDETCORE,pfnExecute}
1069 */
1070static DECLCALLBACK(bool) CidetAppCbExecute(PCIDETCORE pThis)
1071{
1072#if defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
1073 /* Skip tricky stack because windows cannot dispatch exception if RSP/ESP is bad. */
1074 if (pThis->InCtx.fTrickyStack)
1075 return false;
1076#endif
1077
1078 g_pExecutingThis = (PCIDETAPP)pThis;
1079#ifdef RT_OS_WINDOWS
1080 __try
1081 {
1082 CidetAppExecute(&((PCIDETAPP)pThis)->ExecuteCtx, &pThis->InCtx);
1083 }
1084 __except (CidetAppXcptFilter(GetExceptionInformation()))
1085 {
1086 /* Won't end up here... */
1087 }
1088 g_pExecutingThis = NULL;
1089#else
1090 CidetAppExecute(&((PCIDETAPP)pThis)->ExecuteCtx, &pThis->InCtx);
1091 if (g_pExecutingThis)
1092 g_pExecutingThis = NULL;
1093 else
1094 {
1095 RTTESTI_CHECK_RC(sigprocmask(SIG_SETMASK, &g_ProcSigMask, NULL), 0);
1096 RTTESTI_CHECK_RC(sigaltstack(&g_AltStack, NULL), 0);
1097 }
1098#endif
1099
1100 return true;
1101}
1102
1103
1104
1105
1106/*
1107 *
1108 *
1109 * CIDET Application.
1110 * CIDET Application.
1111 * CIDET Application.
1112 *
1113 *
1114 */
1115
1116
1117/**
1118 * @interface_method_impl{CIDETCORE,pfnFailure}
1119 */
1120static DECLCALLBACK(void) CidetAppCbFailureV(PCIDETCORE pThis, const char *pszFormat, va_list va)
1121{
1122 RT_NOREF_PV(pThis);
1123 RTTestIFailedV(pszFormat, va);
1124}
1125
1126
1127static int cidetAppAllocateAndConfigureBuffers(PCIDETAPP pThis)
1128{
1129 /*
1130 * Code buffers.
1131 */
1132 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCodeBuffers); i++)
1133 {
1134 int rc = cidetAppAllocateAndConfigureOneBuffer(pThis, &pThis->aCodeBuffers[i], i, true /*fCode*/,
1135 g_aCodeBufCfgs[i].fFlags);
1136 if (RT_FAILURE(rc))
1137 return rc;
1138 }
1139
1140 /*
1141 * Data buffers.
1142 */
1143 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDataBuffers); i++)
1144 {
1145 int rc = cidetAppAllocateAndConfigureOneBuffer(pThis, &pThis->aDataBuffers[i], i, false /*fCode*/,
1146 g_aDataBufCfgs[i].fFlags);
1147 if (RT_FAILURE(rc))
1148 return rc;
1149 }
1150
1151 /*
1152 * Stack.
1153 */
1154 pThis->cbStack = _32K;
1155 pThis->pbStackLow = (uint8_t *)RTMemPageAlloc(pThis->cbStack);
1156 if (!pThis->pbStackLow)
1157 {
1158 RTTestIFailed("Failed to allocate %u bytes for stack\n", pThis->cbStack);
1159 return false;
1160 }
1161 pThis->pbStackEnd = pThis->pbStackLow + pThis->cbStack;
1162
1163 return true;
1164}
1165
1166
1167static int CidetAppCreate(PPCIDETAPP ppThis)
1168{
1169 *ppThis = NULL;
1170
1171 PCIDETAPP pThis = (PCIDETAPP)RTMemAlloc(sizeof(*pThis));
1172 if (!pThis)
1173 return RTTestIFailedRc(VERR_NO_MEMORY, "Error allocating %zu bytes.", sizeof(*pThis));
1174
1175 /* Create a random source. */
1176 RTRAND hRand;
1177 int rc = RTRandAdvCreateParkMiller(&hRand);
1178 if (RT_SUCCESS(rc))
1179 {
1180 uint64_t uSeed = ASMReadTSC();
1181 rc = RTRandAdvSeed(hRand, uSeed);
1182 if (RT_SUCCESS(rc))
1183 RTTestIPrintf(RTTESTLVL_ALWAYS, "Random seed %#llx\n", uSeed);
1184
1185 /* Initialize the CIDET structure. */
1186 rc = CidetCoreInit(&pThis->Core, hRand);
1187 if (RT_SUCCESS(rc))
1188 {
1189 pThis->Core.pfnReInitDataBuf = CidetAppCbReInitDataBuf;
1190 pThis->Core.pfnSetupDataBuf = CidetAppCbSetupDataBuf;
1191 pThis->Core.pfnIsBufEqual = CidetAppCbIsBufEqual;
1192 pThis->Core.pfnReInitCodeBuf = CidetAppCbReInitCodeBuf;
1193 pThis->Core.pfnSetupCodeBuf = CidetAppCbSetupCodeBuf;
1194 pThis->Core.pfnExecute = CidetAppCbExecute;
1195 pThis->Core.pfnFailure = CidetAppCbFailureV;
1196
1197 pThis->Core.paCodeBufConfigs = g_aCodeBufCfgs;
1198 pThis->Core.cCodeBufConfigs = CIDETAPP_CODE_BUF_COUNT;
1199 pThis->Core.paDataBufConfigs = g_aDataBufCfgs;
1200 pThis->Core.cDataBufConfigs = CIDETAPP_DATA_BUF_COUNT;
1201
1202 rc = cidetAppAllocateAndConfigureBuffers(pThis);
1203 if (RT_SUCCESS(rc))
1204 {
1205 rc = CidetCoreSetTargetMode(&pThis->Core, ARCH_BITS == 32 ? CIDETMODE_PP_32 : CIDETMODE_LM_64);
1206 if (RT_SUCCESS(rc))
1207 {
1208 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_CS] = ASMGetCS();
1209 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_DS] = ASMGetDS();
1210 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_ES] = ASMGetES();
1211 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_FS] = ASMGetFS();
1212 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_GS] = ASMGetGS();
1213 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_SS] = ASMGetSS();
1214 pThis->Core.InTemplateCtx.aGRegs[X86_GREG_xSP] = (uintptr_t)pThis->pbStackEnd - 64;
1215
1216 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_CS;
1217 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_DS;
1218 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_ES;
1219#if !defined(RT_OS_WINDOWS)
1220 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_FS;
1221#endif
1222#if !defined(CIDET_LEAVE_GS_ALONE)
1223 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_GS;
1224#endif
1225
1226 *ppThis = pThis;
1227 return VINF_SUCCESS;
1228 }
1229 rc = RTTestIFailedRc(rc, "Error setting target mode: %Rrc", rc);
1230 }
1231 CidetCoreDelete(&pThis->Core);
1232 }
1233 else
1234 {
1235 rc = RTTestIFailedRc(rc, "CidetCoreInit failed: %Rrc", rc);
1236 RTRandAdvDestroy(hRand);
1237 }
1238 }
1239 else
1240 rc = RTTestIFailedRc(rc, "RTRandAdvCreate failed: %Rrc", rc);
1241 RTMemFree(pThis);
1242 return rc;
1243}
1244
1245
1246static void CidetAppDestroy(PCIDETAPP pThis)
1247{
1248 CidetCoreDelete(&pThis->Core);
1249
1250 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCodeBuffers); i++)
1251 CidetAppDeleteBuffer(&pThis->aCodeBuffers[i]);
1252 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDataBuffers); i++)
1253 CidetAppDeleteBuffer(&pThis->aDataBuffers[i]);
1254 RTMemPageFree(pThis->pbStackLow, pThis->cbStack);
1255
1256 RTMemFree(pThis);
1257}
1258
1259
1260static void CidetAppTestBunch(PCIDETAPP pThis, PCCIDETINSTR paInstructions, uint32_t cInstructions, const char *pszBunchName)
1261{
1262 for (uint32_t iInstr = 0; iInstr < cInstructions; iInstr++)
1263 {
1264 RTTestSubF(g_hTest, "%s - %s", pszBunchName, paInstructions[iInstr].pszMnemonic);
1265 CidetCoreTestInstruction(&pThis->Core, &paInstructions[iInstr]);
1266 }
1267}
1268
1269
1270int main(int argc, char **argv)
1271{
1272 /*
1273 * Initialize the runtime.
1274 */
1275 RTEXITCODE rcExit = RTTestInitExAndCreate(argc, &argv, 0, "cidet-app", &g_hTest);
1276 if (rcExit != RTEXITCODE_SUCCESS)
1277 return rcExit;
1278
1279 /*
1280 * Parse arguments.
1281 */
1282 static const RTGETOPTDEF s_aOptions[] =
1283 {
1284 { "--noop", 'n', RTGETOPT_REQ_NOTHING },
1285 };
1286
1287 int chOpt;
1288 RTGETOPTUNION ValueUnion;
1289 RTGETOPTSTATE GetState;
1290 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
1291 while ((chOpt = RTGetOpt(&GetState, &ValueUnion)))
1292 {
1293 switch (chOpt)
1294 {
1295 case 'n':
1296 break;
1297
1298 case 'h':
1299 RTPrintf("usage: %s\n", argv[0]);
1300 return RTEXITCODE_SUCCESS;
1301
1302 case 'V':
1303 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
1304 return RTEXITCODE_SUCCESS;
1305
1306 default:
1307 return RTGetOptPrintError(chOpt, &ValueUnion);
1308 }
1309 }
1310
1311#ifdef USE_SIGNALS
1312 /*
1313 * Set up signal handlers with alternate stack.
1314 */
1315 /* Get the default signal mask. */
1316 RTTESTI_CHECK_RC_RET(sigprocmask(SIG_BLOCK, NULL, &g_ProcSigMask), 0, RTEXITCODE_FAILURE);
1317
1318 /* Alternative stack so we can play with esp/rsp. */
1319 RT_ZERO(g_AltStack);
1320 g_AltStack.ss_flags = 0;
1321# ifdef SIGSTKSZ
1322 g_AltStack.ss_size = RT_MAX(SIGSTKSZ, _128K);
1323# else
1324 g_AltStack.ss_size = _128K;
1325# endif
1326#ifdef RT_OS_FREEBSD
1327 g_AltStack.ss_sp = (char *)RTMemPageAlloc(g_AltStack.ss_size);
1328#else
1329 g_AltStack.ss_sp = RTMemPageAlloc(g_AltStack.ss_size);
1330#endif
1331 RTTESTI_CHECK_RET(g_AltStack.ss_sp != NULL, RTEXITCODE_FAILURE);
1332 RTTESTI_CHECK_RC_RET(sigaltstack(&g_AltStack, NULL), 0, RTEXITCODE_FAILURE);
1333
1334 /* Default signal action config. */
1335 struct sigaction Act;
1336 RT_ZERO(Act);
1337 Act.sa_sigaction = CidetAppSigHandler;
1338 Act.sa_flags = SA_SIGINFO | SA_ONSTACK;
1339 sigfillset(&Act.sa_mask);
1340
1341 /* Hook the signals we might need. */
1342 sigaction(SIGILL, &Act, NULL);
1343 sigaction(SIGTRAP, &Act, NULL);
1344# ifdef SIGEMT
1345 sigaction(SIGEMT, &Act, NULL);
1346# endif
1347 sigaction(SIGFPE, &Act, NULL);
1348 sigaction(SIGBUS, &Act, NULL);
1349 sigaction(SIGSEGV, &Act, NULL);
1350
1351#elif defined(RT_OS_WINDOWS)
1352 /*
1353 * Register vectored exception handler and override the default unhandled
1354 * exception filter, just to be on the safe side...
1355 */
1356 RTTESTI_CHECK(AddVectoredExceptionHandler(1 /* first */, CidetAppVectoredXcptHandler) != NULL);
1357 SetUnhandledExceptionFilter(CidetAppUnhandledXcptFilter);
1358#endif
1359
1360 /*
1361 * Do the work.
1362 */
1363 RTTestBanner(g_hTest);
1364
1365 PCIDETAPP pThis;
1366 int rc = CidetAppCreate(&pThis);
1367 if (RT_SUCCESS(rc))
1368 {
1369 CidetAppTestBunch(pThis, g_aCidetInstructions1, g_cCidetInstructions1, "First Bunch");
1370
1371 CidetAppDestroy(pThis);
1372 }
1373
1374 return RTTestSummaryAndDestroy(g_hTest);
1375}
1376
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette