VirtualBox

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

Last change on this file since 76585 was 76585, checked in by vboxsync, 6 years ago

*: scm --fix-header-guard-endif

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