VirtualBox

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

Last change on this file since 93603 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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