Chinaunix首页 | 论坛 | 博客
  • 博客访问: 17191
  • 博文数量: 6
  • 博客积分: 1481
  • 博客等级: 上尉
  • 技术积分: 55
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-31 00:24
文章分类
文章存档

2010年(6)

我的朋友
最近访客

分类:

2010-06-25 18:29:04

1 项目要求 
1)修改src/GeekOS/user.c文件中的函数Spawn(),其功能是生成一个用户级进程。
2src/GeekOS/user.c文件中的函数Switch_To_User_Contex(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间。
3src/GeekOS/elf.c文件中的函数Prase_ELF_Executable()
(4)Destry_User_Contex(),Load_User_Programe(),Copy_From_User(),Copy_To_User(),Switch_To_Address_Space()。
5src/GeekOS/kthread.c文件中Start_User_Thread函数和Setup_User_Thread函数。
6src/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) |
给主人留下些什么吧!~~