VirtualBox

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

Last change on this file since 30955 was 30801, checked in by vboxsync, 15 years ago

iprt/asm-amd64-x86.h: Added the missing ASMCpuId_<reg>() variants.

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

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