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

452 lines
15 KiB

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