我正在开发一个简单的内核,我希望有关上下文切换的帮助。到目前为止,我有以下代码:=
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()的输出而不是崩溃。 感谢