VirtualBox

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

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

iprt/asm-amd64-x86.h: Don't use readeflags & writeeflags as they (or at least the latter) seems to confuse compiler optimizations and also is said to have other reordering issues. bugref:9180

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.1 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) - buggy intrinsics in VC++ 2010, reordering/optimizers issues
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 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
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 - see __readeflags() above. */
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 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
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 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
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 - buggy intrinsics in VC++ 2010, reordering/optimizers issues. */
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 * Tests if it a Shanghai CPU based on the ASMCpuId(0) output.
1479 *
1480 * @returns true/false.
1481 * @param uEBX EBX return from ASMCpuId(0).
1482 * @param uECX ECX return from ASMCpuId(0).
1483 * @param uEDX EDX return from ASMCpuId(0).
1484 */
1485DECLINLINE(bool) ASMIsShanghaiCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
1486{
1487 return uEBX == UINT32_C(0x68532020)
1488 && uECX == UINT32_C(0x20206961)
1489 && uEDX == UINT32_C(0x68676e61);
1490}
1491
1492
1493/**
1494 * Tests if this is a Shanghai CPU.
1495 *
1496 * @returns true/false.
1497 * @remarks ASSUMES that cpuid is supported by the CPU.
1498 */
1499DECLINLINE(bool) ASMIsShanghaiCpu(void)
1500{
1501 uint32_t uEAX, uEBX, uECX, uEDX;
1502 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
1503 return ASMIsShanghaiCpuEx(uEBX, uECX, uEDX);
1504}
1505
1506
1507/**
1508 * Checks whether ASMCpuId_EAX(0x00000000) indicates a valid range.
1509 *
1510 *
1511 * @returns true/false.
1512 * @param uEAX The EAX value of CPUID leaf 0x00000000.
1513 *
1514 * @note This only succeeds if there are at least two leaves in the range.
1515 * @remarks The upper range limit is just some half reasonable value we've
1516 * picked out of thin air.
1517 */
1518DECLINLINE(bool) ASMIsValidStdRange(uint32_t uEAX)
1519{
1520 return uEAX >= UINT32_C(0x00000001) && uEAX <= UINT32_C(0x000fffff);
1521}
1522
1523
1524/**
1525 * Checks whether ASMCpuId_EAX(0x80000000) indicates a valid range.
1526 *
1527 * This only succeeds if there are at least two leaves in the range.
1528 *
1529 * @returns true/false.
1530 * @param uEAX The EAX value of CPUID leaf 0x80000000.
1531 *
1532 * @note This only succeeds if there are at least two leaves in the range.
1533 * @remarks The upper range limit is just some half reasonable value we've
1534 * picked out of thin air.
1535 */
1536DECLINLINE(bool) ASMIsValidExtRange(uint32_t uEAX)
1537{
1538 return uEAX >= UINT32_C(0x80000001) && uEAX <= UINT32_C(0x800fffff);
1539}
1540
1541
1542/**
1543 * Checks whether ASMCpuId_EAX(0x40000000) indicates a valid range.
1544 *
1545 * This only succeeds if there are at least two leaves in the range.
1546 *
1547 * @returns true/false.
1548 * @param uEAX The EAX value of CPUID leaf 0x40000000.
1549 *
1550 * @note Unlike ASMIsValidStdRange() and ASMIsValidExtRange(), a single leaf
1551 * is okay here. So, you always need to check the range.
1552 * @remarks The upper range limit is take from the intel docs.
1553 */
1554DECLINLINE(bool) ASMIsValidHypervisorRange(uint32_t uEAX)
1555{
1556 return uEAX >= UINT32_C(0x40000000) && uEAX <= UINT32_C(0x4fffffff);
1557}
1558
1559
1560/**
1561 * Extracts the CPU family from ASMCpuId(1) or ASMCpuId(0x80000001)
1562 *
1563 * @returns Family.
1564 * @param uEAX EAX return from ASMCpuId(1) or ASMCpuId(0x80000001).
1565 */
1566DECLINLINE(uint32_t) ASMGetCpuFamily(uint32_t uEAX)
1567{
1568 return ((uEAX >> 8) & 0xf) == 0xf
1569 ? ((uEAX >> 20) & 0x7f) + 0xf
1570 : ((uEAX >> 8) & 0xf);
1571}
1572
1573
1574/**
1575 * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), Intel variant.
1576 *
1577 * @returns Model.
1578 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1579 */
1580DECLINLINE(uint32_t) ASMGetCpuModelIntel(uint32_t uEAX)
1581{
1582 return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6) /* family! */
1583 ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0)
1584 : ((uEAX >> 4) & 0xf);
1585}
1586
1587
1588/**
1589 * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001), AMD variant.
1590 *
1591 * @returns Model.
1592 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1593 */
1594DECLINLINE(uint32_t) ASMGetCpuModelAMD(uint32_t uEAX)
1595{
1596 return ((uEAX >> 8) & 0xf) == 0xf
1597 ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0)
1598 : ((uEAX >> 4) & 0xf);
1599}
1600
1601
1602/**
1603 * Extracts the CPU model from ASMCpuId(1) or ASMCpuId(0x80000001)
1604 *
1605 * @returns Model.
1606 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1607 * @param fIntel Whether it's an intel CPU. Use ASMIsIntelCpuEx() or ASMIsIntelCpu().
1608 */
1609DECLINLINE(uint32_t) ASMGetCpuModel(uint32_t uEAX, bool fIntel)
1610{
1611 return ((uEAX >> 8) & 0xf) == 0xf || (((uEAX >> 8) & 0xf) == 0x6 && fIntel) /* family! */
1612 ? ((uEAX >> 4) & 0xf) | ((uEAX >> 12) & 0xf0)
1613 : ((uEAX >> 4) & 0xf);
1614}
1615
1616
1617/**
1618 * Extracts the CPU stepping from ASMCpuId(1) or ASMCpuId(0x80000001)
1619 *
1620 * @returns Model.
1621 * @param uEAX EAX from ASMCpuId(1) or ASMCpuId(0x80000001).
1622 */
1623DECLINLINE(uint32_t) ASMGetCpuStepping(uint32_t uEAX)
1624{
1625 return uEAX & 0xf;
1626}
1627
1628
1629/**
1630 * Get cr0.
1631 * @returns cr0.
1632 */
1633#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1634RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR0(void);
1635#else
1636DECLINLINE(RTCCUINTXREG) ASMGetCR0(void)
1637{
1638 RTCCUINTXREG uCR0;
1639# if RT_INLINE_ASM_USES_INTRIN
1640 uCR0 = __readcr0();
1641
1642# elif RT_INLINE_ASM_GNU_STYLE
1643# ifdef RT_ARCH_AMD64
1644 __asm__ __volatile__("movq %%cr0, %0\t\n" : "=r" (uCR0));
1645# else
1646 __asm__ __volatile__("movl %%cr0, %0\t\n" : "=r" (uCR0));
1647# endif
1648# else
1649 __asm
1650 {
1651# ifdef RT_ARCH_AMD64
1652 mov rax, cr0
1653 mov [uCR0], rax
1654# else
1655 mov eax, cr0
1656 mov [uCR0], eax
1657# endif
1658 }
1659# endif
1660 return uCR0;
1661}
1662#endif
1663
1664
1665/**
1666 * Sets the CR0 register.
1667 * @param uCR0 The new CR0 value.
1668 */
1669#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1670RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR0(RTCCUINTXREG uCR0);
1671#else
1672DECLINLINE(void) ASMSetCR0(RTCCUINTXREG uCR0)
1673{
1674# if RT_INLINE_ASM_USES_INTRIN
1675 __writecr0(uCR0);
1676
1677# elif RT_INLINE_ASM_GNU_STYLE
1678# ifdef RT_ARCH_AMD64
1679 __asm__ __volatile__("movq %0, %%cr0\n\t" :: "r" (uCR0));
1680# else
1681 __asm__ __volatile__("movl %0, %%cr0\n\t" :: "r" (uCR0));
1682# endif
1683# else
1684 __asm
1685 {
1686# ifdef RT_ARCH_AMD64
1687 mov rax, [uCR0]
1688 mov cr0, rax
1689# else
1690 mov eax, [uCR0]
1691 mov cr0, eax
1692# endif
1693 }
1694# endif
1695}
1696#endif
1697
1698
1699/**
1700 * Get cr2.
1701 * @returns cr2.
1702 */
1703#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1704RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR2(void);
1705#else
1706DECLINLINE(RTCCUINTXREG) ASMGetCR2(void)
1707{
1708 RTCCUINTXREG uCR2;
1709# if RT_INLINE_ASM_USES_INTRIN
1710 uCR2 = __readcr2();
1711
1712# elif RT_INLINE_ASM_GNU_STYLE
1713# ifdef RT_ARCH_AMD64
1714 __asm__ __volatile__("movq %%cr2, %0\t\n" : "=r" (uCR2));
1715# else
1716 __asm__ __volatile__("movl %%cr2, %0\t\n" : "=r" (uCR2));
1717# endif
1718# else
1719 __asm
1720 {
1721# ifdef RT_ARCH_AMD64
1722 mov rax, cr2
1723 mov [uCR2], rax
1724# else
1725 mov eax, cr2
1726 mov [uCR2], eax
1727# endif
1728 }
1729# endif
1730 return uCR2;
1731}
1732#endif
1733
1734
1735/**
1736 * Sets the CR2 register.
1737 * @param uCR2 The new CR0 value.
1738 */
1739#if RT_INLINE_ASM_EXTERNAL
1740RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR2(RTCCUINTXREG uCR2);
1741#else
1742DECLINLINE(void) ASMSetCR2(RTCCUINTXREG uCR2)
1743{
1744# if RT_INLINE_ASM_GNU_STYLE
1745# ifdef RT_ARCH_AMD64
1746 __asm__ __volatile__("movq %0, %%cr2\n\t" :: "r" (uCR2));
1747# else
1748 __asm__ __volatile__("movl %0, %%cr2\n\t" :: "r" (uCR2));
1749# endif
1750# else
1751 __asm
1752 {
1753# ifdef RT_ARCH_AMD64
1754 mov rax, [uCR2]
1755 mov cr2, rax
1756# else
1757 mov eax, [uCR2]
1758 mov cr2, eax
1759# endif
1760 }
1761# endif
1762}
1763#endif
1764
1765
1766/**
1767 * Get cr3.
1768 * @returns cr3.
1769 */
1770#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1771RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR3(void);
1772#else
1773DECLINLINE(RTCCUINTXREG) ASMGetCR3(void)
1774{
1775 RTCCUINTXREG uCR3;
1776# if RT_INLINE_ASM_USES_INTRIN
1777 uCR3 = __readcr3();
1778
1779# elif RT_INLINE_ASM_GNU_STYLE
1780# ifdef RT_ARCH_AMD64
1781 __asm__ __volatile__("movq %%cr3, %0\t\n" : "=r" (uCR3));
1782# else
1783 __asm__ __volatile__("movl %%cr3, %0\t\n" : "=r" (uCR3));
1784# endif
1785# else
1786 __asm
1787 {
1788# ifdef RT_ARCH_AMD64
1789 mov rax, cr3
1790 mov [uCR3], rax
1791# else
1792 mov eax, cr3
1793 mov [uCR3], eax
1794# endif
1795 }
1796# endif
1797 return uCR3;
1798}
1799#endif
1800
1801
1802/**
1803 * Sets the CR3 register.
1804 *
1805 * @param uCR3 New CR3 value.
1806 */
1807#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1808RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR3(RTCCUINTXREG uCR3);
1809#else
1810DECLINLINE(void) ASMSetCR3(RTCCUINTXREG uCR3)
1811{
1812# if RT_INLINE_ASM_USES_INTRIN
1813 __writecr3(uCR3);
1814
1815# elif RT_INLINE_ASM_GNU_STYLE
1816# ifdef RT_ARCH_AMD64
1817 __asm__ __volatile__("movq %0, %%cr3\n\t" : : "r" (uCR3));
1818# else
1819 __asm__ __volatile__("movl %0, %%cr3\n\t" : : "r" (uCR3));
1820# endif
1821# else
1822 __asm
1823 {
1824# ifdef RT_ARCH_AMD64
1825 mov rax, [uCR3]
1826 mov cr3, rax
1827# else
1828 mov eax, [uCR3]
1829 mov cr3, eax
1830# endif
1831 }
1832# endif
1833}
1834#endif
1835
1836
1837/**
1838 * Reloads the CR3 register.
1839 */
1840#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1841RT_ASM_DECL_PRAGMA_WATCOM(void) ASMReloadCR3(void);
1842#else
1843DECLINLINE(void) ASMReloadCR3(void)
1844{
1845# if RT_INLINE_ASM_USES_INTRIN
1846 __writecr3(__readcr3());
1847
1848# elif RT_INLINE_ASM_GNU_STYLE
1849 RTCCUINTXREG u;
1850# ifdef RT_ARCH_AMD64
1851 __asm__ __volatile__("movq %%cr3, %0\n\t"
1852 "movq %0, %%cr3\n\t"
1853 : "=r" (u));
1854# else
1855 __asm__ __volatile__("movl %%cr3, %0\n\t"
1856 "movl %0, %%cr3\n\t"
1857 : "=r" (u));
1858# endif
1859# else
1860 __asm
1861 {
1862# ifdef RT_ARCH_AMD64
1863 mov rax, cr3
1864 mov cr3, rax
1865# else
1866 mov eax, cr3
1867 mov cr3, eax
1868# endif
1869 }
1870# endif
1871}
1872#endif
1873
1874
1875/**
1876 * Get cr4.
1877 * @returns cr4.
1878 */
1879#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1880RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetCR4(void);
1881#else
1882DECLINLINE(RTCCUINTXREG) ASMGetCR4(void)
1883{
1884 RTCCUINTXREG uCR4;
1885# if RT_INLINE_ASM_USES_INTRIN
1886 uCR4 = __readcr4();
1887
1888# elif RT_INLINE_ASM_GNU_STYLE
1889# ifdef RT_ARCH_AMD64
1890 __asm__ __volatile__("movq %%cr4, %0\t\n" : "=r" (uCR4));
1891# else
1892 __asm__ __volatile__("movl %%cr4, %0\t\n" : "=r" (uCR4));
1893# endif
1894# else
1895 __asm
1896 {
1897# ifdef RT_ARCH_AMD64
1898 mov rax, cr4
1899 mov [uCR4], rax
1900# else
1901 push eax /* just in case */
1902 /*mov eax, cr4*/
1903 _emit 0x0f
1904 _emit 0x20
1905 _emit 0xe0
1906 mov [uCR4], eax
1907 pop eax
1908# endif
1909 }
1910# endif
1911 return uCR4;
1912}
1913#endif
1914
1915
1916/**
1917 * Sets the CR4 register.
1918 *
1919 * @param uCR4 New CR4 value.
1920 */
1921#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1922RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetCR4(RTCCUINTXREG uCR4);
1923#else
1924DECLINLINE(void) ASMSetCR4(RTCCUINTXREG uCR4)
1925{
1926# if RT_INLINE_ASM_USES_INTRIN
1927 __writecr4(uCR4);
1928
1929# elif RT_INLINE_ASM_GNU_STYLE
1930# ifdef RT_ARCH_AMD64
1931 __asm__ __volatile__("movq %0, %%cr4\n\t" : : "r" (uCR4));
1932# else
1933 __asm__ __volatile__("movl %0, %%cr4\n\t" : : "r" (uCR4));
1934# endif
1935# else
1936 __asm
1937 {
1938# ifdef RT_ARCH_AMD64
1939 mov rax, [uCR4]
1940 mov cr4, rax
1941# else
1942 mov eax, [uCR4]
1943 _emit 0x0F
1944 _emit 0x22
1945 _emit 0xE0 /* mov cr4, eax */
1946# endif
1947 }
1948# endif
1949}
1950#endif
1951
1952
1953/**
1954 * Get cr8.
1955 * @returns cr8.
1956 * @remark The lock prefix hack for access from non-64-bit modes is NOT used and 0 is returned.
1957 */
1958#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1959DECLASM(RTCCUINTXREG) ASMGetCR8(void);
1960#else
1961DECLINLINE(RTCCUINTXREG) ASMGetCR8(void)
1962{
1963# ifdef RT_ARCH_AMD64
1964 RTCCUINTXREG uCR8;
1965# if RT_INLINE_ASM_USES_INTRIN
1966 uCR8 = __readcr8();
1967
1968# elif RT_INLINE_ASM_GNU_STYLE
1969 __asm__ __volatile__("movq %%cr8, %0\t\n" : "=r" (uCR8));
1970# else
1971 __asm
1972 {
1973 mov rax, cr8
1974 mov [uCR8], rax
1975 }
1976# endif
1977 return uCR8;
1978# else /* !RT_ARCH_AMD64 */
1979 return 0;
1980# endif /* !RT_ARCH_AMD64 */
1981}
1982#endif
1983
1984
1985/**
1986 * Get XCR0 (eXtended feature Control Register 0).
1987 * @returns xcr0.
1988 */
1989DECLASM(uint64_t) ASMGetXcr0(void);
1990
1991/**
1992 * Sets the XCR0 register.
1993 * @param uXcr0 The new XCR0 value.
1994 */
1995DECLASM(void) ASMSetXcr0(uint64_t uXcr0);
1996
1997struct X86XSAVEAREA;
1998/**
1999 * Save extended CPU state.
2000 * @param pXStateArea Where to save the state.
2001 * @param fComponents Which state components to save.
2002 */
2003DECLASM(void) ASMXSave(struct X86XSAVEAREA RT_FAR *pXStateArea, uint64_t fComponents);
2004
2005/**
2006 * Loads extended CPU state.
2007 * @param pXStateArea Where to load the state from.
2008 * @param fComponents Which state components to load.
2009 */
2010DECLASM(void) ASMXRstor(struct X86XSAVEAREA const RT_FAR *pXStateArea, uint64_t fComponents);
2011
2012
2013struct X86FXSTATE;
2014/**
2015 * Save FPU and SSE CPU state.
2016 * @param pXStateArea Where to save the state.
2017 */
2018DECLASM(void) ASMFxSave(struct X86FXSTATE RT_FAR *pXStateArea);
2019
2020/**
2021 * Load FPU and SSE CPU state.
2022 * @param pXStateArea Where to load the state from.
2023 */
2024DECLASM(void) ASMFxRstor(struct X86FXSTATE const RT_FAR *pXStateArea);
2025
2026
2027/**
2028 * Enables interrupts (EFLAGS.IF).
2029 */
2030#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2031RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntEnable(void);
2032#else
2033DECLINLINE(void) ASMIntEnable(void)
2034{
2035# if RT_INLINE_ASM_GNU_STYLE
2036 __asm("sti\n");
2037# elif RT_INLINE_ASM_USES_INTRIN
2038 _enable();
2039# else
2040 __asm sti
2041# endif
2042}
2043#endif
2044
2045
2046/**
2047 * Disables interrupts (!EFLAGS.IF).
2048 */
2049#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2050RT_ASM_DECL_PRAGMA_WATCOM(void) ASMIntDisable(void);
2051#else
2052DECLINLINE(void) ASMIntDisable(void)
2053{
2054# if RT_INLINE_ASM_GNU_STYLE
2055 __asm("cli\n");
2056# elif RT_INLINE_ASM_USES_INTRIN
2057 _disable();
2058# else
2059 __asm cli
2060# endif
2061}
2062#endif
2063
2064
2065/**
2066 * Disables interrupts and returns previous xFLAGS.
2067 */
2068#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2069RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTREG) ASMIntDisableFlags(void);
2070#else
2071DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void)
2072{
2073 RTCCUINTREG xFlags;
2074# if RT_INLINE_ASM_GNU_STYLE
2075# ifdef RT_ARCH_AMD64
2076 __asm__ __volatile__("pushfq\n\t"
2077 "cli\n\t"
2078 "popq %0\n\t"
2079 : "=r" (xFlags));
2080# else
2081 __asm__ __volatile__("pushfl\n\t"
2082 "cli\n\t"
2083 "popl %0\n\t"
2084 : "=r" (xFlags));
2085# endif
2086# elif RT_INLINE_ASM_USES_INTRIN && !defined(RT_ARCH_X86)
2087 xFlags = ASMGetFlags();
2088 _disable();
2089# else
2090 __asm {
2091 pushfd
2092 cli
2093 pop [xFlags]
2094 }
2095# endif
2096 return xFlags;
2097}
2098#endif
2099
2100
2101/**
2102 * Are interrupts enabled?
2103 *
2104 * @returns true / false.
2105 */
2106DECLINLINE(bool) ASMIntAreEnabled(void)
2107{
2108 RTCCUINTREG uFlags = ASMGetFlags();
2109 return uFlags & 0x200 /* X86_EFL_IF */ ? true : false;
2110}
2111
2112
2113/**
2114 * Halts the CPU until interrupted.
2115 */
2116#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < 14
2117RT_ASM_DECL_PRAGMA_WATCOM(void) ASMHalt(void);
2118#else
2119DECLINLINE(void) ASMHalt(void)
2120{
2121# if RT_INLINE_ASM_GNU_STYLE
2122 __asm__ __volatile__("hlt\n\t");
2123# elif RT_INLINE_ASM_USES_INTRIN
2124 __halt();
2125# else
2126 __asm {
2127 hlt
2128 }
2129# endif
2130}
2131#endif
2132
2133
2134/**
2135 * Reads a machine specific register.
2136 *
2137 * @returns Register content.
2138 * @param uRegister Register to read.
2139 */
2140#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2141RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMRdMsr(uint32_t uRegister);
2142#else
2143DECLINLINE(uint64_t) ASMRdMsr(uint32_t uRegister)
2144{
2145 RTUINT64U u;
2146# if RT_INLINE_ASM_GNU_STYLE
2147 __asm__ __volatile__("rdmsr\n\t"
2148 : "=a" (u.s.Lo),
2149 "=d" (u.s.Hi)
2150 : "c" (uRegister));
2151
2152# elif RT_INLINE_ASM_USES_INTRIN
2153 u.u = __readmsr(uRegister);
2154
2155# else
2156 __asm
2157 {
2158 mov ecx, [uRegister]
2159 rdmsr
2160 mov [u.s.Lo], eax
2161 mov [u.s.Hi], edx
2162 }
2163# endif
2164
2165 return u.u;
2166}
2167#endif
2168
2169
2170/**
2171 * Writes a machine specific register.
2172 *
2173 * @returns Register content.
2174 * @param uRegister Register to write to.
2175 * @param u64Val Value to write.
2176 */
2177#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2178RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val);
2179#else
2180DECLINLINE(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val)
2181{
2182 RTUINT64U u;
2183
2184 u.u = u64Val;
2185# if RT_INLINE_ASM_GNU_STYLE
2186 __asm__ __volatile__("wrmsr\n\t"
2187 ::"a" (u.s.Lo),
2188 "d" (u.s.Hi),
2189 "c" (uRegister));
2190
2191# elif RT_INLINE_ASM_USES_INTRIN
2192 __writemsr(uRegister, u.u);
2193
2194# else
2195 __asm
2196 {
2197 mov ecx, [uRegister]
2198 mov edx, [u.s.Hi]
2199 mov eax, [u.s.Lo]
2200 wrmsr
2201 }
2202# endif
2203}
2204#endif
2205
2206
2207/**
2208 * Reads a machine specific register, extended version (for AMD).
2209 *
2210 * @returns Register content.
2211 * @param uRegister Register to read.
2212 * @param uXDI RDI/EDI value.
2213 */
2214#if RT_INLINE_ASM_EXTERNAL
2215RT_ASM_DECL_PRAGMA_WATCOM(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI);
2216#else
2217DECLINLINE(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI)
2218{
2219 RTUINT64U u;
2220# if RT_INLINE_ASM_GNU_STYLE
2221 __asm__ __volatile__("rdmsr\n\t"
2222 : "=a" (u.s.Lo),
2223 "=d" (u.s.Hi)
2224 : "c" (uRegister),
2225 "D" (uXDI));
2226
2227# else
2228 __asm
2229 {
2230 mov ecx, [uRegister]
2231 xchg edi, [uXDI]
2232 rdmsr
2233 mov [u.s.Lo], eax
2234 mov [u.s.Hi], edx
2235 xchg edi, [uXDI]
2236 }
2237# endif
2238
2239 return u.u;
2240}
2241#endif
2242
2243
2244/**
2245 * Writes a machine specific register, extended version (for AMD).
2246 *
2247 * @returns Register content.
2248 * @param uRegister Register to write to.
2249 * @param uXDI RDI/EDI value.
2250 * @param u64Val Value to write.
2251 */
2252#if RT_INLINE_ASM_EXTERNAL
2253RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val);
2254#else
2255DECLINLINE(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTXREG uXDI, uint64_t u64Val)
2256{
2257 RTUINT64U u;
2258
2259 u.u = u64Val;
2260# if RT_INLINE_ASM_GNU_STYLE
2261 __asm__ __volatile__("wrmsr\n\t"
2262 ::"a" (u.s.Lo),
2263 "d" (u.s.Hi),
2264 "c" (uRegister),
2265 "D" (uXDI));
2266
2267# else
2268 __asm
2269 {
2270 mov ecx, [uRegister]
2271 xchg edi, [uXDI]
2272 mov edx, [u.s.Hi]
2273 mov eax, [u.s.Lo]
2274 wrmsr
2275 xchg edi, [uXDI]
2276 }
2277# endif
2278}
2279#endif
2280
2281
2282
2283/**
2284 * Reads low part of a machine specific register.
2285 *
2286 * @returns Register content.
2287 * @param uRegister Register to read.
2288 */
2289#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2290RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_Low(uint32_t uRegister);
2291#else
2292DECLINLINE(uint32_t) ASMRdMsr_Low(uint32_t uRegister)
2293{
2294 uint32_t u32;
2295# if RT_INLINE_ASM_GNU_STYLE
2296 __asm__ __volatile__("rdmsr\n\t"
2297 : "=a" (u32)
2298 : "c" (uRegister)
2299 : "edx");
2300
2301# elif RT_INLINE_ASM_USES_INTRIN
2302 u32 = (uint32_t)__readmsr(uRegister);
2303
2304#else
2305 __asm
2306 {
2307 mov ecx, [uRegister]
2308 rdmsr
2309 mov [u32], eax
2310 }
2311# endif
2312
2313 return u32;
2314}
2315#endif
2316
2317
2318/**
2319 * Reads high part of a machine specific register.
2320 *
2321 * @returns Register content.
2322 * @param uRegister Register to read.
2323 */
2324#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2325RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMRdMsr_High(uint32_t uRegister);
2326#else
2327DECLINLINE(uint32_t) ASMRdMsr_High(uint32_t uRegister)
2328{
2329 uint32_t u32;
2330# if RT_INLINE_ASM_GNU_STYLE
2331 __asm__ __volatile__("rdmsr\n\t"
2332 : "=d" (u32)
2333 : "c" (uRegister)
2334 : "eax");
2335
2336# elif RT_INLINE_ASM_USES_INTRIN
2337 u32 = (uint32_t)(__readmsr(uRegister) >> 32);
2338
2339# else
2340 __asm
2341 {
2342 mov ecx, [uRegister]
2343 rdmsr
2344 mov [u32], edx
2345 }
2346# endif
2347
2348 return u32;
2349}
2350#endif
2351
2352
2353/**
2354 * Gets dr0.
2355 *
2356 * @returns dr0.
2357 */
2358#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2359RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR0(void);
2360#else
2361DECLINLINE(RTCCUINTXREG) ASMGetDR0(void)
2362{
2363 RTCCUINTXREG uDR0;
2364# if RT_INLINE_ASM_USES_INTRIN
2365 uDR0 = __readdr(0);
2366# elif RT_INLINE_ASM_GNU_STYLE
2367# ifdef RT_ARCH_AMD64
2368 __asm__ __volatile__("movq %%dr0, %0\n\t" : "=r" (uDR0));
2369# else
2370 __asm__ __volatile__("movl %%dr0, %0\n\t" : "=r" (uDR0));
2371# endif
2372# else
2373 __asm
2374 {
2375# ifdef RT_ARCH_AMD64
2376 mov rax, dr0
2377 mov [uDR0], rax
2378# else
2379 mov eax, dr0
2380 mov [uDR0], eax
2381# endif
2382 }
2383# endif
2384 return uDR0;
2385}
2386#endif
2387
2388
2389/**
2390 * Gets dr1.
2391 *
2392 * @returns dr1.
2393 */
2394#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2395RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR1(void);
2396#else
2397DECLINLINE(RTCCUINTXREG) ASMGetDR1(void)
2398{
2399 RTCCUINTXREG uDR1;
2400# if RT_INLINE_ASM_USES_INTRIN
2401 uDR1 = __readdr(1);
2402# elif RT_INLINE_ASM_GNU_STYLE
2403# ifdef RT_ARCH_AMD64
2404 __asm__ __volatile__("movq %%dr1, %0\n\t" : "=r" (uDR1));
2405# else
2406 __asm__ __volatile__("movl %%dr1, %0\n\t" : "=r" (uDR1));
2407# endif
2408# else
2409 __asm
2410 {
2411# ifdef RT_ARCH_AMD64
2412 mov rax, dr1
2413 mov [uDR1], rax
2414# else
2415 mov eax, dr1
2416 mov [uDR1], eax
2417# endif
2418 }
2419# endif
2420 return uDR1;
2421}
2422#endif
2423
2424
2425/**
2426 * Gets dr2.
2427 *
2428 * @returns dr2.
2429 */
2430#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2431RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR2(void);
2432#else
2433DECLINLINE(RTCCUINTXREG) ASMGetDR2(void)
2434{
2435 RTCCUINTXREG uDR2;
2436# if RT_INLINE_ASM_USES_INTRIN
2437 uDR2 = __readdr(2);
2438# elif RT_INLINE_ASM_GNU_STYLE
2439# ifdef RT_ARCH_AMD64
2440 __asm__ __volatile__("movq %%dr2, %0\n\t" : "=r" (uDR2));
2441# else
2442 __asm__ __volatile__("movl %%dr2, %0\n\t" : "=r" (uDR2));
2443# endif
2444# else
2445 __asm
2446 {
2447# ifdef RT_ARCH_AMD64
2448 mov rax, dr2
2449 mov [uDR2], rax
2450# else
2451 mov eax, dr2
2452 mov [uDR2], eax
2453# endif
2454 }
2455# endif
2456 return uDR2;
2457}
2458#endif
2459
2460
2461/**
2462 * Gets dr3.
2463 *
2464 * @returns dr3.
2465 */
2466#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2467RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR3(void);
2468#else
2469DECLINLINE(RTCCUINTXREG) ASMGetDR3(void)
2470{
2471 RTCCUINTXREG uDR3;
2472# if RT_INLINE_ASM_USES_INTRIN
2473 uDR3 = __readdr(3);
2474# elif RT_INLINE_ASM_GNU_STYLE
2475# ifdef RT_ARCH_AMD64
2476 __asm__ __volatile__("movq %%dr3, %0\n\t" : "=r" (uDR3));
2477# else
2478 __asm__ __volatile__("movl %%dr3, %0\n\t" : "=r" (uDR3));
2479# endif
2480# else
2481 __asm
2482 {
2483# ifdef RT_ARCH_AMD64
2484 mov rax, dr3
2485 mov [uDR3], rax
2486# else
2487 mov eax, dr3
2488 mov [uDR3], eax
2489# endif
2490 }
2491# endif
2492 return uDR3;
2493}
2494#endif
2495
2496
2497/**
2498 * Gets dr6.
2499 *
2500 * @returns dr6.
2501 */
2502#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2503RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR6(void);
2504#else
2505DECLINLINE(RTCCUINTXREG) ASMGetDR6(void)
2506{
2507 RTCCUINTXREG uDR6;
2508# if RT_INLINE_ASM_USES_INTRIN
2509 uDR6 = __readdr(6);
2510# elif RT_INLINE_ASM_GNU_STYLE
2511# ifdef RT_ARCH_AMD64
2512 __asm__ __volatile__("movq %%dr6, %0\n\t" : "=r" (uDR6));
2513# else
2514 __asm__ __volatile__("movl %%dr6, %0\n\t" : "=r" (uDR6));
2515# endif
2516# else
2517 __asm
2518 {
2519# ifdef RT_ARCH_AMD64
2520 mov rax, dr6
2521 mov [uDR6], rax
2522# else
2523 mov eax, dr6
2524 mov [uDR6], eax
2525# endif
2526 }
2527# endif
2528 return uDR6;
2529}
2530#endif
2531
2532
2533/**
2534 * Reads and clears DR6.
2535 *
2536 * @returns DR6.
2537 */
2538#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2539RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetAndClearDR6(void);
2540#else
2541DECLINLINE(RTCCUINTXREG) ASMGetAndClearDR6(void)
2542{
2543 RTCCUINTXREG uDR6;
2544# if RT_INLINE_ASM_USES_INTRIN
2545 uDR6 = __readdr(6);
2546 __writedr(6, 0xffff0ff0U); /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2547# elif RT_INLINE_ASM_GNU_STYLE
2548 RTCCUINTXREG uNewValue = 0xffff0ff0U;/* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2549# ifdef RT_ARCH_AMD64
2550 __asm__ __volatile__("movq %%dr6, %0\n\t"
2551 "movq %1, %%dr6\n\t"
2552 : "=r" (uDR6)
2553 : "r" (uNewValue));
2554# else
2555 __asm__ __volatile__("movl %%dr6, %0\n\t"
2556 "movl %1, %%dr6\n\t"
2557 : "=r" (uDR6)
2558 : "r" (uNewValue));
2559# endif
2560# else
2561 __asm
2562 {
2563# ifdef RT_ARCH_AMD64
2564 mov rax, dr6
2565 mov [uDR6], rax
2566 mov rcx, rax
2567 mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2568 mov dr6, rcx
2569# else
2570 mov eax, dr6
2571 mov [uDR6], eax
2572 mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 is zero. */
2573 mov dr6, ecx
2574# endif
2575 }
2576# endif
2577 return uDR6;
2578}
2579#endif
2580
2581
2582/**
2583 * Gets dr7.
2584 *
2585 * @returns dr7.
2586 */
2587#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2588RT_ASM_DECL_PRAGMA_WATCOM(RTCCUINTXREG) ASMGetDR7(void);
2589#else
2590DECLINLINE(RTCCUINTXREG) ASMGetDR7(void)
2591{
2592 RTCCUINTXREG uDR7;
2593# if RT_INLINE_ASM_USES_INTRIN
2594 uDR7 = __readdr(7);
2595# elif RT_INLINE_ASM_GNU_STYLE
2596# ifdef RT_ARCH_AMD64
2597 __asm__ __volatile__("movq %%dr7, %0\n\t" : "=r" (uDR7));
2598# else
2599 __asm__ __volatile__("movl %%dr7, %0\n\t" : "=r" (uDR7));
2600# endif
2601# else
2602 __asm
2603 {
2604# ifdef RT_ARCH_AMD64
2605 mov rax, dr7
2606 mov [uDR7], rax
2607# else
2608 mov eax, dr7
2609 mov [uDR7], eax
2610# endif
2611 }
2612# endif
2613 return uDR7;
2614}
2615#endif
2616
2617
2618/**
2619 * Sets dr0.
2620 *
2621 * @param uDRVal Debug register value to write
2622 */
2623#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2624RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR0(RTCCUINTXREG uDRVal);
2625#else
2626DECLINLINE(void) ASMSetDR0(RTCCUINTXREG uDRVal)
2627{
2628# if RT_INLINE_ASM_USES_INTRIN
2629 __writedr(0, uDRVal);
2630# elif RT_INLINE_ASM_GNU_STYLE
2631# ifdef RT_ARCH_AMD64
2632 __asm__ __volatile__("movq %0, %%dr0\n\t" : : "r" (uDRVal));
2633# else
2634 __asm__ __volatile__("movl %0, %%dr0\n\t" : : "r" (uDRVal));
2635# endif
2636# else
2637 __asm
2638 {
2639# ifdef RT_ARCH_AMD64
2640 mov rax, [uDRVal]
2641 mov dr0, rax
2642# else
2643 mov eax, [uDRVal]
2644 mov dr0, eax
2645# endif
2646 }
2647# endif
2648}
2649#endif
2650
2651
2652/**
2653 * Sets dr1.
2654 *
2655 * @param uDRVal Debug register value to write
2656 */
2657#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2658RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR1(RTCCUINTXREG uDRVal);
2659#else
2660DECLINLINE(void) ASMSetDR1(RTCCUINTXREG uDRVal)
2661{
2662# if RT_INLINE_ASM_USES_INTRIN
2663 __writedr(1, uDRVal);
2664# elif RT_INLINE_ASM_GNU_STYLE
2665# ifdef RT_ARCH_AMD64
2666 __asm__ __volatile__("movq %0, %%dr1\n\t" : : "r" (uDRVal));
2667# else
2668 __asm__ __volatile__("movl %0, %%dr1\n\t" : : "r" (uDRVal));
2669# endif
2670# else
2671 __asm
2672 {
2673# ifdef RT_ARCH_AMD64
2674 mov rax, [uDRVal]
2675 mov dr1, rax
2676# else
2677 mov eax, [uDRVal]
2678 mov dr1, eax
2679# endif
2680 }
2681# endif
2682}
2683#endif
2684
2685
2686/**
2687 * Sets dr2.
2688 *
2689 * @param uDRVal Debug register value to write
2690 */
2691#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2692RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR2(RTCCUINTXREG uDRVal);
2693#else
2694DECLINLINE(void) ASMSetDR2(RTCCUINTXREG uDRVal)
2695{
2696# if RT_INLINE_ASM_USES_INTRIN
2697 __writedr(2, uDRVal);
2698# elif RT_INLINE_ASM_GNU_STYLE
2699# ifdef RT_ARCH_AMD64
2700 __asm__ __volatile__("movq %0, %%dr2\n\t" : : "r" (uDRVal));
2701# else
2702 __asm__ __volatile__("movl %0, %%dr2\n\t" : : "r" (uDRVal));
2703# endif
2704# else
2705 __asm
2706 {
2707# ifdef RT_ARCH_AMD64
2708 mov rax, [uDRVal]
2709 mov dr2, rax
2710# else
2711 mov eax, [uDRVal]
2712 mov dr2, eax
2713# endif
2714 }
2715# endif
2716}
2717#endif
2718
2719
2720/**
2721 * Sets dr3.
2722 *
2723 * @param uDRVal Debug register value to write
2724 */
2725#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2726RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR3(RTCCUINTXREG uDRVal);
2727#else
2728DECLINLINE(void) ASMSetDR3(RTCCUINTXREG uDRVal)
2729{
2730# if RT_INLINE_ASM_USES_INTRIN
2731 __writedr(3, uDRVal);
2732# elif RT_INLINE_ASM_GNU_STYLE
2733# ifdef RT_ARCH_AMD64
2734 __asm__ __volatile__("movq %0, %%dr3\n\t" : : "r" (uDRVal));
2735# else
2736 __asm__ __volatile__("movl %0, %%dr3\n\t" : : "r" (uDRVal));
2737# endif
2738# else
2739 __asm
2740 {
2741# ifdef RT_ARCH_AMD64
2742 mov rax, [uDRVal]
2743 mov dr3, rax
2744# else
2745 mov eax, [uDRVal]
2746 mov dr3, eax
2747# endif
2748 }
2749# endif
2750}
2751#endif
2752
2753
2754/**
2755 * Sets dr6.
2756 *
2757 * @param uDRVal Debug register value to write
2758 */
2759#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2760RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR6(RTCCUINTXREG uDRVal);
2761#else
2762DECLINLINE(void) ASMSetDR6(RTCCUINTXREG uDRVal)
2763{
2764# if RT_INLINE_ASM_USES_INTRIN
2765 __writedr(6, uDRVal);
2766# elif RT_INLINE_ASM_GNU_STYLE
2767# ifdef RT_ARCH_AMD64
2768 __asm__ __volatile__("movq %0, %%dr6\n\t" : : "r" (uDRVal));
2769# else
2770 __asm__ __volatile__("movl %0, %%dr6\n\t" : : "r" (uDRVal));
2771# endif
2772# else
2773 __asm
2774 {
2775# ifdef RT_ARCH_AMD64
2776 mov rax, [uDRVal]
2777 mov dr6, rax
2778# else
2779 mov eax, [uDRVal]
2780 mov dr6, eax
2781# endif
2782 }
2783# endif
2784}
2785#endif
2786
2787
2788/**
2789 * Sets dr7.
2790 *
2791 * @param uDRVal Debug register value to write
2792 */
2793#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2794RT_ASM_DECL_PRAGMA_WATCOM(void) ASMSetDR7(RTCCUINTXREG uDRVal);
2795#else
2796DECLINLINE(void) ASMSetDR7(RTCCUINTXREG uDRVal)
2797{
2798# if RT_INLINE_ASM_USES_INTRIN
2799 __writedr(7, uDRVal);
2800# elif RT_INLINE_ASM_GNU_STYLE
2801# ifdef RT_ARCH_AMD64
2802 __asm__ __volatile__("movq %0, %%dr7\n\t" : : "r" (uDRVal));
2803# else
2804 __asm__ __volatile__("movl %0, %%dr7\n\t" : : "r" (uDRVal));
2805# endif
2806# else
2807 __asm
2808 {
2809# ifdef RT_ARCH_AMD64
2810 mov rax, [uDRVal]
2811 mov dr7, rax
2812# else
2813 mov eax, [uDRVal]
2814 mov dr7, eax
2815# endif
2816 }
2817# endif
2818}
2819#endif
2820
2821
2822/**
2823 * Writes a 8-bit unsigned integer to an I/O port, ordered.
2824 *
2825 * @param Port I/O port to write to.
2826 * @param u8 8-bit integer to write.
2827 */
2828#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2829RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU8(RTIOPORT Port, uint8_t u8);
2830#else
2831DECLINLINE(void) ASMOutU8(RTIOPORT Port, uint8_t u8)
2832{
2833# if RT_INLINE_ASM_GNU_STYLE
2834 __asm__ __volatile__("outb %b1, %w0\n\t"
2835 :: "Nd" (Port),
2836 "a" (u8));
2837
2838# elif RT_INLINE_ASM_USES_INTRIN
2839 __outbyte(Port, u8);
2840
2841# else
2842 __asm
2843 {
2844 mov dx, [Port]
2845 mov al, [u8]
2846 out dx, al
2847 }
2848# endif
2849}
2850#endif
2851
2852
2853/**
2854 * Reads a 8-bit unsigned integer from an I/O port, ordered.
2855 *
2856 * @returns 8-bit integer.
2857 * @param Port I/O port to read from.
2858 */
2859#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2860RT_ASM_DECL_PRAGMA_WATCOM(uint8_t) ASMInU8(RTIOPORT Port);
2861#else
2862DECLINLINE(uint8_t) ASMInU8(RTIOPORT Port)
2863{
2864 uint8_t u8;
2865# if RT_INLINE_ASM_GNU_STYLE
2866 __asm__ __volatile__("inb %w1, %b0\n\t"
2867 : "=a" (u8)
2868 : "Nd" (Port));
2869
2870# elif RT_INLINE_ASM_USES_INTRIN
2871 u8 = __inbyte(Port);
2872
2873# else
2874 __asm
2875 {
2876 mov dx, [Port]
2877 in al, dx
2878 mov [u8], al
2879 }
2880# endif
2881 return u8;
2882}
2883#endif
2884
2885
2886/**
2887 * Writes a 16-bit unsigned integer to an I/O port, ordered.
2888 *
2889 * @param Port I/O port to write to.
2890 * @param u16 16-bit integer to write.
2891 */
2892#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2893RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU16(RTIOPORT Port, uint16_t u16);
2894#else
2895DECLINLINE(void) ASMOutU16(RTIOPORT Port, uint16_t u16)
2896{
2897# if RT_INLINE_ASM_GNU_STYLE
2898 __asm__ __volatile__("outw %w1, %w0\n\t"
2899 :: "Nd" (Port),
2900 "a" (u16));
2901
2902# elif RT_INLINE_ASM_USES_INTRIN
2903 __outword(Port, u16);
2904
2905# else
2906 __asm
2907 {
2908 mov dx, [Port]
2909 mov ax, [u16]
2910 out dx, ax
2911 }
2912# endif
2913}
2914#endif
2915
2916
2917/**
2918 * Reads a 16-bit unsigned integer from an I/O port, ordered.
2919 *
2920 * @returns 16-bit integer.
2921 * @param Port I/O port to read from.
2922 */
2923#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2924RT_ASM_DECL_PRAGMA_WATCOM(uint16_t) ASMInU16(RTIOPORT Port);
2925#else
2926DECLINLINE(uint16_t) ASMInU16(RTIOPORT Port)
2927{
2928 uint16_t u16;
2929# if RT_INLINE_ASM_GNU_STYLE
2930 __asm__ __volatile__("inw %w1, %w0\n\t"
2931 : "=a" (u16)
2932 : "Nd" (Port));
2933
2934# elif RT_INLINE_ASM_USES_INTRIN
2935 u16 = __inword(Port);
2936
2937# else
2938 __asm
2939 {
2940 mov dx, [Port]
2941 in ax, dx
2942 mov [u16], ax
2943 }
2944# endif
2945 return u16;
2946}
2947#endif
2948
2949
2950/**
2951 * Writes a 32-bit unsigned integer to an I/O port, ordered.
2952 *
2953 * @param Port I/O port to write to.
2954 * @param u32 32-bit integer to write.
2955 */
2956#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2957RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutU32(RTIOPORT Port, uint32_t u32);
2958#else
2959DECLINLINE(void) ASMOutU32(RTIOPORT Port, uint32_t u32)
2960{
2961# if RT_INLINE_ASM_GNU_STYLE
2962 __asm__ __volatile__("outl %1, %w0\n\t"
2963 :: "Nd" (Port),
2964 "a" (u32));
2965
2966# elif RT_INLINE_ASM_USES_INTRIN
2967 __outdword(Port, u32);
2968
2969# else
2970 __asm
2971 {
2972 mov dx, [Port]
2973 mov eax, [u32]
2974 out dx, eax
2975 }
2976# endif
2977}
2978#endif
2979
2980
2981/**
2982 * Reads a 32-bit unsigned integer from an I/O port, ordered.
2983 *
2984 * @returns 32-bit integer.
2985 * @param Port I/O port to read from.
2986 */
2987#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2988RT_ASM_DECL_PRAGMA_WATCOM(uint32_t) ASMInU32(RTIOPORT Port);
2989#else
2990DECLINLINE(uint32_t) ASMInU32(RTIOPORT Port)
2991{
2992 uint32_t u32;
2993# if RT_INLINE_ASM_GNU_STYLE
2994 __asm__ __volatile__("inl %w1, %0\n\t"
2995 : "=a" (u32)
2996 : "Nd" (Port));
2997
2998# elif RT_INLINE_ASM_USES_INTRIN
2999 u32 = __indword(Port);
3000
3001# else
3002 __asm
3003 {
3004 mov dx, [Port]
3005 in eax, dx
3006 mov [u32], eax
3007 }
3008# endif
3009 return u32;
3010}
3011#endif
3012
3013
3014/**
3015 * Writes a string of 8-bit unsigned integer items to an I/O port, ordered.
3016 *
3017 * @param Port I/O port to write to.
3018 * @param pau8 Pointer to the string buffer.
3019 * @param c The number of items to write.
3020 */
3021#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3022RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c);
3023#else
3024DECLINLINE(void) ASMOutStrU8(RTIOPORT Port, uint8_t const RT_FAR *pau8, size_t c)
3025{
3026# if RT_INLINE_ASM_GNU_STYLE
3027 __asm__ __volatile__("rep; outsb\n\t"
3028 : "+S" (pau8),
3029 "+c" (c)
3030 : "d" (Port));
3031
3032# elif RT_INLINE_ASM_USES_INTRIN
3033 __outbytestring(Port, (unsigned char RT_FAR *)pau8, (unsigned long)c);
3034
3035# else
3036 __asm
3037 {
3038 mov dx, [Port]
3039 mov ecx, [c]
3040 mov eax, [pau8]
3041 xchg esi, eax
3042 rep outsb
3043 xchg esi, eax
3044 }
3045# endif
3046}
3047#endif
3048
3049
3050/**
3051 * Reads a string of 8-bit unsigned integer items from an I/O port, ordered.
3052 *
3053 * @param Port I/O port to read from.
3054 * @param pau8 Pointer to the string buffer (output).
3055 * @param c The number of items to read.
3056 */
3057#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3058RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c);
3059#else
3060DECLINLINE(void) ASMInStrU8(RTIOPORT Port, uint8_t RT_FAR *pau8, size_t c)
3061{
3062# if RT_INLINE_ASM_GNU_STYLE
3063 __asm__ __volatile__("rep; insb\n\t"
3064 : "+D" (pau8),
3065 "+c" (c)
3066 : "d" (Port));
3067
3068# elif RT_INLINE_ASM_USES_INTRIN
3069 __inbytestring(Port, pau8, (unsigned long)c);
3070
3071# else
3072 __asm
3073 {
3074 mov dx, [Port]
3075 mov ecx, [c]
3076 mov eax, [pau8]
3077 xchg edi, eax
3078 rep insb
3079 xchg edi, eax
3080 }
3081# endif
3082}
3083#endif
3084
3085
3086/**
3087 * Writes a string of 16-bit unsigned integer items to an I/O port, ordered.
3088 *
3089 * @param Port I/O port to write to.
3090 * @param pau16 Pointer to the string buffer.
3091 * @param c The number of items to write.
3092 */
3093#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3094RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c);
3095#else
3096DECLINLINE(void) ASMOutStrU16(RTIOPORT Port, uint16_t const RT_FAR *pau16, size_t c)
3097{
3098# if RT_INLINE_ASM_GNU_STYLE
3099 __asm__ __volatile__("rep; outsw\n\t"
3100 : "+S" (pau16),
3101 "+c" (c)
3102 : "d" (Port));
3103
3104# elif RT_INLINE_ASM_USES_INTRIN
3105 __outwordstring(Port, (unsigned short RT_FAR *)pau16, (unsigned long)c);
3106
3107# else
3108 __asm
3109 {
3110 mov dx, [Port]
3111 mov ecx, [c]
3112 mov eax, [pau16]
3113 xchg esi, eax
3114 rep outsw
3115 xchg esi, eax
3116 }
3117# endif
3118}
3119#endif
3120
3121
3122/**
3123 * Reads a string of 16-bit unsigned integer items from an I/O port, ordered.
3124 *
3125 * @param Port I/O port to read from.
3126 * @param pau16 Pointer to the string buffer (output).
3127 * @param c The number of items to read.
3128 */
3129#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3130RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c);
3131#else
3132DECLINLINE(void) ASMInStrU16(RTIOPORT Port, uint16_t RT_FAR *pau16, size_t c)
3133{
3134# if RT_INLINE_ASM_GNU_STYLE
3135 __asm__ __volatile__("rep; insw\n\t"
3136 : "+D" (pau16),
3137 "+c" (c)
3138 : "d" (Port));
3139
3140# elif RT_INLINE_ASM_USES_INTRIN
3141 __inwordstring(Port, pau16, (unsigned long)c);
3142
3143# else
3144 __asm
3145 {
3146 mov dx, [Port]
3147 mov ecx, [c]
3148 mov eax, [pau16]
3149 xchg edi, eax
3150 rep insw
3151 xchg edi, eax
3152 }
3153# endif
3154}
3155#endif
3156
3157
3158/**
3159 * Writes a string of 32-bit unsigned integer items to an I/O port, ordered.
3160 *
3161 * @param Port I/O port to write to.
3162 * @param pau32 Pointer to the string buffer.
3163 * @param c The number of items to write.
3164 */
3165#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3166RT_ASM_DECL_PRAGMA_WATCOM(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c);
3167#else
3168DECLINLINE(void) ASMOutStrU32(RTIOPORT Port, uint32_t const RT_FAR *pau32, size_t c)
3169{
3170# if RT_INLINE_ASM_GNU_STYLE
3171 __asm__ __volatile__("rep; outsl\n\t"
3172 : "+S" (pau32),
3173 "+c" (c)
3174 : "d" (Port));
3175
3176# elif RT_INLINE_ASM_USES_INTRIN
3177 __outdwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c);
3178
3179# else
3180 __asm
3181 {
3182 mov dx, [Port]
3183 mov ecx, [c]
3184 mov eax, [pau32]
3185 xchg esi, eax
3186 rep outsd
3187 xchg esi, eax
3188 }
3189# endif
3190}
3191#endif
3192
3193
3194/**
3195 * Reads a string of 32-bit unsigned integer items from an I/O port, ordered.
3196 *
3197 * @param Port I/O port to read from.
3198 * @param pau32 Pointer to the string buffer (output).
3199 * @param c The number of items to read.
3200 */
3201#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3202RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c);
3203#else
3204DECLINLINE(void) ASMInStrU32(RTIOPORT Port, uint32_t RT_FAR *pau32, size_t c)
3205{
3206# if RT_INLINE_ASM_GNU_STYLE
3207 __asm__ __volatile__("rep; insl\n\t"
3208 : "+D" (pau32),
3209 "+c" (c)
3210 : "d" (Port));
3211
3212# elif RT_INLINE_ASM_USES_INTRIN
3213 __indwordstring(Port, (unsigned long RT_FAR *)pau32, (unsigned long)c);
3214
3215# else
3216 __asm
3217 {
3218 mov dx, [Port]
3219 mov ecx, [c]
3220 mov eax, [pau32]
3221 xchg edi, eax
3222 rep insd
3223 xchg edi, eax
3224 }
3225# endif
3226}
3227#endif
3228
3229
3230/**
3231 * Invalidate page.
3232 *
3233 * @param uPtr Address of the page to invalidate.
3234 */
3235#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3236RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidatePage(RTCCUINTXREG uPtr);
3237#else
3238DECLINLINE(void) ASMInvalidatePage(RTCCUINTXREG uPtr)
3239{
3240# if RT_INLINE_ASM_USES_INTRIN
3241 __invlpg((void RT_FAR *)uPtr);
3242
3243# elif RT_INLINE_ASM_GNU_STYLE
3244 __asm__ __volatile__("invlpg %0\n\t"
3245 : : "m" (*(uint8_t RT_FAR *)(uintptr_t)uPtr));
3246# else
3247 __asm
3248 {
3249# ifdef RT_ARCH_AMD64
3250 mov rax, [uPtr]
3251 invlpg [rax]
3252# else
3253 mov eax, [uPtr]
3254 invlpg [eax]
3255# endif
3256 }
3257# endif
3258}
3259#endif
3260
3261
3262/**
3263 * Write back the internal caches and invalidate them.
3264 */
3265#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
3266RT_ASM_DECL_PRAGMA_WATCOM(void) ASMWriteBackAndInvalidateCaches(void);
3267#else
3268DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void)
3269{
3270# if RT_INLINE_ASM_USES_INTRIN
3271 __wbinvd();
3272
3273# elif RT_INLINE_ASM_GNU_STYLE
3274 __asm__ __volatile__("wbinvd");
3275# else
3276 __asm
3277 {
3278 wbinvd
3279 }
3280# endif
3281}
3282#endif
3283
3284
3285/**
3286 * Invalidate internal and (perhaps) external caches without first
3287 * flushing dirty cache lines. Use with extreme care.
3288 */
3289#if RT_INLINE_ASM_EXTERNAL
3290RT_ASM_DECL_PRAGMA_WATCOM(void) ASMInvalidateInternalCaches(void);
3291#else
3292DECLINLINE(void) ASMInvalidateInternalCaches(void)
3293{
3294# if RT_INLINE_ASM_GNU_STYLE
3295 __asm__ __volatile__("invd");
3296# else
3297 __asm
3298 {
3299 invd
3300 }
3301# endif
3302}
3303#endif
3304
3305
3306/**
3307 * Memory load/store fence, waits for any pending writes and reads to complete.
3308 * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set.
3309 */
3310DECLINLINE(void) ASMMemoryFenceSSE2(void)
3311{
3312#if RT_INLINE_ASM_GNU_STYLE
3313 __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t");
3314#elif RT_INLINE_ASM_USES_INTRIN
3315 _mm_mfence();
3316#else
3317 __asm
3318 {
3319 _emit 0x0f
3320 _emit 0xae
3321 _emit 0xf0
3322 }
3323#endif
3324}
3325
3326
3327/**
3328 * Memory store fence, waits for any writes to complete.
3329 * Requires the X86_CPUID_FEATURE_EDX_SSE CPUID bit set.
3330 */
3331DECLINLINE(void) ASMWriteFenceSSE(void)
3332{
3333#if RT_INLINE_ASM_GNU_STYLE
3334 __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t");
3335#elif RT_INLINE_ASM_USES_INTRIN
3336 _mm_sfence();
3337#else
3338 __asm
3339 {
3340 _emit 0x0f
3341 _emit 0xae
3342 _emit 0xf8
3343 }
3344#endif
3345}
3346
3347
3348/**
3349 * Memory load fence, waits for any pending reads to complete.
3350 * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set.
3351 */
3352DECLINLINE(void) ASMReadFenceSSE2(void)
3353{
3354#if RT_INLINE_ASM_GNU_STYLE
3355 __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t");
3356#elif RT_INLINE_ASM_USES_INTRIN
3357 _mm_lfence();
3358#else
3359 __asm
3360 {
3361 _emit 0x0f
3362 _emit 0xae
3363 _emit 0xe8
3364 }
3365#endif
3366}
3367
3368#if !defined(_MSC_VER) || !defined(RT_ARCH_AMD64)
3369
3370/*
3371 * Clear the AC bit in the EFLAGS register.
3372 * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set.
3373 * Requires to be executed in R0.
3374 */
3375DECLINLINE(void) ASMClearAC(void)
3376{
3377#if RT_INLINE_ASM_GNU_STYLE
3378 __asm__ __volatile__ (".byte 0x0f,0x01,0xca\n\t");
3379#else
3380 __asm
3381 {
3382 _emit 0x0f
3383 _emit 0x01
3384 _emit 0xca
3385 }
3386#endif
3387}
3388
3389
3390/*
3391 * Set the AC bit in the EFLAGS register.
3392 * Requires the X86_CPUID_STEXT_FEATURE_EBX_SMAP CPUID bit set.
3393 * Requires to be executed in R0.
3394 */
3395DECLINLINE(void) ASMSetAC(void)
3396{
3397#if RT_INLINE_ASM_GNU_STYLE
3398 __asm__ __volatile__ (".byte 0x0f,0x01,0xcb\n\t");
3399#else
3400 __asm
3401 {
3402 _emit 0x0f
3403 _emit 0x01
3404 _emit 0xcb
3405 }
3406#endif
3407}
3408
3409#endif /* !_MSC_VER || !RT_ARCH_AMD64 */
3410
3411
3412/*
3413 * Include #pragma aux definitions for Watcom C/C++.
3414 */
3415#if defined(__WATCOMC__) && ARCH_BITS == 16
3416# define IPRT_ASM_AMD64_X86_WATCOM_16_INSTANTIATE
3417# undef IPRT_INCLUDED_asm_amd64_x86_watcom_16_h
3418# include "asm-amd64-x86-watcom-16.h"
3419#elif defined(__WATCOMC__) && ARCH_BITS == 32
3420# define IPRT_ASM_AMD64_X86_WATCOM_32_INSTANTIATE
3421# undef IPRT_INCLUDED_asm_amd64_x86_watcom_32_h
3422# include "asm-amd64-x86-watcom-32.h"
3423#endif
3424
3425
3426/** @} */
3427#endif /* !IPRT_INCLUDED_asm_amd64_x86_h */
3428
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