forked from mirrors/0ad
updated version of Aken that includes support for MSR and static validation (-> .c instead of .cpp)
closes #754 (please re-open if not) This was SVN commit r9137.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,19 +20,26 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
extern "C" { // must come before ntddk.h
|
||||
// note: staticdv cannot yet check C++ code.
|
||||
|
||||
#include <ntddk.h>
|
||||
#include "aken.h"
|
||||
#include "intrinsics.h"
|
||||
|
||||
#define WIN32_NAME L"\\DosDevices\\Aken"
|
||||
#define DEVICE_NAME L"\\Device\\Aken"
|
||||
|
||||
// placate PREfast
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH AkenCreate;
|
||||
__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH AkenClose;
|
||||
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH AkenDeviceControl;
|
||||
DRIVER_UNLOAD AkenUnload;
|
||||
|
||||
// this driver isn't large, but it's still slightly nicer to make its
|
||||
// functions pageable and thus not waste precious non-paged pool.
|
||||
// #pragma code_seg is more convenient than specifying alloc_text for
|
||||
// every other function.
|
||||
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING registryPath);
|
||||
#pragma alloc_text(INIT, DriverEntry) // => discardable
|
||||
#pragma code_seg(push, "PAGE")
|
||||
|
||||
@@ -75,25 +82,27 @@ note that we guess if the page will have been mapped as cacheable and
|
||||
even try the opposite if that turns out to have been incorrect.
|
||||
*/
|
||||
|
||||
static bool IsMemoryUncacheable(DWORD64 physicalAddress64)
|
||||
static int IsMemoryUncacheable(DWORD64 physicalAddress64)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
// original PC memory - contains BIOS
|
||||
if(physicalAddress64 < 0x100000)
|
||||
return true;
|
||||
return 1;
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWORD64 numBytes64, DWORD64& virtualAddress64)
|
||||
static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWORD64 numBytes64, DWORD64* virtualAddress64)
|
||||
{
|
||||
NTSTATUS ntStatus;
|
||||
|
||||
// (convenience)
|
||||
LARGE_INTEGER physicalAddress;
|
||||
HANDLE hMemory;
|
||||
LARGE_INTEGER physicalAddress; // convenience
|
||||
physicalAddress.QuadPart = physicalAddress64;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// get handle to PhysicalMemory object
|
||||
HANDLE hMemory;
|
||||
{
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
UNICODE_STRING objectName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
|
||||
@@ -151,9 +160,11 @@ static NTSTATUS AkenMapPhysicalMemory(const DWORD64 physicalAddress64, const DWO
|
||||
|
||||
// the mapping rounded our physical base address down to the nearest
|
||||
// 64KiB boundary, so adjust the virtual address accordingly.
|
||||
{
|
||||
const DWORD32 numBytesRoundedDown = physicalAddress.LowPart - physicalBaseAddress.LowPart;
|
||||
ASSERT(numBytesRoundedDown < 0x10000);
|
||||
virtualAddress64 = (DWORD64)virtualBaseAddress + numBytesRoundedDown;
|
||||
*virtualAddress64 = (DWORD64)virtualBaseAddress + numBytesRoundedDown;
|
||||
}
|
||||
}
|
||||
|
||||
ntStatus = STATUS_SUCCESS;
|
||||
@@ -170,6 +181,9 @@ close_handle:
|
||||
|
||||
static NTSTATUS AkenUnmapPhysicalMemory(const DWORD64 virtualAddress)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
{
|
||||
const HANDLE hProcess = (HANDLE)-1;
|
||||
PVOID baseAddress = (PVOID)virtualAddress;
|
||||
NTSTATUS ntStatus = ZwUnmapViewOfSection(hProcess, baseAddress);
|
||||
@@ -178,6 +192,7 @@ static NTSTATUS AkenUnmapPhysicalMemory(const DWORD64 virtualAddress)
|
||||
KdPrint(("AkenUnmapPhysicalMemory: ZwUnmapViewOfSection failed\n"));
|
||||
return ntStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -187,15 +202,19 @@ static NTSTATUS AkenUnmapPhysicalMemory(const DWORD64 virtualAddress)
|
||||
// helper functions called from DeviceControl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static NTSTATUS AkenIoctlReadPort(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
static NTSTATUS AkenIoctlReadPort(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
if(inSize != sizeof(AkenReadPortIn) || outSize != sizeof(AkenReadPortOut))
|
||||
DWORD32 value;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenReadPortIn) || *outSize != sizeof(AkenReadPortOut))
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenReadPortIn* in = (const AkenReadPortIn*)buf;
|
||||
const USHORT port = in->port;
|
||||
const UCHAR numBytes = in->numBytes;
|
||||
DWORD32 value;
|
||||
switch(numBytes)
|
||||
{
|
||||
case 1:
|
||||
@@ -210,18 +229,23 @@ static NTSTATUS AkenIoctlReadPort(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
default:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
KdPrint(("AkenIoctlReadPort: port %x = %x\n", port, value));
|
||||
}
|
||||
|
||||
{
|
||||
AkenReadPortOut* out = (AkenReadPortOut*)buf;
|
||||
out->value = value;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlWritePort(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
static NTSTATUS AkenIoctlWritePort(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
if(inSize != sizeof(AkenWritePortIn) || outSize != 0)
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenWritePortIn) || *outSize != 0)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenWritePortIn* in = (const AkenWritePortIn*)buf;
|
||||
const DWORD32 value = in->value;
|
||||
const USHORT port = in->port;
|
||||
@@ -240,66 +264,153 @@ static NTSTATUS AkenIoctlWritePort(PVOID buf, const ULONG inSize, ULONG& outSize
|
||||
default:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
KdPrint(("AkenIoctlWritePort: port %x := %x\n", port, value));
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlMap(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
|
||||
static NTSTATUS AkenIoctlMap(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
if(inSize != sizeof(AkenMapIn) || outSize != sizeof(AkenMapOut))
|
||||
DWORD64 virtualAddress;
|
||||
NTSTATUS ntStatus;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenMapIn) || *outSize != sizeof(AkenMapOut))
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenMapIn* in = (const AkenMapIn*)buf;
|
||||
const DWORD64 physicalAddress = in->physicalAddress;
|
||||
const DWORD64 numBytes = in->numBytes;
|
||||
ntStatus = AkenMapPhysicalMemory(physicalAddress, numBytes, &virtualAddress);
|
||||
}
|
||||
|
||||
DWORD64 virtualAddress;
|
||||
NTSTATUS ntStatus = AkenMapPhysicalMemory(physicalAddress, numBytes, virtualAddress);
|
||||
|
||||
{
|
||||
AkenMapOut* out = (AkenMapOut*)buf;
|
||||
out->virtualAddress = virtualAddress;
|
||||
}
|
||||
return ntStatus;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlUnmap(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
static NTSTATUS AkenIoctlUnmap(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
if(inSize != sizeof(AkenUnmapIn) || outSize != 0)
|
||||
NTSTATUS ntStatus;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenUnmapIn) || *outSize != 0)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenUnmapIn* in = (const AkenUnmapIn*)buf;
|
||||
const DWORD64 virtualAddress = in->virtualAddress;
|
||||
NTSTATUS ntStatus = AkenUnmapPhysicalMemory(virtualAddress);
|
||||
ntStatus = AkenUnmapPhysicalMemory(virtualAddress);
|
||||
}
|
||||
|
||||
return ntStatus;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlUnknown(PVOID buf, const ULONG inSize, ULONG& outSize)
|
||||
|
||||
static NTSTATUS AkenIoctlReadModelSpecificRegister(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
DWORD64 value;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenReadRegisterIn) || *outSize != sizeof(AkenReadRegisterOut))
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenReadRegisterIn* in = (const AkenReadRegisterIn*)buf;
|
||||
const DWORD64 reg = in->reg;
|
||||
value = __readmsr((int)reg);
|
||||
}
|
||||
|
||||
{
|
||||
AkenReadRegisterOut* out = (AkenReadRegisterOut*)buf;
|
||||
out->value = value;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlWriteModelSpecificRegister(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenWriteRegisterIn) || *outSize != 0)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenWriteRegisterIn* in = (const AkenWriteRegisterIn*)buf;
|
||||
const DWORD64 reg = in->reg;
|
||||
const DWORD64 value = in->value;
|
||||
__writemsr((unsigned long)reg, value);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS AkenIoctlReadPerformanceMonitoringCounter(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
DWORD64 value;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if(inSize != sizeof(AkenReadRegisterIn) || *outSize != sizeof(AkenReadRegisterOut))
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
{
|
||||
const AkenReadRegisterIn* in = (const AkenReadRegisterIn*)buf;
|
||||
const DWORD64 reg = in->reg;
|
||||
value = __readpmc((unsigned long)reg);
|
||||
}
|
||||
|
||||
{
|
||||
AkenReadRegisterOut* out = (AkenReadRegisterOut*)buf;
|
||||
out->value = value;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS AkenIoctlUnknown(PVOID buf, const ULONG inSize, ULONG* outSize)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KdPrint(("AkenIoctlUnknown\n"));
|
||||
outSize = 0;
|
||||
|
||||
*outSize = 0;
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
|
||||
typedef NTSTATUS (*AkenIoctl)(PVOID buf, ULONG inSize, ULONG& outSize);
|
||||
typedef NTSTATUS (*AkenIoctl)(PVOID buf, ULONG inSize, ULONG* outSize);
|
||||
|
||||
static inline AkenIoctl AkenIoctlFromCode(ULONG ioctlCode)
|
||||
static AkenIoctl AkenIoctlFromCode(ULONG ioctlCode)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
switch(ioctlCode)
|
||||
{
|
||||
case IOCTL_AKEN_READ_PORT:
|
||||
return AkenIoctlReadPort;
|
||||
|
||||
case IOCTL_AKEN_WRITE_PORT:
|
||||
return AkenIoctlWritePort;
|
||||
|
||||
case IOCTL_AKEN_MAP:
|
||||
return AkenIoctlMap;
|
||||
|
||||
case IOCTL_AKEN_UNMAP:
|
||||
return AkenIoctlUnmap;
|
||||
|
||||
case IOCTL_AKEN_READ_MSR:
|
||||
return AkenIoctlReadModelSpecificRegister;
|
||||
case IOCTL_AKEN_WRITE_MSR:
|
||||
return AkenIoctlWriteModelSpecificRegister;
|
||||
|
||||
default:
|
||||
return AkenIoctlUnknown;
|
||||
}
|
||||
@@ -312,6 +423,8 @@ static inline AkenIoctl AkenIoctlFromCode(ULONG ioctlCode)
|
||||
|
||||
static NTSTATUS AkenCreate(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||
@@ -321,6 +434,8 @@ static NTSTATUS AkenCreate(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)
|
||||
|
||||
static NTSTATUS AkenClose(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
// same as AkenCreate ATM
|
||||
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
irp->IoStatus.Information = 0;
|
||||
@@ -331,6 +446,9 @@ static NTSTATUS AkenClose(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)
|
||||
|
||||
static NTSTATUS AkenDeviceControl(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
{
|
||||
// get buffer from IRP. all our IOCTLs are METHOD_BUFFERED, so buf is
|
||||
// allocated by the I/O manager and used for both input and output.
|
||||
PVOID buf = irp->AssociatedIrp.SystemBuffer;
|
||||
@@ -340,21 +458,26 @@ static NTSTATUS AkenDeviceControl(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)
|
||||
ULONG outSize = irpStack->Parameters.DeviceIoControl.OutputBufferLength; // modified by AkenIoctl*
|
||||
|
||||
const AkenIoctl akenIoctl = AkenIoctlFromCode(ioctlCode);
|
||||
const NTSTATUS ntStatus = akenIoctl(buf, inSize, outSize);
|
||||
const NTSTATUS ntStatus = akenIoctl(buf, inSize, &outSize);
|
||||
|
||||
irp->IoStatus.Information = outSize; // number of bytes to copy from buf to user's buffer
|
||||
irp->IoStatus.Status = ntStatus;
|
||||
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||
return ntStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static VOID AkenUnload(IN PDRIVER_OBJECT driverObject)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KdPrint(("AkenUnload\n"));
|
||||
|
||||
{
|
||||
UNICODE_STRING win32Name = RTL_CONSTANT_STRING(WIN32_NAME);
|
||||
IoDeleteSymbolicLink(&win32Name);
|
||||
}
|
||||
|
||||
if(driverObject->DeviceObject)
|
||||
IoDeleteDevice(driverObject->DeviceObject);
|
||||
@@ -401,5 +524,3 @@ NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registry
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // extern "C" {
|
||||
@@ -0,0 +1,32 @@
|
||||
@echo off
|
||||
REM ensure header is up to date (simpler than setting include path)
|
||||
copy ..\..\..\..\..\include\lib\sysdep\os\win\aken\aken.h
|
||||
|
||||
cmd /c build_single.bat chk x64
|
||||
cmd /c build_single.bat fre x64
|
||||
cmd /c build_single.bat chk x86
|
||||
REM must come last because each build_single.bat deletes aken.sys,
|
||||
REM and that is the final output name of this step
|
||||
cmd /c build_single.bat fre x86
|
||||
|
||||
cd amd64
|
||||
copy /y aken64*.pdb ..\..\..\..\..\..\..\bin\x64
|
||||
copy /y aken64*.sys ..\..\..\..\..\..\..\bin\x64
|
||||
cd ..
|
||||
|
||||
cd i386
|
||||
copy /y aken*.pdb ..\..\..\..\..\..\..\bin\Win32
|
||||
copy /y aken*.sys ..\..\..\..\..\..\..\bin\Win32
|
||||
cd ..
|
||||
|
||||
echo outputs copied to bin directory; will delete ALL output files after pressing a key
|
||||
pause
|
||||
if exist amd64 (rmdir /S /Q amd64)
|
||||
if exist i386 (rmdir /S /Q i386)
|
||||
if exist objchk_wnet_amd64 (rmdir /S /Q objchk_wnet_amd64)
|
||||
if exist objfre_wnet_amd64 (rmdir /S /Q objfre_wnet_amd64)
|
||||
if exist objchk_wnet_x86 (rmdir /S /Q objchk_wnet_x86)
|
||||
if exist objfre_wnet_x86 (rmdir /S /Q objfre_wnet_x86)
|
||||
if exist *.log (del /Q *.log)
|
||||
if exist *.err (del /Q *.err)
|
||||
if exist *.wrn (del /Q *.wrn)
|
||||
@@ -0,0 +1,67 @@
|
||||
@echo off
|
||||
REM build a single configuration ({chk,fre} x {x64,x64})
|
||||
REM (must be in a separate file to allow invoking in a new cmd - otherwise,
|
||||
REM setenv complains that the environment have already been set)
|
||||
REM arguments: chk|fre x64|x86
|
||||
if %1==chk (goto configOK)
|
||||
if %1==fre (goto configOK)
|
||||
echo first parameter must be either chk or fre
|
||||
goto :eof
|
||||
:configOK
|
||||
if %2==x64 (goto archOK)
|
||||
if %2==x86 (goto archOK)
|
||||
echo second parameter must be either x64 or x64
|
||||
goto :eof
|
||||
:archOK
|
||||
|
||||
|
||||
call C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1\ %1 %2 WNET
|
||||
e:
|
||||
cd \FOM_Work\Programmierung\lowlevel\src\sysdep\os\win\aken
|
||||
|
||||
|
||||
REM delete outputs to ensure they get rebuilt
|
||||
if %2==x64 (goto delete64) else (goto delete32)
|
||||
|
||||
:delete64
|
||||
if not exist amd64 (goto deleteEnd)
|
||||
cd amd64
|
||||
if exist aken.sys (del /Q aken.sys)
|
||||
if exist aken.pdb (del /Q aken.pdb)
|
||||
cd ..
|
||||
goto deleteEnd
|
||||
|
||||
:delete32
|
||||
if not exist i386 (goto deleteEnd)
|
||||
cd i386
|
||||
if exist aken.sys (del /Q aken.sys)
|
||||
if exist aken.pdb (del /Q aken.pdb)
|
||||
cd ..
|
||||
goto deleteEnd
|
||||
|
||||
:deleteEnd
|
||||
|
||||
|
||||
build
|
||||
|
||||
|
||||
REM rename outputs in preparation for build_all's copying them to the binaries directories
|
||||
if %2==x64 (goto rename64) else (goto rename32)
|
||||
|
||||
:rename64
|
||||
if not exist amd64 (goto renameEnd)
|
||||
cd amd64
|
||||
if %1==chk (ren aken.pdb aken64d.pdb) else (ren aken.pdb aken64.pdb)
|
||||
if %1==chk (ren aken.sys aken64d.sys) else (ren aken.sys aken64.sys)
|
||||
cd ..
|
||||
goto renameEnd
|
||||
|
||||
:rename32
|
||||
if not exist i386 (goto renameEnd)
|
||||
cd i386
|
||||
if %1==chk (ren aken.pdb akend.pdb)
|
||||
if %1==chk (ren aken.sys akend.sys)
|
||||
cd ..
|
||||
goto renameEnd
|
||||
|
||||
:renameEnd
|
||||
@@ -2,4 +2,4 @@ TARGETNAME=aken
|
||||
TARGETPATH=.
|
||||
TARGETTYPE=DRIVER
|
||||
|
||||
SOURCES=aken.cpp
|
||||
SOURCES=aken.c
|
||||
|
||||
Reference in New Issue
Block a user