📄 ntoskernel.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 "usb.h"#include "pnp.h"#include "loader.h"/* MDLs describe a range of virtual address with an array of physical * pages right after the header. For different ranges of virtual * addresses, the number of entries of physical pages may be different * (depending on number of entries required). If we want to allocate * MDLs from a pool, the size has to be constant. So we assume that * maximum range used by a driver is MDL_CACHE_PAGES; if a driver * requests an MDL for a bigger region, we allocate it with kmalloc; * otherwise, we allocate from the pool */#define MDL_CACHE_PAGES 3#define MDL_CACHE_SIZE (sizeof(struct mdl) + \ (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES))struct wrap_mdl { struct nt_list list; struct mdl mdl[0];};struct thread_event { struct task_struct *task; BOOLEAN done;};/* everything here is for all drivers/devices - not per driver/device */static NT_SPIN_LOCK dispatcher_lock;NT_SPIN_LOCK ntoskernel_lock;static void *mdl_cache;static struct nt_list wrap_mdl_list;static work_struct_t kdpc_work;static void kdpc_worker(worker_param_t dummy);static struct nt_list kdpc_list;static NT_SPIN_LOCK kdpc_list_lock;static struct nt_list callback_objects;struct nt_list object_list;struct bus_driver { struct nt_list list; char name[MAX_DRIVER_NAME_LEN]; struct driver_object drv_obj;};static struct nt_list bus_driver_list;static work_struct_t ntos_work;static struct nt_list ntos_work_list;static NT_SPIN_LOCK ntos_work_lock;static void ntos_work_worker(worker_param_t dummy);NT_SPIN_LOCK irp_cancel_lock;extern struct nt_list wrap_drivers;static struct nt_list wrap_timer_list;NT_SPIN_LOCK timer_lock;/* compute ticks (100ns) since 1601 until when system booted into * wrap_ticks_to_boot */u64 wrap_ticks_to_boot;#if defined(CONFIG_X86_64)static struct timer_list shared_data_timer;struct kuser_shared_data kuser_shared_data;static void update_user_shared_data_proc(unsigned long data);#endifWIN_SYMBOL_MAP("KeTickCount", &jiffies)WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE)#ifdef USE_OWN_NTOS_WORKQUEUEworkqueue_struct_t *ntos_wq;#endif#if defined(CONFIG_X86_64)static void update_user_shared_data_proc(unsigned long data){ /* timer is supposed to be scheduled every 10ms, but bigger * intervals seem to work (tried upto 50ms) */ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); *((ULONG64 *)&kuser_shared_data.interrupt_time) = jiffies * TICKSPERSEC / HZ; *((ULONG64 *)&kuser_shared_data.tick) = jiffies; mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30));}#endifvoid *allocate_object(ULONG size, enum common_object_type type, struct unicode_string *name){ struct common_object_header *hdr; void *body; KIRQL irql; /* we pad header as prefix to body */ hdr = ExAllocatePoolWithTag(NonPagedPool, OBJECT_SIZE(size), 0); if (!hdr) { WARNING("couldn't allocate memory"); return NULL; } memset(hdr, 0, OBJECT_SIZE(size)); if (name) { hdr->name.buf = ExAllocatePoolWithTag(NonPagedPool, name->max_length, 0); if (!hdr->name.buf) { ExFreePool(hdr); return NULL; } memcpy(hdr->name.buf, name->buf, name->max_length); hdr->name.length = name->length; hdr->name.max_length = name->max_length; } hdr->type = type; hdr->ref_count = 1; irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); /* threads are looked up often (in KeWaitForXXX), so optimize * for fast lookups of threads */ if (type == OBJECT_TYPE_NT_THREAD) InsertHeadList(&object_list, &hdr->list); else InsertTailList(&object_list, &hdr->list); nt_spin_unlock_irql(&ntoskernel_lock, irql); body = HEADER_TO_OBJECT(hdr); TRACE3("allocated hdr: %p, body: %p", hdr, body); return body;}void free_object(void *object){ struct common_object_header *hdr; KIRQL irql; hdr = OBJECT_TO_HEADER(object); irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); RemoveEntryList(&hdr->list); nt_spin_unlock_irql(&ntoskernel_lock, irql); TRACE3("freed hdr: %p, body: %p", hdr, object); if (hdr->name.buf) ExFreePool(hdr->name.buf); ExFreePool(hdr);}static int add_bus_driver(const char *name){ struct bus_driver *bus_driver; KIRQL irql; bus_driver = kmalloc(sizeof(*bus_driver), GFP_KERNEL); if (!bus_driver) { ERROR("couldn't allocate memory"); return -ENOMEM; } memset(bus_driver, 0, sizeof(*bus_driver)); strncpy(bus_driver->name, name, sizeof(bus_driver->name)); bus_driver->name[sizeof(bus_driver->name)-1] = 0; irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); InsertTailList(&bus_driver_list, &bus_driver->list); nt_spin_unlock_irql(&ntoskernel_lock, irql); TRACE1("bus driver %s is at %p", name, &bus_driver->drv_obj); return STATUS_SUCCESS;}struct driver_object *find_bus_driver(const char *name){ struct bus_driver *bus_driver; struct driver_object *drv_obj; KIRQL irql; irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); drv_obj = NULL; nt_list_for_each_entry(bus_driver, &bus_driver_list, list) { if (strcmp(bus_driver->name, name) == 0) drv_obj = &bus_driver->drv_obj; } nt_spin_unlock_irql(&ntoskernel_lock, irql); return drv_obj;}wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertHeadList,3) (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock){ struct nt_list *first; unsigned long flags; ENTER5("head = %p, entry = %p", head, entry); nt_spin_lock_irqsave(lock, flags); first = InsertHeadList(head, entry); nt_spin_unlock_irqrestore(lock, flags); TRACE5("head = %p, old = %p", head, first); return first;}wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertHeadList,3) (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock){ ENTER5("%p", head); return ExfInterlockedInsertHeadList(head, entry, lock);}wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertTailList,3) (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock){ struct nt_list *last; unsigned long flags; ENTER5("head = %p, entry = %p", head, entry); nt_spin_lock_irqsave(lock, flags); last = InsertTailList(head, entry); nt_spin_unlock_irqrestore(lock, flags); TRACE5("head = %p, old = %p", head, last); return last;}wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertTailList,3) (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock){ ENTER5("%p", head); return ExfInterlockedInsertTailList(head, entry, lock);}wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveHeadList,2) (struct nt_list *head, NT_SPIN_LOCK *lock){ struct nt_list *ret; unsigned long flags; ENTER5("head = %p", head); nt_spin_lock_irqsave(lock, flags); ret = RemoveHeadList(head); nt_spin_unlock_irqrestore(lock, flags); TRACE5("head = %p, ret = %p", head, ret); return ret;}wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2) (struct nt_list *head, NT_SPIN_LOCK *lock){ ENTER5("%p", head); return ExfInterlockedRemoveHeadList(head, lock);}wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveTailList,2) (struct nt_list *head, NT_SPIN_LOCK *lock){ struct nt_list *ret; unsigned long flags; ENTER5("head = %p", head); nt_spin_lock_irqsave(lock, flags); ret = RemoveTailList(head); nt_spin_unlock_irqrestore(lock, flags); TRACE5("head = %p, ret = %p", head, ret); return ret;}wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2) (struct nt_list *head, NT_SPIN_LOCK *lock){ ENTER5("%p", head); return ExfInterlockedRemoveTailList(head, lock);}wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPushEntrySList,3) (nt_slist_header *head, struct nt_slist *entry, NT_SPIN_LOCK *lock){ struct nt_slist *ret; ret = PushEntrySList(head, entry, lock); return ret;}wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPushEntrySList,2) (nt_slist_header *head, struct nt_slist *entry){ struct nt_slist *ret; ret = PushEntrySList(head, entry, &ntoskernel_lock); return ret;}wfastcall struct nt_slist *WIN_FUNC(InterlockedPushEntrySList,2) (nt_slist_header *head, struct nt_slist *entry){ struct nt_slist *ret; ret = PushEntrySList(head, entry, &ntoskernel_lock); return ret;}wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPopEntrySList,2) (nt_slist_header *head, NT_SPIN_LOCK *lock){ struct nt_slist *ret; ret = PopEntrySList(head, lock); return ret;}wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPopEntrySList,1) (nt_slist_header *head){ struct nt_slist *ret; ret = PopEntrySList(head, &ntoskernel_lock); return ret;}wfastcall struct nt_slist *WIN_FUNC(InterlockedPopEntrySList,1) (nt_slist_header *head){ struct nt_slist *ret; ret = PopEntrySList(head, &ntoskernel_lock); return ret;}wstdcall USHORT WIN_FUNC(ExQueryDepthSList,1) (nt_slist_header *head){ USHORT depth; ENTER5("%p", head); depth = head->depth; TRACE5("%d, %p", depth, head->next); return depth;}wfastcall LONG WIN_FUNC(InterlockedIncrement,1) (LONG volatile *val){ return post_atomic_add(*val, 1);}wfastcall LONG WIN_FUNC(InterlockedDecrement,1) (LONG volatile *val){ return post_atomic_add(*val, -1);}wfastcall LONG WIN_FUNC(InterlockedExchange,2) (LONG volatile *target, LONG val){ return xchg(target, val);}wfastcall LONG WIN_FUNC(InterlockedCompareExchange,3) (LONG volatile *dest, LONG new, LONG old){ return cmpxchg(dest, old, new);}wfastcall void WIN_FUNC(ExInterlockedAddLargeStatistic,2) (LARGE_INTEGER volatile *plint, ULONG n){ unsigned long flags; save_local_irq(flags);#ifdef CONFIG_X86_64 __asm__ __volatile__( "\n" LOCK_PREFIX "add %1, %0\n\t" : "+m" (*plint) : "r" (n));#else __asm__ __volatile__( "\n" "1:\t" " movl %1, %%ebx\n\t" " movl %%edx, %%ecx\n\t" " addl %%eax, %%ebx\n\t" " adcl $0, %%ecx\n\t" LOCK_PREFIX "cmpxchg8b %0\n\t" " jnz 1b\n\t" : "+m" (*plint) : "m" (n), "A" (*plint) : "ebx", "ecx");#endif restore_local_irq(flags);}static void initialize_object(struct dispatcher_header *dh, enum dh_type type, int state){ memset(dh, 0, sizeof(*dh)); set_object_type(dh, type); dh->signal_state = state; InitializeListHead(&dh->wait_blocks);}static void timer_proc(unsigned long data){ struct wrap_timer *wrap_timer = (struct wrap_timer *)data; struct nt_timer *nt_timer; struct kdpc *kdpc; nt_timer = wrap_timer->nt_timer; TIMERENTER("%p(%p), %lu", wrap_timer, nt_timer, jiffies);#ifdef TIMER_DEBUG BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); BUG_ON(nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC);#endif if (wrap_timer->repeat) mod_timer(&wrap_timer->timer, jiffies + wrap_timer->repeat); KeSetEvent((struct nt_event *)nt_timer, 0, FALSE); kdpc = nt_timer->kdpc; if (kdpc && kdpc->func) {#if 1 LIN2WIN4(kdpc->func, kdpc, kdpc->ctx, kdpc->arg1, kdpc->arg2);#else queue_kdpc(kdpc);#endif } TIMEREXIT(return);}void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, struct kdpc *kdpc, struct ndis_miniport_block *nmb){ struct wrap_timer *wrap_timer; KIRQL irql; /* TODO: if a timer is initialized more than once, we allocate * memory for wrap_timer more than once for the same nt_timer, * wasting memory. We can check if nt_timer->wrap_timer_magic is * set and not allocate, but it is not guaranteed always to be * safe */ TIMERENTER("%p", nt_timer); /* we allocate memory for wrap_timer behind driver's back and * there is no NDIS/DDK function where this memory can be * freed, so we use slack_kmalloc so it gets freed when driver * is unloaded */ if (nmb) wrap_timer = kmalloc(sizeof(*wrap_timer), gfp_irql()); else wrap_timer = slack_kmalloc(sizeof(*wrap_timer)); if (!wrap_timer) { ERROR("couldn't allocate memory for timer"); return; } memset(wrap_timer, 0, sizeof(*wrap_timer)); init_timer(&wrap_timer->timer); wrap_timer->timer.data = (unsigned long)wrap_timer; wrap_timer->timer.function = timer_proc; wrap_timer->nt_timer = nt_timer;#ifdef TIMER_DEBUG wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC;#endif nt_timer->wrap_timer = wrap_timer; nt_timer->kdpc = kdpc; initialize_object(&nt_timer->dh, type, 0); nt_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; irql = nt_spin_lock_irql(&timer_lock, DISPATCH_LEVEL); if (nmb) InsertTailList(&nmb->wnd->wrap_timer_list, &wrap_timer->list); else InsertTailList(&wrap_timer_list, &wrap_timer->list); nt_spin_unlock_irql(&timer_lock, irql); TIMERTRACE("timer %p (%p)", wrap_timer, nt_timer); TIMEREXIT(return);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -