VirtualBox

source: vbox/trunk/include/iprt/asm-amd64-x86.h@ 87835

Last change on this file since 87835 was 87404, checked in by vboxsync, 4 years ago

iprt/asm-amd64-x86.h: Found intrinsics for lidt, sidt, lgdt and sgdt in Visual C++ 2013 and later.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.2 KB
Line 
1/** @file
2 * IPRT - AMD64 and x86 Specific Assembly Functions.
3 */
4
5/*
6 * Copyright (C) 2006-2020 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef IPRT_INCLUDED_asm_amd64_x86_h
27#define IPRT_INCLUDED_asm_amd64_x86_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <iprt/types.h>
33#include <iprt/assert.h>
34#if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)
35# error "Not on AMD64 or x86"
36#endif
37
38#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN
39/* Emit the intrinsics at all optimization levels. */
40# include <iprt/sanitized/intrin.h>
41# pragma intrinsic(_ReadWriteBarrier)
42# pragma intrinsic(__cpuid)
43# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 /*?*/
44# pragma intrinsic(__cpuidex)
45# endif
46# pragma intrinsic(_enable)
47# pragma intrinsic(_disable)
48# pragma intrinsic(__rdtsc)
49# pragma intrinsic(__readmsr)
50# pragma intrinsic(__writemsr)
51# pragma intrinsic(__outbyte)
52# pragma intrinsic(__outbytestring)
53# pragma intrinsic(__outword)
54# pragma intrinsic(__outwordstring)
55# pragma intrinsic(__outdword)
56# pragma intrinsic(__outdwordstring)
57# pragma intrinsic(__inbyte)
58# pragma intrinsic(__inbytestring)
59# pragma intrinsic(__inword)
60# pragma intrinsic(__inwordstring)
61# pragma intrinsic(__indword)
62# pragma intrinsic(__indwordstring)
63# pragma intrinsic(__invlpg)
64# pragma intrinsic(__wbinvd)
65# pragma intrinsic(__readcr0)
66# pragma intrinsic(__readcr2)
67# pragma intrinsic(__readcr3)
68# pragma intrinsic(__readcr4)
69# pragma intrinsic(__writecr0)
70# pragma intrinsic(__writecr3)
71# pragma intrinsic(__writecr4)
72# pragma intrinsic(__readdr)
73# pragma intrinsic(__writedr)
74# ifdef RT_ARCH_AMD64
75# pragma intrinsic(__readcr8)
76# pragma intrinsic(__writecr8)
77# endif
78# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2005
79# pragma intrinsic(__halt)
80# endif
81# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
82/*# pragma intrinsic(__readeflags) - buggy intrinsics in VC++ 2010, reordering/optimizers issues
83# pragma intrinsic(__writeeflags) */
84# pragma intrinsic(__rdtscp)
85# endif
86# if defined(RT_ARCH_AMD64) && RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015 /*?*/
87# pragma intrinsic(_readfsbase_u64)
88# pragma intrinsic(_readgsbase_u64)
89# pragma intrinsic(_writefsbase_u64)
90# pragma intrinsic(_writegsbase_u64)
91# endif
92# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013
93# pragma intrinsic(__lidt)
94# pragma intrinsic(__sidt)
95# pragma intrinsic(_lgdt)
96# pragma intrinsic(_sgdt)
97# endif
98#endif
99
100
101/*
102 * Undefine all symbols we have Watcom C/C++ #pragma aux'es for.
103 */
104#if defined(__WATCOMC__) && ARCH_BITS == 16
105# include "asm-amd64-x86-watcom-16.h"
106#elif defined(__WATCOMC__) && ARCH_BITS == 32
107# include "asm-amd64-x86-watcom-32.h"
108#endif
109
110
111/** @defgroup grp_rt_asm_amd64_x86 AMD64 and x86 Specific ASM Routines
112 * @ingroup grp_rt_asm
113 * @{
114 */
115
116/** @todo find a more proper place for these structures? */
117
118#pragma pack(1)
119/** IDTR */
120typedef struct RTIDTR
121{
122 /** Size of the IDT. */
123 uint16_t cbIdt;
124 /** Address of the IDT. */
125#if ARCH_BITS != 64
126 uint32_t pIdt;
127#else
128 uint64_t pIdt;
129#endif
130} RTIDTR, RT_FAR *PRTIDTR;
131#pragma pack()
132
133#pragma pack(1)
134/** @internal */
135typedef struct RTIDTRALIGNEDINT
136{
137 /** Alignment padding. */
138 uint16_t au16Padding[ARCH_BITS == 64 ? 3 : 1];
139 /** The IDTR structure. */
140 RTIDTR Idtr;
141} RTIDTRALIGNEDINT;
142#pragma pack()
143
144/** Wrapped RTIDTR for preventing misalignment exceptions. */
145typedef union RTIDTRALIGNED
146{
147 /** Try make sure this structure has optimal alignment. */
148 uint64_t auAlignmentHack[ARCH_BITS == 64 ? 2 : 1];
149 /** Aligned structure. */
150 RTIDTRALIGNEDINT s;
151} RTIDTRALIGNED;
152AssertCompileSize(RTIDTRALIGNED, ((ARCH_BITS == 64) + 1) * 8);
153/** Pointer to a an RTIDTR alignment wrapper. */
154typedef RTIDTRALIGNED RT_FAR *PRIDTRALIGNED;
155
156
157#pragma pack(1)
158/** GDTR */
159typedef struct RTGDTR
160{
161 /** Size of the GDT. */
162 uint16_t cbGdt;
163 /** Address of the GDT. */
164#if ARCH_BITS != 64
165 uint32_t pGdt;
166#else
167 uint64_t pGdt;
168#endif
169} RTGDTR, RT_FAR *PRTGDTR;
170#pragma pack()
171
172#pragma pack(1)
173/** @internal */
174typedef struct RTGDTRALIGNEDINT
175{
176 /** Alignment padding. */
177 uint16_t au16Padding[ARCH_BITS == 64 ? 3 : 1];
178 /** The GDTR structure. */
179 RTGDTR Gdtr;
180} RTGDTRALIGNEDINT;
181#pragma pack()
182
183/** Wrapped RTGDTR for preventing misalignment exceptions. */
184typedef union RTGDTRALIGNED
185{
186 /** Try make sure this structure has optimal alignment. */
187 uint64_t auAlignmentHack[ARCH_BITS == 64 ? 2 : 1];
188 /** Aligned structure. */
189 RTGDTRALIGNEDINT s;
190} RTGDTRALIGNED;
191AssertCompileSize(RTIDTRALIGNED, ((ARCH_BITS == 64) + 1) * 8);
192/** Pointer to a an RTGDTR alignment wrapper. */
193typedef RTGDTRALIGNED RT_FAR *PRGDTRALIGNED;
194
195
196/**
197 * Gets the content of the IDTR CPU register.
198 * @param pIdtr Where to store the IDTR contents.
199 */
200#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013
201RT_ASM_DECL_PRAGMA_WATCOM(void) ASMGetIDTR(PRTIDTR pIdtr);
202#else
203DECLINLINE(void) ASMGetIDTR(PRTIDTR pIdtr)
204{
205# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013
206 __sidt(pIdtr);
207# elif RT_INLINE_ASM_GNU_STYLE
208 __asm__ __volatile__("sidt %0" : "=m" (*pIdtr));
209# else
210 __asm
211 {
212# ifdef RT_ARCH_AMD64
213 mov rax, [pIdtr]
214 sidt [rax]
215# else
216 mov eax, [pIdtr]
217 sidt [eax]
218# endif
219 }
220# endif
221}
222#endif
223
224
225/**
226 * Gets the content of the IDTR.LIMIT CPU register.
227 * @returns IDTR limit.
228 */
229#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013
230RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMGetIdtrLimit(void);
231#else
232DECLINLINE(uint16_t) ASMGetIdtrLimit(void)
233{
234 RTIDTRALIGNED TmpIdtr;
235# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013
236 __sidt(&TmpIdtr);
237# elif RT_INLINE_ASM_GNU_STYLE
238 __asm__ __volatile__("sidt %0" : "=m" (TmpIdtr.s.Idtr));
239# else
240 __asm
241 {
242 sidt [TmpIdtr.s.Idtr]
243 }
244# endif
245 return TmpIdtr.s.Idtr.cbIdt;
246}
247#endif
248
249
250/**
251 * Sets the content of the IDTR CPU register.
252 * @param pIdtr Where to load the IDTR contents from
253 */
254#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013
255RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetIDTR(const RTIDTR RT_FAR *pIdtr);
256#else
257DECLINLINE(void) ASMSetIDTR(const RTIDTR RT_FAR *pIdtr)
258{
259# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013
260 __lidt((void *)pIdtr);
261# elif RT_INLINE_ASM_GNU_STYLE
262 __asm__ __volatile__("lidt %0" : : "m" (*pIdtr));
263# else
264 __asm
265 {
266# ifdef RT_ARCH_AMD64
267 mov rax, [pIdtr]
268 lidt [rax]
269# else
270 mov eax, [pIdtr]
271 lidt [eax]
272# endif
273 }
274# endif
275}
276#endif
277
278
279/**
280 * Gets the content of the GDTR CPU register.
281 * @param pGdtr Where to store the GDTR contents.
282 */
283#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013
284RT_ASM_DECL_PRAGMA_WATCOM(void) ASMGetGDTR(PRTGDTR pGdtr);
285#else
286DECLINLINE(void) ASMGetGDTR(PRTGDTR pGdtr)
287{
288# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013
289 _sgdt(pGdtr);
290# elif RT_INLINE_ASM_GNU_STYLE
291 __asm__ __volatile__("sgdt %0" : "=m" (*pGdtr));
292# else
293 __asm
294 {
295# ifdef RT_ARCH_AMD64
296 mov rax, [pGdtr]
297 sgdt [rax]
298# else
299 mov eax, [pGdtr]
300 sgdt [eax]
301# endif
302 }
303# endif
304}
305#endif
306
307
308/**
309 * Sets the content of the GDTR CPU register.
310 * @param pGdtr Where to load the GDTR contents from
311 */
312#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2013
313RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetGDTR(const RTGDTR RT_FAR *pGdtr);
314#else
315DECLINLINE(void) ASMSetGDTR(const RTGDTR RT_FAR *pGdtr)
316{
317# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2013
318 _lgdt((void *)pGdtr);
319# elif RT_INLINE_ASM_GNU_STYLE
320 __asm__ __volatile__("lgdt %0" : : "m" (*pGdtr));
321# else
322 __asm
323 {
324# ifdef RT_ARCH_AMD64
325 mov rax, [pGdtr]
326 lgdt [rax]
327# else
328 mov eax, [pGdtr]
329 lgdt [eax]
330# endif
331 }
332# endif
333}
334#endif
335
336
337
338/**
339 * Get the cs register.
340 * @returns cs.
341 */
342#if RT_INLINE_ASM_EXTERNAL
343RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetCS(void);
344#else
345DECLINLINE(RTSEL) ASMGetCS(void)
346{
347 RTSEL SelCS;
348# if RT_INLINE_ASM_GNU_STYLE
349 __asm__ __volatile__("movw %%cs, %0\n\t" : "=r" (SelCS));
350# else
351 __asm
352 {
353 mov ax, cs
354 mov [SelCS], ax
355 }
356# endif
357 return SelCS;
358}
359#endif
360
361
362/**
363 * Get the DS register.
364 * @returns DS.
365 */
366#if RT_INLINE_ASM_EXTERNAL
367RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetDS(void);
368#else
369DECLINLINE(RTSEL) ASMGetDS(void)
370{
371 RTSEL SelDS;
372# if RT_INLINE_ASM_GNU_STYLE
373 __asm__ __volatile__("movw %%ds, %0\n\t" : "=r" (SelDS));
374# else
375 __asm
376 {
377 mov ax, ds
378 mov [SelDS], ax
379 }
380# endif
381 return SelDS;
382}
383#endif
384
385
386/**
387 * Get the ES register.
388 * @returns ES.
389 */
390#if RT_INLINE_ASM_EXTERNAL
391RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetES(void);
392#else
393DECLINLINE(RTSEL) ASMGetES(void)
394{
395 RTSEL SelES;
396# if RT_INLINE_ASM_GNU_STYLE
397 __asm__ __volatile__("movw %%es, %0\n\t" : "=r" (SelES));
398# else
399 __asm
400 {
401 mov ax, es
402 mov [SelES], ax
403 }
404# endif
405 return SelES;
406}
407#endif
408
409
410/**
411 * Get the FS register.
412 * @returns FS.
413 */
414#if RT_INLINE_ASM_EXTERNAL
415RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetFS(void);
416#else
417DECLINLINE(RTSEL) ASMGetFS(void)
418{
419 RTSEL SelFS;
420# if RT_INLINE_ASM_GNU_STYLE
421 __asm__ __volatile__("movw %%fs, %0\n\t" : "=r" (SelFS));
422# else
423 __asm
424 {
425 mov ax, fs
426 mov [SelFS], ax
427 }
428# endif
429 return SelFS;
430}
431# endif
432
433#ifdef RT_ARCH_AMD64
434
435/**
436 * Get the FS base register.
437 * @returns FS base address.
438 */
439#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/
440DECLASM(uint64_t) ASMGetFSBase(void);
441#else
442DECLINLINE(uint64_t) ASMGetFSBase(void)
443{
444# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015
445 return (uint64_t)_readfsbase_u64();
446# elif RT_INLINE_ASM_GNU_STYLE
447 uint64_t uFSBase;
448 __asm__ __volatile__("rdfsbase %0\n\t" : "=r" (uFSBase));
449 return uFSBase;
450# endif
451}
452# endif
453
454
455/**
456 * Set the FS base register.
457 * @param uNewBase The new base value.
458 */
459#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/
460DECLASM(void) ASMSetFSBase(uint64_t uNewBase);
461#else
462DECLINLINE(void) ASMSetFSBase(uint64_t uNewBase)
463{
464# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015
465 _writefsbase_u64(uNewBase);
466# elif RT_INLINE_ASM_GNU_STYLE
467 __asm__ __volatile__("wrfsbase %0\n\t" : : "r" (uNewBase));
468# endif
469}
470# endif
471
472#endif /* RT_ARCH_AMD64 */
473
474/**
475 * Get the GS register.
476 * @returns GS.
477 */
478#if RT_INLINE_ASM_EXTERNAL
479RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetGS(void);
480#else
481DECLINLINE(RTSEL) ASMGetGS(void)
482{
483 RTSEL SelGS;
484# if RT_INLINE_ASM_GNU_STYLE
485 __asm__ __volatile__("movw %%gs, %0\n\t" : "=r" (SelGS));
486# else
487 __asm
488 {
489 mov ax, gs
490 mov [SelGS], ax
491 }
492# endif
493 return SelGS;
494}
495#endif
496
497#ifdef RT_ARCH_AMD64
498
499/**
500 * Get the GS base register.
501 * @returns GS base address.
502 */
503#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/
504DECLASM(uint64_t) ASMGetGSBase(void);
505#else
506DECLINLINE(uint64_t) ASMGetGSBase(void)
507{
508# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015
509 return (uint64_t)_readgsbase_u64();
510# elif RT_INLINE_ASM_GNU_STYLE
511 uint64_t uGSBase;
512 __asm__ __volatile__("rdgsbase %0\n\t" : "=r" (uGSBase));
513 return uGSBase;
514# endif
515}
516# endif
517
518
519/**
520 * Set the GS base register.
521 * @param uNewBase The new base value.
522 */
523#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2015 /*?*/
524DECLASM(void) ASMSetGSBase(uint64_t uNewBase);
525#else
526DECLINLINE(void) ASMSetGSBase(uint64_t uNewBase)
527{
528# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2015
529 _writegsbase_u64(uNewBase);
530# elif RT_INLINE_ASM_GNU_STYLE
531 __asm__ __volatile__("wrgsbase %0\n\t" : : "r" (uNewBase));
532# endif
533}
534# endif
535
536#endif /* RT_ARCH_AMD64 */
537
538
539/**
540 * Get the SS register.
541 * @returns SS.
542 */
543#if RT_INLINE_ASM_EXTERNAL
544RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetSS(void);
545#else
546DECLINLINE(RTSEL) ASMGetSS(void)
547{
548 RTSEL SelSS;
549# if RT_INLINE_ASM_GNU_STYLE
550 __asm__ __volatile__("movw %%ss, %0\n\t" : "=r" (SelSS));
551# else
552 __asm
553 {
554 mov ax, ss
555 mov [SelSS], ax
556 }
557# endif
558 return SelSS;
559}
560#endif
561
562
563/**
564 * Get the TR register.
565 * @returns TR.
566 */
567#if RT_INLINE_ASM_EXTERNAL
568RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetTR(void);
569#else
570DECLINLINE(RTSEL) ASMGetTR(void)
571{
572 RTSEL SelTR;
573# if RT_INLINE_ASM_GNU_STYLE
574 __asm__ __volatile__("str %w0\n\t" : "=r" (SelTR));
575# else
576 __asm
577 {
578 str ax
579 mov [SelTR], ax
580 }
581# endif
582 return SelTR;
583}
584#endif
585
586
587/**
588 * Get the LDTR register.
589 * @returns LDTR.
590 */
591#if RT_INLINE_ASM_EXTERNAL
592RT_ASM_DECL_PRAGMA_WATCOM(RTSEL) ASMGetLDTR(void);
593#else
594DECLINLINE(RTSEL) ASMGetLDTR(void)
595{
596 RTSEL SelLDTR;
597# if RT_INLINE_ASM_GNU_STYLE
598 __asm__ __volatile__("sldt %w0\n\t" : "=r" (SelLDTR));
599# else
600 __asm
601 {
602 sldt ax
603 mov [SelLDTR], ax
604 }
605# endif
606 return SelLDTR;
607}
608#endif
609
610
611/**
612 * Get the access rights for the segment selector.
613 *
614 * @returns The access rights on success or UINT32_MAX on failure.
615 * @param uSel The selector value.
616 *
617 * @remarks Using UINT32_MAX for failure is chosen because valid access rights
618 * always have bits 0:7 as 0 (on both Intel & AMD).
619 */
620#if RT_INLINE_ASM_EXTERNAL
621RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMGetSegAttr(uint32_t uSel);
622#else
623DECLINLINE(uint32_t) ASMGetSegAttr(uint32_t uSel)
624{
625 uint32_t uAttr;
626 /* LAR only accesses 16-bit of the source operand, but eax for the
627 destination operand is required for getting the full 32-bit access rights. */
628# if RT_INLINE_ASM_GNU_STYLE
629 __asm__ __volatile__("lar %1, %%eax\n\t"
630 "jz done%=\n\t"
631 "movl $0xffffffff, %%eax\n\t"
632 "done%=:\n\t"
633 "movl %%eax, %0\n\t"
634 : "=r" (uAttr)
635 : "r" (uSel)
636 : "cc", "%eax");
637# else
638 __asm
639 {
640 lar eax, [uSel]
641 jz done
642 mov eax, 0ffffffffh
643 done:
644 mov [uAttr], eax
645 }
646# endif
647 return uAttr;
648}
649#endif
650
651
652/**
653 * Get the [RE]FLAGS register.
654 * @returns [RE]FLAGS.
655 */
656#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
657RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMGetFlags(void);
658#else
659DECLINLINE(RTCCUINTREG) ASMGetFlags(void)
660{
661 RTCCUINTREG uFlags;
662# if RT_INLINE_ASM_GNU_STYLE
663# ifdef RT_ARCH_AMD64
664 __asm__ __volatile__("pushfq\n\t"
665 "popq %0\n\t"
666 : "=r" (uFlags));
667# else
668 __asm__ __volatile__("pushfl\n\t"
669 "popl %0\n\t"
670 : "=r" (uFlags));
671# endif
672# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
673 uFlags = __readeflags();
674# else
675 __asm
676 {
677# ifdef RT_ARCH_AMD64
678 pushfq
679 pop [uFlags]
680# else
681 pushfd
682 pop [uFlags]
683# endif
684 }
685# endif
686 return uFlags;
687}
688#endif
689
690
691/**
692 * Set the [RE]FLAGS register.
693 * @param uFlags The new [RE]FLAGS value.
694 */
695#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - see __readeflags() above. */
696RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetFlags(RTCCUINTREG uFlags);
697#else
698DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags)
699{
700# if RT_INLINE_ASM_GNU_STYLE
701# ifdef RT_ARCH_AMD64
702 __asm__ __volatile__("pushq %0\n\t"
703 "popfq\n\t"
704 : : "g" (uFlags));
705# else
706 __asm__ __volatile__("pushl %0\n\t"
707 "popfl\n\t"
708 : : "g" (uFlags));
709# endif
710# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
711 __writeeflags(uFlags);
712# else
713 __asm
714 {
715# ifdef RT_ARCH_AMD64
716 push [uFlags]
717 popfq
718# else
719 push [uFlags]
720 popfd
721# endif
722 }
723# endif
724}
725#endif
726
727
728/**
729 * Modifies the [RE]FLAGS register.
730 * @returns Original value.
731 * @param fAndEfl Flags to keep (applied first).
732 * @param fOrEfl Flags to be set.
733 */
734#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
735RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl);
736#else
737DECLINLINE(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl)
738{
739 RTCCUINTREG fOldEfl;
740# if RT_INLINE_ASM_GNU_STYLE
741# ifdef RT_ARCH_AMD64
742 __asm__ __volatile__("pushfq\n\t"
743 "movq (%%rsp), %0\n\t"
744 "andq %0, %1\n\t"
745 "orq %3, %1\n\t"
746 "mov %1, (%%rsp)\n\t"
747 "popfq\n\t"
748 : "=&r" (fOldEfl),
749 "=r" (fAndEfl)
750 : "1" (fAndEfl),
751 "rn" (fOrEfl) );
752# else
753 __asm__ __volatile__("pushfl\n\t"
754 "movl (%%esp), %0\n\t"
755 "andl %1, (%%esp)\n\t"
756 "orl %2, (%%esp)\n\t"
757 "popfl\n\t"
758 : "=&r" (fOldEfl)
759 : "rn" (fAndEfl),
760 "rn" (fOrEfl) );
761# endif
762# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
763 fOldEfl = __readeflags();
764 __writeeflags((fOldEfl & fAndEfl) | fOrEfl);
765# else
766 __asm
767 {
768# ifdef RT_ARCH_AMD64
769 mov rdx, [fAndEfl]
770 mov rcx, [fOrEfl]
771 pushfq
772 mov rax, [rsp]
773 and rdx, rax
774 or rdx, rcx
775 mov [rsp], rdx
776 popfq
777 mov [fOldEfl], rax
778# else
779 mov edx, [fAndEfl]
780 mov ecx, [fOrEfl]
781 pushfd
782 mov eax, [esp]
783 and edx, eax
784 or edx, ecx
785 mov [esp], edx
786 popfd
787 mov [fOldEfl], eax
788# endif
789 }
790# endif
791 return fOldEfl;
792}
793#endif
794
795
796/**
797 * Modifies the [RE]FLAGS register by ORing in one or more flags.
798 * @returns Original value.
799 * @param fOrEfl The flags to be set (ORed in).
800 */
801#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
802RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl);
803#else
804DECLINLINE(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl)
805{
806 RTCCUINTREG fOldEfl;
807# if RT_INLINE_ASM_GNU_STYLE
808# ifdef RT_ARCH_AMD64
809 __asm__ __volatile__("pushfq\n\t"
810 "movq (%%rsp), %0\n\t"
811 "orq %1, (%%rsp)\n\t"
812 "popfq\n\t"
813 : "=&r" (fOldEfl)
814 : "rn" (fOrEfl) );
815# else
816 __asm__ __volatile__("pushfl\n\t"
817 "movl (%%esp), %0\n\t"
818 "orl %1, (%%esp)\n\t"
819 "popfl\n\t"
820 : "=&r" (fOldEfl)
821 : "rn" (fOrEfl) );
822# endif
823# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
824 fOldEfl = __readeflags();
825 __writeeflags(fOldEfl | fOrEfl);
826# else
827 __asm
828 {
829# ifdef RT_ARCH_AMD64
830 mov rcx, [fOrEfl]
831 pushfq
832 mov rdx, [rsp]
833 or [rsp], rcx
834 popfq
835 mov [fOldEfl], rax
836# else
837 mov ecx, [fOrEfl]
838 pushfd
839 mov edx, [esp]
840 or [esp], ecx
841 popfd
842 mov [fOldEfl], eax
843# endif
844 }
845# endif
846 return fOldEfl;
847}
848#endif
849
850
851/**
852 * Modifies the [RE]FLAGS register by AND'ing out one or more flags.
853 * @returns Original value.
854 * @param fAndEfl The flags to keep.
855 */
856#if RT_INLINE_ASM_EXTERNAL /*&& RT_INLINE_ASM_USES_INTRIN < 15 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
857RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl);
858#else
859DECLINLINE(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl)
860{
861 RTCCUINTREG fOldEfl;
862# if RT_INLINE_ASM_GNU_STYLE
863# ifdef RT_ARCH_AMD64
864 __asm__ __volatile__("pushfq\n\t"
865 "movq (%%rsp), %0\n\t"
866 "andq %1, (%%rsp)\n\t"
867 "popfq\n\t"
868 : "=&r" (fOldEfl)
869 : "rn" (fAndEfl) );
870# else
871 __asm__ __volatile__("pushfl\n\t"
872 "movl (%%esp), %0\n\t"
873 "andl %1, (%%esp)\n\t"
874 "popfl\n\t"
875 : "=&r" (fOldEfl)
876 : "rn" (fAndEfl) );
877# endif
878# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
879 fOldEfl = __readeflags();
880 __writeeflags(fOldEfl & fAndEfl);
881# else
882 __asm
883 {
884# ifdef RT_ARCH_AMD64
885 mov rdx, [fAndEfl]
886 pushfq
887 mov rdx, [rsp]
888 and [rsp], rdx
889 popfq
890 mov [fOldEfl], rax
891# else
892 mov edx, [fAndEfl]
893 pushfd
894 mov edx, [esp]
895 and [esp], edx
896 popfd
897 mov [fOldEfl], eax
898# endif
899 }
900# endif
901 return fOldEfl;
902}
903#endif
904
905
906/**
907 * Gets the content of the CPU timestamp counter register.
908 *
909 * @returns TSC.
910 */
911#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
912RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMReadTSC(void);
913#else
914DECLINLINE(uint64_t) ASMReadTSC(void)
915{
916 RTUINT64U u;
917# if RT_INLINE_ASM_GNU_STYLE
918 __asm__ __volatile__("rdtsc\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi));
919# else
920# if RT_INLINE_ASM_USES_INTRIN
921 u.u = __rdtsc();
922# else
923 __asm
924 {
925 rdtsc
926 mov [u.s.Lo], eax
927 mov [u.s.Hi], edx
928 }
929# endif
930# endif
931 return u.u;
932}
933#endif
934
935
936/**
937 * Gets the content of the CPU timestamp counter register and the
938 * assoicated AUX value.
939 *
940 * @returns TSC.
941 * @param puAux Where to store the AUX value.
942 */
943#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2008
944RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMReadTscWithAux(uint32_t RT_FAR *puAux);
945#else
946DECLINLINE(uint64_t) ASMReadTscWithAux(uint32_t RT_FAR *puAux)
947{
948 RTUINT64U u;
949# if RT_INLINE_ASM_GNU_STYLE
950 /* rdtscp is not supported by ancient linux build VM of course :-( */
951 /*__asm__ __volatile__("rdtscp\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi), "=c" (*puAux)); */
952 __asm__ __volatile__(".byte 0x0f,0x01,0xf9\n\t" : "=a" (u.s.Lo), "=d" (u.s.Hi), "=c" (*puAux));
953# else
954# if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2008
955 u.u = __rdtscp(puAux);
956# else
957 __asm
958 {
959 rdtscp
960 mov [u.s.Lo], eax
961 mov [u.s.Hi], edx
962 mov eax, [puAux]
963 mov [eax], ecx
964 }
965# endif
966# endif
967 return u.u;
968}
969#endif
970
971
972/**
973 * Performs the cpuid instruction returning all registers.
974 *
975 * @param uOperator CPUID operation (eax).
976 * @param pvEAX Where to store eax.
977 * @param pvEBX Where to store ebx.
978 * @param pvECX Where to store ecx.
979 * @param pvEDX Where to store edx.
980 * @remark We're using void pointers to ease the use of special bitfield structures and such.
981 */
982#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
983DECLASM(void) ASMCpuId(uint32_t uOperator, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX);
984#else
985DECLINLINE(void) ASMCpuId(uint32_t uOperator, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX)
986{
987# if RT_INLINE_ASM_GNU_STYLE
988# ifdef RT_ARCH_AMD64
989 RTCCUINTREG uRAX, uRBX, uRCX, uRDX;
990 __asm__ __volatile__ ("cpuid\n\t"
991 : "=a" (uRAX),
992 "=b" (uRBX),
993 "=c" (uRCX),
994 "=d" (uRDX)
995 : "0" (uOperator), "2" (0));
996 *(uint32_t RT_FAR *)pvEAX = (uint32_t)uRAX;
997 *(uint32_t RT_FAR *)pvEBX = (uint32_t)uRBX;
998 *(uint32_t RT_FAR *)pvECX = (uint32_t)uRCX;
999 *(uint32_t RT_FAR *)pvEDX = (uint32_t)uRDX;
1000# else
1001 __asm__ __volatile__ ("xchgl %%ebx, %1\n\t"
1002 "cpuid\n\t"
1003 "xchgl %%ebx, %1\n\t"
1004 : "=a" (*(uint32_t *)pvEAX),
1005 "=r" (*(uint32_t *)pvEBX),
1006 "=c" (*(uint32_t *)pvECX),
1007 "=d" (*(uint32_t *)pvEDX)
1008 : "0" (uOperator), "2" (0));
1009# endif
1010
1011# elif RT_INLINE_ASM_USES_INTRIN
1012 int aInfo[4];
1013 __cpuid(aInfo, uOperator);
1014 *(uint32_t RT_FAR *)pvEAX = aInfo[0];
1015 *(uint32_t RT_FAR *)pvEBX = aInfo[1];
1016 *(uint32_t RT_FAR *)pvECX = aInfo[2];
1017 *(uint32_t RT_FAR *)pvEDX = aInfo[3];
1018
1019# else
1020 uint32_t uEAX;
1021 uint32_t uEBX;
1022 uint32_t uECX;
1023 uint32_t uEDX;
1024 __asm
1025 {
1026 push ebx
1027 mov eax, [uOperator]
1028 cpuid
1029 mov [uEAX], eax
1030 mov [uEBX], ebx
1031 mov [uECX], ecx
1032 mov [uEDX], edx
1033 pop ebx
1034 }
1035 *(uint32_t RT_FAR *)pvEAX = uEAX;
1036 *(uint32_t RT_FAR *)pvEBX = uEBX;
1037 *(uint32_t RT_FAR *)pvECX = uECX;
1038 *(uint32_t RT_FAR *)pvEDX = uEDX;
1039# endif
1040}
1041#endif
1042
1043
1044/**
1045 * Performs the CPUID instruction with EAX and ECX input returning ALL output
1046 * registers.
1047 *
1048 * @param uOperator CPUID operation (eax).
1049 * @param uIdxECX ecx index
1050 * @param pvEAX Where to store eax.
1051 * @param pvEBX Where to store ebx.
1052 * @param pvECX Where to store ecx.
1053 * @param pvEDX Where to store edx.
1054 * @remark We're using void pointers to ease the use of special bitfield structures and such.
1055 */
1056#if RT_INLINE_ASM_EXTERNAL || RT_INLINE_ASM_USES_INTRIN
1057DECLASM(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX);
1058#else
1059DECLINLINE(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX)
1060{
1061# if RT_INLINE_ASM_GNU_STYLE
1062# ifdef RT_ARCH_AMD64
1063 RTCCUINTREG uRAX, uRBX, uRCX, uRDX;
1064 __asm__ ("cpuid\n\t"
1065 : "=a" (uRAX),
1066 "=b" (uRBX),
1067 "=c" (uRCX),
1068 "=d" (uRDX)
1069 : "0" (uOperator),
1070 "2" (uIdxECX));
1071 *(uint32_t RT_FAR *)pvEAX = (uint32_t)uRAX;
1072 *(uint32_t RT_FAR *)pvEBX = (uint32_t)uRBX;
1073 *(uint32_t RT_FAR *)pvECX = (uint32_t)uRCX;
1074 *(uint32_t RT_FAR *)pvEDX = (uint32_t)uRDX;
1075# else
1076 __asm__ ("xchgl %%ebx, %1\n\t"
1077 "cpuid\n\t"
1078 "xchgl %%ebx, %1\n\t"
1079 : "=a" (*(uint32_t *)pvEAX),
1080 "=r" (*(uint32_t *)pvEBX),
1081 "=c" (*(uint32_t *)pvECX),
1082 "=d" (*(uint32_t *)pvEDX)
1083 : "0" (uOperator),
1084 "2" (uIdxECX));
1085# endif
1086
1087# elif RT_INLINE_ASM_USES_INTRIN
1088 int aInfo[4];
1089 __cpuidex(aInfo, uOperator, uIdxECX);
1090 *(uint32_t RT_FAR *)pvEAX = aInfo[0];
1091 *(uint32_t RT_FAR *)pvEBX = aInfo[1];
1092 *(uint32_t RT_FAR *)pvECX = aInfo[2];
1093 *(uint32_t RT_FAR *)pvEDX = aInfo[3];
1094
1095# else
1096 uint32_t uEAX;
1097 uint32_t uEBX;
1098 uint32_t uECX;
1099 uint32_t uEDX;
1100 __asm
1101 {
1102 push ebx
1103 mov eax, [uOperator]
1104 mov ecx, [uIdxECX]
1105 cpuid
1106 mov [uEAX], eax
1107 mov [uEBX], ebx
1108 mov [uECX], ecx
1109 mov [uEDX], edx
1110 pop ebx
1111 }
1112 *(uint32_t RT_FAR *)pvEAX = uEAX;
1113 *(uint32_t RT_FAR *)pvEBX = uEBX;
1114 *(uint32_t RT_FAR *)pvECX = uECX;
1115 *(uint32_t RT_FAR *)pvEDX = uEDX;
1116# endif
1117}
1118#endif
1119
1120
1121/**
1122 * CPUID variant that initializes all 4 registers before the CPUID instruction.
1123 *
1124 * @returns The EAX result value.
1125 * @param uOperator CPUID operation (eax).
1126 * @param uInitEBX The value to assign EBX prior to the CPUID instruction.
1127 * @param uInitECX The value to assign ECX prior to the CPUID instruction.
1128 * @param uInitEDX The value to assign EDX prior to the CPUID instruction.
1129 * @param pvEAX Where to store eax. Optional.
1130 * @param pvEBX Where to store ebx. Optional.
1131 * @param pvECX Where to store ecx. Optional.
1132 * @param pvEDX Where to store edx. Optional.
1133 */
1134DECLASM(uint32_t) ASMCpuIdExSlow(uint32_t uOperator, uint32_t uInitEBX, uint32_t uInitECX, uint32_t uInitEDX,
1135 void RT_FAR *pvEAX, void RT_FAR *pvEBX, void RT_FAR *pvECX, void RT_FAR *pvEDX);
1136
1137
1138/**
1139 * Performs the cpuid instruction returning ecx and edx.
1140 *
1141 * @param uOperator CPUID operation (eax).
1142 * @param pvECX Where to store ecx.
1143 * @param pvEDX Where to store edx.
1144 * @remark We're using void pointers to ease the use of special bitfield structures and such.
1145 */
1146#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1147RT_ASM_DECL_PRAGMA_WATCOM(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void RT_FAR *pvECX, void RT_FAR *pvEDX);
1148#else
1149DECLINLINE(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void RT_FAR *pvECX, void RT_FAR *pvEDX)
1150{
1151 uint32_t uEBX;
1152 ASMCpuId(uOperator, &uOperator, &uEBX, pvECX, pvEDX);
1153}
1154#endif
1155
1156
1157/**
1158 * Performs the cpuid instruction returning eax.
1159 *
1160 * @param uOperator CPUID operation (eax).
1161 * @returns EAX after cpuid operation.
1162 */
1163#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1164RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EAX(uint32_t uOperator);
1165#else
1166DECLINLINE(uint32_t) ASMCpuId_EAX(uint32_t uOperator)
1167{
1168 RTCCUINTREG xAX;
1169# if RT_INLINE_ASM_GNU_STYLE
1170# ifdef RT_ARCH_AMD64
1171 __asm__ ("cpuid"
1172 : "=a" (xAX)
1173 : "0" (uOperator)
1174 : "rbx", "rcx", "rdx");
1175# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__)
1176 __asm__ ("push %%ebx\n\t"
1177 "cpuid\n\t"
1178 "pop %%ebx\n\t"
1179 : "=a" (xAX)
1180 : "0" (uOperator)
1181 : "ecx", "edx");
1182# else
1183 __asm__ ("cpuid"
1184 : "=a" (xAX)
1185 : "0" (uOperator)
1186 : "edx", "ecx", "ebx");
1187# endif
1188
1189# elif RT_INLINE_ASM_USES_INTRIN
1190 int aInfo[4];
1191 __cpuid(aInfo, uOperator);
1192 xAX = aInfo[0];
1193
1194# else
1195 __asm
1196 {
1197 push ebx
1198 mov eax, [uOperator]
1199 cpuid
1200 mov [xAX], eax
1201 pop ebx
1202 }
1203# endif
1204 return (uint32_t)xAX;
1205}
1206#endif
1207
1208
1209/**
1210 * Performs the cpuid instruction returning ebx.
1211 *
1212 * @param uOperator CPUID operation (eax).
1213 * @returns EBX after cpuid operation.
1214 */
1215#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1216RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EBX(uint32_t uOperator);
1217#else
1218DECLINLINE(uint32_t) ASMCpuId_EBX(uint32_t uOperator)
1219{
1220 RTCCUINTREG xBX;
1221# if RT_INLINE_ASM_GNU_STYLE
1222# ifdef RT_ARCH_AMD64
1223 RTCCUINTREG uSpill;
1224 __asm__ ("cpuid"
1225 : "=a" (uSpill),
1226 "=b" (xBX)
1227 : "0" (uOperator)
1228 : "rdx", "rcx");
1229# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__)
1230 __asm__ ("push %%ebx\n\t"
1231 "cpuid\n\t"
1232 "mov %%ebx, %%edx\n\t"
1233 "pop %%ebx\n\t"
1234 : "=a" (uOperator),
1235 "=d" (xBX)
1236 : "0" (uOperator)
1237 : "ecx");
1238# else
1239 __asm__ ("cpuid"
1240 : "=a" (uOperator),
1241 "=b" (xBX)
1242 : "0" (uOperator)
1243 : "edx", "ecx");
1244# endif
1245
1246# elif RT_INLINE_ASM_USES_INTRIN
1247 int aInfo[4];
1248 __cpuid(aInfo, uOperator);
1249 xBX = aInfo[1];
1250
1251# else
1252 __asm
1253 {
1254 push ebx
1255 mov eax, [uOperator]
1256 cpuid
1257 mov [xBX], ebx
1258 pop ebx
1259 }
1260# endif
1261 return (uint32_t)xBX;
1262}
1263#endif
1264
1265
1266/**
1267 * Performs the cpuid instruction returning ecx.
1268 *
1269 * @param uOperator CPUID operation (eax).
1270 * @returns ECX after cpuid operation.
1271 */
1272#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1273RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_ECX(uint32_t uOperator);
1274#else
1275DECLINLINE(uint32_t) ASMCpuId_ECX(uint32_t uOperator)
1276{
1277 RTCCUINTREG xCX;
1278# if RT_INLINE_ASM_GNU_STYLE
1279# ifdef RT_ARCH_AMD64
1280 RTCCUINTREG uSpill;
1281 __asm__ ("cpuid"
1282 : "=a" (uSpill),
1283 "=c" (xCX)
1284 : "0" (uOperator)
1285 : "rbx", "rdx");
1286# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__)
1287 __asm__ ("push %%ebx\n\t"
1288 "cpuid\n\t"
1289 "pop %%ebx\n\t"
1290 : "=a" (uOperator),
1291 "=c" (xCX)
1292 : "0" (uOperator)
1293 : "edx");
1294# else
1295 __asm__ ("cpuid"
1296 : "=a" (uOperator),
1297 "=c" (xCX)
1298 : "0" (uOperator)
1299 : "ebx", "edx");
1300
1301# endif
1302
1303# elif RT_INLINE_ASM_USES_INTRIN
1304 int aInfo[4];
1305 __cpuid(aInfo, uOperator);
1306 xCX = aInfo[2];
1307
1308# else
1309 __asm
1310 {
1311 push ebx
1312 mov eax, [uOperator]
1313 cpuid
1314 mov [xCX], ecx
1315 pop ebx
1316 }
1317# endif
1318 return (uint32_t)xCX;
1319}
1320#endif
1321
1322
1323/**
1324 * Performs the cpuid instruction returning edx.
1325 *
1326 * @param uOperator CPUID operation (eax).
1327 * @returns EDX after cpuid operation.
1328 */
1329#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1330RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMCpuId_EDX(uint32_t uOperator);
1331#else
1332DECLINLINE(uint32_t) ASMCpuId_EDX(uint32_t uOperator)
1333{
1334 RTCCUINTREG xDX;
1335# if RT_INLINE_ASM_GNU_STYLE
1336# ifdef RT_ARCH_AMD64
1337 RTCCUINTREG uSpill;
1338 __asm__ ("cpuid"
1339 : "=a" (uSpill),
1340 "=d" (xDX)
1341 : "0" (uOperator)
1342 : "rbx", "rcx");
1343# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__)
1344 __asm__ ("push %%ebx\n\t"
1345 "cpuid\n\t"
1346 "pop %%ebx\n\t"
1347 : "=a" (uOperator),
1348 "=d" (xDX)
1349 : "0" (uOperator)
1350 : "ecx");
1351# else
1352 __asm__ ("cpuid"
1353 : "=a" (uOperator),
1354 "=d" (xDX)
1355 : "0" (uOperator)
1356 : "ebx", "ecx");
1357# endif
1358
1359# elif RT_INLINE_ASM_USES_INTRIN
1360 int aInfo[4];
1361 __cpuid(aInfo, uOperator);
1362 xDX = aInfo[3];
1363
1364# else
1365 __asm
1366 {
1367 push ebx
1368 mov eax, [uOperator]
1369 cpuid
1370 mov [xDX], edx
1371 pop ebx
1372 }
1373# endif
1374 return (uint32_t)xDX;
1375}
1376#endif
1377
1378
1379/**
1380 * Checks if the current CPU supports CPUID.
1381 *
1382 * @returns true if CPUID is supported.
1383 */
1384#ifdef __WATCOMC__
1385DECLASM(bool) ASMHasCpuId(void);
1386#else
1387DECLINLINE(bool) ASMHasCpuId(void)
1388{
1389# ifdef RT_ARCH_AMD64
1390 return true; /* ASSUME that all amd64 compatible CPUs have cpuid. */
1391# else /* !RT_ARCH_AMD64 */
1392 bool fRet = false;
1393# if RT_INLINE_ASM_GNU_STYLE
1394 uint32_t u1;
1395 uint32_t u2;
1396 __asm__ ("pushf\n\t"
1397 "pop %1\n\t"
1398 "mov %1, %2\n\t"
1399 "xorl $0x200000, %1\n\t"
1400 "push %1\n\t"
1401 "popf\n\t"
1402 "pushf\n\t"
1403 "pop %1\n\t"
1404 "cmpl %1, %2\n\t"
1405 "setne %0\n\t"
1406 "push %2\n\t"
1407 "popf\n\t"
1408 : "=m" (fRet), "=r" (u1), "=r" (u2));
1409# else
1410 __asm
1411 {
1412 pushfd
1413 pop eax
1414 mov ebx, eax
1415 xor eax, 0200000h
1416 push eax
1417 popfd
1418 pushfd
1419 pop eax
1420 cmp eax, ebx
1421 setne fRet
1422 push ebx
1423 popfd
1424 }
1425# endif
1426 return fRet;
1427# endif /* !RT_ARCH_AMD64 */
1428}
1429#endif
1430
1431
1432/**
1433 * Gets the APIC ID of the current CPU.
1434 *
1435 * @returns the APIC ID.
1436 */
1437#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1438RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMGetApicId(void);
1439#else
1440DECLINLINE(uint8_t) ASMGetApicId(void)
1441{
1442 RTCCUINTREG xBX;
1443# if RT_INLINE_ASM_GNU_STYLE
1444# ifdef RT_ARCH_AMD64
1445 RTCCUINTREG uSpill;
1446 __asm__ __volatile__ ("cpuid"
1447 : "=a" (uSpill),
1448 "=b" (xBX)
1449 : "0" (1)
1450 : "rcx", "rdx");
1451# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__)
1452 RTCCUINTREG uSpill;
1453 __asm__ __volatile__ ("mov %%ebx,%1\n\t"
1454 "cpuid\n\t"
1455 "xchgl %%ebx,%1\n\t"
1456 : "=a" (uSpill),
1457 "=rm" (xBX)
1458 : "0" (1)
1459 : "ecx", "edx");
1460# else
1461 RTCCUINTREG uSpill;
1462 __asm__ __volatile__ ("cpuid"
1463 : "=a" (uSpill),
1464 "=b" (xBX)
1465 : "0" (1)
1466 : "ecx", "edx");
1467# endif
1468
1469# elif RT_INLINE_ASM_USES_INTRIN
1470 int aInfo[4];
1471 __cpuid(aInfo, 1);
1472 xBX = aInfo[1];
1473
1474# else
1475 __asm
1476 {
1477 push ebx
1478 mov eax, 1
1479 cpuid
1480 mov [xBX], ebx
1481 pop ebx
1482 }
1483# endif
1484 return (uint8_t)(xBX >> 24);
1485}
1486#endif
1487
1488
1489/**
1490 * Gets the APIC ID of the current CPU using leaf 0xb.
1491 *
1492 * @returns the APIC ID.
1493 */
1494#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2010 /*?*/
1495RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMGetApicIdExt0B(void);
1496#else
1497DECLINLINE(uint32_t) ASMGetApicIdExt0B(void)
1498{
1499# if RT_INLINE_ASM_GNU_STYLE
1500 RTCCUINTREG xDX;
1501# ifdef RT_ARCH_AMD64
1502 RTCCUINTREG uSpillEax, uSpillEcx;
1503 __asm__ __volatile__ ("cpuid"
1504 : "=a" (uSpillEax),
1505 "=c" (uSpillEcx),
1506 "=d" (xDX)
1507 : "0" (0xb),
1508 "1" (0)
1509 : "rbx");
1510# elif (defined(PIC) || defined(__PIC__)) && defined(__i386__)
1511 RTCCUINTREG uSpillEax, uSpillEcx, uSpillEbx;
1512 __asm__ __volatile__ ("mov %%ebx,%2\n\t"
1513 "cpuid\n\t"
1514 "xchgl %%ebx,%2\n\t"
1515 : "=a" (uSpillEax),
1516 "=c" (uSpillEcx),
1517 "=rm" (uSpillEbx),
1518 "=d" (xDX)
1519 : "0" (0xb),
1520 "1" (0));
1521# else
1522 RTCCUINTREG uSpillEax, uSpillEcx;
1523 __asm__ __volatile__ ("cpuid"
1524 : "=a" (uSpillEax),
1525 "=c" (uSpillEcx),
1526 "=d" (xDX)
1527 : "0" (0xb),
1528 "1" (0)
1529 : "ebx");
1530# endif
1531 return (uint32_t)xDX;
1532
1533# elif RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 /*?*/
1534
1535 int aInfo[4];
1536 __cpuidex(aInfo, 0xb, 0);
1537 return aInfo[3];
1538
1539# else
1540 RTCCUINTREG xDX;
1541 __asm
1542 {
1543 push ebx
1544 mov eax, 0xb
1545 xor ecx, ecx
1546 cpuid
1547 mov [xDX], edx
1548 pop ebx
1549 }
1550 return (uint32_t)xDX;
1551# endif
1552}
1553#endif
1554
1555
1556/**
1557 * Gets the APIC ID of the current CPU using leaf 8000001E.
1558 *
1559 * @returns the APIC ID.
1560 */
1561DECLINLINE(uint32_t) ASMGetApicIdExt8000001E(void)
1562{
1563 return ASMCpuId_EAX(0x8000001e);
1564}
1565
1566
1567/**
1568 * Tests if it a genuine Intel CPU based on the ASMCpuId(0) output.
1569 *
1570 * @returns true/false.
1571 * @param uEBX EBX return from ASMCpuId(0)
1572 * @param uECX ECX return from ASMCpuId(0)
1573 * @param uEDX EDX return from ASMCpuId(0)
1574 */
1575DECLINLINE(bool) ASMIsIntelCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
1576{
1577 /* 'GenuineIntel' */
1578 return uEBX == UINT32_C(0x756e6547) /* 'Genu' */
1579 && uEDX == UINT32_C(0x49656e69) /* 'ineI' */
1580 && uECX == UINT32_C(0x6c65746e); /* 'ntel' */
1581}
1582
1583
1584/**
1585 * Tests if this is a genuine Intel CPU.
1586 *
1587 * @returns true/false.
1588 * @remarks ASSUMES that cpuid is supported by the CPU.
1589 */
1590DECLINLINE(bool) ASMIsIntelCpu(void)
1591{
1592 uint32_t uEAX, uEBX, uECX, uEDX;
1593 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
1594 return ASMIsIntelCpuEx(uEBX, uECX, uEDX);
1595}
1596
1597
1598/**
1599 * Tests if it an authentic AMD CPU based on the ASMCpuId(0) output.
1600 *
1601 * @returns true/false.
1602 * @param uEBX EBX return from ASMCpuId(0)
1603 * @param uECX ECX return from ASMCpuId(0)
1604 * @param uEDX EDX return from ASMCpuId(0)
1605 */
1606DECLINLINE(bool) ASMIsAmdCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
1607{
1608 /* 'AuthenticAMD' */
1609 return uEBX == UINT32_C(0x68747541) /* 'Auth' */
1610 && uEDX == UINT32_C(0x69746e65) /* 'enti' */
1611 && uECX == UINT32_C(0x444d4163); /* 'dAMD' */
1612}
1613
1614
1615/**
1616 * Tests if this is an authentic AMD CPU.
1617 *
1618 * @returns true/false.
1619 * @remarks ASSUMES that cpuid is supported by the CPU.
1620 */
1621DECLINLINE(bool) ASMIsAmdCpu(void)
1622{
1623 uint32_t uEAX, uEBX, uECX, uEDX;
1624 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
1625 return ASMIsAmdCpuEx(uEBX, uECX, uEDX);
1626}
1627
1628
1629/**
1630 * Tests if it a centaur hauling VIA CPU based on the ASMCpuId(0) output.
1631 *
1632 * @returns true/false.
1633 * @param uEBX EBX return from ASMCpuId(0).
1634 * @param uECX ECX return from ASMCpuId(0).
1635 * @param uEDX EDX return from ASMCpuId(0).
1636 */
1637DECLINLINE(bool) ASMIsViaCentaurCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
1638{
1639 /* 'CentaurHauls' */
1640 return uEBX == UINT32_C(0x746e6543) /* 'Cent' */
1641 && uEDX == UINT32_C(0x48727561) /* 'aurH' */
1642 && uECX == UINT32_C(0x736c7561); /* 'auls' */
1643}
1644
1645
1646/**
1647 * Tests if this is a centaur hauling VIA CPU.
1648 *
1649 * @returns true/false.
1650 * @remarks ASSUMES that cpuid is supported by the CPU.
1651 */
1652DECLINLINE(bool) ASMIsViaCentaurCpu(void)
1653{
1654 uint32_t uEAX, uEBX, uECX, uEDX;
1655 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
1656 return ASMIsViaCentaurCpuEx(uEBX, uECX, uEDX);
1657}
1658
1659
1660/**
1661 * Tests if it a Shanghai CPU based on the ASMCpuId(0) output.
1662 *
1663 * @returns true/false.
1664 * @param uEBX EBX return from ASMCpuId(0).
1665 * @param uECX ECX return from ASMCpuId(0).
1666 * @param uEDX EDX return from ASMCpuId(0).
1667 */
1668DECLINLINE(bool) ASMIsShanghaiCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
1669{
1670 /* ' Shanghai ' */
1671 return uEBX == UINT32_C(0x68532020) /* ' Sh' */
1672 && uEDX == UINT32_C(0x68676e61) /* 'angh' */
1673 && uECX == UINT32_C(0x20206961); /* 'ai ' */
1674}
1675
1676
1677/**
1678 * Tests if this is a Shanghai CPU.
1679 *
1680 * @returns true/false.
1681 * @remarks ASSUMES that cpuid is supported by the CPU.
1682 */
1683DECLINLINE(bool) ASMIsShanghaiCpu(void)
1684{
1685 uint32_t uEAX, uEBX, uECX, uEDX;
1686 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
1687 return ASMIsShanghaiCpuEx(uEBX, uECX, uEDX);
1688}
1689
1690
1691/**
1692 * Tests if it a genuine Hygon CPU based on the ASMCpuId(0) output.
1693 *
1694 * @returns true/false.
1695 * @param uEBX EBX return from ASMCpuId(0)
1696 * @param uECX ECX return from ASMCpuId(0)
1697 * @param uEDX EDX return from ASMCpuId(0)
1698 */
1699DECLINLINE(bool) ASMIsHygonCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
1700{
1701 /* 'HygonGenuine' */
1702 return uEBX == UINT32_C(0x6f677948) /* Hygo */
1703 && uECX == UINT32_C(0x656e6975) /* uine */
1704 && uEDX == UINT32_C(0x6e65476e); /* nGen */
1705}
1706
1707
1708/**
1709 * Tests if this is a genuine Hygon CPU.
1710 *
1711 * @returns true/false.
1712 * @remarks ASSUMES that cpuid is supported by the CPU.
1713 */
1714DECLINLINE(bool) ASMIsHygonCpu(void)
1715{
1716 uint32_t uEAX, uEBX, uECX, uEDX;
1717 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
1718 return ASMIsHygonCpuEx(uEBX, uECX, uEDX);
1719}
1720
1721
1722/**
1723 * Checks whether ASMCpuId_EAX(0x00000000) indicates a valid range.
1724 *
1725 *
1726 * @returns true/false.
1727 * @param uEAX The EAX value of CPUID leaf 0x00000000.
1728 *
1729 * @note This only succeeds if there are at least two leaves in the range.
1730 * @remarks The upper range limit is just some half reasonable value we've
1731 * picked out of thin air.
1732 */
1733DECLINLINE(bool) ASMIsValidStdRange(uint32_t uEAX)
1734{
1735 return uEAX >= UINT32_C(0x00000001) && uEAX <= UINT32_C(0x000fffff);
1736}
1737
1738
1739/**
1740 * Checks whether ASMCpuId_EAX(0x80000000) indicates a valid range.
1741 *
1742 * This only succeeds if there are at least two leaves in the range.
1743 *
1744 * @returns true/false.
1745 * @param uEAX The EAX value of CPUID leaf 0x80000000.
1746 *
1747 * @note This only succeeds if there are at least two leaves in the range.
1748 * @remarks The upper range limit is just some half reasonable value we've
1749 * picked out of thin air.
1750 */
1751DECLINLINE(bool) ASMIsValidExtRange(uint32_t uEAX)
1752{
1753 return uEAX >= UINT32_C(0x80000001) && uEAX <= UINT32_C(0x800fffff);
1754}
1755
1756
1757/**
1758 * Checks whether ASMCpuId_EAX(0x40000000) indicates a valid range.
1759 *
1760 * This only succeeds if there are at least two leaves in the range.
1761 *
1762 * @returns true/false.
1763 * @param uEAX The EAX value of CPUID leaf 0x40000000.
1764 *
1765 * @note Unlike ASMIsValidStdRange() and ASMIsValidExtRange(), a single leaf
1766 * is okay here. So, you always need to check the range.
1767 * @remarks The upper range limit is take from the intel docs.
1768 */
1769DECLINLINE(bool) ASMIsValidHypervisorRange(uint32_t uEAX)
1770{
1771 return uEAX >= UINT32_C(0x40000000) && uEAX <= UINT32_C(0x4fffffff);
1772}
1773
1774
1775/**
1776 * Extracts the CPU family from ASMCpuId(1) or ASMCpuId(0x80000001)
1777 *
1778 * @returns Family.
1779 * @param uEAX EAX return from ASMCpuId(1) or ASMCpuId(0x80000001).
1780 */
1781DECLINLINE(uint32_t) ASMGetCpuFamily(uint32_t uEAX)
1782{
1783 return ((uEAX >> 8) & 0xf) == 0xf
1784 ? ((uEAX >> 20) & 0x7f) + 0xf
1785 : ((uEAX >> 8) & 0xf);
1786}
1787
1788
1789/**
1790 * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), Intel variant.
1791 *
1792 * @returns Model.
1793 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1794 */
1795DECLINLINE(uint32_t) ASMGetCpuModelIntel(uint32_t uEAX)
1796{
1797 return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6) /* family! */
1798 ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0)
1799 : ((uEAX >> 4) & 0xf);
1800}
1801
1802
1803/**
1804 * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), AMD variant.
1805 *
1806 * @returns Model.
1807 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1808 */
1809DECLINLINE(uint32_t) ASMGetCpuModelAMD(uint32_t uEAX)
1810{
1811 return ((uEAX >> 8) & 0xf) == 0xf
1812 ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0)
1813 : ((uEAX >> 4) & 0xf);
1814}
1815
1816
1817/**
1818 * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001)
1819 *
1820 * @returns Model.
1821 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1822 * @param fIntel Whether it's an intel CPU. Use ASMIsIntelCpuEx() or ASMIsIntelCpu().
1823 */
1824DECLINLINE(uint32_t) ASMGetCpuModel(uint32_t uEAX, bool fIntel)
1825{
1826 return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6 && fIntel) /* family! */
1827 ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0)
1828 : ((uEAX >> 4) & 0xf);
1829}
1830
1831
1832/**
1833 * Extracts the CPU stepping from ASMCpuId(1) or ASMCpuId(0x80000001)
1834 *
1835 * @returns Model.
1836 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1837 */
1838DECLINLINE(uint32_t) ASMGetCpuStepping(uint32_t uEAX)
1839{
1840 return uEAX & 0xf;
1841}
1842
1843
1844/**
1845 * Get cr0.
1846 * @returns cr0.
1847 */
1848#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1849RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR0(void);
1850#else
1851DECLINLINE(RTCCUINTXREG) ASMGetCR0(void)
1852{
1853 RTCCUINTXREG uCR0;
1854# if RT_INLINE_ASM_USES_INTRIN
1855 uCR0 = __readcr0();
1856
1857# elif RT_INLINE_ASM_GNU_STYLE
1858# ifdef RT_ARCH_AMD64
1859 __asm__ __volatile__("movq %%cr0, %0\t\n" : "=r" (uCR0));
1860# else
1861 __asm__ __volatile__("movl %%cr0, %0\t\n" : "=r" (uCR0));
1862# endif
1863# else
1864 __asm
1865 {
1866# ifdef RT_ARCH_AMD64
1867 mov rax, cr0
1868 mov [uCR0], rax
1869# else
1870 mov eax, cr0
1871 mov [uCR0], eax
1872# endif
1873 }
1874# endif
1875 return uCR0;
1876}
1877#endif
1878
1879
1880/**
1881 * Sets the CR0 register.
1882 * @param uCR0 The new CR0 value.
1883 */
1884#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1885RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR0(RTCCUINTXREG uCR0);
1886#else
1887DECLINLINE(void) ASMSetCR0(RTCCUINTXREG uCR0)
1888{
1889# if RT_INLINE_ASM_USES_INTRIN
1890 __writecr0(uCR0);
1891
1892# elif RT_INLINE_ASM_GNU_STYLE
1893# ifdef RT_ARCH_AMD64
1894 __asm__ __volatile__("movq %0, %%cr0\n\t" :: "r" (uCR0));
1895# else
1896 __asm__ __volatile__("movl %0, %%cr0\n\t" :: "r" (uCR0));
1897# endif
1898# else
1899 __asm
1900 {
1901# ifdef RT_ARCH_AMD64
1902 mov rax, [uCR0]
1903 mov cr0, rax
1904# else
1905 mov eax, [uCR0]
1906 mov cr0, eax
1907# endif
1908 }
1909# endif
1910}
1911#endif
1912
1913
1914/**
1915 * Get cr2.
1916 * @returns cr2.
1917 */
1918#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1919RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR2(void);
1920#else
1921DECLINLINE(RTCCUINTXREG) ASMGetCR2(void)
1922{
1923 RTCCUINTXREG uCR2;
1924# if RT_INLINE_ASM_USES_INTRIN
1925 uCR2 = __readcr2();
1926
1927# elif RT_INLINE_ASM_GNU_STYLE
1928# ifdef RT_ARCH_AMD64
1929 __asm__ __volatile__("movq %%cr2, %0\t\n" : "=r" (uCR2));
1930# else
1931 __asm__ __volatile__("movl %%cr2, %0\t\n" : "=r" (uCR2));
1932# endif
1933# else
1934 __asm
1935 {
1936# ifdef RT_ARCH_AMD64
1937 mov rax, cr2
1938 mov [uCR2], rax
1939# else
1940 mov eax, cr2
1941 mov [uCR2], eax
1942# endif
1943 }
1944# endif
1945 return uCR2;
1946}
1947#endif
1948
1949
1950/**
1951 * Sets the CR2 register.
1952 * @param uCR2 The new CR0 value.
1953 */
1954#if RT_INLINE_ASM_EXTERNAL
1955RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR2(RTCCUINTXREG uCR2);
1956#else
1957DECLINLINE(void) ASMSetCR2(RTCCUINTXREG uCR2)
1958{
1959# if RT_INLINE_ASM_GNU_STYLE
1960# ifdef RT_ARCH_AMD64
1961 __asm__ __volatile__("movq %0, %%cr2\n\t" :: "r" (uCR2));
1962# else
1963 __asm__ __volatile__("movl %0, %%cr2\n\t" :: "r" (uCR2));
1964# endif
1965# else
1966 __asm
1967 {
1968# ifdef RT_ARCH_AMD64
1969 mov rax, [uCR2]
1970 mov cr2, rax
1971# else
1972 mov eax, [uCR2]
1973 mov cr2, eax
1974# endif
1975 }
1976# endif
1977}
1978#endif
1979
1980
1981/**
1982 * Get cr3.
1983 * @returns cr3.
1984 */
1985#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1986RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR3(void);
1987#else
1988DECLINLINE(RTCCUINTXREG) ASMGetCR3(void)
1989{
1990 RTCCUINTXREG uCR3;
1991# if RT_INLINE_ASM_USES_INTRIN
1992 uCR3 = __readcr3();
1993
1994# elif RT_INLINE_ASM_GNU_STYLE
1995# ifdef RT_ARCH_AMD64
1996 __asm__ __volatile__("movq %%cr3, %0\t\n" : "=r" (uCR3));
1997# else
1998 __asm__ __volatile__("movl %%cr3, %0\t\n" : "=r" (uCR3));
1999# endif
2000# else
2001 __asm
2002 {
2003# ifdef RT_ARCH_AMD64
2004 mov rax, cr3
2005 mov [uCR3], rax
2006# else
2007 mov eax, cr3
2008 mov [uCR3], eax
2009# endif
2010 }
2011# endif
2012 return uCR3;
2013}
2014#endif
2015
2016
2017/**
2018 * Sets the CR3 register.
2019 *
2020 * @param uCR3 New CR3 value.
2021 */
2022#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2023RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR3(RTCCUINTXREG uCR3);
2024#else
2025DECLINLINE(void) ASMSetCR3(RTCCUINTXREG uCR3)
2026{
2027# if RT_INLINE_ASM_USES_INTRIN
2028 __writecr3(uCR3);
2029
2030# elif RT_INLINE_ASM_GNU_STYLE
2031# ifdef RT_ARCH_AMD64
2032 __asm__ __volatile__("movq %0, %%cr3\n\t" : : "r" (uCR3));
2033# else
2034 __asm__ __volatile__("movl %0, %%cr3\n\t" : : "r" (uCR3));
2035# endif
2036# else
2037 __asm
2038 {
2039# ifdef RT_ARCH_AMD64
2040 mov rax, [uCR3]
2041 mov cr3, rax
2042# else
2043 mov eax, [uCR3]
2044 mov cr3, eax
2045# endif
2046 }
2047# endif
2048}
2049#endif
2050
2051
2052/**
2053 * Reloads the CR3 register.
2054 */
2055#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2056RT_ASM_DECL_PRAGMA_WATCOM(void) ASMReloadCR3(void);
2057#else
2058DECLINLINE(void) ASMReloadCR3(void)
2059{
2060# if RT_INLINE_ASM_USES_INTRIN
2061 __writecr3(__readcr3());
2062
2063# elif RT_INLINE_ASM_GNU_STYLE
2064 RTCCUINTXREG u;
2065# ifdef RT_ARCH_AMD64
2066 __asm__ __volatile__("movq %%cr3, %0\n\t"
2067 "movq %0, %%cr3\n\t"
2068 : "=r" (u));
2069# else
2070 __asm__ __volatile__("movl %%cr3, %0\n\t"
2071 "movl %0, %%cr3\n\t"
2072 : "=r" (u));
2073# endif
2074# else
2075 __asm
2076 {
2077# ifdef RT_ARCH_AMD64
2078 mov rax, cr3
2079 mov cr3, rax
2080# else
2081 mov eax, cr3
2082 mov cr3, eax
2083# endif
2084 }
2085# endif
2086}
2087#endif
2088
2089
2090/**
2091 * Get cr4.
2092 * @returns cr4.
2093 */
2094#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2095RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR4(void);
2096#else
2097DECLINLINE(RTCCUINTXREG) ASMGetCR4(void)
2098{
2099 RTCCUINTXREG uCR4;
2100# if RT_INLINE_ASM_USES_INTRIN
2101 uCR4 = __readcr4();
2102
2103# elif RT_INLINE_ASM_GNU_STYLE
2104# ifdef RT_ARCH_AMD64
2105 __asm__ __volatile__("movq %%cr4, %0\t\n" : "=r" (uCR4));
2106# else
2107 __asm__ __volatile__("movl %%cr4, %0\t\n" : "=r" (uCR4));
2108# endif
2109# else
2110 __asm
2111 {
2112# ifdef RT_ARCH_AMD64
2113 mov rax, cr4
2114 mov [uCR4], rax
2115# else
2116 push eax /* just in case */
2117 /*mov eax, cr4*/
2118 _emit 0x0f
2119 _emit 0x20
2120 _emit 0xe0
2121 mov [uCR4], eax
2122 pop eax
2123# endif
2124 }
2125# endif
2126 return uCR4;
2127}
2128#endif
2129
2130
2131/**
2132 * Sets the CR4 register.
2133 *
2134 * @param uCR4 New CR4 value.
2135 */
2136#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2137RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR4(RTCCUINTXREG uCR4);
2138#else
2139DECLINLINE(void) ASMSetCR4(RTCCUINTXREG uCR4)
2140{
2141# if RT_INLINE_ASM_USES_INTRIN
2142 __writecr4(uCR4);
2143
2144# elif RT_INLINE_ASM_GNU_STYLE
2145# ifdef RT_ARCH_AMD64
2146 __asm__ __volatile__("movq %0, %%cr4\n\t" : : "r" (uCR4));
2147# else
2148 __asm__ __volatile__("movl %0, %%cr4\n\t" : : "r" (uCR4));
2149# endif
2150# else
2151 __asm
2152 {
2153# ifdef RT_ARCH_AMD64
2154 mov rax, [uCR4]
2155 mov cr4, rax
2156# else
2157 mov eax, [uCR4]
2158 _emit 0x0F
2159 _emit 0x22
2160 _emit 0xE0 /* mov cr4, eax */
2161# endif
2162 }
2163# endif
2164}
2165#endif
2166
2167
2168/**
2169 * Get cr8.
2170 * @returns cr8.
2171 * @remark The lock prefix hack for access from non-64-bit modes is NOT used and 0 is returned.
2172 */
2173#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2174DECLASM(RTCCUINTXREG) ASMGetCR8(void);
2175#else
2176DECLINLINE(RTCCUINTXREG) ASMGetCR8(void)
2177{
2178# ifdef RT_ARCH_AMD64
2179 RTCCUINTXREG uCR8;
2180# if RT_INLINE_ASM_USES_INTRIN
2181 uCR8 = __readcr8();
2182
2183# elif RT_INLINE_ASM_GNU_STYLE
2184 __asm__ __volatile__("movq %%cr8, %0\t\n" : "=r" (uCR8));
2185# else
2186 __asm
2187 {
2188 mov rax, cr8
2189 mov [uCR8], rax
2190 }
2191# endif
2192 return uCR8;
2193# else /* !RT_ARCH_AMD64 */
2194 return 0;
2195# endif /* !RT_ARCH_AMD64 */
2196}
2197#endif
2198
2199
2200/**
2201 * Get XCR0 (eXtended feature Control Register 0).
2202 * @returns xcr0.
2203 */
2204DECLASM(uint64_t) ASMGetXcr0(void);
2205
2206/**
2207 * Sets the XCR0 register.
2208 * @param uXcr0 The new XCR0 value.
2209 */
2210DECLASM(void) ASMSetXcr0(uint64_t uXcr0);
2211
2212struct X86XSAVEAREA;
2213/**
2214 * Save extended CPU state.
2215 * @param pXStateArea Where to save the state.
2216 * @param fComponents Which state components to save.
2217 */
2218DECLASM(void) ASMXSave(struct X86XSAVEAREA RT_FAR *pXStateArea, uint64_t fComponents);
2219
2220/**
2221 * Loads extended CPU state.
2222 * @param pXStateArea Where to load the state from.
2223 * @param fComponents Which state components to load.
2224 */
2225DECLASM(void) ASMXRstor(struct X86XSAVEAREA const RT_FAR *pXStateArea, uint64_t fComponents);
2226
2227
2228struct X86FXSTATE;
2229/**
2230 * Save FPU and SSE CPU state.
2231 * @param pXStateArea Where to save the state.
2232 */
2233DECLASM(void) ASMFxSave(struct X86FXSTATE RT_FAR *pXStateArea);
2234
2235/**
2236 * Load FPU and SSE CPU state.
2237 * @param pXStateArea Where to load the state from.
2238 */
2239DECLASM(void) ASMFxRstor(struct X86FXSTATE const RT_FAR *pXStateArea);
2240
2241
2242/**
2243 * Enables interrupts (EFLAGS.IF).
2244 */
2245#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2246RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntEnable(void);
2247#else
2248DECLINLINE(void) ASMIntEnable(void)
2249{
2250# if RT_INLINE_ASM_GNU_STYLE
2251 __asm("sti\n");
2252# elif RT_INLINE_ASM_USES_INTRIN
2253 _enable();
2254# else
2255 __asm sti
2256# endif
2257}
2258#endif
2259
2260
2261/**
2262 * Disables interrupts (!EFLAGS.IF).
2263 */
2264#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2265RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntDisable(void);
2266#else
2267DECLINLINE(void) ASMIntDisable(void)
2268{
2269# if RT_INLINE_ASM_GNU_STYLE
2270 __asm("cli\n");
2271# elif RT_INLINE_ASM_USES_INTRIN
2272 _disable();
2273# else
2274 __asm cli
2275# endif
2276}
2277#endif
2278
2279
2280/**
2281 * Disables interrupts and returns previous xFLAGS.
2282 */
2283#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2284RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMIntDisableFlags(void);
2285#else
2286DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void)
2287{
2288 RTCCUINTREG xFlags;
2289# if RT_INLINE_ASM_GNU_STYLE
2290# ifdef RT_ARCH_AMD64
2291 __asm__ __volatile__("pushfq\n\t"
2292 "cli\n\t"
2293 "popq %0\n\t"
2294 : "=r" (xFlags));
2295# else
2296 __asm__ __volatile__("pushfl\n\t"
2297 "cli\n\t"
2298 "popl %0\n\t"
2299 : "=r" (xFlags));
2300# endif
2301# elif RT_INLINE_ASM_USES_INTRIN && !defined(RT_ARCH_X86)
2302 xFlags = ASMGetFlags();
2303 _disable();
2304# else
2305 __asm {
2306 pushfd
2307 cli
2308 pop [xFlags]
2309 }
2310# endif
2311 return xFlags;
2312}
2313#endif
2314
2315
2316/**
2317 * Are interrupts enabled?
2318 *
2319 * @returns true / false.
2320 */
2321DECLINLINE(bool) ASMIntAreEnabled(void)
2322{
2323 RTCCUINTREG uFlags = ASMGetFlags();
2324 return uFlags & 0x200 /* X86_EFL_IF */ ? true : false;
2325}
2326
2327
2328/**
2329 * Halts the CPU until interrupted.
2330 */
2331#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < RT_MSC_VER_VS2005
2332RT_ASM_DECL_PRAGMA_WATCOM(void) ASMHalt(void);
2333#else
2334DECLINLINE(void) ASMHalt(void)
2335{
2336# if RT_INLINE_ASM_GNU_STYLE
2337 __asm__ __volatile__("hlt\n\t");
2338# elif RT_INLINE_ASM_USES_INTRIN
2339 __halt();
2340# else
2341 __asm {
2342 hlt
2343 }
2344# endif
2345}
2346#endif
2347
2348
2349/**
2350 * Reads a machine specific register.
2351 *
2352 * @returns Register content.
2353 * @param uRegister Register to read.
2354 */
2355#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2356RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMRdMsr(uint32_t uRegister);
2357#else
2358DECLINLINE(uint64_t) ASMRdMsr(uint32_t uRegister)
2359{
2360 RTUINT64U u;
2361# if RT_INLINE_ASM_GNU_STYLE
2362 __asm__ __volatile__("rdmsr\n\t"
2363 : "=a" (u.s.Lo),
2364 "=d" (u.s.Hi)
2365 : "c" (uRegister));
2366
2367# elif RT_INLINE_ASM_USES_INTRIN
2368 u.u = __readmsr(uRegister);
2369
2370# else
2371 __asm
2372 {
2373 mov ecx, [uRegister]
2374 rdmsr
2375 mov [u.s.Lo], eax
2376 mov [u.s.Hi], edx
2377 }
2378# endif
2379
2380 return u.u;
2381}
2382#endif
2383
2384
2385/**
2386 * Writes a machine specific register.
2387 *
2388 * @returns Register content.
2389 * @param uRegister Register to write to.
2390 * @param u64Val Value to write.
2391 */
2392#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2393RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val);
2394#else
2395DECLINLINE(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val)
2396{
2397 RTUINT64U u;
2398
2399 u.u = u64Val;
2400# if RT_INLINE_ASM_GNU_STYLE
2401 __asm__ __volatile__("wrmsr\n\t"
2402 ::"a" (u.s.Lo),
2403 "d" (u.s.Hi),
2404 "c" (uRegister));
2405
2406# elif RT_INLINE_ASM_USES_INTRIN
2407 __writemsr(uRegister, u.u);
2408
2409# else
2410 __asm
2411 {
2412 mov ecx, [uRegister]
2413 mov edx, [u.s.Hi]
2414 mov eax, [u.s.Lo]
2415 wrmsr
2416 }
2417# endif
2418}
2419#endif
2420
2421
2422/**
2423 * Reads a machine specific register, extended version (for AMD).
2424 *
2425 * @returns Register content.
2426 * @param uRegister Register to read.
2427 * @param uXDI RDI/EDI value.
2428 */
2429#if RT_INLINE_ASM_EXTERNAL
2430RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI);
2431#else
2432DECLINLINE(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI)
2433{
2434 RTUINT64U u;
2435# if RT_INLINE_ASM_GNU_STYLE
2436 __asm__ __volatile__("rdmsr\n\t"
2437 : "=a" (u.s.Lo),
2438 "=d" (u.s.Hi)
2439 : "c" (uRegister),
2440 "D" (uXDI));
2441
2442# else
2443 __asm
2444 {
2445 mov ecx, [uRegister]
2446 xchg edi, [uXDI]
2447 rdmsr
2448 mov [u.s.Lo], eax
2449 mov [u.s.Hi], edx
2450 xchg edi, [uXDI]
2451 }
2452# endif
2453
2454 return u.u;
2455}
2456#endif
2457
2458
2459/**
2460 * Writes a machine specific register, extended version (for AMD).
2461 *
2462 * @returns Register content.
2463 * @param uRegister Register to write to.
2464 * @param uXDI RDI/EDI value.
2465 * @param u64Val Value to write.
2466 */
2467#if RT_INLINE_ASM_EXTERNAL
2468RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val);
2469#else
2470DECLINLINE(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val)
2471{
2472 RTUINT64U u;
2473
2474 u.u = u64Val;
2475# if RT_INLINE_ASM_GNU_STYLE
2476 __asm__ __volatile__("wrmsr\n\t"
2477 ::"a" (u.s.Lo),
2478 "d" (u.s.Hi),
2479 "c" (uRegister),
2480 "D" (uXDI));
2481
2482# else
2483 __asm
2484 {
2485 mov ecx, [uRegister]
2486 xchg edi, [uXDI]
2487 mov edx, [u.s.Hi]
2488 mov eax, [u.s.Lo]
2489 wrmsr
2490 xchg edi, [uXDI]
2491 }
2492# endif
2493}
2494#endif
2495
2496
2497
2498/**
2499 * Reads low part of a machine specific register.
2500 *
2501 * @returns Register content.
2502 * @param uRegister Register to read.
2503 */
2504#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2505RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_Low(uint32_t uRegister);
2506#else
2507DECLINLINE(uint32_t) ASMRdMsr_Low(uint32_t uRegister)
2508{
2509 uint32_t u32;
2510# if RT_INLINE_ASM_GNU_STYLE
2511 __asm__ __volatile__("rdmsr\n\t"
2512 : "=a" (u32)
2513 : "c" (uRegister)
2514 : "edx");
2515
2516# elif RT_INLINE_ASM_USES_INTRIN
2517 u32 = (uint32_t)__readmsr(uRegister);
2518
2519#else
2520 __asm
2521 {
2522 mov ecx, [uRegister]
2523 rdmsr
2524 mov [u32], eax
2525 }
2526# endif
2527
2528 return u32;
2529}
2530#endif
2531
2532
2533/**
2534 * Reads high part of a machine specific register.
2535 *
2536 * @returns Register content.
2537 * @param uRegister Register to read.
2538 */
2539#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2540RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_High(uint32_t uRegister);
2541#else
2542DECLINLINE(uint32_t) ASMRdMsr_High(uint32_t uRegister)
2543{
2544 uint32_t u32;
2545# if RT_INLINE_ASM_GNU_STYLE
2546 __asm__ __volatile__("rdmsr\n\t"
2547 : "=d" (u32)
2548 : "c" (uRegister)
2549 : "eax");
2550
2551# elif RT_INLINE_ASM_USES_INTRIN
2552 u32 = (uint32_t)(__readmsr(uRegister) >> 32);
2553
2554# else
2555 __asm
2556 {
2557 mov ecx, [uRegister]
2558 rdmsr
2559 mov [u32], edx
2560 }
2561# endif
2562
2563 return u32;
2564}
2565#endif
2566
2567
2568/**
2569 * Gets dr0.
2570 *
2571 * @returns dr0.
2572 */
2573#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2574RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR0(void);
2575#else
2576DECLINLINE(RTCCUINTXREG) ASMGetDR0(void)
2577{
2578 RTCCUINTXREG uDR0;
2579# if RT_INLINE_ASM_USES_INTRIN
2580 uDR0 = __readdr(0);
2581# elif RT_INLINE_ASM_GNU_STYLE
2582# ifdef RT_ARCH_AMD64
2583 __asm__ __volatile__("movq %%dr0, %0\n\t" : "=r" (uDR0));
2584# else
2585 __asm__ __volatile__("movl %%dr0, %0\n\t" : "=r" (uDR0));
2586# endif
2587# else
2588 __asm
2589 {
2590# ifdef RT_ARCH_AMD64
2591 mov rax, dr0
2592 mov [uDR0], rax
2593# else
2594 mov eax, dr0
2595 mov [uDR0], eax
2596# endif
2597 }
2598# endif
2599 return uDR0;
2600}
2601#endif
2602
2603
2604/**
2605 * Gets dr1.
2606 *
2607 * @returns dr1.
2608 */
2609#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2610RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR1(void);
2611#else
2612DECLINLINE(RTCCUINTXREG) ASMGetDR1(void)
2613{
2614 RTCCUINTXREG uDR1;
2615# if RT_INLINE_ASM_USES_INTRIN
2616 uDR1 = __readdr(1);
2617# elif RT_INLINE_ASM_GNU_STYLE
2618# ifdef RT_ARCH_AMD64
2619 __asm__ __volatile__("movq %%dr1, %0\n\t" : "=r" (uDR1));
2620# else
2621 __asm__ __volatile__("movl %%dr1, %0\n\t" : "=r" (uDR1));
2622# endif
2623# else
2624 __asm
2625 {
2626# ifdef RT_ARCH_AMD64
2627 mov rax, dr1
2628 mov [uDR1], rax
2629# else
2630 mov eax, dr1
2631 mov [uDR1], eax
2632# endif
2633 }
2634# endif
2635 return uDR1;
2636}
2637#endif
2638
2639
2640/**
2641 * Gets dr2.
2642 *
2643 * @returns dr2.
2644 */
2645#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2646RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR2(void);
2647#else
2648DECLINLINE(RTCCUINTXREG) ASMGetDR2(void)
2649{
2650 RTCCUINTXREG uDR2;
2651# if RT_INLINE_ASM_USES_INTRIN
2652 uDR2 = __readdr(2);
2653# elif RT_INLINE_ASM_GNU_STYLE
2654# ifdef RT_ARCH_AMD64
2655 __asm__ __volatile__("movq %%dr2, %0\n\t" : "=r" (uDR2));
2656# else
2657 __asm__ __volatile__("movl %%dr2, %0\n\t" : "=r" (uDR2));
2658# endif
2659# else
2660 __asm
2661 {
2662# ifdef RT_ARCH_AMD64
2663 mov rax, dr2
2664 mov [uDR2], rax
2665# else
2666 mov eax, dr2
2667 mov [uDR2], eax
2668# endif
2669 }
2670# endif
2671 return uDR2;
2672}
2673#endif
2674
2675
2676/**
2677 * Gets dr3.
2678 *
2679 * @returns dr3.
2680 */
2681#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2682RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR3(void);
2683#else
2684DECLINLINE(RTCCUINTXREG) ASMGetDR3(void)
2685{
2686 RTCCUINTXREG uDR3;
2687# if RT_INLINE_ASM_USES_INTRIN
2688 uDR3 = __readdr(3);
2689# elif RT_INLINE_ASM_GNU_STYLE
2690# ifdef RT_ARCH_AMD64
2691 __asm__ __volatile__("movq %%dr3, %0\n\t" : "=r" (uDR3));
2692# else
2693 __asm__ __volatile__("movl %%dr3, %0\n\t" : "=r" (uDR3));
2694# endif
2695# else
2696 __asm
2697 {
2698# ifdef RT_ARCH_AMD64
2699 mov rax, dr3
2700 mov [uDR3], rax
2701# else
2702 mov eax, dr3
2703 mov [uDR3], eax
2704# endif
2705 }
2706# endif
2707 return uDR3;
2708}
2709#endif
2710
2711
2712/**
2713 * Gets dr6.
2714 *
2715 * @returns dr6.
2716 */
2717#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2718RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR6(void);
2719#else
2720DECLINLINE(RTCCUINTXREG) ASMGetDR6(void)
2721{
2722 RTCCUINTXREG uDR6;
2723# if RT_INLINE_ASM_USES_INTRIN
2724 uDR6 = __readdr(6);
2725# elif RT_INLINE_ASM_GNU_STYLE
2726# ifdef RT_ARCH_AMD64
2727 __asm__ __volatile__("movq %%dr6, %0\n\t" : "=r" (uDR6));
2728# else
2729 __asm__ __volatile__("movl %%dr6, %0\n\t" : "=r" (uDR6));
2730# endif
2731# else
2732 __asm
2733 {
2734# ifdef RT_ARCH_AMD64
2735 mov rax, dr6
2736 mov [uDR6], rax
2737# else
2738 mov eax, dr6
2739 mov [uDR6], eax
2740# endif
2741 }
2742# endif
2743 return uDR6;
2744}
2745#endif
2746
2747
2748/**
2749 * Reads and clears DR6.
2750 *
2751 * @returns DR6.
2752 */
2753#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2754RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetAndClearDR6(void);
2755#else
2756DECLINLINE(RTCCUINTXREG) ASMGetAndClearDR6(void)
2757{
2758 RTCCUINTXREG uDR6;
2759# if RT_INLINE_ASM_USES_INTRIN
2760 uDR6 = __readdr(6);
2761 __writedr(6, 0xffff0ff0U); /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2762# elif RT_INLINE_ASM_GNU_STYLE
2763 RTCCUINTXREG uNewValue = 0xffff0ff0U;/* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2764# ifdef RT_ARCH_AMD64
2765 __asm__ __volatile__("movq %%dr6, %0\n\t"
2766 "movq %1, %%dr6\n\t"
2767 : "=r" (uDR6)
2768 : "r" (uNewValue));
2769# else
2770 __asm__ __volatile__("movl %%dr6, %0\n\t"
2771 "movl %1, %%dr6\n\t"
2772 : "=r" (uDR6)
2773 : "r" (uNewValue));
2774# endif
2775# else
2776 __asm
2777 {
2778# ifdef RT_ARCH_AMD64
2779 mov rax, dr6
2780 mov [uDR6], rax
2781 mov rcx, rax
2782 mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2783 mov dr6, rcx
2784# else
2785 mov eax, dr6
2786 mov [uDR6], eax
2787 mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 is zero. */
2788 mov dr6, ecx
2789# endif
2790 }
2791# endif
2792 return uDR6;
2793}
2794#endif
2795
2796
2797/**
2798 * Gets dr7.
2799 *
2800 * @returns dr7.
2801 */
2802#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2803RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR7(void);
2804#else
2805DECLINLINE(RTCCUINTXREG) ASMGetDR7(void)
2806{
2807 RTCCUINTXREG uDR7;
2808# if RT_INLINE_ASM_USES_INTRIN
2809 uDR7 = __readdr(7);
2810# elif RT_INLINE_ASM_GNU_STYLE
2811# ifdef RT_ARCH_AMD64
2812 __asm__ __volatile__("movq %%dr7, %0\n\t" : "=r" (uDR7));
2813# else
2814 __asm__ __volatile__("movl %%dr7, %0\n\t" : "=r" (uDR7));
2815# endif
2816# else
2817 __asm
2818 {
2819# ifdef RT_ARCH_AMD64
2820 mov rax, dr7
2821 mov [uDR7], rax
2822# else
2823 mov eax, dr7
2824 mov [uDR7], eax
2825# endif
2826 }
2827# endif
2828 return uDR7;
2829}
2830#endif
2831
2832
2833/**
2834 * Sets dr0.
2835 *
2836 * @param uDRVal Debug register value to write
2837 */
2838#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2839RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR0(RTCCUINTXREG uDRVal);
2840#else
2841DECLINLINE(void) ASMSetDR0(RTCCUINTXREG uDRVal)
2842{
2843# if RT_INLINE_ASM_USES_INTRIN
2844 __writedr(0, uDRVal);
2845# elif RT_INLINE_ASM_GNU_STYLE
2846# ifdef RT_ARCH_AMD64
2847 __asm__ __volatile__("movq %0, %%dr0\n\t" : : "r" (uDRVal));
2848# else
2849 __asm__ __volatile__("movl %0, %%dr0\n\t" : : "r" (uDRVal));
2850# endif
2851# else
2852 __asm
2853 {
2854# ifdef RT_ARCH_AMD64
2855 mov rax, [uDRVal]
2856 mov dr0, rax
2857# else
2858 mov eax, [uDRVal]
2859 mov dr0, eax
2860# endif
2861 }
2862# endif
2863}
2864#endif
2865
2866
2867/**
2868 * Sets dr1.
2869 *
2870 * @param uDRVal Debug register value to write
2871 */
2872#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2873RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR1(RTCCUINTXREG uDRVal);
2874#else
2875DECLINLINE(void) ASMSetDR1(RTCCUINTXREG uDRVal)
2876{
2877# if RT_INLINE_ASM_USES_INTRIN
2878 __writedr(1, uDRVal);
2879# elif RT_INLINE_ASM_GNU_STYLE
2880# ifdef RT_ARCH_AMD64
2881 __asm__ __volatile__("movq %0, %%dr1\n\t" : : "r" (uDRVal));
2882# else
2883 __asm__ __volatile__("movl %0, %%dr1\n\t" : : "r" (uDRVal));
2884# endif
2885# else
2886 __asm
2887 {
2888# ifdef RT_ARCH_AMD64
2889 mov rax, [uDRVal]
2890 mov dr1, rax
2891# else
2892 mov eax, [uDRVal]
2893 mov dr1, eax
2894# endif
2895 }
2896# endif
2897}
2898#endif
2899
2900
2901/**
2902 * Sets dr2.
2903 *
2904 * @param uDRVal Debug register value to write
2905 */
2906#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2907RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR2(RTCCUINTXREG uDRVal);
2908#else
2909DECLINLINE(void) ASMSetDR2(RTCCUINTXREG uDRVal)
2910{
2911# if RT_INLINE_ASM_USES_INTRIN
2912 __writedr(2, uDRVal);
2913# elif RT_INLINE_ASM_GNU_STYLE
2914# ifdef RT_ARCH_AMD64
2915 __asm__ __volatile__("movq %0, %%dr2\n\t" : : "r" (uDRVal));
2916# else
2917 __asm__ __volatile__("movl %0, %%dr2\n\t" : : "r" (uDRVal));
2918# endif
2919# else
2920 __asm
2921 {
2922# ifdef RT_ARCH_AMD64
2923 mov rax, [uDRVal]
2924 mov dr2, rax
2925# else
2926 mov eax, [uDRVal]
2927 mov dr2, eax
2928# endif
2929 }
2930# endif
2931}
2932#endif
2933
2934
2935/**
2936 * Sets dr3.
2937 *
2938 * @param uDRVal Debug register value to write
2939 */
2940#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2941RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR3(RTCCUINTXREG uDRVal);
2942#else
2943DECLINLINE(void) ASMSetDR3(RTCCUINTXREG uDRVal)
2944{
2945# if RT_INLINE_ASM_USES_INTRIN
2946 __writedr(3, uDRVal);
2947# elif RT_INLINE_ASM_GNU_STYLE
2948# ifdef RT_ARCH_AMD64
2949 __asm__ __volatile__("movq %0, %%dr3\n\t" : : "r" (uDRVal));
2950# else
2951 __asm__ __volatile__("movl %0, %%dr3\n\t" : : "r" (uDRVal));
2952# endif
2953# else
2954 __asm
2955 {
2956# ifdef RT_ARCH_AMD64
2957 mov rax, [uDRVal]
2958 mov dr3, rax
2959# else
2960 mov eax, [uDRVal]
2961 mov dr3, eax
2962# endif
2963 }
2964# endif
2965}
2966#endif
2967
2968
2969/**
2970 * Sets dr6.
2971 *
2972 * @param uDRVal Debug register value to write
2973 */
2974#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2975RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR6(RTCCUINTXREG uDRVal);
2976#else
2977DECLINLINE(void) ASMSetDR6(RTCCUINTXREG uDRVal)
2978{
2979# if RT_INLINE_ASM_USES_INTRIN
2980 __writedr(6, uDRVal);
2981# elif RT_INLINE_ASM_GNU_STYLE
2982# ifdef RT_ARCH_AMD64
2983 __asm__ __volatile__("movq %0, %%dr6\n\t" : : "r" (uDRVal));
2984# else
2985 __asm__ __volatile__("movl %0, %%dr6\n\t" : : "r" (uDRVal));
2986# endif
2987# else
2988 __asm
2989 {
2990# ifdef RT_ARCH_AMD64
2991 mov rax, [uDRVal]
2992 mov dr6, rax
2993# else
2994 mov eax, [uDRVal]
2995 mov dr6, eax
2996# endif
2997 }
2998# endif
2999}
3000#endif
3001
3002
3003/**
3004 * Sets dr7.
3005 *
3006 * @param uDRVal Debug register value to write
3007 */
3008#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3009RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR7(RTCCUINTXREG uDRVal);
3010#else
3011DECLINLINE(void) ASMSetDR7(RTCCUINTXREG uDRVal)
3012{
3013# if RT_INLINE_ASM_USES_INTRIN
3014 __writedr(7, uDRVal);
3015# elif RT_INLINE_ASM_GNU_STYLE
3016# ifdef RT_ARCH_AMD64
3017 __asm__ __volatile__("movq %0, %%dr7\n\t" : : "r" (uDRVal));
3018# else
3019 __asm__ __volatile__("movl %0, %%dr7\n\t" : : "r" (uDRVal));
3020# endif
3021# else
3022 __asm
3023 {
3024# ifdef RT_ARCH_AMD64
3025 mov rax, [uDRVal]
3026 mov dr7, rax
3027# else
3028 mov eax, [uDRVal]
3029 mov dr7, eax
3030# endif
3031 }
3032# endif
3033}
3034#endif
3035
3036
3037/**
3038 * Writes a 8-bit unsigned integer to an I/O port, ordered.
3039 *
3040 * @param Port I/O port to write to.
3041 * @param u8 8-bit integer to write.
3042 */
3043#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3044RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU8(RTIOPORT Port, uint8_t u8);
3045#else
3046DECLINLINE(void) ASMOutU8(RTIOPORT Port, uint8_t u8)
3047{
3048# if RT_INLINE_ASM_GNU_STYLE
3049 __asm__ __volatile__("outb %b1, %w0\n\t"
3050 :: "Nd" (Port),
3051 "a" (u8));
3052
3053# elif RT_INLINE_ASM_USES_INTRIN
3054 __outbyte(Port, u8);
3055
3056# else
3057 __asm
3058 {
3059 mov dx, [Port]
3060 mov al, [u8]
3061 out dx, al
3062 }
3063# endif
3064}
3065#endif
3066
3067
3068/**
3069 * Reads a 8-bit unsigned integer from an I/O port, ordered.
3070 *
3071 * @returns 8-bit integer.
3072 * @param Port I/O port to read from.
3073 */
3074#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3075RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMInU8(RTIOPORT Port);
3076#else
3077DECLINLINE(uint8_t) ASMInU8(RTIOPORT Port)
3078{
3079 uint8_t u8;
3080# if RT_INLINE_ASM_GNU_STYLE
3081 __asm__ __volatile__("inb %w1, %b0\n\t"
3082 : "=a" (u8)
3083 : "Nd" (Port));
3084
3085# elif RT_INLINE_ASM_USES_INTRIN
3086 u8 = __inbyte(Port);
3087
3088# else
3089 __asm
3090 {
3091 mov dx, [Port]
3092 in al, dx
3093 mov [u8], al
3094 }
3095# endif
3096 return u8;
3097}
3098#endif
3099
3100
3101/**
3102 * Writes a 16-bit unsigned integer to an I/O port, ordered.
3103 *
3104 * @param Port I/O port to write to.
3105 * @param u16 16-bit integer to write.
3106 */
3107#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3108RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU16(RTIOPORT Port, uint16_t u16);
3109#else
3110DECLINLINE(void) ASMOutU16(RTIOPORT Port, uint16_t u16)
3111{
3112# if RT_INLINE_ASM_GNU_STYLE
3113 __asm__ __volatile__("outw %w1, %w0\n\t"
3114 :: "Nd" (Port),
3115 "a" (u16));
3116
3117# elif RT_INLINE_ASM_USES_INTRIN
3118 __outword(Port, u16);
3119
3120# else
3121 __asm
3122 {
3123 mov dx, [Port]
3124 mov ax, [u16]
3125 out dx, ax
3126 }
3127# endif
3128}
3129#endif
3130
3131
3132/**
3133 * Reads a 16-bit unsigned integer from an I/O port, ordered.
3134 *
3135 * @returns 16-bit integer.
3136 * @param Port I/O port to read from.
3137 */
3138#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3139RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMInU16(RTIOPORT Port);
3140#else
3141DECLINLINE(uint16_t) ASMInU16(RTIOPORT Port)
3142{
3143 uint16_t u16;
3144# if RT_INLINE_ASM_GNU_STYLE
3145 __asm__ __volatile__("inw %w1, %w0\n\t"
3146 : "=a" (u16)
3147 : "Nd" (Port));
3148
3149# elif RT_INLINE_ASM_USES_INTRIN
3150 u16 = __inword(Port);
3151
3152# else
3153 __asm
3154 {
3155 mov dx, [Port]
3156 in ax, dx
3157 mov [u16], ax
3158 }
3159# endif
3160 return u16;
3161}
3162#endif
3163
3164
3165/**
3166 * Writes a 32-bit unsigned integer to an I/O port, ordered.
3167 *
3168 * @param Port I/O port to write to.
3169 * @param u32 32-bit integer to write.
3170 */
3171#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3172RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU32(RTIOPORT Port, uint32_t u32);
3173#else
3174DECLINLINE(void) ASMOutU32(RTIOPORT Port, uint32_t u32)
3175{
3176# if RT_INLINE_ASM_GNU_STYLE
3177 __asm__ __volatile__("outl %1, %w0\n\t"
3178 :: "Nd" (Port),
3179 "a" (u32));
3180
3181# elif RT_INLINE_ASM_USES_INTRIN
3182 __outdword(Port, u32);
3183
3184# else
3185 __asm
3186 {
3187 mov dx, [Port]
3188 mov eax, [u32]
3189 out dx, eax
3190 }
3191# endif
3192}
3193#endif
3194
3195
3196/**
3197 * Reads a 32-bit unsigned integer from an I/O port, ordered.
3198 *
3199 * @returns 32-bit integer.
3200 * @param Port I/O port to read from.
3201 */
3202#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3203RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMInU32(RTIOPORT Port);
3204#else
3205DECLINLINE(uint32_t) ASMInU32(RTIOPORT Port)
3206{
3207 uint32_t u32;
3208# if RT_INLINE_ASM_GNU_STYLE
3209 __asm__ __volatile__("inl %w1, %0\n\t"
3210 : "=a" (u32)
3211 : "Nd" (Port));
3212
3213# elif RT_INLINE_ASM_USES_INTRIN
3214 u32 = __indword(Port);
3215
3216# else
3217 __asm
3218 {
3219 mov dx, [Port]
3220 in eax, dx
3221 mov [u32], eax
3222 }
3223# endif
3224 return u32;
3225}
3226#endif
3227
3228
3229/**
3230 * Writes a string of 8-bit unsigned integer items to an I/O port, ordered.
3231 *
3232 * @param Port I/O port to write to.
3233 * @param pau8 Pointer to the string buffer.
3234 * @param c The number of items to write.
3235 */
3236#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3237RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c);
3238#else
3239DECLINLINE(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c)
3240{
3241# if RT_INLINE_ASM_GNU_STYLE
3242 __asm__ __volatile__("rep; outsb\n\t"
3243 : "+S" (pau8),
3244 "+c" (c)
3245 : "d" (Port));
3246
3247# elif RT_INLINE_ASM_USES_INTRIN
3248 __outbytestring(Port, (unsigned char RT_FAR *)pau8, (unsigned long)c);
3249
3250# else
3251 __asm
3252 {
3253 mov dx, [Port]
3254 mov ecx, [c]
3255 mov eax, [pau8]
3256 xchg esi, eax
3257 rep outsb
3258 xchg esi, eax
3259 }
3260# endif
3261}
3262#endif
3263
3264
3265/**
3266 * Reads a string of 8-bit unsigned integer items from an I/O port, ordered.
3267 *
3268 * @param Port I/O port to read from.
3269 * @param pau8 Pointer to the string buffer (output).
3270 * @param c The number of items to read.
3271 */
3272#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3273RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c);
3274#else
3275DECLINLINE(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c)
3276{
3277# if RT_INLINE_ASM_GNU_STYLE
3278 __asm__ __volatile__("rep; insb\n\t"
3279 : "+D" (pau8),
3280 "+c" (c)
3281 : "d" (Port));
3282
3283# elif RT_INLINE_ASM_USES_INTRIN
3284 __inbytestring(Port, pau8, (unsigned long)c);
3285
3286# else
3287 __asm
3288 {
3289 mov dx, [Port]
3290 mov ecx, [c]
3291 mov eax, [pau8]
3292 xchg edi, eax
3293 rep insb
3294 xchg edi, eax
3295 }
3296# endif
3297}
3298#endif
3299
3300
3301/**
3302 * Writes a string of 16-bit unsigned integer items to an I/O port, ordered.
3303 *
3304 * @param Port I/O port to write to.
3305 * @param pau16 Pointer to the string buffer.
3306 * @param c The number of items to write.
3307 */
3308#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3309RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c);
3310#else
3311DECLINLINE(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c)
3312{
3313# if RT_INLINE_ASM_GNU_STYLE
3314 __asm__ __volatile__("rep; outsw\n\t"
3315 : "+S" (pau16),
3316 "+c" (c)
3317 : "d" (Port));
3318
3319# elif RT_INLINE_ASM_USES_INTRIN
3320 __outwordstring(Port, (unsigned short RT_FAR *)pau16, (unsigned long)c);
3321
3322# else
3323 __asm
3324 {
3325 mov dx, [Port]
3326 mov ecx, [c]
3327 mov eax, [pau16]
3328 xchg esi, eax
3329 rep outsw
3330 xchg esi, eax
3331 }
3332# endif
3333}
3334#endif
3335
3336
3337/**
3338 * Reads a string of 16-bit unsigned integer items from an I/O port, ordered.
3339 *
3340 * @param Port I/O port to read from.
3341 * @param pau16 Pointer to the string buffer (output).
3342 * @param c The number of items to read.
3343 */
3344#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3345RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c);
3346#else
3347DECLINLINE(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c)
3348{
3349# if RT_INLINE_ASM_GNU_STYLE
3350 __asm__ __volatile__("rep; insw\n\t"
3351 : "+D" (pau16),
3352 "+c" (c)
3353 : "d" (Port));
3354
3355# elif RT_INLINE_ASM_USES_INTRIN
3356 __inwordstring(Port, pau16, (unsigned long)c);
3357
3358# else
3359 __asm
3360 {
3361 mov dx, [Port]
3362 mov ecx, [c]
3363 mov eax, [pau16]
3364 xchg edi, eax
3365 rep insw
3366 xchg edi, eax
3367 }
3368# endif
3369}
3370#endif
3371
3372
3373/**
3374 * Writes a string of 32-bit unsigned integer items to an I/O port, ordered.
3375 *
3376 * @param Port I/O port to write to.
3377 * @param pau32 Pointer to the string buffer.
3378 * @param c The number of items to write.
3379 */
3380#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3381RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c);
3382#else
3383DECLINLINE(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c)
3384{
3385# if RT_INLINE_ASM_GNU_STYLE
3386 __asm__ __volatile__("rep; outsl\n\t"
3387 : "+S" (pau32),
3388 "+c" (c)
3389 : "d" (Port));
3390
3391# elif RT_INLINE_ASM_USES_INTRIN
3392 __outdwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c);
3393
3394# else
3395 __asm
3396 {
3397 mov dx, [Port]
3398 mov ecx, [c]
3399 mov eax, [pau32]
3400 xchg esi, eax
3401 rep outsd
3402 xchg esi, eax
3403 }
3404# endif
3405}
3406#endif
3407
3408
3409/**
3410 * Reads a string of 32-bit unsigned integer items from an I/O port, ordered.
3411 *
3412 * @param Port I/O port to read from.
3413 * @param pau32 Pointer to the string buffer (output).
3414 * @param c The number of items to read.
3415 */
3416#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3417RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c);
3418#else
3419DECLINLINE(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c)
3420{
3421# if RT_INLINE_ASM_GNU_STYLE
3422 __asm__ __volatile__("rep; insl\n\t"
3423 : "+D" (pau32),
3424 "+c" (c)
3425 : "d" (Port));
3426
3427# elif RT_INLINE_ASM_USES_INTRIN
3428 __indwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c);
3429
3430# else
3431 __asm
3432 {
3433 mov dx, [Port]
3434 mov ecx, [c]
3435 mov eax, [pau32]
3436 xchg edi, eax
3437 rep insd
3438 xchg edi, eax
3439 }
3440# endif
3441}
3442#endif
3443
3444
3445/**
3446 * Invalidate page.
3447 *
3448 * @param uPtr Address of the page to invalidate.
3449 */
3450#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3451RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidatePage(RTCCUINTXREG uPtr);
3452#else
3453DECLINLINE(void) ASMInvalidatePage(RTCCUINTXREG uPtr)
3454{
3455# if RT_INLINE_ASM_USES_INTRIN
3456 __invlpg((void RT_FAR *)uPtr);
3457
3458# elif RT_INLINE_ASM_GNU_STYLE
3459 __asm__ __volatile__("invlpg %0\n\t"
3460 : : "m" (*(uint8_t RT_FAR *)(uintptr_t)uPtr));
3461# else
3462 __asm
3463 {
3464# ifdef RT_ARCH_AMD64
3465 mov rax, [uPtr]
3466 invlpg [rax]
3467# else
3468 mov eax, [uPtr]
3469 invlpg [eax]
3470# endif
3471 }
3472# endif
3473}
3474#endif
3475
3476
3477/**
3478 * Write back the internal caches and invalidate them.
3479 */
3480#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3481RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWriteBackAndInvalidateCaches(void);
3482#else
3483DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void)
3484{
3485# if RT_INLINE_ASM_USES_INTRIN
3486 __wbinvd();
3487
3488# elif RT_INLINE_ASM_GNU_STYLE
3489 __asm__ __volatile__("wbinvd");
3490# else
3491 __asm
3492 {
3493 wbinvd
3494 }
3495# endif
3496}
3497#endif
3498
3499
3500/**
3501 * Invalidate internal and (perhaps) external caches without first
3502 * flushing dirty cache lines. Use with extreme care.
3503 */
3504#if RT_INLINE_ASM_EXTERNAL
3505RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidateInternalCaches(void);
3506#else
3507DECLINLINE(void) ASMInvalidateInternalCaches(void)
3508{
3509# if RT_INLINE_ASM_GNU_STYLE
3510 __asm__ __volatile__("invd");
3511# else
3512 __asm
3513 {
3514 invd
3515 }
3516# endif
3517}
3518#endif
3519
3520
3521/**
3522 * Memory load/store fence, waits for any pending writes and reads to complete.
3523 * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set.
3524 */
3525DECLINLINE(void) ASMMemoryFenceSSE2(void)
3526{
3527#if RT_INLINE_ASM_GNU_STYLE
3528 __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t");
3529#elif RT_INLINE_ASM_USES_INTRIN
3530 _mm_mfence();
3531#else
3532 __asm
3533 {
3534 _emit 0x0f
3535 _emit 0xae
3536 _emit 0xf0
3537 }
3538#endif
3539}
3540
3541
3542/**
3543 * Memory store fence, waits for any writes to complete.
3544 * Requires the X86_CPUID_FEATURE_EDX_SSE CPUID bit set.
3545 */
3546DECLINLINE(void) ASMWriteFenceSSE(void)
3547{
3548#if RT_INLINE_ASM_GNU_STYLE
3549 __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t");
3550#elif RT_INLINE_ASM_USES_INTRIN
3551 _mm_sfence();
3552#else
3553 __asm
3554 {
3555 _emit 0x0f
3556 _emit 0xae
3557 _emit 0xf8
3558 }
3559#endif
3560}
3561
3562
3563/**
3564 * Memory load fence, waits for any pending reads to complete.
3565 * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set.
3566 */
3567DECLINLINE(void) ASMReadFenceSSE2(void)
3568{
3569#if RT_INLINE_ASM_GNU_STYLE
3570 __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t");
3571#elif RT_INLINE_ASM_USES_INTRIN
3572 _mm_lfence();
3573#else
3574 __asm
3575 {
3576 _emit 0x0f
3577 _emit 0xae
3578 _emit 0xe8
3579 }
3580#endif
3581}
3582
3583#if !defined(_MSC_VER) || !defined(RT_ARCH_AMD64)
3584
3585/*
3586 * Clear the AC bit in the EFLAGS register.
3587 * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set.
3588 * Requires to be executed in R0.
3589 */
3590DECLINLINE(void) ASMClearAC(void)
3591{
3592#if RT_INLINE_ASM_GNU_STYLE
3593 __asm__ __volatile__ (".byte 0x0f,0x01,0xca\n\t");
3594#else
3595 __asm
3596 {
3597 _emit 0x0f
3598 _emit 0x01
3599 _emit 0xca
3600 }
3601#endif
3602}
3603
3604
3605/*
3606 * Set the AC bit in the EFLAGS register.
3607 * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set.
3608 * Requires to be executed in R0.
3609 */
3610DECLINLINE(void) ASMSetAC(void)
3611{
3612#if RT_INLINE_ASM_GNU_STYLE
3613 __asm__ __volatile__ (".byte 0x0f,0x01,0xcb\n\t");
3614#else
3615 __asm
3616 {
3617 _emit 0x0f
3618 _emit 0x01
3619 _emit 0xcb
3620 }
3621#endif
3622}
3623
3624#endif /* !_MSC_VER || !RT_ARCH_AMD64 */
3625
3626
3627/*
3628 * Include #pragma aux definitions for Watcom C/C++.
3629 */
3630#if defined(__WATCOMC__) && ARCH_BITS == 16
3631# define IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE
3632# undef IPRT_INCLUDED_asm_amd64_x86_watcom_16_h
3633# include "asm-amd64-x86-watcom-16.h"
3634#elif defined(__WATCOMC__) && ARCH_BITS == 32
3635# define IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE
3636# undef IPRT_INCLUDED_asm_amd64_x86_watcom_32_h
3637# include "asm-amd64-x86-watcom-32.h"
3638#endif
3639
3640
3641/** @} */
3642#endif /* !IPRT_INCLUDED_asm_amd64_x86_h */
3643
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