mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-07-25 14:14:26 +00:00
fix very very insidious bug with mapping physical memory (TLB corruption). fix weirdness reported by michael (underlying cause: using cpu_ClockFrequency instead of wcpu_*; that made the timer run at freq=0)
mahaf: now disabled on Win2k because we can't prevent the TLB bug there. removed the CopyPhysical API. wutil: allow querying windows version via number View: fix warning This was SVN commit r5169.
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
#include "lib/posix/posix_pthread.h"
|
||||
#include "lib/sysdep/cpu.h" // CAS
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/res/file/file.h" // FILE_ACCESS
|
||||
// some functions here are called from within mmgr; disable its hooks
|
||||
// so that our allocations don't cause infinite recursion.
|
||||
#ifdef REDEFINED_NEW
|
||||
@@ -237,7 +236,7 @@ LibError debug_write_crashlog(const wchar_t* text)
|
||||
if(!f)
|
||||
{
|
||||
in_progress = 0;
|
||||
WARN_RETURN(ERR::FILE_ACCESS);
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
}
|
||||
|
||||
fputwc(0xfeff, f); // BOM
|
||||
|
||||
+32
-29
@@ -28,32 +28,27 @@ static u8 ComputeChecksum(const void* buf, size_t numBytes)
|
||||
// free() the returned pointer.
|
||||
static const AcpiTable* AllocateCopyOfTable(u64 physicalAddress)
|
||||
{
|
||||
// ACPI table sizes are not known until they've been mapped and copied.
|
||||
// since that is slow, we don't want to do it twice; solution is to copy
|
||||
// into a buffer big enough to hold a typical table. if it should be too
|
||||
// small, we map and copy again. using a temporary buffer, rather than
|
||||
// allocating that much up-front, avoids wasting memory for each table.
|
||||
static const size_t tempTableSize = 4*KiB;
|
||||
static u8 tempTableBuf[tempTableSize];
|
||||
const AcpiTable* tempTable = (const AcpiTable*)tempTableBuf;
|
||||
if(!mahaf_CopyPhysicalMemory(physicalAddress, tempTableSize, (void*)tempTable))
|
||||
// ACPI table sizes are not known until they've been mapped. since that
|
||||
// is slow, we don't want to do it twice; solution is map enough to
|
||||
// hold a typical table. if it should be too small, we do so again.
|
||||
static const size_t initialSize = 4*KiB;
|
||||
const volatile AcpiTable* mappedTable = (const volatile AcpiTable*)mahaf_MapPhysicalMemory(physicalAddress, initialSize);
|
||||
if(!mappedTable)
|
||||
return 0;
|
||||
|
||||
// allocate the final table
|
||||
const size_t size = tempTable->size;
|
||||
const AcpiTable* table = (const AcpiTable*)malloc(size);
|
||||
if(!table)
|
||||
return 0;
|
||||
|
||||
// and fill it.
|
||||
if(size <= tempTableSize)
|
||||
cpu_memcpy((void*)table, tempTable, size);
|
||||
else
|
||||
const size_t size = mappedTable->size;
|
||||
if(initialSize < size)
|
||||
{
|
||||
if(!mahaf_CopyPhysicalMemory(physicalAddress, size, (void*)table))
|
||||
mappedTable = (const volatile AcpiTable*)mahaf_MapPhysicalMemory(physicalAddress, size);
|
||||
if(!mappedTable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AcpiTable* table = (const AcpiTable*)malloc(size);
|
||||
if(table)
|
||||
cpu_memcpy((void*)table, (const void*)mappedTable, size);
|
||||
|
||||
mahaf_UnmapPhysicalMemory((volatile void*)mappedTable);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
@@ -128,31 +123,37 @@ static const RSDP* LocateRsdp(const u8* buf, size_t numBytes)
|
||||
|
||||
static bool LocateAndRetrieveRsdp(uintptr_t physicalAddress, size_t numBytes, RSDP& rsdp)
|
||||
{
|
||||
void* virtualAddress = mahaf_MapPhysicalMemory(physicalAddress, numBytes);
|
||||
const volatile u8* buffer = (const volatile u8*)mahaf_MapPhysicalMemory(physicalAddress, numBytes);
|
||||
if(!buffer)
|
||||
return false;
|
||||
|
||||
const RSDP* prsdp = LocateRsdp((const u8*)virtualAddress, numBytes);
|
||||
const RSDP* prsdp = LocateRsdp((const u8*)buffer, numBytes);
|
||||
if(prsdp)
|
||||
rsdp = *prsdp; // stash in output parameter before unmapping
|
||||
|
||||
mahaf_UnmapPhysicalMemory(virtualAddress);
|
||||
mahaf_UnmapPhysicalMemory((volatile void*)buffer);
|
||||
return (prsdp != 0);
|
||||
}
|
||||
|
||||
|
||||
static uintptr_t LocateEbdaPhysicalAddress()
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct BiosDataArea
|
||||
{
|
||||
u16 serialBase[4];
|
||||
u16 parallelBase[3];
|
||||
u16 ebdaSegment;
|
||||
// ...
|
||||
};
|
||||
const BiosDataArea* bda = (const BiosDataArea*)mahaf_MapPhysicalMemory(0x400, 0x100);
|
||||
#pragma pack(pop)
|
||||
const volatile BiosDataArea* bda = (const volatile BiosDataArea*)mahaf_MapPhysicalMemory(0x400, 0x100);
|
||||
if(!bda)
|
||||
{
|
||||
debug_assert(0);
|
||||
return 0;
|
||||
const uintptr_t ebdaPhysicalAddress = ((uintptr_t)bda->ebdaSegment) * 16;
|
||||
}
|
||||
|
||||
const uintptr_t ebdaPhysicalAddress = ((uintptr_t)bda->ebdaSegment) * 16;
|
||||
mahaf_UnmapPhysicalMemory((void*)bda);
|
||||
return ebdaPhysicalAddress;
|
||||
}
|
||||
|
||||
@@ -161,7 +162,9 @@ static bool RetrieveRsdp(RSDP& rsdp)
|
||||
{
|
||||
// See ACPIspec30b, section 5.2.5.1:
|
||||
// RSDP is either in the first KIB of the extended BIOS data area,
|
||||
if(LocateAndRetrieveRsdp(LocateEbdaPhysicalAddress(), 1*KiB, rsdp))
|
||||
const uintptr_t ebdaPhysicalAddress = LocateEbdaPhysicalAddress();
|
||||
debug_assert(ebdaPhysicalAddress != 0);
|
||||
if(LocateAndRetrieveRsdp(ebdaPhysicalAddress, 1*KiB, rsdp))
|
||||
return true;
|
||||
|
||||
// or in read-only BIOS memory.
|
||||
|
||||
@@ -13,8 +13,48 @@ extern "C" { // must come before ntddk.h
|
||||
// memory mapping
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// references: DDK mapmem.c sample,
|
||||
// http://support.microsoft.com/kb/189327/en-us
|
||||
/*
|
||||
|
||||
there are three approaches to mapping physical memory:
|
||||
(http://www.microsoft.com/whdc/driver/kernel/mem-mgmt.mspx)
|
||||
|
||||
- MmMapIoSpace (http://support.microsoft.com/kb/189327/en-us). despite the
|
||||
name, it maps physical pages of any kind by allocating PTEs. very easy to
|
||||
implement, but occupies precious kernel address space. possible bugs:
|
||||
http://www.osronline.com/showThread.cfm?link=96737
|
||||
http://support.microsoft.com/kb/925793/en-us
|
||||
|
||||
- ZwMapViewOfSection of PhysicalMemory (http://tinyurl.com/yozmgy).
|
||||
a bit bulky, but the WinXP implementation prevents mapping pages with
|
||||
conflicting attributes (see below).
|
||||
|
||||
- MmMapLockedPagesSpecifyCache or MmGetSystemAddressForMdlSafe
|
||||
(http://www.osronline.com/article.cfm?id=423). note: the latter is a macro
|
||||
that calls the former. this is the 'normal' and fully documented way,
|
||||
but it doesn't appear able to map a fixed physical address.
|
||||
(MmAllocatePagesForMdl understandably doesn't work since some pages we
|
||||
want to map are marked as unavailable for allocation, and I don't see
|
||||
another documented way to fill an MDL with PFNs.)
|
||||
|
||||
our choice here is forced by a very insidious issue. if someone else has
|
||||
already mapped a page with different attributes (e.g. cacheable), TLBs
|
||||
may end up corrupted, leading to disaster. the search for a documented
|
||||
means of accessing the page frame database (to check if mapped anywhere
|
||||
and determine the previously set attributes) has not borne fruit, so we
|
||||
must use ZwMapViewOfSection.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static bool IsMemoryUncacheable(DWORD64 physicalAddress64)
|
||||
{
|
||||
// original PC memory - contains BIOS
|
||||
if(physicalAddress64 < 0x100000)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWORD64 numBytes64, DWORD64& virtualAddress64)
|
||||
{
|
||||
NTSTATUS ntStatus;
|
||||
@@ -51,8 +91,11 @@ static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWO
|
||||
}
|
||||
}
|
||||
|
||||
// map desired memory into user PTEs (note: don't use MmMapIoSpace
|
||||
// because that occupies precious non-paged pool)
|
||||
// note: mapmem.c does HalTranslateBusAddress, but we only care about
|
||||
// system memory. translating doesn't appear to be necessary, even if
|
||||
// much existing code uses it (probably due to cargo cult).
|
||||
|
||||
// map desired memory into user PTEs
|
||||
{
|
||||
const HANDLE hProcess = (HANDLE)-1;
|
||||
PVOID virtualBaseAddress = 0; // let ZwMapViewOfSection pick
|
||||
@@ -61,7 +104,9 @@ static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWO
|
||||
LARGE_INTEGER physicalBaseAddress = physicalAddress; // will be rounded down to 64KB boundary
|
||||
const SECTION_INHERIT inheritDisposition = ViewShare;
|
||||
const ULONG allocationType = 0;
|
||||
const ULONG protect = PAGE_READWRITE|PAGE_NOCACHE;
|
||||
ULONG protect = PAGE_READWRITE;
|
||||
if(IsMemoryUncacheable(physicalAddress64))
|
||||
protect |= PAGE_NOCACHE;
|
||||
ntStatus = ZwMapViewOfSection(hMemory, hProcess, &virtualBaseAddress, zeroBits, mappedSize, &physicalBaseAddress, &mappedSize, inheritDisposition, allocationType, protect);
|
||||
if(!NT_SUCCESS(ntStatus))
|
||||
{
|
||||
@@ -173,6 +218,7 @@ static NTSTATUS AkenIoctlMap(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
const AkenMapIn* in = (const AkenMapIn*)buf;
|
||||
const DWORD64 physicalAddress = in->physicalAddress;
|
||||
const DWORD64 numBytes = in->numBytes;
|
||||
|
||||
DWORD64 virtualAddress;
|
||||
NTSTATUS ntStatus = AkenMapPhysicalMemory(physicalAddress, numBytes, virtualAddress);
|
||||
|
||||
@@ -193,29 +239,6 @@ static NTSTATUS AkenIoctlUnmap(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
return ntStatus;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlCopyPhysical(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
{
|
||||
if(inSize != sizeof(AkenCopyPhysicalIn) || outSize != 0)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
const AkenCopyPhysicalIn* in = (const AkenCopyPhysicalIn*)buf;
|
||||
PHYSICAL_ADDRESS physicalAddress;
|
||||
physicalAddress.QuadPart = in->physicalAddress;
|
||||
const ULONG numBytes = (ULONG)in->numBytes;
|
||||
void* userBuffer = (void*)(UINT_PTR)in->userAddress;
|
||||
|
||||
PVOID kernelBuffer = MmMapIoSpace(physicalAddress, numBytes, MmNonCached);
|
||||
if(!kernelBuffer)
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
// (this works because we're called in the user's context)
|
||||
RtlCopyMemory(userBuffer, kernelBuffer, numBytes);
|
||||
|
||||
MmUnmapIoSpace(kernelBuffer, numBytes);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlUnknown(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
{
|
||||
KdPrint(("AkenIoctlUnknown\n"));
|
||||
@@ -242,9 +265,6 @@ static inline AkenIoctl AkenIoctlFromCode(ULONG ioctlCode)
|
||||
case IOCTL_AKEN_UNMAP:
|
||||
return AkenIoctlUnmap;
|
||||
|
||||
case IOCTL_AKEN_COPY_PHYSICAL:
|
||||
return AkenIoctlCopyPhysical;
|
||||
|
||||
default:
|
||||
return AkenIoctlUnknown;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#define IOCTL_AKEN_WRITE_PORT CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+1, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AKEN_MAP CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+2, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AKEN_UNMAP CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+3, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_AKEN_COPY_PHYSICAL CTL_CODE(FILE_DEVICE_AKEN, AKEN_IOCTL+4, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
|
||||
// input and output data structures for the IOCTLs
|
||||
@@ -68,13 +67,6 @@ struct AkenUnmapIn
|
||||
DWORD64 virtualAddress;
|
||||
};
|
||||
|
||||
struct AkenCopyPhysicalIn
|
||||
{
|
||||
DWORD64 physicalAddress;
|
||||
DWORD64 numBytes;
|
||||
DWORD64 userAddress;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // #ifndef INCLUDED_AKEN
|
||||
|
||||
@@ -94,8 +94,14 @@ void mahaf_WritePort32(u16 port, u32 value)
|
||||
}
|
||||
|
||||
|
||||
void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes)
|
||||
volatile void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes)
|
||||
{
|
||||
// WinXP introduced checks that ensure we don't re-map pages with
|
||||
// incompatible attributes. without this, mapping physical pages risks
|
||||
// disaster due to TLB corruption, so disable it for safety.
|
||||
if(wutil_WindowsVersion() < WUTIL_VERSION_XP)
|
||||
return 0;
|
||||
|
||||
AkenMapIn in;
|
||||
in.physicalAddress = (DWORD64)physicalAddress;
|
||||
in.numBytes = (DWORD64)numBytes;
|
||||
@@ -111,12 +117,12 @@ void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes)
|
||||
}
|
||||
|
||||
debug_assert(bytesReturned == sizeof(out));
|
||||
void* virtualAddress = (void*)out.virtualAddress;
|
||||
volatile void* virtualAddress = (volatile void*)out.virtualAddress;
|
||||
return virtualAddress;
|
||||
}
|
||||
|
||||
|
||||
void mahaf_UnmapPhysicalMemory(void* virtualAddress)
|
||||
void mahaf_UnmapPhysicalMemory(volatile void* virtualAddress)
|
||||
{
|
||||
AkenUnmapIn in;
|
||||
in.virtualAddress = (DWORD64)virtualAddress;
|
||||
@@ -128,26 +134,6 @@ void mahaf_UnmapPhysicalMemory(void* virtualAddress)
|
||||
}
|
||||
|
||||
|
||||
bool mahaf_CopyPhysicalMemory(uintptr_t physicalAddress, size_t numBytes, void* buffer)
|
||||
{
|
||||
AkenCopyPhysicalIn in;
|
||||
in.physicalAddress = (DWORD64)physicalAddress;
|
||||
in.numBytes = (DWORD64)numBytes;
|
||||
in.userAddress = (DWORD64)buffer;
|
||||
|
||||
DWORD bytesReturned;
|
||||
LPOVERLAPPED ovl = 0; // synchronous
|
||||
BOOL ok = DeviceIoControl(hAken, (DWORD)IOCTL_AKEN_COPY_PHYSICAL, &in, sizeof(in), 0, 0, &bytesReturned, ovl);
|
||||
if(!ok)
|
||||
{
|
||||
WARN_WIN32_ERR;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// driver installation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -24,12 +24,7 @@ extern void mahaf_WritePort8 (u16 port, u8 value);
|
||||
extern void mahaf_WritePort16(u16 port, u16 value);
|
||||
extern void mahaf_WritePort32(u16 port, u32 value);
|
||||
|
||||
extern void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes);
|
||||
extern void mahaf_UnmapPhysicalMemory(void* virtualAddress);
|
||||
|
||||
/**
|
||||
* @return false on failure (insufficient paged pool?)
|
||||
**/
|
||||
extern bool mahaf_CopyPhysicalMemory(uintptr_t physicalAddress, size_t numBytes, void* buffer);
|
||||
extern volatile void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes);
|
||||
extern void mahaf_UnmapPhysicalMemory(volatile void* virtualAddress);
|
||||
|
||||
#endif // INCLUDED_MAHAF
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
virtual double NominalFrequency() const = 0;
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ uint CounterHPET::CounterBits() const
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
double CounterHPET::NominalFrequency() const
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
virtual double NominalFrequency() const;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ uint CounterPMT::CounterBits() const
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
double CounterPMT::NominalFrequency() const
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
virtual double NominalFrequency() const;
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ uint CounterQPC::CounterBits() const
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
double CounterQPC::NominalFrequency() const
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
virtual double NominalFrequency() const;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ uint CounterTGT::CounterBits() const
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
double CounterTGT::NominalFrequency() const
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
virtual double NominalFrequency() const;
|
||||
|
||||
|
||||
@@ -147,9 +147,9 @@ uint CounterTSC::CounterBits() const
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
double CounterTSC::NominalFrequency() const
|
||||
{
|
||||
return cpu_ClockFrequency();
|
||||
return wcpu_ClockFrequency();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
|
||||
/**
|
||||
* initial measurement of the tick rate. not necessarily correct
|
||||
* (e.g. when using TSC: cpu_ClockFrequency isn't exact).
|
||||
* (e.g. when using TSC: wcpu_ClockFrequency isn't exact).
|
||||
**/
|
||||
virtual double NominalFrequency() const;
|
||||
};
|
||||
|
||||
@@ -283,6 +283,9 @@ static LibError whrt_Init()
|
||||
|
||||
InitCounter();
|
||||
|
||||
// latch initial counter value so that timer starts at 0
|
||||
ts->counter = Counter(); // must come before UpdateTimerState
|
||||
|
||||
UpdateTimerState(); // must come before InitUpdateThread to avoid race
|
||||
|
||||
RETURN_ERR(InitUpdateThread());
|
||||
|
||||
@@ -141,7 +141,7 @@ LibError win_get_snd_info()
|
||||
// find all DLLs related to OpenAL, retrieve their versions,
|
||||
// and store in snd_drv_ver string.
|
||||
wdll_ver_list_init(snd_drv_ver, SND_DRV_VER_LEN);
|
||||
if(!wutil_IsVista())
|
||||
if(wutil_WindowsVersion() < WUTIL_VERSION_VISTA)
|
||||
(void)wdll_ver_list_add(GetDirectSoundDriverPath());
|
||||
StringSet dlls; // ensures uniqueness
|
||||
(void)add_oal_dlls_in_dir(win_exe_dir, &dlls);
|
||||
|
||||
@@ -228,7 +228,8 @@ static void EnableLowFragmentationHeap()
|
||||
//-----------------------------------------------------------------------------
|
||||
// version
|
||||
|
||||
static char versionString[20];
|
||||
static char windowsVersionString[20];
|
||||
static uint windowsVersion; // see WUTIL_VERSION_*
|
||||
|
||||
static void DetectWindowsVersion()
|
||||
{
|
||||
@@ -237,8 +238,14 @@ static void DetectWindowsVersion()
|
||||
HKEY hKey;
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = ARRAY_SIZE(versionString);
|
||||
(void)RegQueryValueEx(hKey, "CurrentVersion", 0, 0, (LPBYTE)versionString, &size);
|
||||
DWORD size = ARRAY_SIZE(windowsVersionString);
|
||||
(void)RegQueryValueEx(hKey, "CurrentVersion", 0, 0, (LPBYTE)windowsVersionString, &size);
|
||||
|
||||
uint major = 0, minor = 0;
|
||||
int ret = sscanf(windowsVersionString, "%d.%d", &major, &minor);
|
||||
debug_assert(ret == 2);
|
||||
debug_assert(major <= 0xFF && minor <= 0xFF);
|
||||
windowsVersion = (major << 8) | minor;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
@@ -248,16 +255,17 @@ static void DetectWindowsVersion()
|
||||
|
||||
const char* wutil_WindowsVersionString()
|
||||
{
|
||||
debug_assert(versionString[0] != '\0');
|
||||
return versionString;
|
||||
debug_assert(windowsVersionString[0] != '\0');
|
||||
return windowsVersionString;
|
||||
}
|
||||
|
||||
bool wutil_IsVista()
|
||||
uint wutil_WindowsVersion()
|
||||
{
|
||||
debug_assert(versionString[0] != '\0');
|
||||
return (versionString[0] >= '6');
|
||||
debug_assert(windowsVersion != 0);
|
||||
return windowsVersion;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Wow64
|
||||
|
||||
|
||||
@@ -99,7 +99,12 @@ extern char win_exe_dir[MAX_PATH+1];
|
||||
//
|
||||
|
||||
extern const char* wutil_WindowsVersionString();
|
||||
extern bool wutil_IsVista();
|
||||
|
||||
// (same format as WINVER)
|
||||
const uint WUTIL_VERSION_XP = 0x0501;
|
||||
const uint WUTIL_VERSION_VISTA = 0x0600;
|
||||
|
||||
extern uint wutil_WindowsVersion();
|
||||
|
||||
|
||||
//
|
||||
|
||||
@@ -52,7 +52,9 @@ double get_time()
|
||||
{
|
||||
double t;
|
||||
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
#if OS_WIN
|
||||
t = whrt_Time();
|
||||
#elif HAVE_CLOCK_GETTIME
|
||||
struct timespec cur;
|
||||
(void)clock_gettime(CLOCK_REALTIME, &cur);
|
||||
t = (cur.tv_sec - start.tv_sec) + (cur.tv_nsec - start.tv_nsec)*1e-9;
|
||||
@@ -60,8 +62,6 @@ double get_time()
|
||||
struct timeval cur;
|
||||
gettimeofday(&cur, 0);
|
||||
t = (cur.tv_sec - start.tv_sec) + (cur.tv_usec - start.tv_usec)*1e-6;
|
||||
#elif OS_WIN
|
||||
t = whrt_Time();
|
||||
#else
|
||||
# error "get_time: add timer implementation for this platform!"
|
||||
#endif
|
||||
|
||||
@@ -43,7 +43,7 @@ private:
|
||||
CCamera dummyCamera;
|
||||
};
|
||||
|
||||
struct SimState;
|
||||
class SimState;
|
||||
|
||||
class ViewGame : public View
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user