清华大学操作系统lab1_实验报告 下载本文

内容发布更新时间 : 2024/5/20 7:51:55星期一 下面是文章的全部内容请认真阅读。

中断向量表一个表项占用8字节,其中2-3字节是段选择子,0-1字节和6-7字节拼成位移,入口地址=段选择子+段内偏移量。

(2) 完善kern/trap/trap.c中对中断向量表进行初始化的函数idt_init

可以在/lab1/kern/mm/mmu.h中可以找到SETGATE函数,查找其具体操作。 idt_init(void) {

extern uintptr_t __vectors[]; int i;

for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {

SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL); //设置IDT }

lidt(&idt_pd); //载入IDT表

(3) 完善trap.c中的中断处理函数trap,在对时钟中断进行处理的部分填写trap函数 case IRQ_OFFSET + IRQ_TIMER:

ticks ++; //一次中断累加1 if (ticks % TICK_NUM == 0) { print_ticks(); }

break;

扩展:

(1) 内核态切换到用户态:

lab1_switch_to_user(void) {

asm volatile (

\

// esp-8 为下一步复制的栈帧留好 tf_ss和tf_esp的位置 \ \ : : \ ); } case T_SWITCH_TOU: if (tf->tf_cs != USER_CS) { switchk2u = *tf;

switchk2u.tf_cs = USER_CS;

switchk2u.tf_ds = switchk2u.tf_es = switchk2u.tf_ss = USER_DS; switchk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8;

//在执行int120前系统在核心态,int不会引起栈的切换

switchk2u.tf_eflags |= FL_IOPL_MASK;

*((uint32_t *)tf - 1) = (uint32_t)&switchk2u; }

break;

最后iret时返回5个值。 (2) 用户态切换到内核态:

lab1_switch_to_kernel(void) { asm volatile ( \

\ :

: \ ); }

case T_SWITCH_TOK: if (tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = tf->tf_es = KERNEL_DS; tf->tf_eflags &= ~FL_IOPL_MASK; //定位临时栈的栈顶

switchu2k = (struct trapframe *)(tf->tf_esp - (sizeof(struct trapframe) - 8)); //复制

memmove(switchu2k, tf, sizeof(struct trapframe) - 8); //在执行int120前系统在核心态,int会引起栈的切换,iret不会引起 //栈的切换

*((uint32_t *)tf - 1) = (uint32_t)switchu2k; /*设置临时栈,指向switchu2k,这样iret返回时,CPU会从switchu2k恢复数据, 而不是从现有栈恢复数据。*/

} break;

最后iret返回三个值

Question:

将用户态转到内核态不用临时栈,直接在原来的栈进行操作?