📄 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 CACHE_MDL_PAGES; if a driver * requests an MDL for a bigger region, we allocate it with kmalloc; * otherwise, we allocate from the pool */#define CACHE_MDL_PAGES 3#define CACHE_MDL_SIZE (sizeof(struct mdl) + \ (sizeof(PFN_NUMBER) * CACHE_MDL_PAGES))struct wrap_mdl { struct nt_list list; struct mdl mdl[0];};struct thread_event_waitq { wait_queue_head_t head; BOOLEAN done;#ifdef EVENT_DEBUG struct task_struct *task;#endif struct thread_event_waitq *next;};/* everything here is for all drivers/devices - not per driver/device */static NT_SPIN_LOCK dispatcher_lock;static struct thread_event_waitq *thread_event_waitq_pool;NT_SPIN_LOCK ntoskernel_lock;static kmem_cache_t *mdl_cache;static struct nt_list wrap_mdl_list;/* use tasklet instead worker to execute kdpc's */#define KDPC_TASKLET 1#ifdef KDPC_TASKLETstatic struct tasklet_struct kdpc_work;static void kdpc_worker(unsigned long dummy);#elsestatic struct work_struct kdpc_work;static void kdpc_worker(void *data);#endifstatic 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 struct work_struct ntos_work_item_work;static struct nt_list ntos_work_item_list;static NT_SPIN_LOCK ntos_work_item_list_lock;static void ntos_work_item_worker(void *data);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);#endifstatic int add_bus_driver(const char *name);static BOOLEAN queue_kdpc(struct kdpc *kdpc);WIN_SYMBOL_MAP("KeTickCount", &jiffies)WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE)#ifdef USE_OWN_NTOS_WORKQUEUEstruct workqueue_struct *ntos_wq;#endifint ntoskernel_init(void){ struct timeval now; nt_spin_lock_init(&dispatcher_lock); nt_spin_lock_init(&ntoskernel_lock); nt_spin_lock_init(&ntos_work_item_list_lock); nt_spin_lock_init(&kdpc_list_lock); nt_spin_lock_init(&irp_cancel_lock); InitializeListHead(&wrap_mdl_list); InitializeListHead(&kdpc_list); InitializeListHead(&callback_objects); InitializeListHead(&bus_driver_list); InitializeListHead(&object_list); InitializeListHead(&ntos_work_item_list);#ifdef KDPC_TASKLET tasklet_init(&kdpc_work, kdpc_worker, 0);#else INIT_WORK(&kdpc_work, kdpc_worker, NULL);#endif INIT_WORK(&ntos_work_item_work, ntos_work_item_worker, NULL); nt_spin_lock_init(&timer_lock); InitializeListHead(&wrap_timer_list); thread_event_waitq_pool = NULL; do_gettimeofday(&now); wrap_ticks_to_boot = (u64)now.tv_sec * TICKSPERSEC; wrap_ticks_to_boot += now.tv_usec * 10; wrap_ticks_to_boot -= jiffies * TICKSPERSEC / HZ; wrap_ticks_to_boot += TICKS_1601_TO_1970;#ifdef USE_OWN_NTOS_WORKQUEUE ntos_wq = create_singlethread_workqueue("ntos_wq");#endif if (add_bus_driver("PCI")#ifdef CONFIG_USB || add_bus_driver("USB")#endif ) { ntoskernel_exit(); return -ENOMEM; } mdl_cache = kmem_cache_create("wrap_mdl", sizeof(struct wrap_mdl) + CACHE_MDL_SIZE, 0, 0, NULL, NULL); DBGTRACE2("%p", mdl_cache); if (!mdl_cache) { ERROR("couldn't allocate MDL cache"); ntoskernel_exit(); return -ENOMEM; }#if defined(CONFIG_X86_64) memset(&kuser_shared_data, 0, sizeof(kuser_shared_data)); init_timer(&shared_data_timer); shared_data_timer.function = update_user_shared_data_proc;#endif return 0;}int ntoskernel_init_device(struct wrap_device *wd){#if defined(CONFIG_X86_64) *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); shared_data_timer.data = (unsigned long)0; /* don't use add_timer - to avoid creating more than one * timer */ mod_timer(&shared_data_timer, jiffies + 1);#endif return 0;}void ntoskernel_exit_device(struct wrap_device *wd){ TRACEENTER2(""); KeFlushQueuedDpcs(); TRACEEXIT2(return);}void ntoskernel_exit(void){ struct nt_list *cur; KIRQL irql; TRACEENTER2("");#ifdef KDPC_TASKLET tasklet_kill(&kdpc_work);#endif /* free kernel (Ke) timers */ DBGTRACE2("freeing timers"); while (1) { struct wrap_timer *wrap_timer; irql = nt_spin_lock_irql(&timer_lock, DISPATCH_LEVEL); cur = RemoveTailList(&wrap_timer_list); nt_spin_unlock_irql(&timer_lock, irql); if (!cur) break; wrap_timer = container_of(cur, struct wrap_timer, list); if (del_timer_sync(&wrap_timer->timer)) WARNING("Buggy Windows driver left timer %p running", &wrap_timer->timer); memset(wrap_timer, 0, sizeof(*wrap_timer)); slack_kfree(wrap_timer); } DBGTRACE2("freeing MDLs"); if (mdl_cache) { irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); if (!IsListEmpty(&wrap_mdl_list)) ERROR("Windows driver didn't free all MDLs; " "freeing them now"); while ((cur = RemoveHeadList(&wrap_mdl_list))) { struct wrap_mdl *wrap_mdl; wrap_mdl = container_of(cur, struct wrap_mdl, list); if (wrap_mdl->mdl->flags & MDL_CACHE_ALLOCATED) kmem_cache_free(mdl_cache, wrap_mdl); else kfree(wrap_mdl); } nt_spin_unlock_irql(&ntoskernel_lock, irql); kmem_cache_destroy(mdl_cache); mdl_cache = NULL; } DBGTRACE2("freeing callbacks"); irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); while ((cur = RemoveHeadList(&callback_objects))) { struct callback_object *object; struct nt_list *ent; object = container_of(cur, struct callback_object, list); while ((ent = RemoveHeadList(&object->callback_funcs))) { struct callback_func *f; f = container_of(ent, struct callback_func, list); kfree(f); } kfree(object); } nt_spin_unlock_irql(&ntoskernel_lock, irql); irql = nt_spin_lock_irql(&dispatcher_lock, DISPATCH_LEVEL); DBGTRACE2("freeing thread event pool"); while (thread_event_waitq_pool) { struct thread_event_waitq *next; next = thread_event_waitq_pool->next; kfree(thread_event_waitq_pool); thread_event_waitq_pool = next; } nt_spin_unlock_irql(&dispatcher_lock, irql); irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); while ((cur = RemoveHeadList(&bus_driver_list))) { struct bus_driver *bus_driver; bus_driver = container_of(cur, struct bus_driver, list); /* TODO: make sure all all drivers are shutdown/removed */ kfree(bus_driver); } nt_spin_unlock_irql(&ntoskernel_lock, irql); TRACEENTER2("freeing objects"); irql = nt_spin_lock_irql(&ntoskernel_lock, DISPATCH_LEVEL); while ((cur = RemoveHeadList(&object_list))) { struct common_object_header *hdr; hdr = container_of(cur, struct common_object_header, list); WARNING("object %p type %d was not freed, freeing it now", HEADER_TO_OBJECT(hdr), hdr->type); ExFreePool(hdr); } nt_spin_unlock_irql(&ntoskernel_lock, irql);#if defined(CONFIG_X86_64) del_timer_sync(&shared_data_timer);#endif#ifdef USE_OWN_NTOS_WORKQUEUE if (ntos_wq) destroy_workqueue(ntos_wq);#endif TRACEEXIT2(return);}#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; shared_data_timer.expires += 30 * HZ / 1000 + 1; add_timer(&shared_data_timer);}#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); DBGTRACE3("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); DBGTRACE3("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); DBGTRACE1("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; TRACEENTER5("head = %p, entry = %p", head, entry); nt_spin_lock_irqsave(lock, flags); first = InsertHeadList(head, entry); nt_spin_unlock_irqrestore(lock, flags); DBGTRACE5("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){ TRACEENTER5("%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; TRACEENTER5("head = %p, entry = %p", head, entry); nt_spin_lock_irqsave(lock, flags); last = InsertTailList(head, entry); nt_spin_unlock_irqrestore(lock, flags); DBGTRACE5("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){ TRACEENTER5("%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; TRACEENTER5("head = %p", head); nt_spin_lock_irqsave(lock, flags); ret = RemoveHeadList(head); nt_spin_unlock_irqrestore(lock, flags); DBGTRACE5("head = %p, ret = %p", head, ret); return ret;}wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2) (struct nt_list *head, NT_SPIN_LOCK *lock){ TRACEENTER5("%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; TRACEENTER5("head = %p", head); nt_spin_lock_irqsave(lock, flags); ret = RemoveTailList(head); nt_spin_unlock_irqrestore(lock, flags); DBGTRACE5("head = %p, ret = %p", head, ret); return ret;}wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -