我有一个分配缓冲区的程序,该缓冲区的指针通过自定义 IOCTL 传递给内核驱动程序。在驱动程序中,我得到一个 Mdl 并使用“MmGetSystemAddressForMdlSafe”锁定用户程序缓冲区的页面,然后使用 Mdl 填充用户程序缓冲区。
如果在用户程序中缓冲区是一个普通数组,驱动程序总是按它应该的方式工作。(WORD 缓冲区[256],其中 word 是无符号短整数)
如果用户程序缓冲区不时使用 new 关键字(WORD *buffer = new WORD[256])
或 malloc 关键字分配,我会收到 BSOD 并且错误是“非分页区域中的页面错误”。(WORD *buffer=(WORD*) malloc(sizeof(*buffer)*256)))
为什么?
谢谢!
编辑(附加细节):
在驱动程序中我使用MmGetSystemAddressForMdlSafe
这种方式:
PVOID p_buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
Irp 是我在处理IRP_MJ_DEVICE_CONTROL
MajorFunction 时作为第二个参数接收的 PIRP。
在我检查它p_buffer
不为空之后,我使用该指针来写入用户缓冲区:
READ_PORT_BUFFER_USHORT((PUSHORT)(USHORT)current_port.address, (PUSHORT)p_buffer, 256)
IOCTL 定义:
#define IOCTL_TEST_READPORT CTL_CODE(FILE_DEVICE_TEST, \
TEST_IOCTL_INDEX + 0, \
METHOD_OUT_DIRECT, \
FILE_ANY_ACCESS)
处理的驱动程序函数IRP_MJ_DEVICE_CONTROL
:
NTSTATUS TESTDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
ULONG input_buffer_size;
ULONG output_buffer_size;
ULONG control_code;
PVOID p_buffer;
NTSTATUS nt_status;
struct port current_port;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
switch (IrpStack->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
control_code = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (control_code)
{
case IOCTL_TEST_READPORT:
p_buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
input_buffer_size = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
if (!p_buffer)
{
nt_status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
if (input_buffer_size)
{
memcpy (¤t_port, Irp->AssociatedIrp.SystemBuffer, input_buffer_size);
switch (current_port.size)
{
case 1:
current_port.value = (ULONG)READ_PORT_UCHAR((PUCHAR)(USHORT)current_port.address);
memcpy (p_buffer, ¤t_port.value, sizeof(current_port.value));
Irp->IoStatus.Information = sizeof(current_port.value);
break;
case 0xF0:
READ_PORT_BUFFER_USHORT((PUSHORT)(USHORT)current_port.address, (PUSHORT)p_buffer, 256);
Irp->IoStatus.Information = sizeof(current_port.value);
break;
case 2:
current_port.value = (ULONG)READ_PORT_USHORT((PUSHORT)(USHORT)current_port.address);
memcpy (p_buffer, ¤t_port.value, sizeof(current_port.value));
Irp->IoStatus.Information = sizeof(current_port.value);
break;
}
}
else
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
case IRP_MJ_CREATE:
KdPrint(("IRP_MJ_CREATE"));
break;
case IRP_MJ_CLOSE:
KdPrint(("IRP_MJ_CLOSE"));
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
break;
}
nt_status = Irp->IoStatus.Status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return nt_status;
}
相关案例在case 0xF0:
里面case IOCTL_TEST_READPORT: