VirtualBox

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

Last change on this file since 58710 was 58705, checked in by vboxsync, 9 years ago

iprt/asm-amd64-x86.h: 16-bit and 32-bit Watcom C/C++ adjustments.

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