VirtualBox

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

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

asm-amd64-x86.h: Added ASMXSave and ASMXRstor.

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