1 项目要求
(1)修改src/GeekOS/user.c文件中的函数Spawn(),其功能是生成一个用户级进程。
(2)src/GeekOS/user.c文件中的函数Switch_To_User_Contex(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间。
(3)src/GeekOS/elf.c文件中的函数Prase_ELF_Executable()。
(4)Destry_User_Contex(),Load_User_Programe(),Copy_From_User(),Copy_To_User(),Switch_To_Address_Space()。
(5)src/GeekOS/kthread.c文件中Start_User_Thread函数和Setup_User_Thread函数。
(6)src/GeekOS/kthread.c相关函数的修改。
2 具体实现代码
User.c
int Spawn(const char *program, const char *command, struct Kernel_Thread **pThread)
{
int rc;
char *exeFileData = 0;
ulong_t exeFileLength;
struct User_Context *userContext = 0;
struct Kernel_Thread *process = 0;
struct Exe_Format exeFormat;
if ((rc = Read_Fully(program, (void**) &exeFileData, &exeFileLength)) != 0 ||
(rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat)) != 0 ||
(rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &userContext)) != 0)
goto fail;
Free(exeFileData);
exeFileData = 0;
/* 开始用户进程 */
process = Start_User_Thread(userContext, false);
if (process != 0) {
KASSERT(process->refCount == 2);
/* 返回核心进程的指针 */
*pThread = process;
} else
rc = ENOMEM;
return rc;
fail:
if (exeFileData != 0)
Free(exeFileData);
if (userContext != 0)
Destroy_User_Context(userContext);
return rc;
}
void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state)
{
static struct User_Context* s_currentUserContext; /* last user context used */
extern int userDebug;
struct User_Context* userContext = kthread->userContext;
KASSERT(!Interrupts_Enabled());
if (userContext == 0) {
/* 核心态进程,无需改变地址空间. */
return;
}
if (userContext != s_currentUserContext) {
ulong_t esp0;
if (userDebug) Print("A[%p]\n", kthread);
Switch_To_Address_Space(userContext);
esp0 = ((ulong_t) kthread->stackPage) + PAGE_SIZE;
if (userDebug) Print("S[%lx]\n", esp0);
/* 新进程的核心栈. */
Set_Kernel_Stack_Pointer(esp0);
/* New user context is active */
s_currentUserContext = userContext;
}
} |
Elf.c中int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength,
struct Exe_Format *exeFormat)
{
elfHeader *hdr;
programHeader *phdr;
int i;
hdr = (elfHeader *) exeFileData;
if (exeFileLength < sizeof(elfHeader) ||
strncmp(exeFileData, "\x7F""ELF", 4) != 0) {
if (elfDebug) Print("Not an ELF executable\n");
return ENOEXEC;
}
if (hdr->phnum > EXE_MAX_SEGMENTS) {
if (elfDebug) Print("Too many segments (%d) in ELF executable\n", hdr->phnum);
return ENOEXEC;
}
if (exeFileLength < hdr->phoff + (hdr->phnum * sizeof(programHeader))) {
if (elfDebug) Print("Not enough room for program header\n");
return ENOEXEC;
}
exeFormat->numSegments = hdr->phnum;
exeFormat->entryAddr = hdr->entry;
phdr = (programHeader *) (exeFileData + hdr->phoff);
for (i = 0; i < hdr->phnum; ++i) {
struct Exe_Segment *segment = &exeFormat->segmentList[i];
/*
填充数据段
*/
segment->offsetInFile = phdr[i].offset;
segment->lengthInFile = phdr[i].fileSize;
segment->startAddress = phdr[i].vaddr;
segment->sizeInMemory = phdr[i].memSize;
if (segment->lengthInFile > segment->sizeInMemory) {
if (elfDebug) Print("Segment %d: length in file (%lu) exceeds size in memory (%lu)\n",
i, segment->lengthInFile, segment->sizeInMemory);
return ENOEXEC;
}
}
return 0;
}
|
Userseg.c中void Destroy_User_Context(struct User_Context* userContext)
{
KASSERT(userContext->refCount == 0);
/* Free the context's LDT descriptor */
Free_Segment_Descriptor(userContext->ldtDescriptor);
/* Free the context's memory */
Disable_Interrupts();
Free(userContext->memory);
Free(userContext);
Enable_Interrupts();
}
int Load_User_Program(char *exeFileData, ulong_t exeFileLength,
struct Exe_Format *exeFormat, const char *command,
struct User_Context **pUserContext)
{
int i;
ulong_t maxva = 0;
unsigned numArgs;
ulong_t argBlockSize;
ulong_t size, argBlockAddr;
struct User_Context *userContext = 0;
for (i = 0; i < exeFormat->numSegments; ++i) {
struct Exe_Segment *segment = &exeFormat->segmentList[i];
ulong_t topva = segment->startAddress + segment->sizeInMemory; /* FIXME: range check */
if (topva > maxva)
maxva = topva;
}
Get_Argument_Block_Size(command, &numArgs, &argBlockSize);
size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE;
argBlockAddr = size;
size += argBlockSize;
userContext = Create_User_Context(size);
if (userContext == 0)
return -1;
for (i = 0; i < exeFormat->numSegments; ++i) {
struct Exe_Segment *segment = &exeFormat->segmentList[i];
memcpy(userContext->memory + segment->startAddress,
exeFileData + segment->offsetInFile,
segment->lengthInFile);
}
Format_Argument_Block(userContext->memory + argBlockAddr, numArgs, argBlockAddr, command);
userContext->entryAddr = exeFormat->entryAddr;
userContext->argBlockAddr = argBlockAddr;
userContext->stackPointerAddr = argBlockAddr;
*pUserContext = userContext;
return 0;
}
bool Copy_From_User(void* destInKernel, ulong_t srcInUser, ulong_t bufSize)
{
struct User_Context* current = g_currentThread->userContext;
if (!Validate_User_Memory(current, srcInUser, bufSize))
return false;
memcpy(destInKernel, User_To_Kernel(current, srcInUser), bufSize);
return true;
}
bool Copy_To_User(ulong_t destInUser, void* srcInKernel, ulong_t bufSize)
{
struct User_Context* current = g_currentThread->userContext;
if (!Validate_User_Memory(current, destInUser, bufSize))
return false;
memcpy(User_To_Kernel(current, destInUser), srcInKernel, bufSize);
return true;
}
void Switch_To_Address_Space(struct User_Context *userContext)
{
ushort_t ldtSelector;
/* Switch to the LDT of the new user context */
ldtSelector = userContext->ldtSelector;
__asm__ __volatile__ (
"lldt %0"
:
: "a" (ldtSelector)
);
}
|
Kthresd.c中Start_User_Thread(struct User_Context* userContext, bool detached)
{
struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached);
if (kthread != 0) {
Setup_User_Thread(kthread, userContext);
Make_Runnable_Atomic(kthread);
}
return kthread;
}
void Setup_User_Thread(
struct Kernel_Thread* kthread, struct User_Context* userContext)
{
extern int userDebug;
ulong_t eflags = EFLAGS_IF;
ushort_t csSelector=userContext->csSelector;
ushort_t dsSelector=userContext->dsSelector;
Attach_User_Context(kthread, userContext);
Push(kthread, dsSelector);
Push(kthread, userContext->stackPointerAddr);
Push(kthread, eflags);
Push(kthread, csSelector);
Push(kthread, userContext->entryAddr);
if (userDebug) Print("Entry addr=%lx\n", userContext->entryAddr);
Push(kthread, 0);
Push(kthread, 0);
Push(kthread, 0); /* eax */
Push(kthread, 0); /* ebx */
Push(kthread, 0); /* edx */
Push(kthread, 0); /* edx */
Push(kthread, userContext->argBlockAddr); /* esi */
Push(kthread, 0); /* edi */
Push(kthread, 0); /* ebp */
Push(kthread, dsSelector); /* ds */
Push(kthread, dsSelector); /* es */
Push(kthread, dsSelector); /* fs */
Push(kthread, dsSelector); /* gs */
}
|
Syscall.c中static int Sys_Exit(struct Interrupt_State* state)
{
Exit(state->ebx);
}
static int Sys_PrintString(struct Interrupt_State* state)
{
int rc = 0;
uint_t length = state->ecx;
uchar_t* buf = 0;
if (length > 0) {
/* Copy string into kernel. */
if ((rc = Copy_User_String(state->ebx, length, 1023, (char**) &buf)) != 0)
goto done;
/* Write to console. */
Put_Buf(buf, length);
}
done:
if (buf != 0)
Free(buf);
return rc;
}
static int Sys_GetKey(struct Interrupt_State* state)
{
return Wait_For_Key();
}
static int Sys_SetAttr(struct Interrupt_State* state)
{
Set_Current_Attr((uchar_t) state->ebx);
return 0;
}
static int Sys_GetCursor(struct Interrupt_State* state)
{
int row, col;
Get_Cursor(&row, &col);
if (!Copy_To_User(state->ebx, &row, sizeof(int)) ||
!Copy_To_User(state->ecx, &col, sizeof(int)))
return -1;
return 0;
}
static int Sys_PutCursor(struct Interrupt_State* state)
{
return Put_Cursor(state->ebx, state->ecx) ? 0 : -1;
}
static int Sys_Spawn(struct Interrupt_State* state)
{
int rc;
char *program = 0;
char *command = 0;
struct Kernel_Thread *process;
/* Copy program name and command from user space. */
if ((rc = Copy_User_String(state->ebx, state->ecx, VFS_MAX_PATH_LEN, &program)) != 0 ||
(rc = Copy_User_String(state->edx, state->esi, 1023, &command)) != 0)
goto done;
Enable_Interrupts();
rc = Spawn(program, command, &process);
if (rc == 0) {
KASSERT(process != 0);
rc = process->pid;
}
Disable_Interrupts();
done:
if (program != 0)
Free(program);
if (command != 0)
Free(command);
return rc;
}
static int Sys_Wait(struct Interrupt_State* state)
{
int exitCode;
struct Kernel_Thread *kthread = Lookup_Thread(state->ebx);
if (kthread == 0)
return -12;
Enable_Interrupts();
exitCode = Join(kthread);
Disable_Interrupts();
return exitCode;
}
static int Sys_GetPID(struct Interrupt_State* state)
{
return g_currentThread->pid;
}
|
阅读(3431) | 评论(0) | 转发(0) |