📄 thread.c
字号:
/* * thread.c * * Copyright (C) 2006 Insigme Co., Ltd * * Authors: * - Limin Jin * * This software has been developed while working on the Linux Unified Kernel * project (http://linux.insigma.com.cn) in the Insigma Reaserch Institute, * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). * * The project is sponsored by Insigma Co., Ltd. * * The authors can be reached at linux@insigma.com.cn. * * 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. * * Revision History: * Jan 2006 - Created. *//* * thread.c: thread implementation * Reference to ReactOS code */#include <linux/win32_process.h>#include <linux/mm.h>#include <asm/uaccess.h>#include <asm/ldt.h>#include <linux/file.h>#include <linux/nls.h>#include <linux/list.h>#include "../objwait.h"#include "../thread.h"#include "../apc.h"#include "../process.h"#include "thread.h"#include "../win32.h"#include "../mm/virtual.h"#include "../mm/attach.h"#include "../w32syscall.h"#ifdef CONFIG_UNIFIED_KERNEL//#define kdebug(fmt ...)//#define ktrace(fmt ...)extern long do_fork_from_task(task_t *ptsk, unsigned long process_flags, unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr);extern asmlinkage void KiThreadStartup(void);extern PTEB STDCALLMmCreateTeb(PEPROCESS Process, PCLIENT_ID ClientId, PINITIAL_TEB InitialTeb);extern void STDCALLPspThreadSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2);extern unsigned long get_ntdll_entry(void);extern unsigned long get_interp_entry(void);/* * PspUserThreadStartup * prepare for jump to userspace to execute after new thread waken */VOIDSTDCALLPspUserThreadStartup(PKSTART_ROUTINE StartRoutine, PVOID StartContext){ struct ethread *thread; PKAPC thread_apc; void * start_stack; ktrace("PspUserThreadStartup\n"); if (!(thread = thread_find())) { kdebug("***error find thread\n"); return; } if (!(thread_apc = kmalloc(sizeof(struct kapc),GFP_KERNEL))) { kdebug("***error malloc, No memory\n"); return; } start_stack = (void *)thread->et_task->mm->start_stack; /* user stack base */ KeInitializeApc(thread_apc, &thread->tcb, OriginalApcEnvironment, PspThreadSpecialApc, NULL, (PKNORMAL_ROUTINE)get_ntdll_entry(), UserMode, start_stack); KeInsertQueueApc(thread_apc, (void *)get_interp_entry(), thread->threads_process->spare0[0], IO_NO_INCREMENT); thread->tcb.apc_state.uapc_pending = 1; set_tsk_thread_flag(current, TIF_APC); try_module_get(THIS_MODULE); asm("movl %0, %%fs\n" : : "r"(TEB_SELECTOR)); return;} /* end PspUserThreadStartup *//* * Ke386InitThreadWithContext * init context for thread */VOIDSTDCALLKe386InitThreadWithContext(PKTHREAD Thread, PKSYSTEM_ROUTINE SystemRoutine, PKSTART_ROUTINE StartRoutine, /* FIXME */ PVOID StartContext, /* FIXME */ PCONTEXT Context){ struct thread_info *info; struct task_struct *p; unsigned long * trapframe; struct pt_regs * regs; PCONTEXT context; if (!(context = kmalloc(sizeof(*context),GFP_KERNEL))) { kdebug("***error malloc, No memory\n"); return; } if (copy_from_user(context, Context, sizeof(*context))) { kdebug("copy from user error\n"); return; } info = (struct thread_info *)((unsigned long)Thread->stack_base - THREAD_SIZE); p = info->task; /* set for switch */ trapframe = (unsigned long *)((unsigned long)Thread->stack_base - 8 - sizeof(struct pt_regs) - 12); regs = (struct pt_regs *)(trapframe + 3); trapframe[0] = (unsigned long)SystemRoutine; trapframe[1] = (unsigned long)StartRoutine; trapframe[2] = (unsigned long)StartContext; p->thread.eip = (unsigned long)KiThreadStartup; p->thread.esp = (unsigned long)trapframe; p->thread.esp0 = (unsigned long)(regs+1); p->thread.fs = TEB_SELECTOR; /* set for userspace */ regs->esp = context->Esp; regs->eip = context->Eip; kfree(context); return;} /* end Ke386InitThreadWithContext *//* * KeInitializeThread * initialize kthread */VOIDSTDCALLKeInitializeThread(PKPROCESS Process, PKTHREAD Thread, PKSYSTEM_ROUTINE SystemRoutine, PKSTART_ROUTINE StartRoutine, /* FIXME */ PVOID StartContext, /* FIXME */ PCONTEXT Context, PVOID Teb, PVOID KernelStack){ ktrace("KeInitializeThread kprocess %x, kthread %x, systemroutine %x, context %x, teb %x, kernelstack %x\n", Process, Thread, SystemRoutine, Context, Teb, KernelStack); KThreadInit(Thread, (struct eprocess *)Process); /*NOW FIXME Initialize the Suspend APC */ /* Initialize the Suspend Semaphore */ sema_init(&Thread->suspend_semaphore, 0); /* Set the TEB */ Thread->teb = Teb; /* Allocate Stack use linux task stack and init * Set the Thread Stacks */ Thread->initial_stack = (PCHAR)KernelStack + THREAD_SIZE; Thread->stack_base = (PCHAR)KernelStack + THREAD_SIZE; Thread->stack_limit = (ULONG_PTR)KernelStack + sizeof(struct thread_info); /* FIXME * Establish the pde's for the new stack and the thread structure within the * address space of the new process. They are accessed while taskswitching or * while handling page faults. At this point it isn't possible to call the * page fault handler for the missing pde's. */ MmUpdatePageDir(((struct ethread *)Thread)->et_task->mm, (void *)Thread->stack_limit, THREAD_SIZE); MmUpdatePageDir(((struct ethread *)Thread)->et_task->mm, Thread, sizeof(struct ethread)); Ke386InitThreadWithContext(Thread, SystemRoutine, StartRoutine, StartContext, Context); return;} /* end KeInitializeThread *//* * PspCreateThread * create thread */NTSTATUSSTDCALLPspCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, IN PEPROCESS TargetProcess, /* FIXME */ OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended, IN PKSTART_ROUTINE StartRoutine OPTIONAL, /* FIXME */ IN PVOID StartContext OPTIONAL) /* FIXME */{ struct eprocess * process; struct ethread * thread, * old_thread, *cur_thread; struct task_struct * new_tsk; struct win32_object * proc_obj = NULL, * thread_obj; struct ethread_cons_data etcd; struct teb * teb_base; long cpid; ktrace("PspCreateThread\n"); /* current still be regarded */ if (ProcessHandle&&ProcessHandle!=NtCurrentProcess()) { if(!(cur_thread=thread_find())) { kdebug("***error find thread\n"); return -EINVAL; } proc_obj = GetObject(cur_thread, ProcessHandle, &process_objclass); if (IS_ERR(proc_obj)) { kdebug("can't find created eprocess\n"); return -EINVAL; } process = proc_obj->o_private; objput(proc_obj); } else { if (TargetProcess) { process = (struct eprocess * )TargetProcess; if (IS_ERR(proc_obj)) { kdebug("can't find created eprocess\n"); return -EINVAL; } } else { if(!(cur_thread=thread_find())) { kdebug("***error find thread\n"); return -EINVAL; } process = cur_thread->threads_process; } } if (!process->fork_in_progress) { /* second and more */ old_thread = list_entry(process->thread_list_head.next, struct ethread, thread_list_entry); cpid = do_fork_from_task(old_thread->et_task, CREATE_THREAD, SIGCHLD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, old_thread->tcb.trap_frame->esp, (struct pt_regs *)old_thread->tcb.trap_frame, 0, NULL, NULL); new_tsk = find_task_by_pid(cpid); etcd.etcd_task = new_tsk; etcd.etcd_process = process->ep_obj; etcd.etcd_stack_top = (unsigned long)InitialTeb->StackBase; //stack_top thread_obj = AllocObject(&thread_objclass, NULL, &etcd); if (IS_ERR(thread_obj)) { kdebug("can't find created ethread\n"); return -EINVAL; } /* the thread object can now be put, since a reference is held * by the Linux task structure. Similarly the process object * is now referenced by the thread object and can also be put */ objput(thread_obj); thread = thread_obj->o_private; } else { /* for first thread */ thread = process->fork_in_progress; new_tsk = thread->et_task; } module_put(THIS_MODULE); /* FIXME Create Cid Handle */ memset(&thread->cid, 0, sizeof(struct client_id)); /* set user stack base */ thread->et_task->mm->start_stack = (unsigned long)InitialTeb->StackBase; if (ThreadContext) { /* Create Teb */ teb_base = (struct teb * )MmCreateTeb(process, (PCLIENT_ID)&thread->cid, InitialTeb); /* Set the Start Addresses */ thread->start_address = (PVOID)ThreadContext->Eip; thread->win32_start_address = (PVOID)ThreadContext->Eax; /*FIXME */ /* intialize kthread */ KeInitializeThread(&process->pcb, &thread->tcb, PspUserThreadStartup, NULL, NULL, ThreadContext, teb_base, new_tsk->thread_info); } else { /* FIXME PsCreateSystemThread */ } /* move ethread to eprocess's thread_list * Insert the Thread into the Process's Thread List * Note, this is the ETHREAD Thread List. It is removed in * ps/kill.c!PspExitThread. */ set_task_state(new_tsk, TASK_RUNNING); clear_tsk_need_resched(new_tsk); wake_up_new_task(new_tsk, CLONE_VM | CLONE_FS | CLONE_FILES| CLONE_SIGHAND); /* FIXME Notify Thread Creation */ /* NOW FIXME Suspend the Thread if we have to */ /* FIXME: SECURITY */ /* FIXME Dispatch thread */ return STATUS_SUCCESS;} /* end PspCreateThread *//* * NtCreateThread */NTSTATUS STDCALLNtCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended){ PINITIAL_TEB safe_initial_teb; NTSTATUS status; ktrace("NtCreateThread\n"); /* copy data form userspace */ if (!(safe_initial_teb = kmalloc(sizeof(INITIAL_TEB), GFP_KERNEL))) { kdebug("***error malloc, No memory\n"); return -EINVAL; } if (copy_from_user(safe_initial_teb, InitialTeb, sizeof(INITIAL_TEB))) return -EFAULT; /* Call the shared function */ status = PspCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, NULL, ClientId, ThreadContext, safe_initial_teb, CreateSuspended, NULL, NULL); kfree(safe_initial_teb); return status;} /* end NtCreateThread */#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -