Jos - lab4 (Part A) Round-Robin Scheduling

来源:互联网 发布:最小中文linux操作系统 编辑:程序博客网 时间:2024/06/05 10:14

Exercise 6.Implement round-robin scheduling in sched_yield()as described above. Don't forget to modifysyscall() to dispatchsys_yield().

这段code不算太多,不过一直碰到一个问题,每次sys_halt()以后就出现Gerneral Protection的exception:

HLT—Halt
Opcode Instruction Description
F4 HLT Halt
Description
Stops instruction execution and places the processor in a HALT state. An enabled interrupt
(including NMI and SMI), a debug exception, the BINIT# signal, the INIT# signal, or the
RESET# signal will resume execution. If an interrupt (including NMI) is used to resume execu-
tion after a HLT instruction, the saved instruction pointer (CS:EIP) points to the instruction
following the HLT instruction.
The HLT instruction is a privileged instruction. When the processor is running in protected or
virtual-8086 mode, the privilege level of a program or procedure must be 0 to execute the HLT
instruction.

看起来是发生的权限问题,而根据打出的栈信息来看,cs[bit1][bit0] = 00, 已经是最高级别了,所以看到权限访问上是没有问题的。

  trap 0x0000000d General Protection
  err  0x00000102
  eip  0xf0105499
  cs   0x----0008

flag 0x00000246

继续追踪,发现在原来的算法中如果当前指向的envs[0]是RUNNABLE状态的话,就会永远处于被忽略的状态,在原来的轮询中永远排不上,结果就导致了改进入monitor()的循环,却进了halt。至于最后为什么导致generation protection的问题,还没有完全搞清楚。粗线部分是后加的补丁。

 32         int i, pos = 0;
 33         struct Env *thisenv = thiscpu->cpu_env;
 34         if (thisenv == NULL)
 35                 thisenv = &envs[0];
 37         // find the position of thisenv in envs[]
 38         for (i = 0; i < NENV; i++) {
 39                 if (&envs[i] == thisenv) {
 40                         pos = i;
 41                         break;
 42                 }
 43         }
 45         for (i = (pos+1)%NENV; i != pos; i = (i+1)%NENV) {
 46                 if (envs[i].env_status == ENV_RUNNABLE) {
 47                         // Following are all done in env_run()
 48                         //c->cpu_env->env_status = ENV_RUNNABLE;
 49                         //c->cpu_env = &envs[i];
 50                         //unlock_kernel();
 52                         env_run(&envs[i]);
 53                 }
 54         }
 55         //if ((i == pos) && (thisenv->env_status == ENV_RUNNING)) {
 56         if ((thisenv->env_status == ENV_RUNNING) || (thisenv->env_status == ENV_RUNNABLE)) {
 59                         env_run(thisenv);
 60         }
 62         // sched_halt never returns
 63         sched_halt();

可是在cpu数目多的情况下还是会出现一定概率的page fault,从user在执行env_destroy的时候。

根据trap_init_percpu()的提示应该是设置某个cpu的TSS时出问题了。观察过几个log,发现enviroment[1000]在free后又被调用了,仔细review上面的代码逻辑,就会发现还是有问题的,如果thisenv为NULL的情况下默认把它设置成env[0],会造成一定概率下它被两个以上的cpu同时run起来(见56行),因此最后的版本如下:

 32         int i, pos = 0;
 33         struct Env *thisenv = thiscpu->cpu_env;
 63         if (thisenv != NULL) {
 65                 // find the position of thisenv in envs[]
 66                 for (i = 0; i < NENV; i++) {
 67                         if (&envs[i] == thisenv) {
 68                                 pos = i;
 69                                 break;
 70                         }
 71                 }
 73         }
 74         for (i = (pos+1)%NENV; i != pos; i = (i+1)%NENV) {
 75                 if (envs[i].env_status == ENV_RUNNABLE) {
 77                         env_run(&envs[i]);
 78                 }
 79         }
 80         if (envs[i].env_status == ENV_RUNNABLE) { // envs[pos] will be exclusive by above loop
 82                 env_run(&envs[i]);
 83         }
 84         if (thisenv != NULL) {
 85                 if (thisenv->env_status == ENV_RUNNING) {
 87                         env_run(thisenv);
 88                 }
 89         }
 92         // sched_halt never returns
 93         sched_halt();



最后再回头稍微提一下hlt造成的General Protection fault:

General Protection Fault

A General Protection Fault may occur for various reasons. The most common are:

  • Segment error (privilege, type, limit, read/write rights).
  • Executing a privileged instruction while CPL != 0.
  • Writing a 1 in a reserved register field.
  • Referencing or accessing a null-descriptor.

The saved instruction pointer points to the instruction which caused the exception.

Error code: The General Protection Fault sets an error code, which is thesegment selector index when the exception is segment related. Otherwise, 0.

Selector Error Code

 31         16   15         3   2   1   0+---+--  --+---+---+--  --+---+---+---+---+|   Reserved   |    Index     |  Tbl  | E |+---+--  --+---+---+--  --+---+---+---+---+
 LengthNameDescriptionE1 bitExternalWhen set, the exception originated externally to the processor.Tbl2 bitsIDT/GDT/LDT tableThis is one of the following values:ValueDescription0b00The Selector Index references a descriptor in the GDT.0b01The Selector Index references a descriptor in the IDT.0b10The Selector Index references a descriptor in the LDT.0b11The Selector Index references a descriptor in the IDT.Index13 bitsSelector IndexThe index in the GDT, IDT or LDT.

我们发现halt的error code 是102,根据上文的信息,这个异常还是和segment相关,并非halt的权限访问问题,并且tbl=0x01(IDT), Index = 0x102>>3 = 0x20, 可是idt[20]并不存在!!!到了这个份上,我只想怀疑是qemu模拟器的bug -_-|||

Question

3. In your implementation of env_run() you should havecalled lcr3(). Before and after the call tolcr3(), your code makes references (at least it should)to the variablee, the argument to env_run.Upon loading the %cr3 register, the addressing contextused by the MMU is instantly changed. But a virtualaddress (namelye) has meaning relative to a givenaddress context--the address context specifies the physical address towhich the virtual address maps. Why can the pointere bedereferenced both before and after the addressing switch?

A: For every userspace environment, they shared the same ENVS[] with each other(in fact the whole kernel part virtual memory), so the e is dereferenced to the same address.

1 0