3 * Runtime CPU detection library.
4 * (C) 2009-2012 Jonathan Campbell.
5 * Hackipedia DOS library.
7 * This code is licensed under the LGPL.
8 * <insert LGPL legal text here>
12 #ifndef __HW_CPU_CPU_H
13 #define __HW_CPU_CPU_H
19 # if defined(TARGET_WINDOWS)
22 # if TARGET_MSDOS == 32
30 /* FIX: Open Watcom does not provide inpd/outpd in 16-bit real mode, so we have to provide it ourself */
31 /* We assume for the same stupid reasons the pragma aux function can't be used because it's a 386 level instruction */
32 #if TARGET_MSDOS == 16
33 uint32_t __cdecl inpd(uint16_t port);
34 void __cdecl outpd(uint16_t port,uint32_t data);
37 #if TARGET_MSDOS == 16
38 static inline uint32_t ptr2phys(void far *p) {
39 return (((uint32_t)FP_SEG(p)) << 4UL) +
40 ((uint32_t)FP_OFF(p));
45 struct cpu_cpuid_features {
47 uint32_t raw[4]; /* EAX, EBX, EDX, ECX */
54 struct cpu_cpuid_ext_features {
56 uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
63 struct cpu_cpuid_ext_cache_tlb {
65 uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
72 struct cpu_cpuid_ext_cache_tlb_l2 {
74 uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
81 struct cpu_cpuid_ext_longmode {
83 uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
90 struct cpu_cpuid_ext_apm {
92 uint32_t raw[1]; /* EAX */
100 uint32_t eax,ebx,ecx,edx;
104 /* "Basic" CPU level */
116 extern const char * cpu_basic_level_str[CPU_MAX];
117 extern char cpu_cpuid_vendor[13];
118 extern struct cpu_cpuid_features cpu_cpuid_features;
119 extern signed char cpu_basic_level;
120 extern uint32_t cpu_cpuid_max;
121 extern unsigned char cpu_flags;
122 extern uint16_t cpu_tmp1;
125 #define cpu_v86_active (cpu_flags & CPU_FLAG_V86_ACTIVE)
127 #define cpu_basic_level_to_string(x) (x >= 0 ? cpu_basic_level_str[x] : "?")
129 /* CPU flag: CPU supports CPUID */
130 #define CPU_FLAG_CPUID (1 << 0)
131 #define CPU_FLAG_FPU (1 << 1)
132 #define CPU_FLAG_CPUID_EXT (1 << 2)
133 #define CPU_FLAG_V86_ACTIVE (1 << 3)
134 #define CPU_FLAG_PROTECTED_MODE (1 << 4)
135 #define CPU_FLAG_PROTECTED_MODE_32 (1 << 5)
136 /* ^ Windows-specific: we are not only a 16-bit Win16 app, but Windows is running in 386 enhanced mode
137 * and we can safely use 32-bit registers and hacks. This will always be set for
138 * Win32 and 32-bit DOS, obviously. If set, PROTECTED_MODE is also set. */
139 #define CPU_FLAG_DONT_WRITE_RDTSC (1 << 6)
142 int cpu_basic_probe(); /* external assembly language function */
145 #pragma aux _cli = "cli"
147 #pragma aux _sti = "sti"
149 static inline void _sti_if_flags(unsigned int f) {
150 if (f&0x200) _sti(); /* if IF bit was set, then restore interrupts by STI */
153 /* NTS: remember for Watcom: 16-bit realmode sizeof(int) == 2, 32-bit flat mode sizeof(int) == 4 */
154 static unsigned int get_cpu_flags();
155 #if TARGET_MSDOS == 32
156 #pragma aux get_cpu_flags = \
161 #pragma aux get_cpu_flags = \
167 static void set_cpu_flags(unsigned int f);
168 #if TARGET_MSDOS == 32
169 #pragma aux set_cpu_flags = \
174 #pragma aux set_cpu_flags = \
180 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
181 /* Watcom does not offer int86/int386 for Win32s/Win9x/NT/etc */
183 static inline void just_int86(unsigned char c,union REGS *r1,union REGS *r2) {
192 #if TARGET_MSDOS == 32
193 static inline void cpu_cpuid(uint32_t idx,struct cpuid_result *x);
194 #pragma aux cpu_cpuid = \
207 void cpu_cpuid(uint32_t idx,struct cpuid_result *x);
210 #if TARGET_MSDOS == 32
211 static inline uint64_t cpu_rdmsr(const uint32_t idx);
212 #pragma aux cpu_rdmsr = \
218 static inline void cpu_wrmsr(const uint32_t idx,const uint64_t val);
219 #pragma aux cpu_wrmsr = \
224 /* This is too much code to inline insert everywhere---unless you want extra-large EXEs.
225 * It's better to conform to Watcom's register calling convention and make it a function.
226 * Note that if you look at the assembly language most of the code is shuffling the values
227 * around to convert EDX:EAX to AX:BX:CX:DX and disabling interrupts during the call. */
229 uint64_t cpu_rdmsr(const uint32_t idx);
230 void cpu_wrmsr(const uint32_t idx,const uint64_t val);
233 #endif /* __HW_CPU_CPU_H */