VirtualBox

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

最後變更 在這個檔案從81605是 81605,由 vboxsync 提交於 5 年 前

VMM (and related changes): Add support for Hygon Dhyana CPUs. Modified and improved contribution by Hongyong Zang submitted under MIT license. Thank you!

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

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