VirtualBox

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

Last change on this file since 54924 was 54260, checked in by vboxsync, 10 years ago

iprt/asm-amd64-x86.h: Build fix for linux.x86 VM used to build the validation kit.

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