《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
9.3 KiB

  1. #include <defs.h>
  2. #include <mmu.h>
  3. #include <memlayout.h>
  4. #include <clock.h>
  5. #include <trap.h>
  6. #include <x86.h>
  7. #include <stdio.h>
  8. #include <assert.h>
  9. #include <console.h>
  10. #include <vmm.h>
  11. #include <swap.h>
  12. #include <kdebug.h>
  13. #include <unistd.h>
  14. #include <syscall.h>
  15. #include <error.h>
  16. #include <sched.h>
  17. #include <sync.h>
  18. #define TICK_NUM 100
  19. static void print_ticks() {
  20. cprintf("%d ticks\n",TICK_NUM);
  21. #ifdef DEBUG_GRADE
  22. cprintf("End of Test.\n");
  23. panic("EOT: kernel seems ok.");
  24. #endif
  25. }
  26. /* *
  27. * Interrupt descriptor table:
  28. *
  29. * Must be built at run time because shifted function addresses can't
  30. * be represented in relocation records.
  31. * */
  32. static struct gatedesc idt[256] = {{0}};
  33. static struct pseudodesc idt_pd = {
  34. sizeof(idt) - 1, (uintptr_t)idt
  35. };
  36. /* idt_init - initialize IDT to each of the entry points in kern/trap/vectors.S */
  37. void
  38. idt_init(void) {
  39. /* LAB1 YOUR CODE : STEP 2 */
  40. /* (1) Where are the entry addrs of each Interrupt Service Routine (ISR)?
  41. * All ISR's entry addrs are stored in __vectors. where is uintptr_t __vectors[] ?
  42. * __vectors[] is in kern/trap/vector.S which is produced by tools/vector.c
  43. * (try "make" command in lab1, then you will find vector.S in kern/trap DIR)
  44. * You can use "extern uintptr_t __vectors[];" to define this extern variable which will be used later.
  45. * (2) Now you should setup the entries of ISR in Interrupt Description Table (IDT).
  46. * Can you see idt[256] in this file? Yes, it's IDT! you can use SETGATE macro to setup each item of IDT
  47. * (3) After setup the contents of IDT, you will let CPU know where is the IDT by using 'lidt' instruction.
  48. * You don't know the meaning of this instruction? just google it! and check the libs/x86.h to know more.
  49. * Notice: the argument of lidt is idt_pd. try to find it!
  50. */
  51. /* LAB5 YOUR CODE */
  52. //you should update your lab1 code (just add ONE or TWO lines of code), let user app to use syscall to get the service of ucore
  53. //so you should setup the syscall interrupt gate in here
  54. extern uintptr_t __vectors[];
  55. int i;
  56. for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
  57. SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
  58. }
  59. SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);
  60. lidt(&idt_pd);
  61. }
  62. static const char *
  63. trapname(int trapno) {
  64. static const char * const excnames[] = {
  65. "Divide error",
  66. "Debug",
  67. "Non-Maskable Interrupt",
  68. "Breakpoint",
  69. "Overflow",
  70. "BOUND Range Exceeded",
  71. "Invalid Opcode",
  72. "Device Not Available",
  73. "Double Fault",
  74. "Coprocessor Segment Overrun",
  75. "Invalid TSS",
  76. "Segment Not Present",
  77. "Stack Fault",
  78. "General Protection",
  79. "Page Fault",
  80. "(unknown trap)",
  81. "x87 FPU Floating-Point Error",
  82. "Alignment Check",
  83. "Machine-Check",
  84. "SIMD Floating-Point Exception"
  85. };
  86. if (trapno < sizeof(excnames)/sizeof(const char * const)) {
  87. return excnames[trapno];
  88. }
  89. if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16) {
  90. return "Hardware Interrupt";
  91. }
  92. return "(unknown trap)";
  93. }
  94. /* trap_in_kernel - test if trap happened in kernel */
  95. bool
  96. trap_in_kernel(struct trapframe *tf) {
  97. return (tf->tf_cs == (uint16_t)KERNEL_CS);
  98. }
  99. static const char *IA32flags[] = {
  100. "CF", NULL, "PF", NULL, "AF", NULL, "ZF", "SF",
  101. "TF", "IF", "DF", "OF", NULL, NULL, "NT", NULL,
  102. "RF", "VM", "AC", "VIF", "VIP", "ID", NULL, NULL,
  103. };
  104. void
  105. print_trapframe(struct trapframe *tf) {
  106. cprintf("trapframe at %p\n", tf);
  107. print_regs(&tf->tf_regs);
  108. cprintf(" ds 0x----%04x\n", tf->tf_ds);
  109. cprintf(" es 0x----%04x\n", tf->tf_es);
  110. cprintf(" fs 0x----%04x\n", tf->tf_fs);
  111. cprintf(" gs 0x----%04x\n", tf->tf_gs);
  112. cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
  113. cprintf(" err 0x%08x\n", tf->tf_err);
  114. cprintf(" eip 0x%08x\n", tf->tf_eip);
  115. cprintf(" cs 0x----%04x\n", tf->tf_cs);
  116. cprintf(" flag 0x%08x ", tf->tf_eflags);
  117. int i, j;
  118. for (i = 0, j = 1; i < sizeof(IA32flags) / sizeof(IA32flags[0]); i ++, j <<= 1) {
  119. if ((tf->tf_eflags & j) && IA32flags[i] != NULL) {
  120. cprintf("%s,", IA32flags[i]);
  121. }
  122. }
  123. cprintf("IOPL=%d\n", (tf->tf_eflags & FL_IOPL_MASK) >> 12);
  124. if (!trap_in_kernel(tf)) {
  125. cprintf(" esp 0x%08x\n", tf->tf_esp);
  126. cprintf(" ss 0x----%04x\n", tf->tf_ss);
  127. }
  128. }
  129. void
  130. print_regs(struct pushregs *regs) {
  131. cprintf(" edi 0x%08x\n", regs->reg_edi);
  132. cprintf(" esi 0x%08x\n", regs->reg_esi);
  133. cprintf(" ebp 0x%08x\n", regs->reg_ebp);
  134. cprintf(" oesp 0x%08x\n", regs->reg_oesp);
  135. cprintf(" ebx 0x%08x\n", regs->reg_ebx);
  136. cprintf(" edx 0x%08x\n", regs->reg_edx);
  137. cprintf(" ecx 0x%08x\n", regs->reg_ecx);
  138. cprintf(" eax 0x%08x\n", regs->reg_eax);
  139. }
  140. static inline void
  141. print_pgfault(struct trapframe *tf) {
  142. /* error_code:
  143. * bit 0 == 0 means no page found, 1 means protection fault
  144. * bit 1 == 0 means read, 1 means write
  145. * bit 2 == 0 means kernel, 1 means user
  146. * */
  147. cprintf("page fault at 0x%08x: %c/%c [%s].\n", rcr2(),
  148. (tf->tf_err & 4) ? 'U' : 'K',
  149. (tf->tf_err & 2) ? 'W' : 'R',
  150. (tf->tf_err & 1) ? "protection fault" : "no page found");
  151. }
  152. static int
  153. pgfault_handler(struct trapframe *tf) {
  154. extern struct mm_struct *check_mm_struct;
  155. if(check_mm_struct !=NULL) { //used for test check_swap
  156. print_pgfault(tf);
  157. }
  158. struct mm_struct *mm;
  159. if (check_mm_struct != NULL) {
  160. assert(current == idleproc);
  161. mm = check_mm_struct;
  162. }
  163. else {
  164. if (current == NULL) {
  165. print_trapframe(tf);
  166. print_pgfault(tf);
  167. panic("unhandled page fault.\n");
  168. }
  169. mm = current->mm;
  170. }
  171. return do_pgfault(mm, tf->tf_err, rcr2());
  172. }
  173. static volatile int in_swap_tick_event = 0;
  174. extern struct mm_struct *check_mm_struct;
  175. static void
  176. trap_dispatch(struct trapframe *tf) {
  177. char c;
  178. int ret=0;
  179. switch (tf->tf_trapno) {
  180. case T_PGFLT: //page fault
  181. if ((ret = pgfault_handler(tf)) != 0) {
  182. print_trapframe(tf);
  183. if (current == NULL) {
  184. panic("handle pgfault failed. ret=%d\n", ret);
  185. }
  186. else {
  187. if (trap_in_kernel(tf)) {
  188. panic("handle pgfault failed in kernel mode. ret=%d\n", ret);
  189. }
  190. cprintf("killed by kernel.\n");
  191. panic("handle user mode pgfault failed. ret=%d\n", ret);
  192. do_exit(-E_KILLED);
  193. }
  194. }
  195. break;
  196. case T_SYSCALL:
  197. syscall();
  198. break;
  199. case IRQ_OFFSET + IRQ_TIMER:
  200. #if 0
  201. LAB3 : If some page replacement algorithm(such as CLOCK PRA) need tick to change the priority of pages,
  202. then you can add code here.
  203. #endif
  204. /* LAB1 YOUR CODE : STEP 3 */
  205. /* handle the timer interrupt */
  206. /* (1) After a timer interrupt, you should record this event using a global variable (increase it), such as ticks in kern/driver/clock.c
  207. * (2) Every TICK_NUM cycle, you can print some info using a funciton, such as print_ticks().
  208. * (3) Too Simple? Yes, I think so!
  209. */
  210. /* LAB5 YOUR CODE */
  211. /* you should upate you lab1 code (just add ONE or TWO lines of code):
  212. * Every TICK_NUM cycle, you should set current process's current->need_resched = 1
  213. */
  214. ticks ++;
  215. if (ticks % TICK_NUM == 0) {
  216. assert(current != NULL);
  217. current->need_resched = 1;
  218. }
  219. break;
  220. case IRQ_OFFSET + IRQ_COM1:
  221. c = cons_getc();
  222. cprintf("serial [%03d] %c\n", c, c);
  223. break;
  224. case IRQ_OFFSET + IRQ_KBD:
  225. c = cons_getc();
  226. cprintf("kbd [%03d] %c\n", c, c);
  227. break;
  228. //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes.
  229. case T_SWITCH_TOU:
  230. case T_SWITCH_TOK:
  231. panic("T_SWITCH_** ??\n");
  232. break;
  233. case IRQ_OFFSET + IRQ_IDE1:
  234. case IRQ_OFFSET + IRQ_IDE2:
  235. /* do nothing */
  236. break;
  237. default:
  238. print_trapframe(tf);
  239. if (current != NULL) {
  240. cprintf("unhandled trap.\n");
  241. do_exit(-E_KILLED);
  242. }
  243. // in kernel, it must be a mistake
  244. panic("unexpected trap in kernel.\n");
  245. }
  246. }
  247. /* *
  248. * trap - handles or dispatches an exception/interrupt. if and when trap() returns,
  249. * the code in kern/trap/trapentry.S restores the old CPU state saved in the
  250. * trapframe and then uses the iret instruction to return from the exception.
  251. * */
  252. void
  253. trap(struct trapframe *tf) {
  254. // dispatch based on what type of trap occurred
  255. // used for previous projects
  256. if (current == NULL) {
  257. trap_dispatch(tf);
  258. }
  259. else {
  260. // keep a trapframe chain in stack
  261. struct trapframe *otf = current->tf;
  262. current->tf = tf;
  263. bool in_kernel = trap_in_kernel(tf);
  264. trap_dispatch(tf);
  265. current->tf = otf;
  266. if (!in_kernel) {
  267. if (current->flags & PF_EXITING) {
  268. do_exit(-E_KILLED);
  269. }
  270. if (current->need_resched) {
  271. schedule();
  272. }
  273. }
  274. }
  275. }