1
0
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:
janwas
2011-04-01 15:06:52 +00:00
parent d5b3201bfe
commit 6026330fce
8 changed files with 626 additions and 406 deletions
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
+1 -1
View File
@@ -2,4 +2,4 @@ TARGETNAME=aken
TARGETPATH=.
TARGETTYPE=DRIVER
SOURCES=aken.cpp
SOURCES=aken.c