《操作系统》的实验代码。
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.

400 lines
13 KiB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
  1. #include <vmm.h>
  2. #include <sync.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <stdio.h>
  6. #include <error.h>
  7. #include <pmm.h>
  8. #include <x86.h>
  9. #include <swap.h>
  10. #include <kmalloc.h>
  11. /*
  12. vmm design include two parts: mm_struct (mm) & vma_struct (vma)
  13. mm is the memory manager for the set of continuous virtual memory
  14. area which have the same PDT. vma is a continuous virtual memory area.
  15. There a linear link list for vma & a redblack link list for vma in mm.
  16. ---------------
  17. mm related functions:
  18. golbal functions
  19. struct mm_struct * mm_create(void)
  20. void mm_destroy(struct mm_struct *mm)
  21. int do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr)
  22. --------------
  23. vma related functions:
  24. global functions
  25. struct vma_struct * vma_create (uintptr_t vm_start, uintptr_t vm_end,...)
  26. void insert_vma_struct(struct mm_struct *mm, struct vma_struct *vma)
  27. struct vma_struct * find_vma(struct mm_struct *mm, uintptr_t addr)
  28. local functions
  29. inline void check_vma_overlap(struct vma_struct *prev, struct vma_struct *next)
  30. ---------------
  31. check correctness functions
  32. void check_vmm(void);
  33. void check_vma_struct(void);
  34. void check_pgfault(void);
  35. */
  36. static void check_vmm(void);
  37. static void check_vma_struct(void);
  38. static void check_pgfault(void);
  39. // mm_create - alloc a mm_struct & initialize it.
  40. struct mm_struct *
  41. mm_create(void) {
  42. struct mm_struct *mm = kmalloc(sizeof(struct mm_struct));
  43. if (mm != NULL) {
  44. list_init(&(mm->mmap_list));
  45. mm->mmap_cache = NULL;
  46. mm->pgdir = NULL;
  47. mm->map_count = 0;
  48. if (swap_init_ok) swap_init_mm(mm);
  49. else mm->sm_priv = NULL;
  50. }
  51. return mm;
  52. }
  53. // vma_create - alloc a vma_struct & initialize it. (addr range: vm_start~vm_end)
  54. struct vma_struct *
  55. vma_create(uintptr_t vm_start, uintptr_t vm_end, uint32_t vm_flags) {
  56. struct vma_struct *vma = kmalloc(sizeof(struct vma_struct));
  57. if (vma != NULL) {
  58. vma->vm_start = vm_start;
  59. vma->vm_end = vm_end;
  60. vma->vm_flags = vm_flags;
  61. }
  62. return vma;
  63. }
  64. // find_vma - find a vma (vma->vm_start <= addr <= vma_vm_end)
  65. struct vma_struct *
  66. find_vma(struct mm_struct *mm, uintptr_t addr) {
  67. struct vma_struct *vma = NULL;
  68. if (mm != NULL) {
  69. vma = mm->mmap_cache;
  70. if (!(vma != NULL && vma->vm_start <= addr && vma->vm_end > addr)) {
  71. bool found = 0;
  72. list_entry_t *list = &(mm->mmap_list), *le = list;
  73. while ((le = list_next(le)) != list) {
  74. vma = le2vma(le, list_link);
  75. if (vma->vm_start<=addr && addr < vma->vm_end) {
  76. found = 1;
  77. break;
  78. }
  79. }
  80. if (!found) {
  81. vma = NULL;
  82. }
  83. }
  84. if (vma != NULL) {
  85. mm->mmap_cache = vma;
  86. }
  87. }
  88. return vma;
  89. }
  90. // check_vma_overlap - check if vma1 overlaps vma2 ?
  91. static inline void
  92. check_vma_overlap(struct vma_struct *prev, struct vma_struct *next) {
  93. assert(prev->vm_start < prev->vm_end);
  94. assert(prev->vm_end <= next->vm_start);
  95. assert(next->vm_start < next->vm_end);
  96. }
  97. // insert_vma_struct -insert vma in mm's list link
  98. void
  99. insert_vma_struct(struct mm_struct *mm, struct vma_struct *vma) {
  100. assert(vma->vm_start < vma->vm_end);
  101. list_entry_t *list = &(mm->mmap_list);
  102. list_entry_t *le_prev = list, *le_next;
  103. list_entry_t *le = list;
  104. while ((le = list_next(le)) != list) {
  105. struct vma_struct *mmap_prev = le2vma(le, list_link);
  106. if (mmap_prev->vm_start > vma->vm_start) {
  107. break;
  108. }
  109. le_prev = le;
  110. }
  111. le_next = list_next(le_prev);
  112. /* check overlap */
  113. if (le_prev != list) {
  114. check_vma_overlap(le2vma(le_prev, list_link), vma);
  115. }
  116. if (le_next != list) {
  117. check_vma_overlap(vma, le2vma(le_next, list_link));
  118. }
  119. vma->vm_mm = mm;
  120. list_add_after(le_prev, &(vma->list_link));
  121. mm->map_count ++;
  122. }
  123. // mm_destroy - free mm and mm internal fields
  124. void
  125. mm_destroy(struct mm_struct *mm) {
  126. list_entry_t *list = &(mm->mmap_list), *le;
  127. while ((le = list_next(list)) != list) {
  128. list_del(le);
  129. kfree(le2vma(le, list_link)); //kfree vma
  130. }
  131. kfree(mm); //kfree mm
  132. mm=NULL;
  133. }
  134. // vmm_init - initialize virtual memory management
  135. // - now just call check_vmm to check correctness of vmm
  136. void
  137. vmm_init(void) {
  138. check_vmm();
  139. }
  140. // check_vmm - check correctness of vmm
  141. static void
  142. check_vmm(void) {
  143. size_t nr_free_pages_store = nr_free_pages();
  144. check_vma_struct();
  145. check_pgfault();
  146. cprintf("check_vmm() succeeded.\n");
  147. }
  148. static void
  149. check_vma_struct(void) {
  150. size_t nr_free_pages_store = nr_free_pages();
  151. struct mm_struct *mm = mm_create();
  152. assert(mm != NULL);
  153. int step1 = 10, step2 = step1 * 10;
  154. int i;
  155. for (i = step1; i >= 1; i --) {
  156. struct vma_struct *vma = vma_create(i * 5, i * 5 + 2, 0);
  157. assert(vma != NULL);
  158. insert_vma_struct(mm, vma);
  159. }
  160. for (i = step1 + 1; i <= step2; i ++) {
  161. struct vma_struct *vma = vma_create(i * 5, i * 5 + 2, 0);
  162. assert(vma != NULL);
  163. insert_vma_struct(mm, vma);
  164. }
  165. list_entry_t *le = list_next(&(mm->mmap_list));
  166. for (i = 1; i <= step2; i ++) {
  167. assert(le != &(mm->mmap_list));
  168. struct vma_struct *mmap = le2vma(le, list_link);
  169. assert(mmap->vm_start == i * 5 && mmap->vm_end == i * 5 + 2);
  170. le = list_next(le);
  171. }
  172. for (i = 5; i <= 5 * step2; i +=5) {
  173. struct vma_struct *vma1 = find_vma(mm, i);
  174. assert(vma1 != NULL);
  175. struct vma_struct *vma2 = find_vma(mm, i+1);
  176. assert(vma2 != NULL);
  177. struct vma_struct *vma3 = find_vma(mm, i+2);
  178. assert(vma3 == NULL);
  179. struct vma_struct *vma4 = find_vma(mm, i+3);
  180. assert(vma4 == NULL);
  181. struct vma_struct *vma5 = find_vma(mm, i+4);
  182. assert(vma5 == NULL);
  183. assert(vma1->vm_start == i && vma1->vm_end == i + 2);
  184. assert(vma2->vm_start == i && vma2->vm_end == i + 2);
  185. }
  186. for (i =4; i>=0; i--) {
  187. struct vma_struct *vma_below_5= find_vma(mm,i);
  188. if (vma_below_5 != NULL ) {
  189. cprintf("vma_below_5: i %x, start %x, end %x\n",i, vma_below_5->vm_start, vma_below_5->vm_end);
  190. }
  191. assert(vma_below_5 == NULL);
  192. }
  193. mm_destroy(mm);
  194. cprintf("check_vma_struct() succeeded!\n");
  195. }
  196. struct mm_struct *check_mm_struct;
  197. // check_pgfault - check correctness of pgfault handler
  198. static void
  199. check_pgfault(void) {
  200. size_t nr_free_pages_store = nr_free_pages();
  201. check_mm_struct = mm_create();
  202. assert(check_mm_struct != NULL);
  203. struct mm_struct *mm = check_mm_struct;
  204. pde_t *pgdir = mm->pgdir = boot_pgdir;
  205. assert(pgdir[0] == 0);
  206. struct vma_struct *vma = vma_create(0, PTSIZE, VM_WRITE);
  207. assert(vma != NULL);
  208. insert_vma_struct(mm, vma);
  209. uintptr_t addr = 0x100;
  210. assert(find_vma(mm, addr) == vma);
  211. int i, sum = 0;
  212. for (i = 0; i < 100; i ++) {
  213. *(char *)(addr + i) = i;
  214. sum += i;
  215. }
  216. for (i = 0; i < 100; i ++) {
  217. sum -= *(char *)(addr + i);
  218. }
  219. assert(sum == 0);
  220. page_remove(pgdir, ROUNDDOWN(addr, PGSIZE));
  221. free_page(pa2page(pgdir[0]));
  222. pgdir[0] = 0;
  223. mm->pgdir = NULL;
  224. mm_destroy(mm);
  225. check_mm_struct = NULL;
  226. assert(nr_free_pages_store == nr_free_pages());
  227. cprintf("check_pgfault() succeeded!\n");
  228. }
  229. //page fault number
  230. volatile unsigned int pgfault_num=0;
  231. /* do_pgfault - interrupt handler to process the page fault execption
  232. * @mm : the control struct for a set of vma using the same PDT
  233. * @error_code : the error code recorded in trapframe->tf_err which is setted by x86 hardware
  234. * @addr : the addr which causes a memory access exception, (the contents of the CR2 register)
  235. *
  236. * CALL GRAPH: trap--> trap_dispatch-->pgfault_handler-->do_pgfault
  237. * The processor provides ucore's do_pgfault function with two items of information to aid in diagnosing
  238. * the exception and recovering from it.
  239. * (1) The contents of the CR2 register. The processor loads the CR2 register with the
  240. * 32-bit linear address that generated the exception. The do_pgfault fun can
  241. * use this address to locate the corresponding page directory and page-table
  242. * entries.
  243. * (2) An error code on the kernel stack. The error code for a page fault has a format different from
  244. * that for other exceptions. The error code tells the exception handler three things:
  245. * -- The P flag (bit 0) indicates whether the exception was due to a not-present page (0)
  246. * or to either an access rights violation or the use of a reserved bit (1).
  247. * -- The W/R flag (bit 1) indicates whether the memory access that caused the exception
  248. * was a read (0) or write (1).
  249. * -- The U/S flag (bit 2) indicates whether the processor was executing at user mode (1)
  250. * or supervisor mode (0) at the time of the exception.
  251. */
  252. int
  253. do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr) {
  254. int ret = -E_INVAL;
  255. //try to find a vma which include addr
  256. struct vma_struct *vma = find_vma(mm, addr);
  257. pgfault_num++;
  258. //If the addr is in the range of a mm's vma?
  259. if (vma == NULL || vma->vm_start > addr) {
  260. cprintf("not valid addr %x, and can not find it in vma\n", addr);
  261. goto failed;
  262. }
  263. //check the error_code
  264. switch (error_code & 3) {
  265. default:
  266. /* error code flag : default is 3 ( W/R=1, P=1): write, present */
  267. case 2: /* error code flag : (W/R=1, P=0): write, not present */
  268. if (!(vma->vm_flags & VM_WRITE)) {
  269. cprintf("do_pgfault failed: error code flag = write AND not present, but the addr's vma cannot write\n");
  270. goto failed;
  271. }
  272. break;
  273. case 1: /* error code flag : (W/R=0, P=1): read, present */
  274. cprintf("do_pgfault failed: error code flag = read AND present\n");
  275. goto failed;
  276. case 0: /* error code flag : (W/R=0, P=0): read, not present */
  277. if (!(vma->vm_flags & (VM_READ | VM_EXEC))) {
  278. cprintf("do_pgfault failed: error code flag = read AND not present, but the addr's vma cannot read or exec\n");
  279. goto failed;
  280. }
  281. }
  282. /* IF (write an existed addr ) OR
  283. * (write an non_existed addr && addr is writable) OR
  284. * (read an non_existed addr && addr is readable)
  285. * THEN
  286. * continue process
  287. */
  288. uint32_t perm = PTE_U;
  289. if (vma->vm_flags & VM_WRITE) {
  290. perm |= PTE_W;
  291. }
  292. addr = ROUNDDOWN(addr, PGSIZE);
  293. ret = -E_NO_MEM;
  294. pte_t *ptep=NULL;
  295. /*LAB3 EXERCISE 1: YOUR CODE
  296. * Maybe you want help comment, BELOW comments can help you finish the code
  297. *
  298. * Some Useful MACROs and DEFINEs, you can use them in below implementation.
  299. * MACROs or Functions:
  300. * get_pte : get an pte and return the kernel virtual address of this pte for la
  301. * if the PT contians this pte didn't exist, alloc a page for PT (notice the 3th parameter '1')
  302. * pgdir_alloc_page : call alloc_page & page_insert functions to allocate a page size memory & setup
  303. * an addr map pa<--->la with linear address la and the PDT pgdir
  304. * DEFINES:
  305. * VM_WRITE : If vma->vm_flags & VM_WRITE == 1/0, then the vma is writable/non writable
  306. * PTE_W 0x002 // page table/directory entry flags bit : Writeable
  307. * PTE_U 0x004 // page table/directory entry flags bit : User can access
  308. * VARIABLES:
  309. * mm->pgdir : the PDT of these vma
  310. *
  311. */
  312. #if 0
  313. /*LAB3 EXERCISE 1: YOUR CODE*/
  314. ptep = ??? //(1) try to find a pte, if pte's PT(Page Table) isn't existed, then create a PT.
  315. if (*ptep == 0) {
  316. //(2) if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
  317. }
  318. else {
  319. /*LAB3 EXERCISE 2: YOUR CODE
  320. * Now we think this pte is a swap entry, we should load data from disk to a page with phy addr,
  321. * and map the phy addr with logical addr, trigger swap manager to record the access situation of this page.
  322. *
  323. * Some Useful MACROs and DEFINEs, you can use them in below implementation.
  324. * MACROs or Functions:
  325. * swap_in(mm, addr, &page) : alloc a memory page, then according to the swap entry in PTE for addr,
  326. * find the addr of disk page, read the content of disk page into this memroy page
  327. * page_insert build the map of phy addr of an Page with the linear addr la
  328. * swap_map_swappable set the page swappable
  329. */
  330. if(swap_init_ok) {
  331. struct Page *page=NULL;
  332. //(1)According to the mm AND addr, try to load the content of right disk page
  333. // into the memory which page managed.
  334. //(2) According to the mm, addr AND page, setup the map of phy addr <---> logical addr
  335. //(3) make the page swappable.
  336. }
  337. else {
  338. cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
  339. goto failed;
  340. }
  341. }
  342. #endif
  343. ret = 0;
  344. failed:
  345. return ret;
  346. }