2010-02-08 17:23:39 +01:00
|
|
|
/* Copyright (c) 2010 Wildfire Games
|
2009-04-18 19:00:33 +02:00
|
|
|
*
|
2010-02-08 17:23:39 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
* the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included
|
|
|
|
* in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
2009-04-18 19:00:33 +02:00
|
|
|
*/
|
|
|
|
|
2009-04-18 19:51:05 +02:00
|
|
|
/*
|
|
|
|
* CPU-specific routines common to 32 and 64-bit x86
|
2008-05-12 20:15:08 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef INCLUDED_X86_X64
|
|
|
|
#define INCLUDED_X86_X64
|
|
|
|
|
2008-09-27 12:23:05 +02:00
|
|
|
#if !ARCH_X86_X64
|
|
|
|
#error "including x86_x64.h without ARCH_X86_X64=1"
|
2008-05-12 20:15:08 +02:00
|
|
|
#endif
|
|
|
|
|
2009-11-03 17:30:21 +01:00
|
|
|
#if MSC_VERSION
|
|
|
|
#include <intrin.h> // __rdtsc
|
|
|
|
#endif
|
|
|
|
|
2008-05-12 20:15:08 +02:00
|
|
|
/**
|
|
|
|
* registers used/returned by x86_x64_cpuid
|
|
|
|
**/
|
|
|
|
struct x86_x64_CpuidRegs
|
|
|
|
{
|
|
|
|
u32 eax;
|
|
|
|
u32 ebx;
|
|
|
|
u32 ecx;
|
|
|
|
u32 edx;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* invoke CPUID instruction.
|
|
|
|
* @param regs input/output registers.
|
|
|
|
* regs->eax must be set to the desired function.
|
|
|
|
* some functions (e.g. 4) require regs->ecx to be set as well.
|
|
|
|
* rationale: this interface (input/output structure vs. function parameters)
|
|
|
|
* avoids unnecessary copying/initialization if some inputs aren't needed
|
|
|
|
* and allows graceful expansion to functions that require further inputs.
|
|
|
|
* @return true on success or false if the sub-function isn't supported.
|
|
|
|
**/
|
2009-04-18 10:41:10 +02:00
|
|
|
LIB_API bool x86_x64_cpuid(x86_x64_CpuidRegs* regs);
|
2008-05-12 20:15:08 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* CPU vendor.
|
|
|
|
* (this is exposed because some CPUID functions are vendor-specific.)
|
|
|
|
* (an enum is easier to compare than the original string values.)
|
|
|
|
**/
|
|
|
|
enum x86_x64_Vendors
|
|
|
|
{
|
|
|
|
X86_X64_VENDOR_UNKNOWN,
|
|
|
|
X86_X64_VENDOR_INTEL,
|
2008-12-17 17:32:46 +01:00
|
|
|
X86_X64_VENDOR_AMD
|
2008-05-12 20:15:08 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
LIB_API x86_x64_Vendors x86_x64_Vendor();
|
|
|
|
|
|
|
|
|
2010-08-06 15:03:44 +02:00
|
|
|
LIB_API size_t x86_x64_Model();
|
|
|
|
|
|
|
|
LIB_API size_t x86_x64_Family();
|
|
|
|
|
|
|
|
|
2008-05-12 20:15:08 +02:00
|
|
|
/**
|
|
|
|
* @return the colloquial processor generation
|
|
|
|
* (5 = Pentium, 6 = Pentium Pro/II/III / K6, 7 = Pentium4 / Athlon, 8 = Core / Opteron)
|
|
|
|
**/
|
|
|
|
LIB_API size_t x86_x64_Generation();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* bit indices of CPU capability flags (128 bits).
|
|
|
|
* values are defined by IA-32 CPUID feature flags - do not change!
|
|
|
|
**/
|
|
|
|
enum x86_x64_Cap
|
|
|
|
{
|
|
|
|
// standard (ecx) - currently only defined by Intel
|
|
|
|
X86_X64_CAP_SSE3 = 0+0, // Streaming SIMD Extensions 3
|
|
|
|
X86_X64_CAP_EST = 0+7, // Enhanced Speedstep Technology
|
2010-02-08 16:56:43 +01:00
|
|
|
X86_X64_CAP_SSSE3 = 0+9, // Supplemental Streaming SIMD Extensions 3
|
|
|
|
X86_X64_CAP_SSE41 = 0+19, // Streaming SIMD Extensions 4.1
|
|
|
|
X86_X64_CAP_SSE42 = 0+20, // Streaming SIMD Extensions 4.2
|
2008-05-12 20:15:08 +02:00
|
|
|
|
|
|
|
// standard (edx)
|
2010-02-08 16:56:43 +01:00
|
|
|
X86_X64_CAP_FPU = 32+0, // Floating Point Unit
|
|
|
|
X86_X64_CAP_TSC = 32+4, // TimeStamp Counter
|
2010-08-06 15:03:44 +02:00
|
|
|
X86_X64_CAP_MSR = 32+5, // Model Specific Registers
|
2010-02-08 16:56:43 +01:00
|
|
|
X86_X64_CAP_CMOV = 32+15, // Conditional MOVe
|
|
|
|
X86_X64_CAP_TM_SCC = 32+22, // Thermal Monitoring and Software Controlled Clock
|
|
|
|
X86_X64_CAP_MMX = 32+23, // MultiMedia eXtensions
|
|
|
|
X86_X64_CAP_SSE = 32+25, // Streaming SIMD Extensions
|
|
|
|
X86_X64_CAP_SSE2 = 32+26, // Streaming SIMD Extensions 2
|
|
|
|
X86_X64_CAP_HT = 32+28, // HyperThreading
|
2008-05-12 20:15:08 +02:00
|
|
|
|
|
|
|
// extended (ecx)
|
2010-02-08 16:56:43 +01:00
|
|
|
X86_X64_CAP_AMD_CMP_LEGACY = 64+1, // N-core and X86_X64_CAP_HT is falsely set
|
2008-05-12 20:15:08 +02:00
|
|
|
|
|
|
|
// extended (edx)
|
2010-02-08 16:56:43 +01:00
|
|
|
X86_X64_CAP_AMD_MP = 96+19, // MultiProcessing capable; reserved on AMD64
|
2008-05-12 20:15:08 +02:00
|
|
|
X86_X64_CAP_AMD_MMX_EXT = 96+22,
|
|
|
|
X86_X64_CAP_AMD_3DNOW_PRO = 96+30,
|
|
|
|
X86_X64_CAP_AMD_3DNOW = 96+31
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return whether the CPU supports the indicated x86_x64_Cap / feature flag.
|
|
|
|
**/
|
|
|
|
LIB_API bool x86_x64_cap(x86_x64_Cap cap);
|
|
|
|
|
|
|
|
|
2008-06-01 10:25:12 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2009-01-06 21:17:06 +01:00
|
|
|
// cache and TLB
|
2008-06-01 10:25:12 +02:00
|
|
|
|
|
|
|
enum x86_x64_CacheType
|
|
|
|
{
|
2009-01-06 21:17:06 +01:00
|
|
|
// (values match the CPUID.4 definition)
|
|
|
|
X86_X64_CACHE_TYPE_NULL,
|
2008-06-01 10:25:12 +02:00
|
|
|
X86_X64_CACHE_TYPE_DATA,
|
|
|
|
X86_X64_CACHE_TYPE_INSTRUCTION,
|
|
|
|
X86_X64_CACHE_TYPE_UNIFIED
|
|
|
|
// note: further values are "reserved"
|
|
|
|
};
|
|
|
|
|
2009-01-06 21:17:06 +01:00
|
|
|
const u8 x86_x64_fullyAssociative = 0xFF;
|
|
|
|
|
2010-07-22 18:17:33 +02:00
|
|
|
struct x86_x64_Cache
|
2008-06-01 10:25:12 +02:00
|
|
|
{
|
2009-01-06 21:17:06 +01:00
|
|
|
/**
|
|
|
|
* (used to determine if this cache is unified or disabled)
|
|
|
|
**/
|
2008-06-01 10:25:12 +02:00
|
|
|
x86_x64_CacheType type;
|
|
|
|
size_t level;
|
|
|
|
size_t associativity;
|
2009-01-06 21:17:06 +01:00
|
|
|
size_t lineSize; /// [bytes]
|
2008-06-01 10:25:12 +02:00
|
|
|
size_t sharedBy;
|
2009-01-06 21:17:06 +01:00
|
|
|
size_t totalSize; /// [bytes]
|
2008-06-01 10:25:12 +02:00
|
|
|
};
|
|
|
|
|
2009-01-06 21:17:06 +01:00
|
|
|
/**
|
|
|
|
* describes all levels of a cache.
|
|
|
|
* instruction and data caches are returned separately by the corresponding
|
|
|
|
* accessor function; unified cache levels are reported by both.
|
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
struct x86_x64_Caches
|
2009-01-06 21:17:06 +01:00
|
|
|
{
|
2010-07-22 18:17:33 +02:00
|
|
|
size_t numLevels;
|
|
|
|
x86_x64_Cache* levels;
|
2009-01-06 21:17:06 +01:00
|
|
|
};
|
2008-06-01 10:25:12 +02:00
|
|
|
|
|
|
|
/**
|
2010-07-22 18:17:33 +02:00
|
|
|
* @return pointer to a static x86_x64_Caches describing the instruction caches.
|
2008-06-01 10:25:12 +02:00
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
LIB_API const x86_x64_Caches* x86_x64_ICaches();
|
2009-01-06 21:17:06 +01:00
|
|
|
|
|
|
|
/**
|
2010-07-22 18:17:33 +02:00
|
|
|
* @return pointer to a static x86_x64_Caches describing the data caches.
|
2009-01-06 21:17:06 +01:00
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
LIB_API const x86_x64_Caches* x86_x64_DCaches();
|
2008-06-01 10:25:12 +02:00
|
|
|
|
|
|
|
LIB_API size_t x86_x64_L1CacheLineSize();
|
2008-10-13 17:08:30 +02:00
|
|
|
LIB_API size_t x86_x64_L2CacheLineSize();
|
2008-06-01 10:25:12 +02:00
|
|
|
|
2009-01-06 21:17:06 +01:00
|
|
|
/**
|
2010-07-22 18:17:33 +02:00
|
|
|
* Translation Lookaside Buffer.
|
2009-01-06 21:17:06 +01:00
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
struct x86_x64_TLB
|
2009-01-06 21:17:06 +01:00
|
|
|
{
|
|
|
|
x86_x64_CacheType type;
|
|
|
|
size_t level;
|
|
|
|
size_t associativity;
|
|
|
|
size_t pageSize;
|
|
|
|
size_t entries;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2010-07-22 18:17:33 +02:00
|
|
|
* describes all levels of a TLB.
|
2009-01-06 21:17:06 +01:00
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
struct x86_x64_TLBs
|
2009-01-06 21:17:06 +01:00
|
|
|
{
|
2010-07-22 18:17:33 +02:00
|
|
|
size_t numLevels;
|
|
|
|
x86_x64_TLB* levels;
|
2009-01-06 21:17:06 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2010-07-22 18:17:33 +02:00
|
|
|
* @return pointer to a static x86_x64_TLB describing the instruction TLBs.
|
2009-01-06 21:17:06 +01:00
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
LIB_API const x86_x64_TLBs* x86_x64_ITLBs();
|
2009-01-06 21:17:06 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return pointer to a static x86_x64_TLB describing the data TLB.
|
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
LIB_API const x86_x64_TLBs* x86_x64_DTLBs();
|
2009-01-06 21:17:06 +01:00
|
|
|
|
|
|
|
/**
|
2010-07-22 18:17:33 +02:00
|
|
|
* @return coverage, i.e. total size [MiB] of the given TLBs
|
2009-01-06 21:17:06 +01:00
|
|
|
**/
|
2010-07-22 18:17:33 +02:00
|
|
|
LIB_API size_t x86_x64_TLBCoverage(const x86_x64_TLBs* tlb);
|
2009-01-06 21:17:06 +01:00
|
|
|
|
2008-06-01 10:25:12 +02:00
|
|
|
|
2008-05-12 20:15:08 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// stateless
|
|
|
|
|
|
|
|
/**
|
2008-05-13 21:43:02 +02:00
|
|
|
* @return APIC ID of the currently executing processor or zero if the
|
|
|
|
* platform does not have an xAPIC (i.e. 7th generation x86 or below).
|
2008-05-12 20:15:08 +02:00
|
|
|
*
|
2008-05-13 21:43:02 +02:00
|
|
|
* rationale: the alternative of accessing the APIC mmio registers is not
|
|
|
|
* feasible - mahaf_MapPhysicalMemory only works reliably on WinXP. we also
|
|
|
|
* don't want to intefere with the OS's constant use of the APIC registers.
|
2008-05-12 20:15:08 +02:00
|
|
|
**/
|
|
|
|
LIB_API u8 x86_x64_ApicId();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the current value of the TimeStampCounter (a counter of
|
|
|
|
* CPU cycles since power-on, which is useful for high-resolution timing
|
|
|
|
* but potentially differs between multiple CPUs)
|
2009-11-03 17:30:21 +01:00
|
|
|
*
|
|
|
|
* notes:
|
|
|
|
* - a macro avoids call overhead, which is important for TIMER_ACCRUE.
|
|
|
|
* - x64 RDTSC writes to edx:eax and clears the upper halves of rdx and rax.
|
2008-05-12 20:15:08 +02:00
|
|
|
**/
|
2009-11-03 17:30:21 +01:00
|
|
|
#if MSC_VERSION
|
|
|
|
#define x86_x64_rdtsc __rdtsc
|
|
|
|
#else
|
2008-05-12 20:15:08 +02:00
|
|
|
LIB_API u64 x86_x64_rdtsc();
|
2009-11-03 17:30:21 +01:00
|
|
|
#endif
|
2008-05-12 20:15:08 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* trigger a breakpoint inside this function when it is called.
|
|
|
|
**/
|
2009-11-03 17:30:21 +01:00
|
|
|
LIB_API void x86_x64_DebugBreak();
|
2008-05-12 20:15:08 +02:00
|
|
|
|
2008-05-13 21:43:02 +02:00
|
|
|
/**
|
|
|
|
* measure the CPU clock frequency via x86_x64_rdtsc and timer_Time.
|
|
|
|
* (it follows that this must not be called from WHRT init.)
|
|
|
|
* this takes several milliseconds (i.e. much longer than
|
|
|
|
* os_cpu_ClockFrequency) but delivers accurate measurements.
|
|
|
|
**/
|
|
|
|
LIB_API double x86_x64_ClockFrequency();
|
|
|
|
|
2008-05-12 20:15:08 +02:00
|
|
|
#endif // #ifndef INCLUDED_X86_X64
|