VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstInlineAsm.cpp@ 30282

Last change on this file since 30282 was 30163, checked in by vboxsync, 14 years ago

tstInlineAsm.cpp: guest phys addr

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 47.7 KB
Line 
1/* $Id: tstInlineAsm.cpp 30163 2010-06-11 14:13:10Z vboxsync $ */
2/** @file
3 * IPRT Testcase - inline assembly.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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* Header Files *
29*******************************************************************************/
30#include <iprt/asm.h>
31#include <iprt/asm-math.h>
32#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
33# include <iprt/asm-amd64-x86.h>
34#else
35# include <iprt/time.h>
36#endif
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/initterm.h>
40#include <iprt/param.h>
41#include <iprt/thread.h>
42#include <iprt/test.h>
43
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49#define CHECKVAL(val, expect, fmt) \
50 do \
51 { \
52 if ((val) != (expect)) \
53 { \
54 RTTestIErrorInc(); \
55 RTPrintf("%s, %d: " #val ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (expect), (val)); \
56 } \
57 } while (0)
58
59#define CHECKOP(op, expect, fmt, type) \
60 do \
61 { \
62 type val = op; \
63 if (val != (type)(expect)) \
64 { \
65 RTTestIErrorInc(); \
66 RTPrintf("%s, %d: " #op ": expected " fmt " got " fmt "\n", __FUNCTION__, __LINE__, (type)(expect), val); \
67 } \
68 } while (0)
69
70
71#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
72
73const char *getCacheAss(unsigned u)
74{
75 if (u == 0)
76 return "res0 ";
77 if (u == 1)
78 return "direct";
79 if (u >= 256)
80 return "???";
81
82 char *pszRet;
83 RTStrAPrintf(&pszRet, "%d way", u); /* intentional leak! */
84 return pszRet;
85}
86
87
88const char *getL2CacheAss(unsigned u)
89{
90 switch (u)
91 {
92 case 0: return "off ";
93 case 1: return "direct";
94 case 2: return "2 way ";
95 case 3: return "res3 ";
96 case 4: return "4 way ";
97 case 5: return "res5 ";
98 case 6: return "8 way ";
99 case 7: return "res7 ";
100 case 8: return "16 way";
101 case 9: return "res9 ";
102 case 10: return "res10 ";
103 case 11: return "res11 ";
104 case 12: return "res12 ";
105 case 13: return "res13 ";
106 case 14: return "res14 ";
107 case 15: return "fully ";
108 default:
109 return "????";
110 }
111}
112
113
114/**
115 * Test and dump all possible info from the CPUID instruction.
116 *
117 * @remark Bits shared with the libc cpuid.c program. This all written by me, so no worries.
118 * @todo transform the dumping into a generic runtime function. We'll need it for logging!
119 */
120void tstASMCpuId(void)
121{
122 unsigned iBit;
123 struct
124 {
125 uint32_t uEBX, uEAX, uEDX, uECX;
126 } s;
127 if (!ASMHasCpuId())
128 {
129 RTPrintf("tstInlineAsm: warning! CPU doesn't support CPUID\n");
130 return;
131 }
132
133 /*
134 * Try the 0 function and use that for checking the ASMCpuId_* variants.
135 */
136 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
137
138 uint32_t u32 = ASMCpuId_ECX(0);
139 CHECKVAL(u32, s.uECX, "%x");
140
141 u32 = ASMCpuId_EDX(0);
142 CHECKVAL(u32, s.uEDX, "%x");
143
144 uint32_t uECX2 = s.uECX - 1;
145 uint32_t uEDX2 = s.uEDX - 1;
146 ASMCpuId_ECX_EDX(0, &uECX2, &uEDX2);
147
148 CHECKVAL(uECX2, s.uECX, "%x");
149 CHECKVAL(uEDX2, s.uEDX, "%x");
150
151 /*
152 * Done testing, dump the information.
153 */
154 RTPrintf("tstInlineAsm: CPUID Dump\n");
155 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
156 const uint32_t cFunctions = s.uEAX;
157
158 /* raw dump */
159 RTPrintf("\n"
160 " RAW Standard CPUIDs\n"
161 "Function eax ebx ecx edx\n");
162 for (unsigned iStd = 0; iStd <= cFunctions + 3; iStd++)
163 {
164 ASMCpuId(iStd, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
165 RTPrintf("%08x %08x %08x %08x %08x%s\n",
166 iStd, s.uEAX, s.uEBX, s.uECX, s.uEDX, iStd <= cFunctions ? "" : "*");
167 }
168
169 /*
170 * Understandable output
171 */
172 ASMCpuId(0, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
173 RTPrintf("Name: %.04s%.04s%.04s\n"
174 "Support: 0-%u\n",
175 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
176 bool const fIntel = ASMIsIntelCpuEx(s.uEBX, s.uECX, s.uEDX);
177
178 /*
179 * Get Features.
180 */
181 if (cFunctions >= 1)
182 {
183 static const char * const s_apszTypes[4] = { "primary", "overdrive", "MP", "reserved" };
184 ASMCpuId(1, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
185 RTPrintf("Family: %#x \tExtended: %#x \tEffective: %#x\n"
186 "Model: %#x \tExtended: %#x \tEffective: %#x\n"
187 "Stepping: %d\n"
188 "Type: %d (%s)\n"
189 "APIC ID: %#04x\n"
190 "Logical CPUs: %d\n"
191 "CLFLUSH Size: %d\n"
192 "Brand ID: %#04x\n",
193 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ASMGetCpuFamily(s.uEAX),
194 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ASMGetCpuModel(s.uEAX, fIntel),
195 ASMGetCpuStepping(s.uEAX),
196 (s.uEAX >> 12) & 0x3, s_apszTypes[(s.uEAX >> 12) & 0x3],
197 (s.uEBX >> 24) & 0xff,
198 (s.uEBX >> 16) & 0xff,
199 (s.uEBX >> 8) & 0xff,
200 (s.uEBX >> 0) & 0xff);
201
202 RTPrintf("Features EDX: ");
203 if (s.uEDX & RT_BIT(0)) RTPrintf(" FPU");
204 if (s.uEDX & RT_BIT(1)) RTPrintf(" VME");
205 if (s.uEDX & RT_BIT(2)) RTPrintf(" DE");
206 if (s.uEDX & RT_BIT(3)) RTPrintf(" PSE");
207 if (s.uEDX & RT_BIT(4)) RTPrintf(" TSC");
208 if (s.uEDX & RT_BIT(5)) RTPrintf(" MSR");
209 if (s.uEDX & RT_BIT(6)) RTPrintf(" PAE");
210 if (s.uEDX & RT_BIT(7)) RTPrintf(" MCE");
211 if (s.uEDX & RT_BIT(8)) RTPrintf(" CX8");
212 if (s.uEDX & RT_BIT(9)) RTPrintf(" APIC");
213 if (s.uEDX & RT_BIT(10)) RTPrintf(" 10");
214 if (s.uEDX & RT_BIT(11)) RTPrintf(" SEP");
215 if (s.uEDX & RT_BIT(12)) RTPrintf(" MTRR");
216 if (s.uEDX & RT_BIT(13)) RTPrintf(" PGE");
217 if (s.uEDX & RT_BIT(14)) RTPrintf(" MCA");
218 if (s.uEDX & RT_BIT(15)) RTPrintf(" CMOV");
219 if (s.uEDX & RT_BIT(16)) RTPrintf(" PAT");
220 if (s.uEDX & RT_BIT(17)) RTPrintf(" PSE36");
221 if (s.uEDX & RT_BIT(18)) RTPrintf(" PSN");
222 if (s.uEDX & RT_BIT(19)) RTPrintf(" CLFSH");
223 if (s.uEDX & RT_BIT(20)) RTPrintf(" 20");
224 if (s.uEDX & RT_BIT(21)) RTPrintf(" DS");
225 if (s.uEDX & RT_BIT(22)) RTPrintf(" ACPI");
226 if (s.uEDX & RT_BIT(23)) RTPrintf(" MMX");
227 if (s.uEDX & RT_BIT(24)) RTPrintf(" FXSR");
228 if (s.uEDX & RT_BIT(25)) RTPrintf(" SSE");
229 if (s.uEDX & RT_BIT(26)) RTPrintf(" SSE2");
230 if (s.uEDX & RT_BIT(27)) RTPrintf(" SS");
231 if (s.uEDX & RT_BIT(28)) RTPrintf(" HTT");
232 if (s.uEDX & RT_BIT(29)) RTPrintf(" 29");
233 if (s.uEDX & RT_BIT(30)) RTPrintf(" 30");
234 if (s.uEDX & RT_BIT(31)) RTPrintf(" 31");
235 RTPrintf("\n");
236
237 /** @todo check intel docs. */
238 RTPrintf("Features ECX: ");
239 if (s.uECX & RT_BIT(0)) RTPrintf(" SSE3");
240 for (iBit = 1; iBit < 13; iBit++)
241 if (s.uECX & RT_BIT(iBit))
242 RTPrintf(" %d", iBit);
243 if (s.uECX & RT_BIT(13)) RTPrintf(" CX16");
244 for (iBit = 14; iBit < 32; iBit++)
245 if (s.uECX & RT_BIT(iBit))
246 RTPrintf(" %d", iBit);
247 RTPrintf("\n");
248 }
249
250 /*
251 * Extended.
252 * Implemented after AMD specs.
253 */
254 /** @todo check out the intel specs. */
255 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
256 if (!s.uEAX && !s.uEBX && !s.uECX && !s.uEDX)
257 {
258 RTPrintf("No extended CPUID info? Check the manual on how to detect this...\n");
259 return;
260 }
261 const uint32_t cExtFunctions = s.uEAX | 0x80000000;
262
263 /* raw dump */
264 RTPrintf("\n"
265 " RAW Extended CPUIDs\n"
266 "Function eax ebx ecx edx\n");
267 for (unsigned iExt = 0x80000000; iExt <= cExtFunctions + 3; iExt++)
268 {
269 ASMCpuId(iExt, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
270 RTPrintf("%08x %08x %08x %08x %08x%s\n",
271 iExt, s.uEAX, s.uEBX, s.uECX, s.uEDX, iExt <= cExtFunctions ? "" : "*");
272 }
273
274 /*
275 * Understandable output
276 */
277 ASMCpuId(0x80000000, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
278 RTPrintf("Ext Name: %.4s%.4s%.4s\n"
279 "Ext Supports: 0x80000000-%#010x\n",
280 &s.uEBX, &s.uEDX, &s.uECX, s.uEAX);
281
282 if (cExtFunctions >= 0x80000001)
283 {
284 ASMCpuId(0x80000001, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
285 RTPrintf("Family: %#x \tExtended: %#x \tEffective: %#x\n"
286 "Model: %#x \tExtended: %#x \tEffective: %#x\n"
287 "Stepping: %d\n"
288 "Brand ID: %#05x\n",
289 (s.uEAX >> 8) & 0xf, (s.uEAX >> 20) & 0x7f, ASMGetCpuFamily(s.uEAX),
290 (s.uEAX >> 4) & 0xf, (s.uEAX >> 16) & 0x0f, ASMGetCpuModel(s.uEAX, fIntel),
291 ASMGetCpuStepping(s.uEAX),
292 s.uEBX & 0xfff);
293
294 RTPrintf("Features EDX: ");
295 if (s.uEDX & RT_BIT(0)) RTPrintf(" FPU");
296 if (s.uEDX & RT_BIT(1)) RTPrintf(" VME");
297 if (s.uEDX & RT_BIT(2)) RTPrintf(" DE");
298 if (s.uEDX & RT_BIT(3)) RTPrintf(" PSE");
299 if (s.uEDX & RT_BIT(4)) RTPrintf(" TSC");
300 if (s.uEDX & RT_BIT(5)) RTPrintf(" MSR");
301 if (s.uEDX & RT_BIT(6)) RTPrintf(" PAE");
302 if (s.uEDX & RT_BIT(7)) RTPrintf(" MCE");
303 if (s.uEDX & RT_BIT(8)) RTPrintf(" CMPXCHG8B");
304 if (s.uEDX & RT_BIT(9)) RTPrintf(" APIC");
305 if (s.uEDX & RT_BIT(10)) RTPrintf(" 10");
306 if (s.uEDX & RT_BIT(11)) RTPrintf(" SysCallSysRet");
307 if (s.uEDX & RT_BIT(12)) RTPrintf(" MTRR");
308 if (s.uEDX & RT_BIT(13)) RTPrintf(" PGE");
309 if (s.uEDX & RT_BIT(14)) RTPrintf(" MCA");
310 if (s.uEDX & RT_BIT(15)) RTPrintf(" CMOV");
311 if (s.uEDX & RT_BIT(16)) RTPrintf(" PAT");
312 if (s.uEDX & RT_BIT(17)) RTPrintf(" PSE36");
313 if (s.uEDX & RT_BIT(18)) RTPrintf(" 18");
314 if (s.uEDX & RT_BIT(19)) RTPrintf(" 19");
315 if (s.uEDX & RT_BIT(20)) RTPrintf(" NX");
316 if (s.uEDX & RT_BIT(21)) RTPrintf(" 21");
317 if (s.uEDX & RT_BIT(22)) RTPrintf(" MmxExt");
318 if (s.uEDX & RT_BIT(23)) RTPrintf(" MMX");
319 if (s.uEDX & RT_BIT(24)) RTPrintf(" FXSR");
320 if (s.uEDX & RT_BIT(25)) RTPrintf(" FastFXSR");
321 if (s.uEDX & RT_BIT(26)) RTPrintf(" 26");
322 if (s.uEDX & RT_BIT(27)) RTPrintf(" RDTSCP");
323 if (s.uEDX & RT_BIT(28)) RTPrintf(" 28");
324 if (s.uEDX & RT_BIT(29)) RTPrintf(" LongMode");
325 if (s.uEDX & RT_BIT(30)) RTPrintf(" 3DNowExt");
326 if (s.uEDX & RT_BIT(31)) RTPrintf(" 3DNow");
327 RTPrintf("\n");
328
329 RTPrintf("Features ECX: ");
330 if (s.uECX & RT_BIT(0)) RTPrintf(" LahfSahf");
331 if (s.uECX & RT_BIT(1)) RTPrintf(" CmpLegacy");
332 if (s.uECX & RT_BIT(2)) RTPrintf(" SVM");
333 if (s.uECX & RT_BIT(3)) RTPrintf(" 3");
334 if (s.uECX & RT_BIT(4)) RTPrintf(" AltMovCr8");
335 for (iBit = 5; iBit < 32; iBit++)
336 if (s.uECX & RT_BIT(iBit))
337 RTPrintf(" %d", iBit);
338 RTPrintf("\n");
339 }
340
341 char szString[4*4*3+1] = {0};
342 if (cExtFunctions >= 0x80000002)
343 ASMCpuId(0x80000002, &szString[0 + 0], &szString[0 + 4], &szString[0 + 8], &szString[0 + 12]);
344 if (cExtFunctions >= 0x80000003)
345 ASMCpuId(0x80000003, &szString[16 + 0], &szString[16 + 4], &szString[16 + 8], &szString[16 + 12]);
346 if (cExtFunctions >= 0x80000004)
347 ASMCpuId(0x80000004, &szString[32 + 0], &szString[32 + 4], &szString[32 + 8], &szString[32 + 12]);
348 if (cExtFunctions >= 0x80000002)
349 RTPrintf("Full Name: %s\n", szString);
350
351 if (cExtFunctions >= 0x80000005)
352 {
353 ASMCpuId(0x80000005, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
354 RTPrintf("TLB 2/4M Instr/Uni: %s %3d entries\n"
355 "TLB 2/4M Data: %s %3d entries\n",
356 getCacheAss((s.uEAX >> 8) & 0xff), (s.uEAX >> 0) & 0xff,
357 getCacheAss((s.uEAX >> 24) & 0xff), (s.uEAX >> 16) & 0xff);
358 RTPrintf("TLB 4K Instr/Uni: %s %3d entries\n"
359 "TLB 4K Data: %s %3d entries\n",
360 getCacheAss((s.uEBX >> 8) & 0xff), (s.uEBX >> 0) & 0xff,
361 getCacheAss((s.uEBX >> 24) & 0xff), (s.uEBX >> 16) & 0xff);
362 RTPrintf("L1 Instr Cache Line Size: %d bytes\n"
363 "L1 Instr Cache Lines Per Tag: %d\n"
364 "L1 Instr Cache Associativity: %s\n"
365 "L1 Instr Cache Size: %d KB\n",
366 (s.uEDX >> 0) & 0xff,
367 (s.uEDX >> 8) & 0xff,
368 getCacheAss((s.uEDX >> 16) & 0xff),
369 (s.uEDX >> 24) & 0xff);
370 RTPrintf("L1 Data Cache Line Size: %d bytes\n"
371 "L1 Data Cache Lines Per Tag: %d\n"
372 "L1 Data Cache Associativity: %s\n"
373 "L1 Data Cache Size: %d KB\n",
374 (s.uECX >> 0) & 0xff,
375 (s.uECX >> 8) & 0xff,
376 getCacheAss((s.uECX >> 16) & 0xff),
377 (s.uECX >> 24) & 0xff);
378 }
379
380 if (cExtFunctions >= 0x80000006)
381 {
382 ASMCpuId(0x80000006, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
383 RTPrintf("L2 TLB 2/4M Instr/Uni: %s %4d entries\n"
384 "L2 TLB 2/4M Data: %s %4d entries\n",
385 getL2CacheAss((s.uEAX >> 12) & 0xf), (s.uEAX >> 0) & 0xfff,
386 getL2CacheAss((s.uEAX >> 28) & 0xf), (s.uEAX >> 16) & 0xfff);
387 RTPrintf("L2 TLB 4K Instr/Uni: %s %4d entries\n"
388 "L2 TLB 4K Data: %s %4d entries\n",
389 getL2CacheAss((s.uEBX >> 12) & 0xf), (s.uEBX >> 0) & 0xfff,
390 getL2CacheAss((s.uEBX >> 28) & 0xf), (s.uEBX >> 16) & 0xfff);
391 RTPrintf("L2 Cache Line Size: %d bytes\n"
392 "L2 Cache Lines Per Tag: %d\n"
393 "L2 Cache Associativity: %s\n"
394 "L2 Cache Size: %d KB\n",
395 (s.uEDX >> 0) & 0xff,
396 (s.uEDX >> 8) & 0xf,
397 getL2CacheAss((s.uEDX >> 12) & 0xf),
398 (s.uEDX >> 16) & 0xffff);
399 }
400
401 if (cExtFunctions >= 0x80000007)
402 {
403 ASMCpuId(0x80000007, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
404 RTPrintf("APM Features: ");
405 if (s.uEDX & RT_BIT(0)) RTPrintf(" TS");
406 if (s.uEDX & RT_BIT(1)) RTPrintf(" FID");
407 if (s.uEDX & RT_BIT(2)) RTPrintf(" VID");
408 if (s.uEDX & RT_BIT(3)) RTPrintf(" TTP");
409 if (s.uEDX & RT_BIT(4)) RTPrintf(" TM");
410 if (s.uEDX & RT_BIT(5)) RTPrintf(" STC");
411 if (s.uEDX & RT_BIT(6)) RTPrintf(" 6");
412 if (s.uEDX & RT_BIT(7)) RTPrintf(" 7");
413 if (s.uEDX & RT_BIT(8)) RTPrintf(" TscInvariant");
414 for (iBit = 9; iBit < 32; iBit++)
415 if (s.uEDX & RT_BIT(iBit))
416 RTPrintf(" %d", iBit);
417 RTPrintf("\n");
418 }
419
420 if (cExtFunctions >= 0x80000008)
421 {
422 ASMCpuId(0x80000008, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
423 RTPrintf("Physical Address Width: %d bits\n"
424 "Virtual Address Width: %d bits\n",
425 "Guest Physical Address Width: %d bits\n",
426 (s.uEAX >> 0) & 0xff,
427 (s.uEAX >> 8) & 0xff,
428 (s.uEAX >> 16) & 0xff);
429 RTPrintf("Physical Core Count: %d\n",
430 ((s.uECX >> 0) & 0xff) + 1);
431 if ((s.uECX >> 12) & 0xf)
432 RTPrintf("ApicIdCoreIdSize: %d bits\n", (s.uECX >> 12) & 0xf);
433 }
434
435 if (cExtFunctions >= 0x8000000a)
436 {
437 ASMCpuId(0x8000000a, &s.uEAX, &s.uEBX, &s.uECX, &s.uEDX);
438 RTPrintf("SVM Revision: %d (%#x)\n"
439 "Number of Address Space IDs: %d (%#x)\n",
440 s.uEAX & 0xff, s.uEAX & 0xff,
441 s.uEBX, s.uEBX);
442 }
443}
444
445#endif /* AMD64 || X86 */
446
447static void tstASMAtomicXchgU8(void)
448{
449 struct
450 {
451 uint8_t u8Dummy0;
452 uint8_t u8;
453 uint8_t u8Dummy1;
454 } s;
455
456 s.u8 = 0;
457 s.u8Dummy0 = s.u8Dummy1 = 0x42;
458 CHECKOP(ASMAtomicXchgU8(&s.u8, 1), 0, "%#x", uint8_t);
459 CHECKVAL(s.u8, 1, "%#x");
460
461 CHECKOP(ASMAtomicXchgU8(&s.u8, 0), 1, "%#x", uint8_t);
462 CHECKVAL(s.u8, 0, "%#x");
463
464 CHECKOP(ASMAtomicXchgU8(&s.u8, 0xff), 0, "%#x", uint8_t);
465 CHECKVAL(s.u8, 0xff, "%#x");
466
467 CHECKOP(ASMAtomicXchgU8(&s.u8, 0x87), 0xffff, "%#x", uint8_t);
468 CHECKVAL(s.u8, 0x87, "%#x");
469 CHECKVAL(s.u8Dummy0, 0x42, "%#x");
470 CHECKVAL(s.u8Dummy1, 0x42, "%#x");
471}
472
473
474static void tstASMAtomicXchgU16(void)
475{
476 struct
477 {
478 uint16_t u16Dummy0;
479 uint16_t u16;
480 uint16_t u16Dummy1;
481 } s;
482
483 s.u16 = 0;
484 s.u16Dummy0 = s.u16Dummy1 = 0x1234;
485 CHECKOP(ASMAtomicXchgU16(&s.u16, 1), 0, "%#x", uint16_t);
486 CHECKVAL(s.u16, 1, "%#x");
487
488 CHECKOP(ASMAtomicXchgU16(&s.u16, 0), 1, "%#x", uint16_t);
489 CHECKVAL(s.u16, 0, "%#x");
490
491 CHECKOP(ASMAtomicXchgU16(&s.u16, 0xffff), 0, "%#x", uint16_t);
492 CHECKVAL(s.u16, 0xffff, "%#x");
493
494 CHECKOP(ASMAtomicXchgU16(&s.u16, 0x8765), 0xffff, "%#x", uint16_t);
495 CHECKVAL(s.u16, 0x8765, "%#x");
496 CHECKVAL(s.u16Dummy0, 0x1234, "%#x");
497 CHECKVAL(s.u16Dummy1, 0x1234, "%#x");
498}
499
500
501static void tstASMAtomicXchgU32(void)
502{
503 struct
504 {
505 uint32_t u32Dummy0;
506 uint32_t u32;
507 uint32_t u32Dummy1;
508 } s;
509
510 s.u32 = 0;
511 s.u32Dummy0 = s.u32Dummy1 = 0x11223344;
512
513 CHECKOP(ASMAtomicXchgU32(&s.u32, 1), 0, "%#x", uint32_t);
514 CHECKVAL(s.u32, 1, "%#x");
515
516 CHECKOP(ASMAtomicXchgU32(&s.u32, 0), 1, "%#x", uint32_t);
517 CHECKVAL(s.u32, 0, "%#x");
518
519 CHECKOP(ASMAtomicXchgU32(&s.u32, ~0U), 0, "%#x", uint32_t);
520 CHECKVAL(s.u32, ~0U, "%#x");
521
522 CHECKOP(ASMAtomicXchgU32(&s.u32, 0x87654321), ~0U, "%#x", uint32_t);
523 CHECKVAL(s.u32, 0x87654321, "%#x");
524
525 CHECKVAL(s.u32Dummy0, 0x11223344, "%#x");
526 CHECKVAL(s.u32Dummy1, 0x11223344, "%#x");
527}
528
529
530static void tstASMAtomicXchgU64(void)
531{
532 struct
533 {
534 uint64_t u64Dummy0;
535 uint64_t u64;
536 uint64_t u64Dummy1;
537 } s;
538
539 s.u64 = 0;
540 s.u64Dummy0 = s.u64Dummy1 = 0x1122334455667788ULL;
541
542 CHECKOP(ASMAtomicXchgU64(&s.u64, 1), 0ULL, "%#llx", uint64_t);
543 CHECKVAL(s.u64, 1ULL, "%#llx");
544
545 CHECKOP(ASMAtomicXchgU64(&s.u64, 0), 1ULL, "%#llx", uint64_t);
546 CHECKVAL(s.u64, 0ULL, "%#llx");
547
548 CHECKOP(ASMAtomicXchgU64(&s.u64, ~0ULL), 0ULL, "%#llx", uint64_t);
549 CHECKVAL(s.u64, ~0ULL, "%#llx");
550
551 CHECKOP(ASMAtomicXchgU64(&s.u64, 0xfedcba0987654321ULL), ~0ULL, "%#llx", uint64_t);
552 CHECKVAL(s.u64, 0xfedcba0987654321ULL, "%#llx");
553
554 CHECKVAL(s.u64Dummy0, 0x1122334455667788ULL, "%#llx");
555 CHECKVAL(s.u64Dummy1, 0x1122334455667788ULL, "%#llx");
556}
557
558
559static void tstASMAtomicXchgPtr(void)
560{
561 void *pv = NULL;
562
563 CHECKOP(ASMAtomicXchgPtr(&pv, (void *)(~(uintptr_t)0)), NULL, "%p", void *);
564 CHECKVAL(pv, (void *)(~(uintptr_t)0), "%p");
565
566 CHECKOP(ASMAtomicXchgPtr(&pv, (void *)0x87654321), (void *)(~(uintptr_t)0), "%p", void *);
567 CHECKVAL(pv, (void *)0x87654321, "%p");
568
569 CHECKOP(ASMAtomicXchgPtr(&pv, NULL), (void *)0x87654321, "%p", void *);
570 CHECKVAL(pv, NULL, "%p");
571}
572
573
574static void tstASMAtomicCmpXchgU8(void)
575{
576 struct
577 {
578 uint8_t u8Before;
579 uint8_t u8;
580 uint8_t u8After;
581 } u = { 0xcc, 0xff, 0xaa };
582
583 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0, 0), false, "%d", bool);
584 CHECKVAL(u.u8, 0xff, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
585
586 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0, 0xff), true, "%d", bool);
587 CHECKVAL(u.u8, 0, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
588
589 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0x79, 0xff), false, "%d", bool);
590 CHECKVAL(u.u8, 0, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
591
592 CHECKOP(ASMAtomicCmpXchgU8(&u.u8, 0x97, 0), true, "%d", bool);
593 CHECKVAL(u.u8, 0x97, "%x"); CHECKVAL(u.u8Before, 0xcc, "%x"); CHECKVAL(u.u8After, 0xaa, "%x");
594}
595
596
597static void tstASMAtomicCmpXchgU32(void)
598{
599 uint32_t u32 = 0xffffffff;
600
601 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0, 0), false, "%d", bool);
602 CHECKVAL(u32, 0xffffffff, "%x");
603
604 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0, 0xffffffff), true, "%d", bool);
605 CHECKVAL(u32, 0, "%x");
606
607 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0x8008efd, 0xffffffff), false, "%d", bool);
608 CHECKVAL(u32, 0, "%x");
609
610 CHECKOP(ASMAtomicCmpXchgU32(&u32, 0x8008efd, 0), true, "%d", bool);
611 CHECKVAL(u32, 0x8008efd, "%x");
612}
613
614
615static void tstASMAtomicCmpXchgU64(void)
616{
617 uint64_t u64 = 0xffffffffffffffULL;
618
619 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0, 0), false, "%d", bool);
620 CHECKVAL(u64, 0xffffffffffffffULL, "%#llx");
621
622 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0, 0xffffffffffffffULL), true, "%d", bool);
623 CHECKVAL(u64, 0, "%x");
624
625 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0xffffffff), false, "%d", bool);
626 CHECKVAL(u64, 0, "%x");
627
628 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0xffffffff00000000ULL), false, "%d", bool);
629 CHECKVAL(u64, 0, "%x");
630
631 CHECKOP(ASMAtomicCmpXchgU64(&u64, 0x80040008008efdULL, 0), true, "%d", bool);
632 CHECKVAL(u64, 0x80040008008efdULL, "%#llx");
633}
634
635
636static void tstASMAtomicCmpXchgExU32(void)
637{
638 uint32_t u32 = 0xffffffff;
639 uint32_t u32Old = 0x80005111;
640
641 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0, &u32Old), false, "%d", bool);
642 CHECKVAL(u32, 0xffffffff, "%x");
643 CHECKVAL(u32Old, 0xffffffff, "%x");
644
645 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0xffffffff, &u32Old), true, "%d", bool);
646 CHECKVAL(u32, 0, "%x");
647 CHECKVAL(u32Old, 0xffffffff, "%x");
648
649 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0x8008efd, 0xffffffff, &u32Old), false, "%d", bool);
650 CHECKVAL(u32, 0, "%x");
651 CHECKVAL(u32Old, 0, "%x");
652
653 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0x8008efd, 0, &u32Old), true, "%d", bool);
654 CHECKVAL(u32, 0x8008efd, "%x");
655 CHECKVAL(u32Old, 0, "%x");
656
657 CHECKOP(ASMAtomicCmpXchgExU32(&u32, 0, 0x8008efd, &u32Old), true, "%d", bool);
658 CHECKVAL(u32, 0, "%x");
659 CHECKVAL(u32Old, 0x8008efd, "%x");
660}
661
662
663static void tstASMAtomicCmpXchgExU64(void)
664{
665 uint64_t u64 = 0xffffffffffffffffULL;
666 uint64_t u64Old = 0x8000000051111111ULL;
667
668 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0, &u64Old), false, "%d", bool);
669 CHECKVAL(u64, 0xffffffffffffffffULL, "%llx");
670 CHECKVAL(u64Old, 0xffffffffffffffffULL, "%llx");
671
672 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0xffffffffffffffffULL, &u64Old), true, "%d", bool);
673 CHECKVAL(u64, 0ULL, "%llx");
674 CHECKVAL(u64Old, 0xffffffffffffffffULL, "%llx");
675
676 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0xffffffff, &u64Old), false, "%d", bool);
677 CHECKVAL(u64, 0ULL, "%llx");
678 CHECKVAL(u64Old, 0ULL, "%llx");
679
680 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0xffffffff00000000ULL, &u64Old), false, "%d", bool);
681 CHECKVAL(u64, 0ULL, "%llx");
682 CHECKVAL(u64Old, 0ULL, "%llx");
683
684 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0x80040008008efdULL, 0, &u64Old), true, "%d", bool);
685 CHECKVAL(u64, 0x80040008008efdULL, "%llx");
686 CHECKVAL(u64Old, 0ULL, "%llx");
687
688 CHECKOP(ASMAtomicCmpXchgExU64(&u64, 0, 0x80040008008efdULL, &u64Old), true, "%d", bool);
689 CHECKVAL(u64, 0ULL, "%llx");
690 CHECKVAL(u64Old, 0x80040008008efdULL, "%llx");
691}
692
693
694static void tstASMAtomicReadU64(void)
695{
696 uint64_t u64 = 0;
697
698 CHECKOP(ASMAtomicReadU64(&u64), 0ULL, "%#llx", uint64_t);
699 CHECKVAL(u64, 0ULL, "%#llx");
700
701 u64 = ~0ULL;
702 CHECKOP(ASMAtomicReadU64(&u64), ~0ULL, "%#llx", uint64_t);
703 CHECKVAL(u64, ~0ULL, "%#llx");
704
705 u64 = 0xfedcba0987654321ULL;
706 CHECKOP(ASMAtomicReadU64(&u64), 0xfedcba0987654321ULL, "%#llx", uint64_t);
707 CHECKVAL(u64, 0xfedcba0987654321ULL, "%#llx");
708}
709
710
711static void tstASMAtomicUoReadU64(void)
712{
713 uint64_t u64 = 0;
714
715 CHECKOP(ASMAtomicUoReadU64(&u64), 0ULL, "%#llx", uint64_t);
716 CHECKVAL(u64, 0ULL, "%#llx");
717
718 u64 = ~0ULL;
719 CHECKOP(ASMAtomicUoReadU64(&u64), ~0ULL, "%#llx", uint64_t);
720 CHECKVAL(u64, ~0ULL, "%#llx");
721
722 u64 = 0xfedcba0987654321ULL;
723 CHECKOP(ASMAtomicUoReadU64(&u64), 0xfedcba0987654321ULL, "%#llx", uint64_t);
724 CHECKVAL(u64, 0xfedcba0987654321ULL, "%#llx");
725}
726
727
728static void tstASMAtomicAddS32(void)
729{
730 int32_t i32Rc;
731 int32_t i32 = 10;
732#define MYCHECK(op, rc, val) \
733 do { \
734 i32Rc = op; \
735 if (i32Rc != (rc)) \
736 { \
737 RTPrintf("%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
738 RTTestIErrorInc(); \
739 } \
740 if (i32 != (val)) \
741 { \
742 RTPrintf("%s, %d: FAILURE: %s => i32=%d expected %d\n", __FUNCTION__, __LINE__, #op, i32, val); \
743 RTTestIErrorInc(); \
744 } \
745 } while (0)
746 MYCHECK(ASMAtomicAddS32(&i32, 1), 10, 11);
747 MYCHECK(ASMAtomicAddS32(&i32, -2), 11, 9);
748 MYCHECK(ASMAtomicAddS32(&i32, -9), 9, 0);
749 MYCHECK(ASMAtomicAddS32(&i32, -0x7fffffff), 0, -0x7fffffff);
750 MYCHECK(ASMAtomicAddS32(&i32, 0), -0x7fffffff, -0x7fffffff);
751 MYCHECK(ASMAtomicAddS32(&i32, 0x7fffffff), -0x7fffffff, 0);
752 MYCHECK(ASMAtomicAddS32(&i32, 0), 0, 0);
753#undef MYCHECK
754}
755
756
757static void tstASMAtomicDecIncS32(void)
758{
759 int32_t i32Rc;
760 int32_t i32 = 10;
761#define MYCHECK(op, rc) \
762 do { \
763 i32Rc = op; \
764 if (i32Rc != (rc)) \
765 { \
766 RTPrintf("%s, %d: FAILURE: %s -> %d expected %d\n", __FUNCTION__, __LINE__, #op, i32Rc, rc); \
767 RTTestIErrorInc(); \
768 } \
769 if (i32 != (rc)) \
770 { \
771 RTPrintf("%s, %d: FAILURE: %s => i32=%d expected %d\n", __FUNCTION__, __LINE__, #op, i32, rc); \
772 RTTestIErrorInc(); \
773 } \
774 } while (0)
775 MYCHECK(ASMAtomicDecS32(&i32), 9);
776 MYCHECK(ASMAtomicDecS32(&i32), 8);
777 MYCHECK(ASMAtomicDecS32(&i32), 7);
778 MYCHECK(ASMAtomicDecS32(&i32), 6);
779 MYCHECK(ASMAtomicDecS32(&i32), 5);
780 MYCHECK(ASMAtomicDecS32(&i32), 4);
781 MYCHECK(ASMAtomicDecS32(&i32), 3);
782 MYCHECK(ASMAtomicDecS32(&i32), 2);
783 MYCHECK(ASMAtomicDecS32(&i32), 1);
784 MYCHECK(ASMAtomicDecS32(&i32), 0);
785 MYCHECK(ASMAtomicDecS32(&i32), -1);
786 MYCHECK(ASMAtomicDecS32(&i32), -2);
787 MYCHECK(ASMAtomicIncS32(&i32), -1);
788 MYCHECK(ASMAtomicIncS32(&i32), 0);
789 MYCHECK(ASMAtomicIncS32(&i32), 1);
790 MYCHECK(ASMAtomicIncS32(&i32), 2);
791 MYCHECK(ASMAtomicIncS32(&i32), 3);
792 MYCHECK(ASMAtomicDecS32(&i32), 2);
793 MYCHECK(ASMAtomicIncS32(&i32), 3);
794 MYCHECK(ASMAtomicDecS32(&i32), 2);
795 MYCHECK(ASMAtomicIncS32(&i32), 3);
796#undef MYCHECK
797}
798
799
800static void tstASMAtomicAndOrU32(void)
801{
802 uint32_t u32 = 0xffffffff;
803
804 ASMAtomicOrU32(&u32, 0xffffffff);
805 CHECKVAL(u32, 0xffffffff, "%x");
806
807 ASMAtomicAndU32(&u32, 0xffffffff);
808 CHECKVAL(u32, 0xffffffff, "%x");
809
810 ASMAtomicAndU32(&u32, 0x8f8f8f8f);
811 CHECKVAL(u32, 0x8f8f8f8f, "%x");
812
813 ASMAtomicOrU32(&u32, 0x70707070);
814 CHECKVAL(u32, 0xffffffff, "%x");
815
816 ASMAtomicAndU32(&u32, 1);
817 CHECKVAL(u32, 1, "%x");
818
819 ASMAtomicOrU32(&u32, 0x80000000);
820 CHECKVAL(u32, 0x80000001, "%x");
821
822 ASMAtomicAndU32(&u32, 0x80000000);
823 CHECKVAL(u32, 0x80000000, "%x");
824
825 ASMAtomicAndU32(&u32, 0);
826 CHECKVAL(u32, 0, "%x");
827
828 ASMAtomicOrU32(&u32, 0x42424242);
829 CHECKVAL(u32, 0x42424242, "%x");
830}
831
832
833void tstASMMemZeroPage(void)
834{
835 struct
836 {
837 uint64_t u64Magic1;
838 uint8_t abPage[PAGE_SIZE];
839 uint64_t u64Magic2;
840 } Buf1, Buf2, Buf3;
841
842 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
843 memset(Buf1.abPage, 0x55, sizeof(Buf1.abPage));
844 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
845 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
846 memset(Buf2.abPage, 0x77, sizeof(Buf2.abPage));
847 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
848 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
849 memset(Buf3.abPage, 0x99, sizeof(Buf3.abPage));
850 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
851 ASMMemZeroPage(Buf1.abPage);
852 ASMMemZeroPage(Buf2.abPage);
853 ASMMemZeroPage(Buf3.abPage);
854 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
855 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
856 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
857 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
858 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
859 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
860 {
861 RTPrintf("tstInlineAsm: ASMMemZeroPage violated one/both magic(s)!\n");
862 RTTestIErrorInc();
863 }
864 for (unsigned i = 0; i < sizeof(Buf1.abPage); i++)
865 if (Buf1.abPage[i])
866 {
867 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
868 RTTestIErrorInc();
869 }
870 for (unsigned i = 0; i < sizeof(Buf2.abPage); i++)
871 if (Buf2.abPage[i])
872 {
873 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
874 RTTestIErrorInc();
875 }
876 for (unsigned i = 0; i < sizeof(Buf3.abPage); i++)
877 if (Buf3.abPage[i])
878 {
879 RTPrintf("tstInlineAsm: ASMMemZeroPage didn't clear byte at offset %#x!\n", i);
880 RTTestIErrorInc();
881 }
882}
883
884
885void tstASMMemIsZeroPage(RTTEST hTest)
886{
887 RTTestSub(hTest, "ASMMemIsZeroPage");
888
889 void *pvPage1 = RTTestGuardedAllocHead(hTest, PAGE_SIZE);
890 void *pvPage2 = RTTestGuardedAllocTail(hTest, PAGE_SIZE);
891 RTTESTI_CHECK_RETV(pvPage1 && pvPage2);
892
893 memset(pvPage1, 0, PAGE_SIZE);
894 memset(pvPage2, 0, PAGE_SIZE);
895 RTTESTI_CHECK(ASMMemIsZeroPage(pvPage1));
896 RTTESTI_CHECK(ASMMemIsZeroPage(pvPage2));
897
898 memset(pvPage1, 0xff, PAGE_SIZE);
899 memset(pvPage2, 0xff, PAGE_SIZE);
900 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage1));
901 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage2));
902
903 memset(pvPage1, 0, PAGE_SIZE);
904 memset(pvPage2, 0, PAGE_SIZE);
905 for (unsigned off = 0; off < PAGE_SIZE; off++)
906 {
907 ((uint8_t *)pvPage1)[off] = 1;
908 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage1));
909 ((uint8_t *)pvPage1)[off] = 0;
910
911 ((uint8_t *)pvPage2)[off] = 0x80;
912 RTTESTI_CHECK(!ASMMemIsZeroPage(pvPage2));
913 ((uint8_t *)pvPage2)[off] = 0;
914 }
915
916 RTTestSubDone(hTest);
917}
918
919
920void tstASMMemZero32(void)
921{
922 struct
923 {
924 uint64_t u64Magic1;
925 uint8_t abPage[PAGE_SIZE - 32];
926 uint64_t u64Magic2;
927 } Buf1, Buf2, Buf3;
928
929 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
930 memset(Buf1.abPage, 0x55, sizeof(Buf1.abPage));
931 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
932 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
933 memset(Buf2.abPage, 0x77, sizeof(Buf2.abPage));
934 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
935 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
936 memset(Buf3.abPage, 0x99, sizeof(Buf3.abPage));
937 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
938 ASMMemZero32(Buf1.abPage, sizeof(Buf1.abPage));
939 ASMMemZero32(Buf2.abPage, sizeof(Buf2.abPage));
940 ASMMemZero32(Buf3.abPage, sizeof(Buf3.abPage));
941 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
942 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
943 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
944 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
945 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
946 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
947 {
948 RTPrintf("tstInlineAsm: ASMMemZero32 violated one/both magic(s)!\n");
949 RTTestIErrorInc();
950 }
951 for (unsigned i = 0; i < RT_ELEMENTS(Buf1.abPage); i++)
952 if (Buf1.abPage[i])
953 {
954 RTPrintf("tstInlineAsm: ASMMemZero32 didn't clear byte at offset %#x!\n", i);
955 RTTestIErrorInc();
956 }
957 for (unsigned i = 0; i < RT_ELEMENTS(Buf2.abPage); i++)
958 if (Buf2.abPage[i])
959 {
960 RTPrintf("tstInlineAsm: ASMMemZero32 didn't clear byte at offset %#x!\n", i);
961 RTTestIErrorInc();
962 }
963 for (unsigned i = 0; i < RT_ELEMENTS(Buf3.abPage); i++)
964 if (Buf3.abPage[i])
965 {
966 RTPrintf("tstInlineAsm: ASMMemZero32 didn't clear byte at offset %#x!\n", i);
967 RTTestIErrorInc();
968 }
969}
970
971
972void tstASMMemFill32(void)
973{
974 struct
975 {
976 uint64_t u64Magic1;
977 uint32_t au32Page[PAGE_SIZE / 4];
978 uint64_t u64Magic2;
979 } Buf1;
980 struct
981 {
982 uint64_t u64Magic1;
983 uint32_t au32Page[(PAGE_SIZE / 4) - 3];
984 uint64_t u64Magic2;
985 } Buf2;
986 struct
987 {
988 uint64_t u64Magic1;
989 uint32_t au32Page[(PAGE_SIZE / 4) - 1];
990 uint64_t u64Magic2;
991 } Buf3;
992
993 Buf1.u64Magic1 = UINT64_C(0xffffffffffffffff);
994 memset(Buf1.au32Page, 0x55, sizeof(Buf1.au32Page));
995 Buf1.u64Magic2 = UINT64_C(0xffffffffffffffff);
996 Buf2.u64Magic1 = UINT64_C(0xffffffffffffffff);
997 memset(Buf2.au32Page, 0x77, sizeof(Buf2.au32Page));
998 Buf2.u64Magic2 = UINT64_C(0xffffffffffffffff);
999 Buf3.u64Magic1 = UINT64_C(0xffffffffffffffff);
1000 memset(Buf3.au32Page, 0x99, sizeof(Buf3.au32Page));
1001 Buf3.u64Magic2 = UINT64_C(0xffffffffffffffff);
1002 ASMMemFill32(Buf1.au32Page, sizeof(Buf1.au32Page), 0xdeadbeef);
1003 ASMMemFill32(Buf2.au32Page, sizeof(Buf2.au32Page), 0xcafeff01);
1004 ASMMemFill32(Buf3.au32Page, sizeof(Buf3.au32Page), 0xf00dd00f);
1005 if ( Buf1.u64Magic1 != UINT64_C(0xffffffffffffffff)
1006 || Buf1.u64Magic2 != UINT64_C(0xffffffffffffffff)
1007 || Buf2.u64Magic1 != UINT64_C(0xffffffffffffffff)
1008 || Buf2.u64Magic2 != UINT64_C(0xffffffffffffffff)
1009 || Buf3.u64Magic1 != UINT64_C(0xffffffffffffffff)
1010 || Buf3.u64Magic2 != UINT64_C(0xffffffffffffffff))
1011 {
1012 RTPrintf("tstInlineAsm: ASMMemFill32 violated one/both magic(s)!\n");
1013 RTTestIErrorInc();
1014 }
1015 for (unsigned i = 0; i < RT_ELEMENTS(Buf1.au32Page); i++)
1016 if (Buf1.au32Page[i] != 0xdeadbeef)
1017 {
1018 RTPrintf("tstInlineAsm: ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf1.au32Page[i], 0xdeadbeef);
1019 RTTestIErrorInc();
1020 }
1021 for (unsigned i = 0; i < RT_ELEMENTS(Buf2.au32Page); i++)
1022 if (Buf2.au32Page[i] != 0xcafeff01)
1023 {
1024 RTPrintf("tstInlineAsm: ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf2.au32Page[i], 0xcafeff01);
1025 RTTestIErrorInc();
1026 }
1027 for (unsigned i = 0; i < RT_ELEMENTS(Buf3.au32Page); i++)
1028 if (Buf3.au32Page[i] != 0xf00dd00f)
1029 {
1030 RTPrintf("tstInlineAsm: ASMMemFill32 %#x: %#x exepcted %#x\n", i, Buf3.au32Page[i], 0xf00dd00f);
1031 RTTestIErrorInc();
1032 }
1033}
1034
1035
1036
1037void tstASMMath(void)
1038{
1039 uint64_t u64 = ASMMult2xU32RetU64(UINT32_C(0x80000000), UINT32_C(0x10000000));
1040 CHECKVAL(u64, UINT64_C(0x0800000000000000), "%#018RX64");
1041
1042 uint32_t u32 = ASMDivU64ByU32RetU32(UINT64_C(0x0800000000000000), UINT32_C(0x10000000));
1043 CHECKVAL(u32, UINT32_C(0x80000000), "%#010RX32");
1044
1045#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1046 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000000000001), UINT32_C(0x00000001), UINT32_C(0x00000001));
1047 CHECKVAL(u64, UINT64_C(0x0000000000000001), "%#018RX64");
1048 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x0000000100000000), UINT32_C(0x80000000), UINT32_C(0x00000002));
1049 CHECKVAL(u64, UINT64_C(0x4000000000000000), "%#018RX64");
1050 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfedcba9876543210), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1051 CHECKVAL(u64, UINT64_C(0xfedcba9876543210), "%#018RX64");
1052 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xffffffff), UINT32_C(0xffffffff));
1053 CHECKVAL(u64, UINT64_C(0xffffffffffffffff), "%#018RX64");
1054 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xffffffffffffffff), UINT32_C(0xfffffff0), UINT32_C(0xffffffff));
1055 CHECKVAL(u64, UINT64_C(0xfffffff0fffffff0), "%#018RX64");
1056 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0x58734981), UINT32_C(0xf8694045));
1057 CHECKVAL(u64, UINT64_C(0x128b9c3d43184763), "%#018RX64");
1058 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0x3415934810359583), UINT32_C(0xf8694045), UINT32_C(0x58734981));
1059 CHECKVAL(u64, UINT64_C(0x924719355cd35a27), "%#018RX64");
1060
1061# if 0 /* bird: question is whether this should trap or not:
1062 *
1063 * frank: Of course it must trap:
1064 *
1065 * 0xfffffff8 * 0x77d7daf8 = 0x77d7daf441412840
1066 *
1067 * During the following division, the quotient must fit into a 32-bit register.
1068 * Therefore the smallest valid divisor is
1069 *
1070 * (0x77d7daf441412840 >> 32) + 1 = 0x77d7daf5
1071 *
1072 * which is definitely greater than 0x3b9aca00.
1073 *
1074 * bird: No, the C version does *not* crash. So, the question is whether there's any
1075 * code depending on it not crashing.
1076 *
1077 * Of course the assembly versions of the code crash right now for the reasons you've
1078 * given, but the 32-bit MSC version does not crash.
1079 *
1080 * frank: The C version does not crash but delivers incorrect results for this case.
1081 * The reason is
1082 *
1083 * u.s.Hi = (unsigned long)(u64Hi / u32C);
1084 *
1085 * Here the division is actually 64-bit by 64-bit but the 64-bit result is truncated
1086 * to 32 bit. If using this (optimized and fast) function we should just be sure that
1087 * the operands are in a valid range.
1088 */
1089 u64 = ASMMultU64ByU32DivByU32(UINT64_C(0xfffffff8c65d6731), UINT32_C(0x77d7daf8), UINT32_C(0x3b9aca00));
1090 CHECKVAL(u64, UINT64_C(0x02b8f9a2aa74e3dc), "%#018RX64");
1091# endif
1092#endif /* AMD64 || X86 */
1093
1094 u32 = ASMModU64ByU32RetU32(UINT64_C(0x0ffffff8c65d6731), UINT32_C(0x77d7daf8));
1095 CHECKVAL(u32, UINT32_C(0x3B642451), "%#010RX32");
1096
1097 int32_t i32;
1098 i32 = ASMModS64ByS32RetS32(INT64_C(-11), INT32_C(-2));
1099 CHECKVAL(i32, INT32_C(-1), "%010RI32");
1100 i32 = ASMModS64ByS32RetS32(INT64_C(-11), INT32_C(2));
1101 CHECKVAL(i32, INT32_C(-1), "%010RI32");
1102 i32 = ASMModS64ByS32RetS32(INT64_C(11), INT32_C(-2));
1103 CHECKVAL(i32, INT32_C(1), "%010RI32");
1104
1105 i32 = ASMModS64ByS32RetS32(INT64_C(92233720368547758), INT32_C(2147483647));
1106 CHECKVAL(i32, INT32_C(2104533974), "%010RI32");
1107 i32 = ASMModS64ByS32RetS32(INT64_C(-92233720368547758), INT32_C(2147483647));
1108 CHECKVAL(i32, INT32_C(-2104533974), "%010RI32");
1109}
1110
1111
1112void tstASMByteSwap(void)
1113{
1114 RTPrintf("tstInlineASM: TESTING - ASMByteSwap*\n");
1115
1116 uint64_t u64In = UINT64_C(0x0011223344556677);
1117 uint64_t u64Out = ASMByteSwapU64(u64In);
1118 CHECKVAL(u64In, UINT64_C(0x0011223344556677), "%#018RX64");
1119 CHECKVAL(u64Out, UINT64_C(0x7766554433221100), "%#018RX64");
1120 u64Out = ASMByteSwapU64(u64Out);
1121 CHECKVAL(u64Out, u64In, "%#018RX64");
1122 u64In = UINT64_C(0x0123456789abcdef);
1123 u64Out = ASMByteSwapU64(u64In);
1124 CHECKVAL(u64In, UINT64_C(0x0123456789abcdef), "%#018RX64");
1125 CHECKVAL(u64Out, UINT64_C(0xefcdab8967452301), "%#018RX64");
1126 u64Out = ASMByteSwapU64(u64Out);
1127 CHECKVAL(u64Out, u64In, "%#018RX64");
1128 u64In = 0;
1129 u64Out = ASMByteSwapU64(u64In);
1130 CHECKVAL(u64Out, u64In, "%#018RX64");
1131 u64In = ~(uint64_t)0;
1132 u64Out = ASMByteSwapU64(u64In);
1133 CHECKVAL(u64Out, u64In, "%#018RX64");
1134
1135 uint32_t u32In = UINT32_C(0x00112233);
1136 uint32_t u32Out = ASMByteSwapU32(u32In);
1137 CHECKVAL(u32In, UINT32_C(0x00112233), "%#010RX32");
1138 CHECKVAL(u32Out, UINT32_C(0x33221100), "%#010RX32");
1139 u32Out = ASMByteSwapU32(u32Out);
1140 CHECKVAL(u32Out, u32In, "%#010RX32");
1141 u32In = UINT32_C(0x12345678);
1142 u32Out = ASMByteSwapU32(u32In);
1143 CHECKVAL(u32In, UINT32_C(0x12345678), "%#010RX32");
1144 CHECKVAL(u32Out, UINT32_C(0x78563412), "%#010RX32");
1145 u32Out = ASMByteSwapU32(u32Out);
1146 CHECKVAL(u32Out, u32In, "%#010RX32");
1147 u32In = 0;
1148 u32Out = ASMByteSwapU32(u32In);
1149 CHECKVAL(u32Out, u32In, "%#010RX32");
1150 u32In = ~(uint32_t)0;
1151 u32Out = ASMByteSwapU32(u32In);
1152 CHECKVAL(u32Out, u32In, "%#010RX32");
1153
1154 uint16_t u16In = UINT16_C(0x0011);
1155 uint16_t u16Out = ASMByteSwapU16(u16In);
1156 CHECKVAL(u16In, UINT16_C(0x0011), "%#06RX16");
1157 CHECKVAL(u16Out, UINT16_C(0x1100), "%#06RX16");
1158 u16Out = ASMByteSwapU16(u16Out);
1159 CHECKVAL(u16Out, u16In, "%#06RX16");
1160 u16In = UINT16_C(0x1234);
1161 u16Out = ASMByteSwapU16(u16In);
1162 CHECKVAL(u16In, UINT16_C(0x1234), "%#06RX16");
1163 CHECKVAL(u16Out, UINT16_C(0x3412), "%#06RX16");
1164 u16Out = ASMByteSwapU16(u16Out);
1165 CHECKVAL(u16Out, u16In, "%#06RX16");
1166 u16In = 0;
1167 u16Out = ASMByteSwapU16(u16In);
1168 CHECKVAL(u16Out, u16In, "%#06RX16");
1169 u16In = ~(uint16_t)0;
1170 u16Out = ASMByteSwapU16(u16In);
1171 CHECKVAL(u16Out, u16In, "%#06RX16");
1172}
1173
1174
1175void tstASMBench(void)
1176{
1177 /*
1178 * Make this static. We don't want to have this located on the stack.
1179 */
1180 static uint8_t volatile s_u8;
1181 static int8_t volatile s_i8;
1182 static uint16_t volatile s_u16;
1183 static int16_t volatile s_i16;
1184 static uint32_t volatile s_u32;
1185 static int32_t volatile s_i32;
1186 static uint64_t volatile s_u64;
1187 static int64_t volatile s_i64;
1188 register unsigned i;
1189 const unsigned cRounds = 2000000;
1190 register uint64_t u64Elapsed;
1191
1192 RTPrintf("tstInlineASM: Benchmarking:\n");
1193
1194#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1195# define BENCH(op, str) \
1196 do { \
1197 RTThreadYield(); \
1198 u64Elapsed = ASMReadTSC(); \
1199 for (i = cRounds; i > 0; i--) \
1200 op; \
1201 u64Elapsed = ASMReadTSC() - u64Elapsed; \
1202 RTPrintf(" %-30s %3llu cycles\n", str, u64Elapsed / cRounds); \
1203 } while (0)
1204#else
1205# define BENCH(op, str) \
1206 do { \
1207 RTThreadYield(); \
1208 u64Elapsed = RTTimeNanoTS(); \
1209 for (i = cRounds; i > 0; i--) \
1210 op; \
1211 u64Elapsed = RTTimeNanoTS() - u64Elapsed; \
1212 RTPrintf(" %-30s %3llu ns\n", str, u64Elapsed / cRounds); \
1213 } while (0)
1214#endif
1215
1216 BENCH(s_u32 = 0, "s_u32 = 0:");
1217 BENCH(ASMAtomicUoReadU8(&s_u8), "ASMAtomicUoReadU8:");
1218 BENCH(ASMAtomicUoReadS8(&s_i8), "ASMAtomicUoReadS8:");
1219 BENCH(ASMAtomicUoReadU16(&s_u16), "ASMAtomicUoReadU16:");
1220 BENCH(ASMAtomicUoReadS16(&s_i16), "ASMAtomicUoReadS16:");
1221 BENCH(ASMAtomicUoReadU32(&s_u32), "ASMAtomicUoReadU32:");
1222 BENCH(ASMAtomicUoReadS32(&s_i32), "ASMAtomicUoReadS32:");
1223 BENCH(ASMAtomicUoReadU64(&s_u64), "ASMAtomicUoReadU64:");
1224 BENCH(ASMAtomicUoReadS64(&s_i64), "ASMAtomicUoReadS64:");
1225 BENCH(ASMAtomicReadU8(&s_u8), "ASMAtomicReadU8:");
1226 BENCH(ASMAtomicReadS8(&s_i8), "ASMAtomicReadS8:");
1227 BENCH(ASMAtomicReadU16(&s_u16), "ASMAtomicReadU16:");
1228 BENCH(ASMAtomicReadS16(&s_i16), "ASMAtomicReadS16:");
1229 BENCH(ASMAtomicReadU32(&s_u32), "ASMAtomicReadU32:");
1230 BENCH(ASMAtomicReadS32(&s_i32), "ASMAtomicReadS32:");
1231 BENCH(ASMAtomicReadU64(&s_u64), "ASMAtomicReadU64:");
1232 BENCH(ASMAtomicReadS64(&s_i64), "ASMAtomicReadS64:");
1233 BENCH(ASMAtomicUoWriteU8(&s_u8, 0), "ASMAtomicUoWriteU8:");
1234 BENCH(ASMAtomicUoWriteS8(&s_i8, 0), "ASMAtomicUoWriteS8:");
1235 BENCH(ASMAtomicUoWriteU16(&s_u16, 0), "ASMAtomicUoWriteU16:");
1236 BENCH(ASMAtomicUoWriteS16(&s_i16, 0), "ASMAtomicUoWriteS16:");
1237 BENCH(ASMAtomicUoWriteU32(&s_u32, 0), "ASMAtomicUoWriteU32:");
1238 BENCH(ASMAtomicUoWriteS32(&s_i32, 0), "ASMAtomicUoWriteS32:");
1239 BENCH(ASMAtomicUoWriteU64(&s_u64, 0), "ASMAtomicUoWriteU64:");
1240 BENCH(ASMAtomicUoWriteS64(&s_i64, 0), "ASMAtomicUoWriteS64:");
1241 BENCH(ASMAtomicWriteU8(&s_u8, 0), "ASMAtomicWriteU8:");
1242 BENCH(ASMAtomicWriteS8(&s_i8, 0), "ASMAtomicWriteS8:");
1243 BENCH(ASMAtomicWriteU16(&s_u16, 0), "ASMAtomicWriteU16:");
1244 BENCH(ASMAtomicWriteS16(&s_i16, 0), "ASMAtomicWriteS16:");
1245 BENCH(ASMAtomicWriteU32(&s_u32, 0), "ASMAtomicWriteU32:");
1246 BENCH(ASMAtomicWriteS32(&s_i32, 0), "ASMAtomicWriteS32:");
1247 BENCH(ASMAtomicWriteU64(&s_u64, 0), "ASMAtomicWriteU64:");
1248 BENCH(ASMAtomicWriteS64(&s_i64, 0), "ASMAtomicWriteS64:");
1249 BENCH(ASMAtomicXchgU8(&s_u8, 0), "ASMAtomicXchgU8:");
1250 BENCH(ASMAtomicXchgS8(&s_i8, 0), "ASMAtomicXchgS8:");
1251 BENCH(ASMAtomicXchgU16(&s_u16, 0), "ASMAtomicXchgU16:");
1252 BENCH(ASMAtomicXchgS16(&s_i16, 0), "ASMAtomicXchgS16:");
1253 BENCH(ASMAtomicXchgU32(&s_u32, 0), "ASMAtomicXchgU32:");
1254 BENCH(ASMAtomicXchgS32(&s_i32, 0), "ASMAtomicXchgS32:");
1255 BENCH(ASMAtomicXchgU64(&s_u64, 0), "ASMAtomicXchgU64:");
1256 BENCH(ASMAtomicXchgS64(&s_i64, 0), "ASMAtomicXchgS64:");
1257 BENCH(ASMAtomicCmpXchgU32(&s_u32, 0, 0), "ASMAtomicCmpXchgU32:");
1258 BENCH(ASMAtomicCmpXchgS32(&s_i32, 0, 0), "ASMAtomicCmpXchgS32:");
1259 BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 0), "ASMAtomicCmpXchgU64:");
1260 BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 0), "ASMAtomicCmpXchgS64:");
1261 BENCH(ASMAtomicCmpXchgU32(&s_u32, 0, 1), "ASMAtomicCmpXchgU32/neg:");
1262 BENCH(ASMAtomicCmpXchgS32(&s_i32, 0, 1), "ASMAtomicCmpXchgS32/neg:");
1263 BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 1), "ASMAtomicCmpXchgU64/neg:");
1264 BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 1), "ASMAtomicCmpXchgS64/neg:");
1265 BENCH(ASMAtomicIncU32(&s_u32), "ASMAtomicIncU32:");
1266 BENCH(ASMAtomicIncS32(&s_i32), "ASMAtomicIncS32:");
1267 BENCH(ASMAtomicDecU32(&s_u32), "ASMAtomicDecU32:");
1268 BENCH(ASMAtomicDecS32(&s_i32), "ASMAtomicDecS32:");
1269 BENCH(ASMAtomicAddU32(&s_u32, 5), "ASMAtomicAddU32:");
1270 BENCH(ASMAtomicAddS32(&s_i32, 5), "ASMAtomicAddS32:");
1271
1272 RTPrintf("Done.\n");
1273
1274#undef BENCH
1275}
1276
1277
1278int main(int argc, char *argv[])
1279{
1280 RTTEST hTest;
1281 int rc = RTTestInitAndCreate("tstInlineAsm", &hTest);
1282 if (rc)
1283 return rc;
1284 RTTestBanner(hTest);
1285
1286 /*
1287 * Execute the tests.
1288 */
1289#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1290 tstASMCpuId();
1291#endif
1292 tstASMAtomicXchgU8();
1293 tstASMAtomicXchgU16();
1294 tstASMAtomicXchgU32();
1295 tstASMAtomicXchgU64();
1296 tstASMAtomicXchgPtr();
1297 tstASMAtomicCmpXchgU8();
1298 tstASMAtomicCmpXchgU32();
1299 tstASMAtomicCmpXchgU64();
1300 tstASMAtomicCmpXchgExU32();
1301 tstASMAtomicCmpXchgExU64();
1302 tstASMAtomicReadU64();
1303 tstASMAtomicUoReadU64();
1304 tstASMAtomicAddS32();
1305 tstASMAtomicDecIncS32();
1306 tstASMAtomicAndOrU32();
1307 tstASMMemZeroPage();
1308 tstASMMemIsZeroPage(hTest);
1309 tstASMMemZero32();
1310 tstASMMemFill32();
1311 tstASMMath();
1312 tstASMByteSwap();
1313 tstASMBench();
1314
1315 /*
1316 * Show the result.
1317 */
1318 return RTTestSummaryAndDestroy(hTest);
1319}
1320
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