使用tss进行内核上下文切换

时间:2013-07-06 16:27:32

标签: operating-system kernel nasm osdev

我正在开发一个简单的内核,我希望有关上下文切换的帮助。到目前为止,我有以下代码:=

inline
void protect_init_tsssegment(  register
                           struct segment_descriptor *psd,
                           unsigned int base,
                           unsigned int limit,  /* must be >= 0x67, sizeof struct TSS in struct process */
               unsigned char privilege )
{
     /* see figure 6-3 of Intel developer's manual */
     protect_init_systemdesc(psd,base,limit);
     /* system descriptor */
     _SET_DESC_SYSTEM(psd,_DESC_SYSSEG);
     /* mark as present */
     _SET_DESC_PRESENT(psd,_DESC_PRESENTF);
     /* privilege level */
     _SET_DESC_DPL(psd,privilege);
     /* TSS descriptor */
     _SET_DESC_TYPE(psd,_DESC_TSS);

  }/* protect_init_tsssegment */

static
void init_proc_loop()
{
    for(;;)
        printk("init_proc_loop:: idle\n");

}// init_proc_loop

static
void load_tss_in_gdt(void *tss, unsigned char priv, int gdt)
{
    struct segment_descriptor *psd = &GDT[gdt];
    protect_init_tsssegment(psd,
                           (unsigned int)tss,
                           sizeof(struct tss),
                           priv);
}// load_tss_in_gdt

    // Create a struct process entry for init task.
    void create_init_task()
{
    unsigned long msize = PAGE_SIZE + sizeof(struct process);
    struct process *proc = (struct process *)kmalloc(msize);
    unsigned int i = 0, j = 0;

    printk("create_init_task called line %d file %s\n",__LINE__,__FILE__);

    memset(proc, 0x0, msize);
    i = alloc_gdt();
    load_tss_in_gdt(&(proc->p_tss), 0, i);
    proc->p_tss_seg = i * 8; // Offset into GDT table.
    proc->p_state   = P_UNINTERUPTIBLE;
    proc->p_pid     = 1;
    proc->p_parent  = 1;
    proc->p_counter = (1 << 20); // Starting count. Decrement and pick lowest.
    proc->p_priority= 0; // Initially on the first queue.
    proc->p_tss.previous_task_link = 0;
    proc->p_tss.esp0 = msize + (long)proc; // Assume that stack grows down.
    proc->p_tss.ss0 = KERNEL_CS;
    proc->p_tss.cr3 = get_page_dir();
    proc->p_tss.eip = &init_proc_loop;
    proc->p_tss.eflags = 0x0002;
    proc->p_tss.eax = 0; // Return value for child is 0.
    proc->p_tss.ebx = 0;
    proc->p_tss.ecx = 0;
    proc->p_tss.edx = 0;
    proc->p_tss.esp = 0;
    proc->p_tss.esp = msize + (long)proc;
    proc->p_tss.ebp = 0;
    proc->p_tss.esi = 0;
    proc->p_tss.edi = 0;
    proc->p_tss.es = KERNEL_DS;
    proc->p_tss.cs = KERNEL_CS;
    proc->p_tss.ss = KERNEL_CS;
    proc->p_tss.ds = KERNEL_DS;
    proc->p_tss.fs = KERNEL_DS;
    proc->p_tss.gs = KERNEL_DS;
    // Save the math cpu state.
    __asm__("clts; fnsave %0"::"m" (proc->p_tss.i387));
    proc->p_exec = NULL;
    proc->p_exec_size = 0;
    proc->p_elf_entry = NULL;
    proc->p_argc = 0;
    proc->p_envp = NULL;
    proc->p_delete_argv = 0;
    proc->p_argv = NULL;
    proc->p_first_exec = 0; // No, we are running in the kernel.

    // Setup root access.
    proc->p_uid  = 0;
    proc->p_euid = 0;
    proc->p_suid = 0;
    proc->p_gid  = 0;
    proc->p_egid = 0;
    proc->p_sgid = 0;

    // Insert into queue 0.
    i = proc->p_priority;
    if(process_tab[i]) {
        proc->p_next = process_tab[i]->p_next;
        proc->p_prev = process_tab[i];
        proc->p_next->p_prev = proc;
        process_tab[i]->p_next = proc;
    } else {
        // Insert as the head.
        proc->p_next = proc;
        proc->p_prev = proc;
        process_tab[i] = proc;
    }
}// create_init_task

    // current is a pointer to struct process which is selected
    // in schedule(), we want to switch to it. current->p_tss_seg
    // is intended to be the offset into the gdt where the tss
    // segment descriptor lives. I calculate it as index * 8 bytes
    // so if we are at index 6, p_tss_seg is 48.
void
c_switch_to_current(void)
{
    unsigned int sel[2] = {0};

    if(current_process) {
        // sel[0] = offset which is not used in a task switch.
        sel[1] = current_process->p_tss_seg;
        printk("c_switch_to_current:: switching task seg %d\n",sel[1]);
        asm("lcall %0": :"m" (*sel));
    } else {
        panic("c_switch_to_current:: null current_process\n");
    }

}// c_switch_to_current

当我调用c_switch_to_current在schedule()之后切换到当前进程时, 内核收到无效操作的异常,然后是页面错误。 我不确定问题是什么,并希望得到帮助。我期望看到 init_proc_loop()的输出而不是崩溃。 感谢

0 个答案:

没有答案