📄 ntoskernel_io.c
字号:
/* * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#include "ntoskernel.h"#include "ndis.h"#include "wrapndis.h"#include "usb.h"#include "loader.h"extern NT_SPIN_LOCK ntoskernel_lock;extern NT_SPIN_LOCK irp_cancel_lock;extern struct nt_list object_list;wstdcall void WIN_FUNC(IoAcquireCancelSpinLock,1) (KIRQL *irql){ *irql = nt_spin_lock_irql(&irp_cancel_lock, DISPATCH_LEVEL);}wstdcall void WIN_FUNC(IoReleaseCancelSpinLock,1) (KIRQL irql){ nt_spin_unlock_irql(&irp_cancel_lock, irql);}wstdcall int WIN_FUNC(IoIsWdmVersionAvailable,2) (UCHAR major, UCHAR minor){ IOENTER("%d, %x", major, minor); if ((major == 6 && minor == 0x00) || // Vista (major == 1 && (minor == 0x30 || // Windows 2003 minor == 0x20 || // Windows XP minor == 0x10))) // Windows 2000 IOEXIT(return TRUE); IOEXIT(return FALSE);}wstdcall BOOLEAN WIN_FUNC(IoIs32bitProcess,1) (struct irp *irp){#ifdef CONFIG_X86_64 return FALSE;#else return TRUE;#endif}wstdcall void WIN_FUNC(IoInitializeIrp,3) (struct irp *irp, USHORT size, CCHAR stack_count){ IOENTER("irp: %p, %d, %d", irp, size, stack_count); memset(irp, 0, size); irp->size = size; irp->stack_count = stack_count; irp->current_location = stack_count; IoGetCurrentIrpStackLocation(irp) = IRP_SL(irp, stack_count); IOEXIT(return);}wstdcall void WIN_FUNC(IoReuseIrp,2) (struct irp *irp, NTSTATUS status){ IOENTER("%p, %d", irp, status); if (irp) { UCHAR alloc_flags; alloc_flags = irp->alloc_flags; IoInitializeIrp(irp, irp->size, irp->stack_count); irp->alloc_flags = alloc_flags; irp->io_status.status = status; } IOEXIT(return);}wstdcall struct irp *WIN_FUNC(IoAllocateIrp,2) (char stack_count, BOOLEAN charge_quota){ struct irp *irp; int irp_size; IOENTER("count: %d", stack_count); stack_count++; irp_size = IoSizeOfIrp(stack_count); irp = kmalloc(irp_size, gfp_irql()); if (irp) IoInitializeIrp(irp, irp_size, stack_count); IOTRACE("irp %p", irp); IOEXIT(return irp);}wstdcall BOOLEAN WIN_FUNC(IoCancelIrp,1) (struct irp *irp){ typeof(irp->cancel_routine) cancel_routine; /* NB: this function may be called at DISPATCH_LEVEL */ IOTRACE("irp: %p", irp); if (!irp) return FALSE; DUMP_IRP(irp); IoAcquireCancelSpinLock(&irp->cancel_irql); cancel_routine = xchg(&irp->cancel_routine, NULL); IOTRACE("%p", cancel_routine); irp->cancel = TRUE; if (cancel_routine) { struct io_stack_location *irp_sl; irp_sl = IoGetCurrentIrpStackLocation(irp); IOTRACE("%p, %p", irp_sl, irp_sl->dev_obj); /* cancel_routine will release the spin lock */ LIN2WIN2(cancel_routine, irp_sl->dev_obj, irp); /* in usb's cancel, irp->cancel is set to indicate * status of cancel */ IOEXIT(return xchg(&irp->cancel, TRUE)); } else { IOTRACE("irp %p already canceled", irp); IoReleaseCancelSpinLock(irp->cancel_irql); IOEXIT(return FALSE); }}wstdcall void IoQueueThreadIrp(struct irp *irp){ struct nt_thread *thread; KIRQL irql; thread = get_current_nt_thread(); if (thread) { IOTRACE("thread: %p, task: %p", thread, thread->task); irp->flags |= IRP_SYNCHRONOUS_API; irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); InsertTailList(&thread->irps, &irp->thread_list); IoIrpThread(irp) = thread; nt_spin_unlock_irql(&thread->lock, irql); } else IoIrpThread(irp) = NULL;}wstdcall void IoDequeueThreadIrp(struct irp *irp){ struct nt_thread *thread; KIRQL irql; thread = IoIrpThread(irp); if (thread) { irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); RemoveEntryList(&irp->thread_list); nt_spin_unlock_irql(&thread->lock, irql); }}wstdcall void WIN_FUNC(IoFreeIrp,1) (struct irp *irp){ IOENTER("irp = %p", irp); if (irp->flags & IRP_SYNCHRONOUS_API) IoDequeueThreadIrp(irp); kfree(irp); IOEXIT(return);}wstdcall struct irp *WIN_FUNC(IoBuildAsynchronousFsdRequest,6) (ULONG major_fn, struct device_object *dev_obj, void *buffer, ULONG length, LARGE_INTEGER *offset, struct io_status_block *user_status){ struct irp *irp; struct io_stack_location *irp_sl; IOENTER("%p", dev_obj); if (!dev_obj) IOEXIT(return NULL); irp = IoAllocateIrp(dev_obj->stack_count, FALSE); if (irp == NULL) { WARNING("couldn't allocate irp"); IOEXIT(return NULL); } irp_sl = IoGetNextIrpStackLocation(irp); irp_sl->major_fn = major_fn; IOTRACE("major_fn: %d", major_fn); irp_sl->minor_fn = 0; irp_sl->flags = 0; irp_sl->control = 0; irp_sl->dev_obj = dev_obj; irp_sl->file_obj = NULL; irp_sl->completion_routine = NULL; if (dev_obj->flags & DO_DIRECT_IO) { irp->mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, irp); if (irp->mdl == NULL) { IoFreeIrp(irp); return NULL; } MmProbeAndLockPages(irp->mdl, KernelMode, major_fn == IRP_MJ_WRITE ? IoReadAccess : IoWriteAccess); IOTRACE("mdl: %p", irp->mdl); } else if (dev_obj->flags & DO_BUFFERED_IO) { irp->associated_irp.system_buffer = buffer; irp->flags = IRP_BUFFERED_IO; irp->mdl = NULL; IOTRACE("buffer: %p", buffer); } if (major_fn == IRP_MJ_READ) { irp_sl->params.read.length = length; irp_sl->params.read.byte_offset = *offset; } else if (major_fn == IRP_MJ_WRITE) { irp_sl->params.write.length = length; irp_sl->params.write.byte_offset = *offset; } irp->user_status = user_status; IOTRACE("irp: %p", irp); return irp;}wstdcall struct irp *WIN_FUNC(IoBuildSynchronousFsdRequest,7) (ULONG major_fn, struct device_object *dev_obj, void *buf, ULONG length, LARGE_INTEGER *offset, struct nt_event *event, struct io_status_block *user_status){ struct irp *irp; irp = IoBuildAsynchronousFsdRequest(major_fn, dev_obj, buf, length, offset, user_status); if (irp == NULL) return NULL; irp->user_event = event; IoQueueThreadIrp(irp); return irp;}wstdcall struct irp *WIN_FUNC(IoBuildDeviceIoControlRequest,9) (ULONG ioctl, struct device_object *dev_obj, void *input_buf, ULONG input_buf_len, void *output_buf, ULONG output_buf_len, BOOLEAN internal_ioctl, struct nt_event *event, struct io_status_block *io_status){ struct irp *irp; struct io_stack_location *irp_sl; ULONG buf_len; IOENTER("%p, 0x%08x, %d", dev_obj, ioctl, internal_ioctl); if (!dev_obj) IOEXIT(return NULL); irp = IoAllocateIrp(dev_obj->stack_count, FALSE); if (irp == NULL) { WARNING("couldn't allocate irp"); return NULL; } irp_sl = IoGetNextIrpStackLocation(irp); irp_sl->params.dev_ioctl.code = ioctl; irp_sl->params.dev_ioctl.input_buf_len = input_buf_len; irp_sl->params.dev_ioctl.output_buf_len = output_buf_len; irp_sl->major_fn = (internal_ioctl) ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; IOTRACE("%d", IO_METHOD_FROM_CTL_CODE(ioctl)); switch (IO_METHOD_FROM_CTL_CODE(ioctl)) { case METHOD_BUFFERED: buf_len = max(input_buf_len, output_buf_len); if (buf_len) { irp->associated_irp.system_buffer = ExAllocatePoolWithTag(NonPagedPool, buf_len, 0); if (!irp->associated_irp.system_buffer) { IoFreeIrp(irp); IOEXIT(return NULL); } irp->associated_irp.system_buffer = input_buf; if (input_buf) memcpy(irp->associated_irp.system_buffer, input_buf, input_buf_len); irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; if (output_buf) irp->flags = IRP_INPUT_OPERATION; irp->user_buf = output_buf; } else irp->user_buf = NULL; break; case METHOD_IN_DIRECT: case METHOD_OUT_DIRECT: if (input_buf) { irp->associated_irp.system_buffer = ExAllocatePoolWithTag(NonPagedPool, input_buf_len, 0); if (!irp->associated_irp.system_buffer) { IoFreeIrp(irp); IOEXIT(return NULL); } memcpy(irp->associated_irp.system_buffer, input_buf, input_buf_len); irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; } /* TODO: we are supposed to setup MDL, but USB layer * doesn't use MDLs. Moreover, USB layer mirrors * non-DMAable buffers, so no need to allocate * DMAable buffer here */ if (output_buf) { irp->associated_irp.system_buffer = ExAllocatePoolWithTag(NonPagedPool, output_buf_len, 0); if (!irp->associated_irp.system_buffer) { IoFreeIrp(irp); IOEXIT(return NULL); } irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; } break; case METHOD_NEITHER: irp->user_buf = output_buf; irp_sl->params.dev_ioctl.type3_input_buf = input_buf; break; } irp->user_status = io_status; irp->user_event = event; IoQueueThreadIrp(irp); IOTRACE("irp: %p", irp); IOEXIT(return irp);}wfastcall NTSTATUS WIN_FUNC(IofCallDriver,2) (struct device_object *dev_obj, struct irp *irp){ struct io_stack_location *irp_sl; NTSTATUS status; driver_dispatch_t *major_func; struct driver_object *drv_obj; IOTRACE("%p, %p, %p, %d, %d, %p", dev_obj, irp, dev_obj->drv_obj, irp->current_location, irp->stack_count, IoGetCurrentIrpStackLocation(irp)); if (irp->current_location <= 0) { ERROR("invalid irp: %p, %d", irp, irp->current_location); return STATUS_INVALID_PARAMETER; } IoSetNextIrpStackLocation(irp); DUMP_IRP(irp); irp_sl = IoGetCurrentIrpStackLocation(irp); drv_obj = dev_obj->drv_obj; irp_sl->dev_obj = dev_obj; major_func = drv_obj->major_func[irp_sl->major_fn]; IOTRACE("major_func: %p, dev_obj: %p", major_func, dev_obj); if (major_func) status = LIN2WIN2(major_func, dev_obj, irp); else { ERROR("major_function %d is not implemented", irp_sl->major_fn); status = STATUS_NOT_SUPPORTED; } IOEXIT(return status);}wfastcall void WIN_FUNC(IofCompleteRequest,2) (struct irp *irp, CHAR prio_boost){#ifdef IO_DEBUG DUMP_IRP(irp); if (irp->io_status.status == STATUS_PENDING) { ERROR("invalid irp: %p, STATUS_PENDING", irp); return; } if (irp->current_location < 0) { ERROR("invalid irp: %p, %d", irp, irp->current_location); return; }#endif while (irp->current_location < irp->stack_count) { struct io_stack_location *irp_sl; struct device_object *dev_obj; NTSTATUS status; irp_sl = IoGetCurrentIrpStackLocation(irp); DUMP_IRP(irp); if (irp_sl->control & SL_PENDING_RETURNED) irp->pending_returned = TRUE; /* current_location and dev_obj must be same as when * driver called IoSetCompletionRoutine, which sets * completion routine at next (lower) location, which * is what we are going to call below; so we set * current_location and dev_obj for the previous * (higher) location */ IoSkipCurrentIrpStackLocation(irp); if (irp->current_location < irp->stack_count) dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; else dev_obj = NULL; IOTRACE("%d, %d, %p", irp->current_location, irp->stack_count, dev_obj); if (irp_sl->completion_routine && ((irp->io_status.status == STATUS_SUCCESS && irp_sl->control & SL_INVOKE_ON_SUCCESS) || (irp->io_status.status != STATUS_SUCCESS && irp_sl->control & SL_INVOKE_ON_ERROR) || (irp->cancel == TRUE && irp_sl->control & SL_INVOKE_ON_CANCEL))) { IOTRACE("calling completion_routine at: %p, %p", irp_sl->completion_routine, irp_sl->context); status = LIN2WIN3(irp_sl->completion_routine, dev_obj, irp, irp_sl->context); IOTRACE("status: %08X", status); if (status == STATUS_MORE_PROCESSING_REQUIRED) IOEXIT(return); } else { /* propagate pending status to next irp_sl */ if (irp->pending_returned && irp->current_location < irp->stack_count) IoMarkIrpPending(irp); } } if (irp->user_status) { irp->user_status->status = irp->io_status.status; irp->user_status->info = irp->io_status.info; } if (irp->user_event) { IOTRACE("setting event %p", irp->user_event); KeSetEvent(irp->user_event, prio_boost, FALSE); } if (irp->associated_irp.system_buffer && (irp->flags & IRP_DEALLOCATE_BUFFER)) ExFreePool(irp->associated_irp.system_buffer); else { struct mdl *mdl; while ((mdl = irp->mdl)) { irp->mdl = mdl->next; MmUnlockPages(mdl); IoFreeMdl(mdl); } } IOTRACE("freeing irp %p", irp); IoFreeIrp(irp); IOEXIT(return);}wstdcall NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp){ IoSkipCurrentIrpStackLocation(irp); IOEXIT(return IoCallDriver(dev_obj, irp));}wstdcall NTSTATUS IoIrpSyncComplete(struct device_object *dev_obj, struct irp *irp, void *context){ if (irp->pending_returned == TRUE) KeSetEvent(context, IO_NO_INCREMENT, FALSE); IOEXIT(return STATUS_MORE_PROCESSING_REQUIRED);}WIN_FUNC_DECL(IoIrpSyncComplete,3)wstdcall NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, struct irp *irp){ struct nt_event event; NTSTATUS status; IoCopyCurrentIrpStackLocationToNext(irp); KeInitializeEvent(&event, SynchronizationEvent, FALSE); /* completion function is called as Windows function */ IoSetCompletionRoutine(irp, WIN_FUNC_PTR(IoIrpSyncComplete,3), &event, TRUE, TRUE, TRUE); status = IoCallDriver(dev_obj, irp); IOTRACE("%08X", status); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = irp->io_status.status; } IOTRACE("%08X", status); IOEXIT(return status);}WIN_FUNC_DECL(IoSyncForwardIrp,2)wstdcall NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, struct irp *irp){ NTSTATUS status; IoCopyCurrentIrpStackLocationToNext(irp); status = IoCallDriver(dev_obj, irp); IOEXIT(return status);}WIN_FUNC_DECL(IoAsyncForwardIrp,2)wstdcall NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, struct irp *irp){ struct io_stack_location *irp_sl; NTSTATUS status; irp_sl = IoGetCurrentIrpStackLocation(irp); WARNING("%d:%d not implemented", irp_sl->major_fn, irp_sl->minor_fn); irp->io_status.status = STATUS_SUCCESS; irp->io_status.info = 0; status = irp->io_status.status; IoCompleteRequest(irp, IO_NO_INCREMENT); IOEXIT(return status);}WIN_FUNC_DECL(IoInvalidDeviceRequest,2)static irqreturn_t io_irq_isr(int irq, void *data ISR_PT_REGS_PARAM_DECL){ struct kinterrupt *interrupt = data; BOOLEAN ret; nt_spin_lock(&interrupt->lock); ret = LIN2WIN2(interrupt->service_routine, interrupt, interrupt->service_context); nt_spin_unlock(&interrupt->lock); if (ret == TRUE) return IRQ_HANDLED; else return IRQ_NONE;}wstdcall NTSTATUS WIN_FUNC(IoConnectInterrupt,11) (struct kinterrupt **kinterrupt, PKSERVICE_ROUTINE service_routine, void *service_context, NT_SPIN_LOCK *lock, ULONG vector, KIRQL irql, KIRQL synch_irql, enum kinterrupt_mode interrupt_mode, BOOLEAN shareable, KAFFINITY processor_enable_mask, BOOLEAN floating_save){ struct kinterrupt *interrupt; IOENTER(""); interrupt = kmalloc(sizeof(*interrupt), GFP_KERNEL); if (!interrupt) IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); memset(interrupt, 0, sizeof(*interrupt)); interrupt->vector = vector; interrupt->processor_enable_mask = processor_enable_mask; nt_spin_lock_init(&interrupt->lock); if (lock) interrupt->actual_lock = lock; else interrupt->actual_lock = &interrupt->lock;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -