📄 mt2_thread.c
字号:
/***************************************************************************
** File name : mt2_thread.c
** Author : x.cheng
** Create date :
**
** Comment:
** function for thread management
**
** Revisions:
** $Log: mt2_thread.c,v $
** Revision 1.2 2005/07/27 07:19:35 x.cheng
** bug fix - save father's privilege level to iPrivilege
**
** Revision 1.1.1.1 2005/07/27 06:53:15 x.cheng
** add into repositories
**
**
***************************************************************************/
#include "const.h"
#include "type.h"
#include "stdarg.h"
#include "stdlib.h"
#include "string.h"
#include "queue.h"
#include "..\..\inc\i386\page.h" //kernel\inc\i386
#include "..\..\inc\i386\x86.h"
#include "..\..\inc\i386\system.h"
#include "..\..\inc\task.h" //kernel\inc
#include "..\..\inc\mts.h"
#include "..\..\inc\tui.h"
#include "..\..\inc\debug.h"
#define __USER_SPACE_ALLOCTOR__
#include "..\..\inc\vmm.h"
#define __MTS_SRC__
#include "..\inc\def_mts.h"
#include "..\inc\def_sched.h"
/* debug preprocessor instrument
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
#endif
#endif
***************************/
/************************************************************
*************************************************************
** Function Name: pstMt2CreateThread
** Author: x.cheng
**
** Comment:
** reate a new thread of a process.
**
** List of parameters:
** pvRoutine - The address of the entry point for the thread.
** szName - The name of the new task
**
** Return value:
** A pointer to the new-created thread structure.
** error: NULL If an error occurs (in particular out-of-memory)
**
** Revisions:
** This routine must be executed in mutual exclusion, because if
** the current task is killed during the thread creation, the
** space allocated before will be lost.
*************************************************************
*************************************************************/
ts_Task* pstMt2CreateThread(void *pvRoutine, char *szName)
{
ts_Task* pstNewThread, *pstFatherProcess;
int iPrivilege;
if ( NULL==g_pstCurrentTask )
return NULL;
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("create thread, name= %s, routine at= %p\n", szName, pvRoutine);
Mt5BrowserQueue(&g_pstWaitQueue, "Wait");
#endif
#endif
vScheduleEnterCritialRegion();
// --- Create the task structure ------------------------------ //
//!
//! IA-32 Intel(R) Architecture Software Developer's Manual
//! Volume 3: System Programming Guide - Chapter 6 - reports:
//!
//! "If paging is used, care should be taken to avoid placing a
//! page boundary within the part of the TSS that the processor
//! reads during a task switch (the first 104 bytes). If a page
//! boundary is placed within this part of the TSS, the pages on
//! either side of the boundary must be present at the same time
//! and contiguous in physical memory.
//!
//! 在发生任务切换的时候,CPU 总是读TSS段开始的物理地址连续的104个字节,
//! 在读取这些字节的时候,可能并不使用分页转换。因此如果分配的给TSS
//! 的物理内存不连续(跨页)的话,则为将来的任务切换埋下了隐患...
pstNewThread = pvVmmKeAlignMalloc( PAGE_SIZE, sizeof(ts_Task), GFP_KERNEL );
//pstNewTask的地址总是在PAGE_SIZE界上开始,比如0xD0001000
if (pstNewThread == NULL) {
//out of virtua memory
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("%s: cannot allocate task structure for '%s'\n", __FUNCTION__, szName);
#endif
#endif
vScheduleLeaveCriticalRegion();
return NULL;
}
// Add the task into the zombie queue, so if the current task
// is killed the space allocated until now can be freed by the
// kpager daemon.
iAddQueueNode(&g_pstZombieQueue, pstNewThread);
pstNewThread->ucState = TASK_STATE_NEW;
// Create the kernel(Ring0) stack.
pstNewThread->ulRing0Stack = (unsigned long)pvVmmKeMalloc(TASK_KERNEL_STACK_SIZE, GFP_KERNEL);
if ( NULL == pstNewThread->ulRing0Stack ) {
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("%s: cannot allocate Ring0 stack for '%s'\n", __FUNCTION__, szName);
#endif
#endif
vVmmKeFree(pstNewThread);
vScheduleLeaveCriticalRegion();
return NULL;
}
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("%s: pstNewThread->ulRing0Stack =%p\n", __FUNCTION__, pstNewThread->ulRing0Stack);
#endif
#endif
// Zero the stack..
memset( (void *)pstNewThread->ulRing0Stack, 0, TASK_KERNEL_STACK_SIZE);
// Setup the privileged stack in tss.
// when switch to ring0, stack is different with ring3(user mode) one.
pstNewThread->stTSS.ss0 = KERNEL_STACK;
pstNewThread->stTSS.esp0 = ulAlignDown(
(unsigned long)(pstNewThread->ulRing0Stack) + TASK_KERNEL_STACK_SIZE - sizeof(unsigned long), sizeof(unsigned long) );
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("%s: pstNewThread->stTSS.esp0 =%p\n", __FUNCTION__, pstNewThread->stTSS.esp0 );
kprintf("sizeof(ts_TSS_IO)=%x, &pstNewThread->stTSS=%p, ACS_TSSSEG=%x\n", sizeof(ts_TSS_IO),
&pstNewThread->stTSS, ACS_TSSSEG);
#endif
#endif
// Setup the TSS
pstNewThread->uiTssSelector = uiSetupGdtEntry(sizeof(ts_TSS_IO), (unsigned long)&pstNewThread->stTSS, ACS_TSSSEG, 0);
if ( NULL == pstNewThread->uiTssSelector ) {
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("%s: out of GDT entrys!!!can't create task '%s'\n", __FUNCTION__, szName);
#endif
#endif
vVmmKeFree(pstNewThread);
vVmmKeFree( (void *)pstNewThread->ulRing0Stack );
vScheduleLeaveCriticalRegion();
return NULL;
}
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("%s: pstNewThread->uiTssSelector =%x\n", __FUNCTION__, pstNewThread->uiTssSelector );
#endif
#endif
// set the task type
pstNewThread->stFlags.Type = TASK_TYPE_THREAD;
// get father's privilege level(KERNEL_PRIVILEGE or USER_PRIVILEGE)
iPrivilege = pstNewThread->iPrivilege = g_pstCurrentTask->iPrivilege;
// Get the first process between all the parents of the
// current thread. This is necessary to setup properly
// the user space. Remember that every thread share the
// same address space.
pstFatherProcess = g_pstCurrentTask;
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("pstFatherProcess at %p, ->szName= %s, ->stFlags.Type= %d\n", pstFatherProcess, pstFatherProcess->szName,pstFatherProcess->stFlags.Type);
vDbgDummy();
#endif
#endif
while( pstFatherProcess->stFlags.Type == TASK_TYPE_THREAD ) {
pstFatherProcess = pstFatherProcess->pstFather;
}
// Setup the thread heap equal to the father's heap.
pstNewThread->ulHeapStart = pstFatherProcess->ulHeapStart;
pstNewThread->ulHeapSize = pstFatherProcess->ulHeapSize;
// Setup the task address space.
pstNewThread->stTSS.cr3 = pstFatherProcess->stTSS.cr3;
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("pstNewThread->stTSS.cr3 = %08x\n", pstNewThread->stTSS.cr3);
vDbgDummy(); //dummy function for break point assertion...
#endif
#endif
// Get the same page directory of the father.
pstNewThread->pulPdbr = pstFatherProcess->pulPdbr;
// Get the same pdbr counter of the father.
pstNewThread->ulPdbrUpdateCounter = pstFatherProcess->ulPdbrUpdateCounter;
//create the task stack
pstNewThread->stTSS.ss = (iPrivilege == KERNEL_PRIVILEGE) ? KERNEL_STACK : USER_STACK | 3;
if ( KERNEL_PRIVILEGE == iPrivilege ) {
pstNewThread->stTSS.esp = (unsigned long)pulMt5SetupStack( pstNewThread->stTSS.esp0+sizeof(unsigned long) );
} else {
// Put the thread's stack in the heap.
//pstNewThread->ulRing3Stack = (unsigned long) umalloc( STACK_SIZE );
//未完待续...
PANIC();
}
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
kprintf("pstNewThread->stTSS.ss = %04x\tpstNewThread->stTSS.esp = %08x\n", pstNewThread->stTSS.ss, pstNewThread->stTSS.esp);
vDbgDummy(); //dummy function for break point assertion...
#endif
#endif
//setup the io port mapping
pstNewThread->stTSS.uiIoMapAddr = sizeof(ts_TSS);
memsetl( pstNewThread->stTSS.aulIoMap, 0xFFFFFFFF, IO_MAP_SIZE);
// Setup general registers.
if ( iPrivilege == KERNEL_PRIVILEGE ) {
pstNewThread->stTSS.ds = pstNewThread->stTSS.es =
pstNewThread->stTSS.fs = pstNewThread->stTSS.gs = KERNEL_DATA;
} else {
pstNewThread->stTSS.ds = pstNewThread->stTSS.es =
pstNewThread->stTSS.fs = pstNewThread->stTSS.gs = USER_DATA | 3;
}
// setup the eflags register.
pstNewThread->stTSS.eflags = EFLAGS_IOPL0 | EFLAGS_IF | 0x02;
// setup the starting address(program counter).
pstNewThread->stTSS.cs = (iPrivilege == KERNEL_PRIVILEGE) ? KERNEL_CODE : USER_CODE | 3;
pstNewThread->stTSS.eip = (unsigned long)pvRoutine;
// store the process's name
strncpy( pstNewThread->szName, szName, sizeof(pstNewThread->szName)-2 );
// Set the process credentials.
pstNewThread->iPid = iMt5GeneratePid();
//id setup...
// set the parent
pstNewThread->pstFather = g_pstCurrentTask;
// set the console
pstNewThread->iConsole = g_pstCurrentTask->iConsole;
// set the priority
pstNewThread->iPriority = pstNewThread->iCounter = HIGH_PRIORITY;
// insert the task to the ready queue.
iRemoveQueueNode(&g_pstZombieQueue, pstNewThread);
iAddQueueNode(&g_pstReadyQueue, pstNewThread);
pstNewThread->ucState = TASK_STATE_READY;
#ifdef _DEBUG__
#ifdef _DEBUG_MTS__
Mt5BrowserQueue(&g_pstZombieQueue, "Zombie");
Mt5BrowserQueue(&g_pstWaitQueue, "Wait");
Mt5BrowserQueue(&g_pstReadyQueue, "Ready");
#endif
#endif
vScheduleLeaveCriticalRegion();
// This is a little trick... Because we exit
// from a very long critical region we call
// the scheduler to enforce a new task selection.
vMt3Schedule();
return (pstNewThread);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -