VirtualBox

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

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

asm-amd64-x86.h: Added ASMGetXcr0 & ASMSetXcr0.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.8 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 * Get XCR0 (eXtended feature Control Register 0).
1730 * @returns xcr0.
1731 */
1732DECLASM(uint64_t) ASMGetXcr0(void);
1733
1734
1735/**
1736 * Sets the XCR0 register.
1737 * @param uXcr0 The new XCR0 value.
1738 */
1739DECLASM(void) ASMSetXcr0(uint64_t uXcr0);
1740
1741
1742/**
1743 * Enables interrupts (EFLAGS.IF).
1744 */
1745#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1746DECLASM(void) ASMIntEnable(void);
1747#else
1748DECLINLINE(void) ASMIntEnable(void)
1749{
1750# if RT_INLINE_ASM_GNU_STYLE
1751 __asm("sti\n");
1752# elif RT_INLINE_ASM_USES_INTRIN
1753 _enable();
1754# else
1755 __asm sti
1756# endif
1757}
1758#endif
1759
1760
1761/**
1762 * Disables interrupts (!EFLAGS.IF).
1763 */
1764#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1765DECLASM(void) ASMIntDisable(void);
1766#else
1767DECLINLINE(void) ASMIntDisable(void)
1768{
1769# if RT_INLINE_ASM_GNU_STYLE
1770 __asm("cli\n");
1771# elif RT_INLINE_ASM_USES_INTRIN
1772 _disable();
1773# else
1774 __asm cli
1775# endif
1776}
1777#endif
1778
1779
1780/**
1781 * Disables interrupts and returns previous xFLAGS.
1782 */
1783#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1784DECLASM(RTCCUINTREG) ASMIntDisableFlags(void);
1785#else
1786DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void)
1787{
1788 RTCCUINTREG xFlags;
1789# if RT_INLINE_ASM_GNU_STYLE
1790# ifdef RT_ARCH_AMD64
1791 __asm__ __volatile__("pushfq\n\t"
1792 "cli\n\t"
1793 "popq %0\n\t"
1794 : "=r" (xFlags));
1795# else
1796 __asm__ __volatile__("pushfl\n\t"
1797 "cli\n\t"
1798 "popl %0\n\t"
1799 : "=r" (xFlags));
1800# endif
1801# elif RT_INLINE_ASM_USES_INTRIN && !defined(RT_ARCH_X86)
1802 xFlags = ASMGetFlags();
1803 _disable();
1804# else
1805 __asm {
1806 pushfd
1807 cli
1808 pop [xFlags]
1809 }
1810# endif
1811 return xFlags;
1812}
1813#endif
1814
1815
1816/**
1817 * Are interrupts enabled?
1818 *
1819 * @returns true / false.
1820 */
1821DECLINLINE(bool) ASMIntAreEnabled(void)
1822{
1823 RTCCUINTREG uFlags = ASMGetFlags();
1824 return uFlags & 0x200 /* X86_EFL_IF */ ? true : false;
1825}
1826
1827
1828/**
1829 * Halts the CPU until interrupted.
1830 */
1831#if RT_INLINE_ASM_EXTERNAL
1832DECLASM(void) ASMHalt(void);
1833#else
1834DECLINLINE(void) ASMHalt(void)
1835{
1836# if RT_INLINE_ASM_GNU_STYLE
1837 __asm__ __volatile__("hlt\n\t");
1838# else
1839 __asm {
1840 hlt
1841 }
1842# endif
1843}
1844#endif
1845
1846
1847/**
1848 * Reads a machine specific register.
1849 *
1850 * @returns Register content.
1851 * @param uRegister Register to read.
1852 */
1853#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1854DECLASM(uint64_t) ASMRdMsr(uint32_t uRegister);
1855#else
1856DECLINLINE(uint64_t) ASMRdMsr(uint32_t uRegister)
1857{
1858 RTUINT64U u;
1859# if RT_INLINE_ASM_GNU_STYLE
1860 __asm__ __volatile__("rdmsr\n\t"
1861 : "=a" (u.s.Lo),
1862 "=d" (u.s.Hi)
1863 : "c" (uRegister));
1864
1865# elif RT_INLINE_ASM_USES_INTRIN
1866 u.u = __readmsr(uRegister);
1867
1868# else
1869 __asm
1870 {
1871 mov ecx, [uRegister]
1872 rdmsr
1873 mov [u.s.Lo], eax
1874 mov [u.s.Hi], edx
1875 }
1876# endif
1877
1878 return u.u;
1879}
1880#endif
1881
1882
1883/**
1884 * Writes a machine specific register.
1885 *
1886 * @returns Register content.
1887 * @param uRegister Register to write to.
1888 * @param u64Val Value to write.
1889 */
1890#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
1891DECLASM(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val);
1892#else
1893DECLINLINE(void) ASMWrMsr(uint32_t uRegister, uint64_t u64Val)
1894{
1895 RTUINT64U u;
1896
1897 u.u = u64Val;
1898# if RT_INLINE_ASM_GNU_STYLE
1899 __asm__ __volatile__("wrmsr\n\t"
1900 ::"a" (u.s.Lo),
1901 "d" (u.s.Hi),
1902 "c" (uRegister));
1903
1904# elif RT_INLINE_ASM_USES_INTRIN
1905 __writemsr(uRegister, u.u);
1906
1907# else
1908 __asm
1909 {
1910 mov ecx, [uRegister]
1911 mov edx, [u.s.Hi]
1912 mov eax, [u.s.Lo]
1913 wrmsr
1914 }
1915# endif
1916}
1917#endif
1918
1919
1920/**
1921 * Reads a machine specific register, extended version (for AMD).
1922 *
1923 * @returns Register content.
1924 * @param uRegister Register to read.
1925 * @param uXDI RDI/EDI value.
1926 */
1927#if RT_INLINE_ASM_EXTERNAL
1928DECLASM(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTREG uXDI);
1929#else
1930DECLINLINE(uint64_t) ASMRdMsrEx(uint32_t uRegister, RTCCUINTREG uXDI)
1931{
1932 RTUINT64U u;
1933# if RT_INLINE_ASM_GNU_STYLE
1934 __asm__ __volatile__("rdmsr\n\t"
1935 : "=a" (u.s.Lo),
1936 "=d" (u.s.Hi)
1937 : "c" (uRegister),
1938 "D" (uXDI));
1939
1940# else
1941 __asm
1942 {
1943 mov ecx, [uRegister]
1944 xchg edi, [uXDI]
1945 rdmsr
1946 mov [u.s.Lo], eax
1947 mov [u.s.Hi], edx
1948 xchg edi, [uXDI]
1949 }
1950# endif
1951
1952 return u.u;
1953}
1954#endif
1955
1956
1957/**
1958 * Writes a machine specific register, extended version (for AMD).
1959 *
1960 * @returns Register content.
1961 * @param uRegister Register to write to.
1962 * @param uXDI RDI/EDI value.
1963 * @param u64Val Value to write.
1964 */
1965#if RT_INLINE_ASM_EXTERNAL
1966DECLASM(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTREG uXDI, uint64_t u64Val);
1967#else
1968DECLINLINE(void) ASMWrMsrEx(uint32_t uRegister, RTCCUINTREG uXDI, uint64_t u64Val)
1969{
1970 RTUINT64U u;
1971
1972 u.u = u64Val;
1973# if RT_INLINE_ASM_GNU_STYLE
1974 __asm__ __volatile__("wrmsr\n\t"
1975 ::"a" (u.s.Lo),
1976 "d" (u.s.Hi),
1977 "c" (uRegister),
1978 "D" (uXDI));
1979
1980# else
1981 __asm
1982 {
1983 mov ecx, [uRegister]
1984 xchg edi, [uXDI]
1985 mov edx, [u.s.Hi]
1986 mov eax, [u.s.Lo]
1987 wrmsr
1988 xchg edi, [uXDI]
1989 }
1990# endif
1991}
1992#endif
1993
1994
1995
1996/**
1997 * Reads low part of a machine specific register.
1998 *
1999 * @returns Register content.
2000 * @param uRegister Register to read.
2001 */
2002#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2003DECLASM(uint32_t) ASMRdMsr_Low(uint32_t uRegister);
2004#else
2005DECLINLINE(uint32_t) ASMRdMsr_Low(uint32_t uRegister)
2006{
2007 uint32_t u32;
2008# if RT_INLINE_ASM_GNU_STYLE
2009 __asm__ __volatile__("rdmsr\n\t"
2010 : "=a" (u32)
2011 : "c" (uRegister)
2012 : "edx");
2013
2014# elif RT_INLINE_ASM_USES_INTRIN
2015 u32 = (uint32_t)__readmsr(uRegister);
2016
2017#else
2018 __asm
2019 {
2020 mov ecx, [uRegister]
2021 rdmsr
2022 mov [u32], eax
2023 }
2024# endif
2025
2026 return u32;
2027}
2028#endif
2029
2030
2031/**
2032 * Reads high part of a machine specific register.
2033 *
2034 * @returns Register content.
2035 * @param uRegister Register to read.
2036 */
2037#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2038DECLASM(uint32_t) ASMRdMsr_High(uint32_t uRegister);
2039#else
2040DECLINLINE(uint32_t) ASMRdMsr_High(uint32_t uRegister)
2041{
2042 uint32_t u32;
2043# if RT_INLINE_ASM_GNU_STYLE
2044 __asm__ __volatile__("rdmsr\n\t"
2045 : "=d" (u32)
2046 : "c" (uRegister)
2047 : "eax");
2048
2049# elif RT_INLINE_ASM_USES_INTRIN
2050 u32 = (uint32_t)(__readmsr(uRegister) >> 32);
2051
2052# else
2053 __asm
2054 {
2055 mov ecx, [uRegister]
2056 rdmsr
2057 mov [u32], edx
2058 }
2059# endif
2060
2061 return u32;
2062}
2063#endif
2064
2065
2066/**
2067 * Gets dr0.
2068 *
2069 * @returns dr0.
2070 */
2071#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2072DECLASM(RTCCUINTREG) ASMGetDR0(void);
2073#else
2074DECLINLINE(RTCCUINTREG) ASMGetDR0(void)
2075{
2076 RTCCUINTREG uDR0;
2077# if RT_INLINE_ASM_USES_INTRIN
2078 uDR0 = __readdr(0);
2079# elif RT_INLINE_ASM_GNU_STYLE
2080# ifdef RT_ARCH_AMD64
2081 __asm__ __volatile__("movq %%dr0, %0\n\t" : "=r" (uDR0));
2082# else
2083 __asm__ __volatile__("movl %%dr0, %0\n\t" : "=r" (uDR0));
2084# endif
2085# else
2086 __asm
2087 {
2088# ifdef RT_ARCH_AMD64
2089 mov rax, dr0
2090 mov [uDR0], rax
2091# else
2092 mov eax, dr0
2093 mov [uDR0], eax
2094# endif
2095 }
2096# endif
2097 return uDR0;
2098}
2099#endif
2100
2101
2102/**
2103 * Gets dr1.
2104 *
2105 * @returns dr1.
2106 */
2107#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2108DECLASM(RTCCUINTREG) ASMGetDR1(void);
2109#else
2110DECLINLINE(RTCCUINTREG) ASMGetDR1(void)
2111{
2112 RTCCUINTREG uDR1;
2113# if RT_INLINE_ASM_USES_INTRIN
2114 uDR1 = __readdr(1);
2115# elif RT_INLINE_ASM_GNU_STYLE
2116# ifdef RT_ARCH_AMD64
2117 __asm__ __volatile__("movq %%dr1, %0\n\t" : "=r" (uDR1));
2118# else
2119 __asm__ __volatile__("movl %%dr1, %0\n\t" : "=r" (uDR1));
2120# endif
2121# else
2122 __asm
2123 {
2124# ifdef RT_ARCH_AMD64
2125 mov rax, dr1
2126 mov [uDR1], rax
2127# else
2128 mov eax, dr1
2129 mov [uDR1], eax
2130# endif
2131 }
2132# endif
2133 return uDR1;
2134}
2135#endif
2136
2137
2138/**
2139 * Gets dr2.
2140 *
2141 * @returns dr2.
2142 */
2143#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2144DECLASM(RTCCUINTREG) ASMGetDR2(void);
2145#else
2146DECLINLINE(RTCCUINTREG) ASMGetDR2(void)
2147{
2148 RTCCUINTREG uDR2;
2149# if RT_INLINE_ASM_USES_INTRIN
2150 uDR2 = __readdr(2);
2151# elif RT_INLINE_ASM_GNU_STYLE
2152# ifdef RT_ARCH_AMD64
2153 __asm__ __volatile__("movq %%dr2, %0\n\t" : "=r" (uDR2));
2154# else
2155 __asm__ __volatile__("movl %%dr2, %0\n\t" : "=r" (uDR2));
2156# endif
2157# else
2158 __asm
2159 {
2160# ifdef RT_ARCH_AMD64
2161 mov rax, dr2
2162 mov [uDR2], rax
2163# else
2164 mov eax, dr2
2165 mov [uDR2], eax
2166# endif
2167 }
2168# endif
2169 return uDR2;
2170}
2171#endif
2172
2173
2174/**
2175 * Gets dr3.
2176 *
2177 * @returns dr3.
2178 */
2179#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2180DECLASM(RTCCUINTREG) ASMGetDR3(void);
2181#else
2182DECLINLINE(RTCCUINTREG) ASMGetDR3(void)
2183{
2184 RTCCUINTREG uDR3;
2185# if RT_INLINE_ASM_USES_INTRIN
2186 uDR3 = __readdr(3);
2187# elif RT_INLINE_ASM_GNU_STYLE
2188# ifdef RT_ARCH_AMD64
2189 __asm__ __volatile__("movq %%dr3, %0\n\t" : "=r" (uDR3));
2190# else
2191 __asm__ __volatile__("movl %%dr3, %0\n\t" : "=r" (uDR3));
2192# endif
2193# else
2194 __asm
2195 {
2196# ifdef RT_ARCH_AMD64
2197 mov rax, dr3
2198 mov [uDR3], rax
2199# else
2200 mov eax, dr3
2201 mov [uDR3], eax
2202# endif
2203 }
2204# endif
2205 return uDR3;
2206}
2207#endif
2208
2209
2210/**
2211 * Gets dr6.
2212 *
2213 * @returns dr6.
2214 */
2215#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2216DECLASM(RTCCUINTREG) ASMGetDR6(void);
2217#else
2218DECLINLINE(RTCCUINTREG) ASMGetDR6(void)
2219{
2220 RTCCUINTREG uDR6;
2221# if RT_INLINE_ASM_USES_INTRIN
2222 uDR6 = __readdr(6);
2223# elif RT_INLINE_ASM_GNU_STYLE
2224# ifdef RT_ARCH_AMD64
2225 __asm__ __volatile__("movq %%dr6, %0\n\t" : "=r" (uDR6));
2226# else
2227 __asm__ __volatile__("movl %%dr6, %0\n\t" : "=r" (uDR6));
2228# endif
2229# else
2230 __asm
2231 {
2232# ifdef RT_ARCH_AMD64
2233 mov rax, dr6
2234 mov [uDR6], rax
2235# else
2236 mov eax, dr6
2237 mov [uDR6], eax
2238# endif
2239 }
2240# endif
2241 return uDR6;
2242}
2243#endif
2244
2245
2246/**
2247 * Reads and clears DR6.
2248 *
2249 * @returns DR6.
2250 */
2251#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2252DECLASM(RTCCUINTREG) ASMGetAndClearDR6(void);
2253#else
2254DECLINLINE(RTCCUINTREG) ASMGetAndClearDR6(void)
2255{
2256 RTCCUINTREG uDR6;
2257# if RT_INLINE_ASM_USES_INTRIN
2258 uDR6 = __readdr(6);
2259 __writedr(6, 0xffff0ff0U); /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2260# elif RT_INLINE_ASM_GNU_STYLE
2261 RTCCUINTREG uNewValue = 0xffff0ff0U;/* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2262# ifdef RT_ARCH_AMD64
2263 __asm__ __volatile__("movq %%dr6, %0\n\t"
2264 "movq %1, %%dr6\n\t"
2265 : "=r" (uDR6)
2266 : "r" (uNewValue));
2267# else
2268 __asm__ __volatile__("movl %%dr6, %0\n\t"
2269 "movl %1, %%dr6\n\t"
2270 : "=r" (uDR6)
2271 : "r" (uNewValue));
2272# endif
2273# else
2274 __asm
2275 {
2276# ifdef RT_ARCH_AMD64
2277 mov rax, dr6
2278 mov [uDR6], rax
2279 mov rcx, rax
2280 mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 and 63-31 are zero. */
2281 mov dr6, rcx
2282# else
2283 mov eax, dr6
2284 mov [uDR6], eax
2285 mov ecx, 0ffff0ff0h; /* 31-16 and 4-11 are 1's, 12 is zero. */
2286 mov dr6, ecx
2287# endif
2288 }
2289# endif
2290 return uDR6;
2291}
2292#endif
2293
2294
2295/**
2296 * Gets dr7.
2297 *
2298 * @returns dr7.
2299 */
2300#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2301DECLASM(RTCCUINTREG) ASMGetDR7(void);
2302#else
2303DECLINLINE(RTCCUINTREG) ASMGetDR7(void)
2304{
2305 RTCCUINTREG uDR7;
2306# if RT_INLINE_ASM_USES_INTRIN
2307 uDR7 = __readdr(7);
2308# elif RT_INLINE_ASM_GNU_STYLE
2309# ifdef RT_ARCH_AMD64
2310 __asm__ __volatile__("movq %%dr7, %0\n\t" : "=r" (uDR7));
2311# else
2312 __asm__ __volatile__("movl %%dr7, %0\n\t" : "=r" (uDR7));
2313# endif
2314# else
2315 __asm
2316 {
2317# ifdef RT_ARCH_AMD64
2318 mov rax, dr7
2319 mov [uDR7], rax
2320# else
2321 mov eax, dr7
2322 mov [uDR7], eax
2323# endif
2324 }
2325# endif
2326 return uDR7;
2327}
2328#endif
2329
2330
2331/**
2332 * Sets dr0.
2333 *
2334 * @param uDRVal Debug register value to write
2335 */
2336#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2337DECLASM(void) ASMSetDR0(RTCCUINTREG uDRVal);
2338#else
2339DECLINLINE(void) ASMSetDR0(RTCCUINTREG uDRVal)
2340{
2341# if RT_INLINE_ASM_USES_INTRIN
2342 __writedr(0, uDRVal);
2343# elif RT_INLINE_ASM_GNU_STYLE
2344# ifdef RT_ARCH_AMD64
2345 __asm__ __volatile__("movq %0, %%dr0\n\t" : : "r" (uDRVal));
2346# else
2347 __asm__ __volatile__("movl %0, %%dr0\n\t" : : "r" (uDRVal));
2348# endif
2349# else
2350 __asm
2351 {
2352# ifdef RT_ARCH_AMD64
2353 mov rax, [uDRVal]
2354 mov dr0, rax
2355# else
2356 mov eax, [uDRVal]
2357 mov dr0, eax
2358# endif
2359 }
2360# endif
2361}
2362#endif
2363
2364
2365/**
2366 * Sets dr1.
2367 *
2368 * @param uDRVal Debug register value to write
2369 */
2370#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2371DECLASM(void) ASMSetDR1(RTCCUINTREG uDRVal);
2372#else
2373DECLINLINE(void) ASMSetDR1(RTCCUINTREG uDRVal)
2374{
2375# if RT_INLINE_ASM_USES_INTRIN
2376 __writedr(1, uDRVal);
2377# elif RT_INLINE_ASM_GNU_STYLE
2378# ifdef RT_ARCH_AMD64
2379 __asm__ __volatile__("movq %0, %%dr1\n\t" : : "r" (uDRVal));
2380# else
2381 __asm__ __volatile__("movl %0, %%dr1\n\t" : : "r" (uDRVal));
2382# endif
2383# else
2384 __asm
2385 {
2386# ifdef RT_ARCH_AMD64
2387 mov rax, [uDRVal]
2388 mov dr1, rax
2389# else
2390 mov eax, [uDRVal]
2391 mov dr1, eax
2392# endif
2393 }
2394# endif
2395}
2396#endif
2397
2398
2399/**
2400 * Sets dr2.
2401 *
2402 * @param uDRVal Debug register value to write
2403 */
2404#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2405DECLASM(void) ASMSetDR2(RTCCUINTREG uDRVal);
2406#else
2407DECLINLINE(void) ASMSetDR2(RTCCUINTREG uDRVal)
2408{
2409# if RT_INLINE_ASM_USES_INTRIN
2410 __writedr(2, uDRVal);
2411# elif RT_INLINE_ASM_GNU_STYLE
2412# ifdef RT_ARCH_AMD64
2413 __asm__ __volatile__("movq %0, %%dr2\n\t" : : "r" (uDRVal));
2414# else
2415 __asm__ __volatile__("movl %0, %%dr2\n\t" : : "r" (uDRVal));
2416# endif
2417# else
2418 __asm
2419 {
2420# ifdef RT_ARCH_AMD64
2421 mov rax, [uDRVal]
2422 mov dr2, rax
2423# else
2424 mov eax, [uDRVal]
2425 mov dr2, eax
2426# endif
2427 }
2428# endif
2429}
2430#endif
2431
2432
2433/**
2434 * Sets dr3.
2435 *
2436 * @param uDRVal Debug register value to write
2437 */
2438#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2439DECLASM(void) ASMSetDR3(RTCCUINTREG uDRVal);
2440#else
2441DECLINLINE(void) ASMSetDR3(RTCCUINTREG uDRVal)
2442{
2443# if RT_INLINE_ASM_USES_INTRIN
2444 __writedr(3, uDRVal);
2445# elif RT_INLINE_ASM_GNU_STYLE
2446# ifdef RT_ARCH_AMD64
2447 __asm__ __volatile__("movq %0, %%dr3\n\t" : : "r" (uDRVal));
2448# else
2449 __asm__ __volatile__("movl %0, %%dr3\n\t" : : "r" (uDRVal));
2450# endif
2451# else
2452 __asm
2453 {
2454# ifdef RT_ARCH_AMD64
2455 mov rax, [uDRVal]
2456 mov dr3, rax
2457# else
2458 mov eax, [uDRVal]
2459 mov dr3, eax
2460# endif
2461 }
2462# endif
2463}
2464#endif
2465
2466
2467/**
2468 * Sets dr6.
2469 *
2470 * @param uDRVal Debug register value to write
2471 */
2472#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2473DECLASM(void) ASMSetDR6(RTCCUINTREG uDRVal);
2474#else
2475DECLINLINE(void) ASMSetDR6(RTCCUINTREG uDRVal)
2476{
2477# if RT_INLINE_ASM_USES_INTRIN
2478 __writedr(6, uDRVal);
2479# elif RT_INLINE_ASM_GNU_STYLE
2480# ifdef RT_ARCH_AMD64
2481 __asm__ __volatile__("movq %0, %%dr6\n\t" : : "r" (uDRVal));
2482# else
2483 __asm__ __volatile__("movl %0, %%dr6\n\t" : : "r" (uDRVal));
2484# endif
2485# else
2486 __asm
2487 {
2488# ifdef RT_ARCH_AMD64
2489 mov rax, [uDRVal]
2490 mov dr6, rax
2491# else
2492 mov eax, [uDRVal]
2493 mov dr6, eax
2494# endif
2495 }
2496# endif
2497}
2498#endif
2499
2500
2501/**
2502 * Sets dr7.
2503 *
2504 * @param uDRVal Debug register value to write
2505 */
2506#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2507DECLASM(void) ASMSetDR7(RTCCUINTREG uDRVal);
2508#else
2509DECLINLINE(void) ASMSetDR7(RTCCUINTREG uDRVal)
2510{
2511# if RT_INLINE_ASM_USES_INTRIN
2512 __writedr(7, uDRVal);
2513# elif RT_INLINE_ASM_GNU_STYLE
2514# ifdef RT_ARCH_AMD64
2515 __asm__ __volatile__("movq %0, %%dr7\n\t" : : "r" (uDRVal));
2516# else
2517 __asm__ __volatile__("movl %0, %%dr7\n\t" : : "r" (uDRVal));
2518# endif
2519# else
2520 __asm
2521 {
2522# ifdef RT_ARCH_AMD64
2523 mov rax, [uDRVal]
2524 mov dr7, rax
2525# else
2526 mov eax, [uDRVal]
2527 mov dr7, eax
2528# endif
2529 }
2530# endif
2531}
2532#endif
2533
2534
2535/**
2536 * Writes a 8-bit unsigned integer to an I/O port, ordered.
2537 *
2538 * @param Port I/O port to write to.
2539 * @param u8 8-bit integer to write.
2540 */
2541#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2542DECLASM(void) ASMOutU8(RTIOPORT Port, uint8_t u8);
2543#else
2544DECLINLINE(void) ASMOutU8(RTIOPORT Port, uint8_t u8)
2545{
2546# if RT_INLINE_ASM_GNU_STYLE
2547 __asm__ __volatile__("outb %b1, %w0\n\t"
2548 :: "Nd" (Port),
2549 "a" (u8));
2550
2551# elif RT_INLINE_ASM_USES_INTRIN
2552 __outbyte(Port, u8);
2553
2554# else
2555 __asm
2556 {
2557 mov dx, [Port]
2558 mov al, [u8]
2559 out dx, al
2560 }
2561# endif
2562}
2563#endif
2564
2565
2566/**
2567 * Reads a 8-bit unsigned integer from an I/O port, ordered.
2568 *
2569 * @returns 8-bit integer.
2570 * @param Port I/O port to read from.
2571 */
2572#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2573DECLASM(uint8_t) ASMInU8(RTIOPORT Port);
2574#else
2575DECLINLINE(uint8_t) ASMInU8(RTIOPORT Port)
2576{
2577 uint8_t u8;
2578# if RT_INLINE_ASM_GNU_STYLE
2579 __asm__ __volatile__("inb %w1, %b0\n\t"
2580 : "=a" (u8)
2581 : "Nd" (Port));
2582
2583# elif RT_INLINE_ASM_USES_INTRIN
2584 u8 = __inbyte(Port);
2585
2586# else
2587 __asm
2588 {
2589 mov dx, [Port]
2590 in al, dx
2591 mov [u8], al
2592 }
2593# endif
2594 return u8;
2595}
2596#endif
2597
2598
2599/**
2600 * Writes a 16-bit unsigned integer to an I/O port, ordered.
2601 *
2602 * @param Port I/O port to write to.
2603 * @param u16 16-bit integer to write.
2604 */
2605#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2606DECLASM(void) ASMOutU16(RTIOPORT Port, uint16_t u16);
2607#else
2608DECLINLINE(void) ASMOutU16(RTIOPORT Port, uint16_t u16)
2609{
2610# if RT_INLINE_ASM_GNU_STYLE
2611 __asm__ __volatile__("outw %w1, %w0\n\t"
2612 :: "Nd" (Port),
2613 "a" (u16));
2614
2615# elif RT_INLINE_ASM_USES_INTRIN
2616 __outword(Port, u16);
2617
2618# else
2619 __asm
2620 {
2621 mov dx, [Port]
2622 mov ax, [u16]
2623 out dx, ax
2624 }
2625# endif
2626}
2627#endif
2628
2629
2630/**
2631 * Reads a 16-bit unsigned integer from an I/O port, ordered.
2632 *
2633 * @returns 16-bit integer.
2634 * @param Port I/O port to read from.
2635 */
2636#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2637DECLASM(uint16_t) ASMInU16(RTIOPORT Port);
2638#else
2639DECLINLINE(uint16_t) ASMInU16(RTIOPORT Port)
2640{
2641 uint16_t u16;
2642# if RT_INLINE_ASM_GNU_STYLE
2643 __asm__ __volatile__("inw %w1, %w0\n\t"
2644 : "=a" (u16)
2645 : "Nd" (Port));
2646
2647# elif RT_INLINE_ASM_USES_INTRIN
2648 u16 = __inword(Port);
2649
2650# else
2651 __asm
2652 {
2653 mov dx, [Port]
2654 in ax, dx
2655 mov [u16], ax
2656 }
2657# endif
2658 return u16;
2659}
2660#endif
2661
2662
2663/**
2664 * Writes a 32-bit unsigned integer to an I/O port, ordered.
2665 *
2666 * @param Port I/O port to write to.
2667 * @param u32 32-bit integer to write.
2668 */
2669#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2670DECLASM(void) ASMOutU32(RTIOPORT Port, uint32_t u32);
2671#else
2672DECLINLINE(void) ASMOutU32(RTIOPORT Port, uint32_t u32)
2673{
2674# if RT_INLINE_ASM_GNU_STYLE
2675 __asm__ __volatile__("outl %1, %w0\n\t"
2676 :: "Nd" (Port),
2677 "a" (u32));
2678
2679# elif RT_INLINE_ASM_USES_INTRIN
2680 __outdword(Port, u32);
2681
2682# else
2683 __asm
2684 {
2685 mov dx, [Port]
2686 mov eax, [u32]
2687 out dx, eax
2688 }
2689# endif
2690}
2691#endif
2692
2693
2694/**
2695 * Reads a 32-bit unsigned integer from an I/O port, ordered.
2696 *
2697 * @returns 32-bit integer.
2698 * @param Port I/O port to read from.
2699 */
2700#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2701DECLASM(uint32_t) ASMInU32(RTIOPORT Port);
2702#else
2703DECLINLINE(uint32_t) ASMInU32(RTIOPORT Port)
2704{
2705 uint32_t u32;
2706# if RT_INLINE_ASM_GNU_STYLE
2707 __asm__ __volatile__("inl %w1, %0\n\t"
2708 : "=a" (u32)
2709 : "Nd" (Port));
2710
2711# elif RT_INLINE_ASM_USES_INTRIN
2712 u32 = __indword(Port);
2713
2714# else
2715 __asm
2716 {
2717 mov dx, [Port]
2718 in eax, dx
2719 mov [u32], eax
2720 }
2721# endif
2722 return u32;
2723}
2724#endif
2725
2726
2727/**
2728 * Writes a string of 8-bit unsigned integer items to an I/O port, ordered.
2729 *
2730 * @param Port I/O port to write to.
2731 * @param pau8 Pointer to the string buffer.
2732 * @param c The number of items to write.
2733 */
2734#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2735DECLASM(void) ASMOutStrU8(RTIOPORT Port, uint8_t const *pau8, size_t c);
2736#else
2737DECLINLINE(void) ASMOutStrU8(RTIOPORT Port, uint8_t const *pau8, size_t c)
2738{
2739# if RT_INLINE_ASM_GNU_STYLE
2740 __asm__ __volatile__("rep; outsb\n\t"
2741 : "+S" (pau8),
2742 "+c" (c)
2743 : "d" (Port));
2744
2745# elif RT_INLINE_ASM_USES_INTRIN
2746 __outbytestring(Port, (unsigned char *)pau8, (unsigned long)c);
2747
2748# else
2749 __asm
2750 {
2751 mov dx, [Port]
2752 mov ecx, [c]
2753 mov eax, [pau8]
2754 xchg esi, eax
2755 rep outsb
2756 xchg esi, eax
2757 }
2758# endif
2759}
2760#endif
2761
2762
2763/**
2764 * Reads a string of 8-bit unsigned integer items from an I/O port, ordered.
2765 *
2766 * @param Port I/O port to read from.
2767 * @param pau8 Pointer to the string buffer (output).
2768 * @param c The number of items to read.
2769 */
2770#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2771DECLASM(void) ASMInStrU8(RTIOPORT Port, uint8_t *pau8, size_t c);
2772#else
2773DECLINLINE(void) ASMInStrU8(RTIOPORT Port, uint8_t *pau8, size_t c)
2774{
2775# if RT_INLINE_ASM_GNU_STYLE
2776 __asm__ __volatile__("rep; insb\n\t"
2777 : "+D" (pau8),
2778 "+c" (c)
2779 : "d" (Port));
2780
2781# elif RT_INLINE_ASM_USES_INTRIN
2782 __inbytestring(Port, pau8, (unsigned long)c);
2783
2784# else
2785 __asm
2786 {
2787 mov dx, [Port]
2788 mov ecx, [c]
2789 mov eax, [pau8]
2790 xchg edi, eax
2791 rep insb
2792 xchg edi, eax
2793 }
2794# endif
2795}
2796#endif
2797
2798
2799/**
2800 * Writes a string of 16-bit unsigned integer items to an I/O port, ordered.
2801 *
2802 * @param Port I/O port to write to.
2803 * @param pau16 Pointer to the string buffer.
2804 * @param c The number of items to write.
2805 */
2806#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2807DECLASM(void) ASMOutStrU16(RTIOPORT Port, uint16_t const *pau16, size_t c);
2808#else
2809DECLINLINE(void) ASMOutStrU16(RTIOPORT Port, uint16_t const *pau16, size_t c)
2810{
2811# if RT_INLINE_ASM_GNU_STYLE
2812 __asm__ __volatile__("rep; outsw\n\t"
2813 : "+S" (pau16),
2814 "+c" (c)
2815 : "d" (Port));
2816
2817# elif RT_INLINE_ASM_USES_INTRIN
2818 __outwordstring(Port, (unsigned short *)pau16, (unsigned long)c);
2819
2820# else
2821 __asm
2822 {
2823 mov dx, [Port]
2824 mov ecx, [c]
2825 mov eax, [pau16]
2826 xchg esi, eax
2827 rep outsw
2828 xchg esi, eax
2829 }
2830# endif
2831}
2832#endif
2833
2834
2835/**
2836 * Reads a string of 16-bit unsigned integer items from an I/O port, ordered.
2837 *
2838 * @param Port I/O port to read from.
2839 * @param pau16 Pointer to the string buffer (output).
2840 * @param c The number of items to read.
2841 */
2842#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2843DECLASM(void) ASMInStrU16(RTIOPORT Port, uint16_t *pau16, size_t c);
2844#else
2845DECLINLINE(void) ASMInStrU16(RTIOPORT Port, uint16_t *pau16, size_t c)
2846{
2847# if RT_INLINE_ASM_GNU_STYLE
2848 __asm__ __volatile__("rep; insw\n\t"
2849 : "+D" (pau16),
2850 "+c" (c)
2851 : "d" (Port));
2852
2853# elif RT_INLINE_ASM_USES_INTRIN
2854 __inwordstring(Port, pau16, (unsigned long)c);
2855
2856# else
2857 __asm
2858 {
2859 mov dx, [Port]
2860 mov ecx, [c]
2861 mov eax, [pau16]
2862 xchg edi, eax
2863 rep insw
2864 xchg edi, eax
2865 }
2866# endif
2867}
2868#endif
2869
2870
2871/**
2872 * Writes a string of 32-bit unsigned integer items to an I/O port, ordered.
2873 *
2874 * @param Port I/O port to write to.
2875 * @param pau32 Pointer to the string buffer.
2876 * @param c The number of items to write.
2877 */
2878#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2879DECLASM(void) ASMOutStrU32(RTIOPORT Port, uint32_t const *pau32, size_t c);
2880#else
2881DECLINLINE(void) ASMOutStrU32(RTIOPORT Port, uint32_t const *pau32, size_t c)
2882{
2883# if RT_INLINE_ASM_GNU_STYLE
2884 __asm__ __volatile__("rep; outsl\n\t"
2885 : "+S" (pau32),
2886 "+c" (c)
2887 : "d" (Port));
2888
2889# elif RT_INLINE_ASM_USES_INTRIN
2890 __outdwordstring(Port, (unsigned long *)pau32, (unsigned long)c);
2891
2892# else
2893 __asm
2894 {
2895 mov dx, [Port]
2896 mov ecx, [c]
2897 mov eax, [pau32]
2898 xchg esi, eax
2899 rep outsd
2900 xchg esi, eax
2901 }
2902# endif
2903}
2904#endif
2905
2906
2907/**
2908 * Reads a string of 32-bit unsigned integer items from an I/O port, ordered.
2909 *
2910 * @param Port I/O port to read from.
2911 * @param pau32 Pointer to the string buffer (output).
2912 * @param c The number of items to read.
2913 */
2914#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2915DECLASM(void) ASMInStrU32(RTIOPORT Port, uint32_t *pau32, size_t c);
2916#else
2917DECLINLINE(void) ASMInStrU32(RTIOPORT Port, uint32_t *pau32, size_t c)
2918{
2919# if RT_INLINE_ASM_GNU_STYLE
2920 __asm__ __volatile__("rep; insl\n\t"
2921 : "+D" (pau32),
2922 "+c" (c)
2923 : "d" (Port));
2924
2925# elif RT_INLINE_ASM_USES_INTRIN
2926 __indwordstring(Port, (unsigned long *)pau32, (unsigned long)c);
2927
2928# else
2929 __asm
2930 {
2931 mov dx, [Port]
2932 mov ecx, [c]
2933 mov eax, [pau32]
2934 xchg edi, eax
2935 rep insd
2936 xchg edi, eax
2937 }
2938# endif
2939}
2940#endif
2941
2942
2943/**
2944 * Invalidate page.
2945 *
2946 * @param pv Address of the page to invalidate.
2947 */
2948#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2949DECLASM(void) ASMInvalidatePage(void *pv);
2950#else
2951DECLINLINE(void) ASMInvalidatePage(void *pv)
2952{
2953# if RT_INLINE_ASM_USES_INTRIN
2954 __invlpg(pv);
2955
2956# elif RT_INLINE_ASM_GNU_STYLE
2957 __asm__ __volatile__("invlpg %0\n\t"
2958 : : "m" (*(uint8_t *)pv));
2959# else
2960 __asm
2961 {
2962# ifdef RT_ARCH_AMD64
2963 mov rax, [pv]
2964 invlpg [rax]
2965# else
2966 mov eax, [pv]
2967 invlpg [eax]
2968# endif
2969 }
2970# endif
2971}
2972#endif
2973
2974
2975/**
2976 * Write back the internal caches and invalidate them.
2977 */
2978#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
2979DECLASM(void) ASMWriteBackAndInvalidateCaches(void);
2980#else
2981DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void)
2982{
2983# if RT_INLINE_ASM_USES_INTRIN
2984 __wbinvd();
2985
2986# elif RT_INLINE_ASM_GNU_STYLE
2987 __asm__ __volatile__("wbinvd");
2988# else
2989 __asm
2990 {
2991 wbinvd
2992 }
2993# endif
2994}
2995#endif
2996
2997
2998/**
2999 * Invalidate internal and (perhaps) external caches without first
3000 * flushing dirty cache lines. Use with extreme care.
3001 */
3002#if RT_INLINE_ASM_EXTERNAL
3003DECLASM(void) ASMInvalidateInternalCaches(void);
3004#else
3005DECLINLINE(void) ASMInvalidateInternalCaches(void)
3006{
3007# if RT_INLINE_ASM_GNU_STYLE
3008 __asm__ __volatile__("invd");
3009# else
3010 __asm
3011 {
3012 invd
3013 }
3014# endif
3015}
3016#endif
3017
3018
3019/**
3020 * Memory load/store fence, waits for any pending writes and reads to complete.
3021 * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set.
3022 */
3023DECLINLINE(void) ASMMemoryFenceSSE2(void)
3024{
3025#if RT_INLINE_ASM_GNU_STYLE
3026 __asm__ __volatile__ (".byte 0x0f,0xae,0xf0\n\t");
3027#elif RT_INLINE_ASM_USES_INTRIN
3028 _mm_mfence();
3029#else
3030 __asm
3031 {
3032 _emit 0x0f
3033 _emit 0xae
3034 _emit 0xf0
3035 }
3036#endif
3037}
3038
3039
3040/**
3041 * Memory store fence, waits for any writes to complete.
3042 * Requires the X86_CPUID_FEATURE_EDX_SSE CPUID bit set.
3043 */
3044DECLINLINE(void) ASMWriteFenceSSE(void)
3045{
3046#if RT_INLINE_ASM_GNU_STYLE
3047 __asm__ __volatile__ (".byte 0x0f,0xae,0xf8\n\t");
3048#elif RT_INLINE_ASM_USES_INTRIN
3049 _mm_sfence();
3050#else
3051 __asm
3052 {
3053 _emit 0x0f
3054 _emit 0xae
3055 _emit 0xf8
3056 }
3057#endif
3058}
3059
3060
3061/**
3062 * Memory load fence, waits for any pending reads to complete.
3063 * Requires the X86_CPUID_FEATURE_EDX_SSE2 CPUID bit set.
3064 */
3065DECLINLINE(void) ASMReadFenceSSE2(void)
3066{
3067#if RT_INLINE_ASM_GNU_STYLE
3068 __asm__ __volatile__ (".byte 0x0f,0xae,0xe8\n\t");
3069#elif RT_INLINE_ASM_USES_INTRIN
3070 _mm_lfence();
3071#else
3072 __asm
3073 {
3074 _emit 0x0f
3075 _emit 0xae
3076 _emit 0xe8
3077 }
3078#endif
3079}
3080
3081/** @} */
3082#endif
3083
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