2025-04-27 07:49:33 -04:00

618 lines
16 KiB
C

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
ioctl.c
Abstract:
ACPI BIOS Simulator / Generic 3rd Party Operation Region Provider
IO Device Control Handler module
Create/Close File Handler module
Author(s):
Vincent Geglia
Michael T. Murphy
Chris Burgess
Environment:
Kernel mode
Notes:
Revision History:
--*/
//
// General includes
//
#include "ntddk.h"
#include "acpiioct.h"
//
// Specific includes
//
#include "asimlib.h"
#include "ioctl.h"
#include "opregion.h"
#include "util.h"
//
// Private function prototypes
//
NTSTATUS
AcpisimIoctlMethod
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
AcpisimIoctlMethodComplex
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
AcpisimIoctlLoadTable
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
//
// Irp dispatch routine handler function prototype
//
typedef
NTSTATUS
(*PIRP_DISPATCH_ROUTINE) (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
//
// Irp dispatch table definition
//
typedef struct _IRP_DISPATCH_TABLE {
ULONG IrpFunction;
TCHAR IrpName[50];
PIRP_DISPATCH_ROUTINE IrpHandler;
} IRP_DISPATCH_TABLE, *PIRP_DISPATCH_TABLE;
//
// IOCTL table
//
IOCTL_DISPATCH_TABLE IoctlDispatchTable [] = {
IOCTL_ACPISIM_METHOD, "IOCTL_ACPISIM_METHOD", AcpisimIoctlMethod,
IOCTL_ACPISIM_METHOD_COMPLEX, "IOCTL_ACPISIM_METHOD_COMPLEX", AcpisimIoctlMethodComplex,
IOCTL_ACPISIM_LOAD_TABLE, "IOCTL_ACPISIM_LOAD_TABLE", AcpisimIoctlLoadTable
};
NTSTATUS AcpisimHandleIoctl
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the handler for IOCTL requests. This is the "meat" of
the driver so to speak. All of the op-region accesses from user
mode are handled here. The implementer should perform the action
and return an appropriate status, or return STATUS_UNSUPPORTED if
the IOCTL is unrecognized.
Arguments:
DeviceObject - pointer to the device object the IRP pertains to
Irp - pointer to the IRP
Return Value:
result of IRP processing
--*/
{
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp);
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG count = 0;
DBG_PRINT (DBG_INFO, "Entering AcpisimHandleIoctl\n");
while (count < sizeof (IoctlDispatchTable) / sizeof (IOCTL_DISPATCH_TABLE)) {
if (irpsp->Parameters.DeviceIoControl.IoControlCode == IoctlDispatchTable[count].IoctlFunction) {
DBG_PRINT (DBG_INFO, "Recognized %s\n", IoctlDispatchTable[count].IoctlName);
status = IoctlDispatchTable[count].IoctlHandler (DeviceObject, Irp);
//
// We handled it, complete it.
//
goto ExitAcpisimDispatchIoctl;
}
count ++;
}
//
// If we get here, its because we don't recognize this IOCTL, simply pass it down.
//
status = STATUS_NOT_SUPPORTED;
ExitAcpisimDispatchIoctl:
DBG_PRINT (DBG_INFO, "Exiting AcpisimHandleIoctl\n");
return status;
}
NTSTATUS
AcpisimIoctlMethod
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine simply evaluates a method through IOCTL_ACPISIM_METHOD
calls.
Arguments:
DeviceObject - pointer to the device object the IRP pertains to
Irp - pointer to the IRP
Return Value:
result of IRP processing
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
UCHAR methodname[4];
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp);
DBG_PRINT (DBG_INFO, "Entering AcpisimIoctlMethod.\n");
RtlZeroMemory (&methodname, sizeof (methodname));
//
// Get the method we want to run
//
if (irpsp->Parameters.DeviceIoControl.InputBufferLength != 4 || (!Irp->AssociatedIrp.SystemBuffer && !irpsp->Parameters.DeviceIoControl.Type3InputBuffer)) {
DBG_PRINT (DBG_ERROR, "IOCTL not called correctly. Ignoring.\n");
goto ExitAcpisimIoctlMethod;
}
//
// We need to figure out where the data is coming from
//
if (Irp->AssociatedIrp.SystemBuffer) {
RtlCopyMemory (&methodname, Irp->AssociatedIrp.SystemBuffer, 4);
} else {
RtlCopyMemory (&methodname, irpsp->Parameters.DeviceIoControl.Type3InputBuffer, 4);
}
status = AcpisimEvalAcpiMethod (DeviceObject, methodname, 0);
ExitAcpisimIoctlMethod:
DBG_PRINT (DBG_INFO, "Exiting AcpisimIoctlMethod.\n");
return status;
}
NTSTATUS
AcpisimIoctlMethodComplex
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine simply evaluates a method through IOCTL_ACPISIM_METHOD
calls, but also takes arguments to pass to the ACPI method.
Arguments:
DeviceObject - pointer to the device object the IRP pertains to
Irp - pointer to the IRP
Return Value:
result of IRP processing
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PACPI_EVAL_INPUT_BUFFER_COMPLEX inputbuffer = 0;
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp);
DBG_PRINT (DBG_INFO, "Entering AcpisimIoctlMethodComplex.\n");
//
// Get the method we want to run
//
if (!irpsp->Parameters.DeviceIoControl.InputBufferLength || (!Irp->AssociatedIrp.SystemBuffer && !irpsp->Parameters.DeviceIoControl.Type3InputBuffer)) {
DBG_PRINT (DBG_ERROR, "IOCTL not called correctly. Ignoring.\n");
goto ExitAcpisimIoctlMethodComplex;
}
inputbuffer = (PACPI_EVAL_INPUT_BUFFER_COMPLEX) ExAllocatePoolWithTag (
NonPagedPool,
irpsp->Parameters.DeviceIoControl.InputBufferLength,
ACPISIM_TAG
);
if (!inputbuffer) {
DBG_PRINT (DBG_ERROR, "Error allocating memory.\n");
goto ExitAcpisimIoctlMethodComplex;
}
//
// We need to figure out where the data is coming from
//
if (Irp->AssociatedIrp.SystemBuffer) {
RtlCopyMemory (inputbuffer, Irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.DeviceIoControl.InputBufferLength);
} else {
RtlCopyMemory (inputbuffer, irpsp->Parameters.DeviceIoControl.Type3InputBuffer, irpsp->Parameters.DeviceIoControl.InputBufferLength);
}
status = AcpisimEvalAcpiMethodComplex (DeviceObject, inputbuffer, 0);
ExitAcpisimIoctlMethodComplex:
if (inputbuffer) {
ExFreePool (inputbuffer);
}
DBG_PRINT (DBG_INFO, "Exiting AcpisimIoctlMethodComplex.\n");
return status;
}
NTSTATUS
AcpisimIoctlLoadTable
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp);
PACPISIM_LOAD_TABLE loadtable = 0;
HANDLE filehandle = 0;
OBJECT_ATTRIBUTES fileobject;
UNICODE_STRING filename;
ANSI_STRING filenameansi;
IO_STATUS_BLOCK iostatus;
FILE_STANDARD_INFORMATION fileinformation;
PACPI_EVAL_INPUT_BUFFER_COMPLEX inputbuffer = 0;
PHYSICAL_ADDRESS physicaladdress;
ULONG size = 0;
PACPI_METHOD_ARGUMENT argument = 0;
PVOID LoadTablePtr = 0;
ULONG LoadTableSize = 0;
DBG_PRINT (DBG_INFO, "Entering AcpisimIoctlLoadTable.\n");
//
// Make sure the IOCTL is formed correctly
//
if (irpsp->Parameters.DeviceIoControl.InputBufferLength < 4 ||
(!Irp->AssociatedIrp.SystemBuffer && !irpsp->Parameters.DeviceIoControl.Type3InputBuffer)) {
DBG_PRINT (DBG_ERROR, "IOCTL not called correctly. Ignoring.\n");
goto ExitAcpisimIoctlLoadTable;
}
loadtable = (PACPISIM_LOAD_TABLE) ExAllocatePoolWithTag (
NonPagedPool,
irpsp->Parameters.DeviceIoControl.InputBufferLength,
ACPISIM_TAG
);
if (!loadtable) {
DBG_PRINT (DBG_ERROR, "Error allocating memory.\n");
goto ExitAcpisimIoctlLoadTable;
}
//
// We need to figure out where the data is coming from
//
if (Irp->AssociatedIrp.SystemBuffer) {
RtlCopyMemory (loadtable, Irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.DeviceIoControl.InputBufferLength);
} else {
RtlCopyMemory (loadtable, irpsp->Parameters.DeviceIoControl.Type3InputBuffer, irpsp->Parameters.DeviceIoControl.InputBufferLength);
}
if (loadtable->Signature != ACPISIM_LOAD_TABLE_SIGNATURE) {
DBG_PRINT (DBG_ERROR, "IOCTL_ACPISIM_LOAD_TABLE passed in, but signature doesn't match. Ignoring...\n");
goto ExitAcpisimIoctlLoadTable;
}
//
// Set up the file name path
//
RtlInitAnsiString (
&filenameansi,
loadtable->Filepath
);
if (!NT_SUCCESS (RtlAnsiStringToUnicodeString (
&filename,
&filenameansi,
TRUE
)))
{
DBG_PRINT (DBG_ERROR, "Unable to allocate string.\n");
goto ExitAcpisimIoctlLoadTable;
}
InitializeObjectAttributes (
&fileobject,
&filename,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the file
//
status = ZwOpenFile (
&filehandle,
FILE_ALL_ACCESS,
&fileobject,
&iostatus,
0,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS (status)) {
DBG_PRINT (DBG_ERROR, "Unable to open %s (%lx).\n", loadtable->Filepath, status);
goto ExitAcpisimIoctlLoadTable;
}
//
// Get the file size
//
status = ZwQueryInformationFile (
filehandle,
&iostatus,
&fileinformation,
sizeof (FILE_STANDARD_INFORMATION),
FileStandardInformation
);
if (!NT_SUCCESS (status)) {
DBG_PRINT (DBG_ERROR, "Unable to query %s (%lx).\n", loadtable->Filepath, status);
goto ExitAcpisimIoctlLoadTable;
}
//
// We don't handle the case where the table is actually larger then
// 4GB.
//
if (fileinformation.EndOfFile.HighPart) {
DBG_PRINT (DBG_ERROR, "Table size exceeds 4GB!. Ignoring.\n");
goto ExitAcpisimIoctlLoadTable;
}
LoadTablePtr = ExAllocatePoolWithTag (
NonPagedPool,
fileinformation.EndOfFile.LowPart,
ACPISIM_TAG
);
if (!LoadTablePtr) {
DBG_PRINT (DBG_ERROR, "Unable to allocate memory for ACPI table.\n");
goto ExitAcpisimIoctlLoadTable;
}
//
// Read in the file
//
status = ZwReadFile (
filehandle,
NULL,
NULL,
NULL,
&iostatus,
LoadTablePtr,
fileinformation.EndOfFile.LowPart,
0,
NULL
);
if (!NT_SUCCESS (status)) {
DBG_PRINT (DBG_ERROR, "Unable to read %s (%lx).\n", loadtable->Filepath, status);
goto ExitAcpisimIoctlLoadTable;
}
LoadTableSize = fileinformation.EndOfFile.LowPart;
//
// Get the address of the table we just loaded into memory
//
physicaladdress = MmGetPhysicalAddress (LoadTablePtr);
//
// Make sure the table is in 32bit address space (ACPI 1.0 doesn't
// support 64bit addresses)
//
if (physicaladdress.HighPart) {
DBG_PRINT (DBG_ERROR, "SSDT is outside 32bit address range. Ignoring.\n");
goto ExitAcpisimIoctlLoadTable;
}
//
// Let's get our input buffer set up
//
size = sizeof (ACPI_EVAL_INPUT_BUFFER_COMPLEX) + (sizeof (ACPI_METHOD_ARGUMENT) * 2);
inputbuffer = ExAllocatePoolWithTag (
NonPagedPool,
size,
ACPISIM_TAG
);
if (!inputbuffer) {
DBG_PRINT (DBG_ERROR, "Unable to allocate memory for input buffer.\n");
goto ExitAcpisimIoctlLoadTable;
}
//
// We need to pass the physical address of our table into the LDTB
// method.
//
inputbuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
RtlCopyMemory (inputbuffer->MethodName, "LDTB", 4);
inputbuffer->Size = size;
inputbuffer->ArgumentCount = 3;
argument = inputbuffer->Argument;
argument->Type = ACPI_METHOD_ARGUMENT_INTEGER;
argument->DataLength = sizeof (ULONG);
argument->Argument = physicaladdress.LowPart;
//
// We also need to pass the size of the table into the LDTB method
//
argument = ACPI_METHOD_NEXT_ARGUMENT (argument);
argument->Type = ACPI_METHOD_ARGUMENT_INTEGER;
argument->DataLength = sizeof (ULONG);
argument->Argument = LoadTableSize;
//
// Next, we tell it which "slot" to use
//
argument = ACPI_METHOD_NEXT_ARGUMENT (argument);
argument->Type = ACPI_METHOD_ARGUMENT_INTEGER;
argument->DataLength = sizeof (ULONG);
argument->Argument = loadtable->TableNumber;
//
// Ok, now let's evaluate the method to load the table
//
status = AcpisimEvalAcpiMethodComplex (DeviceObject, inputbuffer, 0);
if (!NT_SUCCESS (status)) {
DBG_PRINT (DBG_ERROR, "Unable to evaluate LDTB method (%lx).\n", status);
goto ExitAcpisimIoctlLoadTable;
}
ExitAcpisimIoctlLoadTable:
//
// Cleanup
//
if (inputbuffer) {
ExFreePool (inputbuffer);
}
if (LoadTablePtr) {
ExFreePool (LoadTablePtr);
LoadTableSize = 0;
}
if (filename.Buffer) {
RtlFreeUnicodeString (&filename);
}
if (filehandle) {
ZwClose (filehandle);
}
if (loadtable) {
ExFreePool (loadtable);
}
DBG_PRINT (DBG_INFO, "Exiting AcpisimIoctlLoadTable.\n");
return status;
}