void set_tss_gate(int nr, long base, int dpl, long limit) { char *addr = ((char*)gdt) + _TSS(nr); *(short*)addr = limit; *(short*)(addr + 2) = base & 0xffff; *(addr + 4) = (base >> 16) & 0xff; *(addr + 5) = 0x80 + ((dpl & 0x03) << 5) + 0x09; *(addr + 6) = 0x00; *(addr + 7) = (base >> 24) & 0xff; }
void init_schedule() { current = (struct task_t *)0; tasks_count = 0; register_task(0); tasks[0].t_counter = 0; tasks[0].t_priority = 0; current = &tasks[0]; asm volatile ("pushfl; andl $0xffffbfff, (%esp); popfl"); /* clear NT */ asm volatile ("ltr %%ax"::"a"(_TSS(0))); asm volatile ("lldt %%ax"::"a"(_LDT(0))); }
static void switch_to(int next) { struct {long a,b;} tmp; if (&tasks[next] == current) { return ; } if (current) { current->t_state = TASK_READY; } current = &tasks[next]; current->t_state = TASK_RUNNING; tmp.b = _TSS(next); asm volatile ( "ljmp %0" ::"m"(*&tmp.a) ); }
} void sched_init(void) { /* 初始化进程控制块指针数组 */ /* nothing.在bss段,已被清零 */ proc[0] = &init_proc.proc; current = proc[0]; ticks = 0; /* 设置进程0的ldt和tss描述符 */ set_ldt_desc(0, V_KERNEL_ZONE_START+(unsigned long)&(proc[0]->ldt)); set_tss_desc(0, V_KERNEL_ZONE_START+(unsigned long)&(proc[0]->tss)); /* 装载进程0的ldt和tss选择符,第一次需我们来加载 */ lldt(_LDT(0)); ltr(_TSS(0)); /* 挂载时钟中断处理程序 */ set_idt(INT_R0, timer_int, NR_TIMER_INT); /* 设置8253定时器芯片 */ out_b(0x43, 0x36); out_b(0x40, (LATCH & 0xff)); out_b(0x40, ((LATCH>>8) & 0xff)); /* 挂载系统调用处理程序 */
asmlinkage int sys_fork(struct pt_regs regs) { struct task_struct *tsk; int nr; long flags; unsigned long used_memory = 0; save_flags(flags); cli(); // find a free entry in the process table nr = find_empty_process(); if (nr < 0) { printk("fork: pids not available at the moment!\n"); goto fork_no_entry; } // allocate a page for the process descriptor tsk = (struct task_struct *) get_free_page(); if (!tsk) { goto fork_no_mem; } // copy descriptor: pid and counter will contain different values for // father and child *tsk = *current; tsk->pid = nr; tsk->counter = tsk->priority; // if we are forking the idle process, we assume its child will call an // exec just after the fork. In this case we do not duplicate code/data. // If we are forking whatever process, so it is necessary allocate a // page for it (containing code and data) e setup its LDT to the new // address space if (current->pid != 0) { // allocate memory for code/data tsk->mem = (char *) get_free_pages(current->used_pages); if (!tsk->mem) { goto fork_data_no_mem; } // total memory used by current process used_memory = current->used_pages * PAGE_SIZE; // copy process data memcpy(tsk->mem, current->mem, used_memory); // set up LDT set_code_desc(&(tsk->ldt[1]), (u_long) tsk->mem, used_memory); set_data_desc(&(tsk->ldt[2]), (u_long) tsk->mem, used_memory); } // setup TSS tsk->tss.back_link = 0; tsk->tss.esp0 = PAGE_SIZE + (unsigned long) tsk; tsk->tss.ss0 = KERNEL_DS; tsk->tss.esp1 = 0; tsk->tss.ss1 = 0; tsk->tss.esp2 = 0; tsk->tss.ss2 = 0; tsk->tss.cr3 = 0; tsk->tss.eip = regs.eip; tsk->tss.eflags = regs.eflags; tsk->tss.eax = 0; tsk->tss.ecx = regs.ecx; tsk->tss.edx = regs.edx; tsk->tss.ebx = regs.ebx; tsk->tss.esp = regs.esp; tsk->tss.ebp = regs.ebp; tsk->tss.esi = regs.esi; tsk->tss.edi = regs.edi; tsk->tss.es = regs.xes & 0xffff; tsk->tss.cs = regs.xcs & 0xffff; tsk->tss.ss = regs.xss & 0xffff; tsk->tss.ds = regs.xds & 0xffff; // it is not necessary set FS and GS tsk->tss.ldt = _LDT(nr); tsk->tss.trace = 0; tsk->tss.bitmap = 0xDFFF; tsk->tss.tr = _TSS(nr); set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY, &(tsk->tss)); set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, &(tsk->ldt), 3); task[nr] = tsk; restore_flags(flags); return nr; fork_data_no_mem: free_page(tsk); fork_no_mem: restore_flags(flags); return -ENOMEM; fork_no_entry: restore_flags(flags); return -EAGAIN; }