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

647 lines
21 KiB

10 years ago
  1. #include <defs.h>
  2. #include <x86.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <mmu.h>
  6. #include <memlayout.h>
  7. #include <pmm.h>
  8. #include <default_pmm.h>
  9. #include <sync.h>
  10. #include <error.h>
  11. /* *
  12. * Task State Segment:
  13. *
  14. * The TSS may reside anywhere in memory. A special segment register called
  15. * the Task Register (TR) holds a segment selector that points a valid TSS
  16. * segment descriptor which resides in the GDT. Therefore, to use a TSS
  17. * the following must be done in function gdt_init:
  18. * - create a TSS descriptor entry in GDT
  19. * - add enough information to the TSS in memory as needed
  20. * - load the TR register with a segment selector for that segment
  21. *
  22. * There are several fileds in TSS for specifying the new stack pointer when a
  23. * privilege level change happens. But only the fields SS0 and ESP0 are useful
  24. * in our os kernel.
  25. *
  26. * The field SS0 contains the stack segment selector for CPL = 0, and the ESP0
  27. * contains the new ESP value for CPL = 0. When an interrupt happens in protected
  28. * mode, the x86 CPU will look in the TSS for SS0 and ESP0 and load their value
  29. * into SS and ESP respectively.
  30. * */
  31. static struct taskstate ts = {0};
  32. // virtual address of physicall page array
  33. struct Page *pages;
  34. // amount of physical memory (in pages)
  35. size_t npage = 0;
  36. // virtual address of boot-time page directory
  37. pde_t *boot_pgdir = NULL;
  38. // physical address of boot-time page directory
  39. uintptr_t boot_cr3;
  40. // physical memory management
  41. const struct pmm_manager *pmm_manager;
  42. /* *
  43. * The page directory entry corresponding to the virtual address range
  44. * [VPT, VPT + PTSIZE) points to the page directory itself. Thus, the page
  45. * directory is treated as a page table as well as a page directory.
  46. *
  47. * One result of treating the page directory as a page table is that all PTEs
  48. * can be accessed though a "virtual page table" at virtual address VPT. And the
  49. * PTE for number n is stored in vpt[n].
  50. *
  51. * A second consequence is that the contents of the current page directory will
  52. * always available at virtual address PGADDR(PDX(VPT), PDX(VPT), 0), to which
  53. * vpd is set bellow.
  54. * */
  55. pte_t * const vpt = (pte_t *)VPT;
  56. pde_t * const vpd = (pde_t *)PGADDR(PDX(VPT), PDX(VPT), 0);
  57. /* *
  58. * Global Descriptor Table:
  59. *
  60. * The kernel and user segments are identical (except for the DPL). To load
  61. * the %ss register, the CPL must equal the DPL. Thus, we must duplicate the
  62. * segments for the user and the kernel. Defined as follows:
  63. * - 0x0 : unused (always faults -- for trapping NULL far pointers)
  64. * - 0x8 : kernel code segment
  65. * - 0x10: kernel data segment
  66. * - 0x18: user code segment
  67. * - 0x20: user data segment
  68. * - 0x28: defined for tss, initialized in gdt_init
  69. * */
  70. static struct segdesc gdt[] = {
  71. SEG_NULL,
  72. [SEG_KTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_KERNEL),
  73. [SEG_KDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_KERNEL),
  74. [SEG_UTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_USER),
  75. [SEG_UDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_USER),
  76. [SEG_TSS] = SEG_NULL,
  77. };
  78. static struct pseudodesc gdt_pd = {
  79. sizeof(gdt) - 1, (uintptr_t)gdt
  80. };
  81. static void check_alloc_page(void);
  82. static void check_pgdir(void);
  83. static void check_boot_pgdir(void);
  84. /* *
  85. * lgdt - load the global descriptor table register and reset the
  86. * data/code segement registers for kernel.
  87. * */
  88. static inline void
  89. lgdt(struct pseudodesc *pd) {
  90. asm volatile ("lgdt (%0)" :: "r" (pd));
  91. asm volatile ("movw %%ax, %%gs" :: "a" (USER_DS));
  92. asm volatile ("movw %%ax, %%fs" :: "a" (USER_DS));
  93. asm volatile ("movw %%ax, %%es" :: "a" (KERNEL_DS));
  94. asm volatile ("movw %%ax, %%ds" :: "a" (KERNEL_DS));
  95. asm volatile ("movw %%ax, %%ss" :: "a" (KERNEL_DS));
  96. // reload cs
  97. asm volatile ("ljmp %0, $1f\n 1:\n" :: "i" (KERNEL_CS));
  98. }
  99. /* *
  100. * load_esp0 - change the ESP0 in default task state segment,
  101. * so that we can use different kernel stack when we trap frame
  102. * user to kernel.
  103. * */
  104. void
  105. load_esp0(uintptr_t esp0) {
  106. ts.ts_esp0 = esp0;
  107. }
  108. /* gdt_init - initialize the default GDT and TSS */
  109. static void
  110. gdt_init(void) {
  111. // set boot kernel stack and default SS0
  112. load_esp0((uintptr_t)bootstacktop);
  113. ts.ts_ss0 = KERNEL_DS;
  114. // initialize the TSS filed of the gdt
  115. gdt[SEG_TSS] = SEGTSS(STS_T32A, (uintptr_t)&ts, sizeof(ts), DPL_KERNEL);
  116. // reload all segment registers
  117. lgdt(&gdt_pd);
  118. // load the TSS
  119. ltr(GD_TSS);
  120. }
  121. //init_pmm_manager - initialize a pmm_manager instance
  122. static void
  123. init_pmm_manager(void) {
  124. pmm_manager = &default_pmm_manager;
  125. cprintf("memory management: %s\n", pmm_manager->name);
  126. pmm_manager->init();
  127. }
  128. //init_memmap - call pmm->init_memmap to build Page struct for free memory
  129. static void
  130. init_memmap(struct Page *base, size_t n) {
  131. pmm_manager->init_memmap(base, n);
  132. }
  133. //alloc_pages - call pmm->alloc_pages to allocate a continuous n*PAGESIZE memory
  134. struct Page *
  135. alloc_pages(size_t n) {
  136. struct Page *page=NULL;
  137. bool intr_flag;
  138. local_intr_save(intr_flag);
  139. {
  140. page = pmm_manager->alloc_pages(n);
  141. }
  142. local_intr_restore(intr_flag);
  143. return page;
  144. }
  145. //free_pages - call pmm->free_pages to free a continuous n*PAGESIZE memory
  146. void
  147. free_pages(struct Page *base, size_t n) {
  148. bool intr_flag;
  149. local_intr_save(intr_flag);
  150. {
  151. pmm_manager->free_pages(base, n);
  152. }
  153. local_intr_restore(intr_flag);
  154. }
  155. //nr_free_pages - call pmm->nr_free_pages to get the size (nr*PAGESIZE)
  156. //of current free memory
  157. size_t
  158. nr_free_pages(void) {
  159. size_t ret;
  160. bool intr_flag;
  161. local_intr_save(intr_flag);
  162. {
  163. ret = pmm_manager->nr_free_pages();
  164. }
  165. local_intr_restore(intr_flag);
  166. return ret;
  167. }
  168. /* pmm_init - initialize the physical memory management */
  169. static void
  170. page_init(void) {
  171. struct e820map *memmap = (struct e820map *)(0x8000 + KERNBASE);
  172. uint64_t maxpa = 0;
  173. cprintf("e820map:\n");
  174. int i;
  175. for (i = 0; i < memmap->nr_map; i ++) {
  176. uint64_t begin = memmap->map[i].addr, end = begin + memmap->map[i].size;
  177. cprintf(" memory: %08llx, [%08llx, %08llx], type = %d.\n",
  178. memmap->map[i].size, begin, end - 1, memmap->map[i].type);
  179. if (memmap->map[i].type == E820_ARM) {
  180. if (maxpa < end && begin < KMEMSIZE) {
  181. maxpa = end;
  182. }
  183. }
  184. }
  185. if (maxpa > KMEMSIZE) {
  186. maxpa = KMEMSIZE;
  187. }
  188. extern char end[];
  189. npage = maxpa / PGSIZE;
  190. pages = (struct Page *)ROUNDUP((void *)end, PGSIZE);
  191. for (i = 0; i < npage; i ++) {
  192. SetPageReserved(pages + i);
  193. }
  194. uintptr_t freemem = PADDR((uintptr_t)pages + sizeof(struct Page) * npage);
  195. for (i = 0; i < memmap->nr_map; i ++) {
  196. uint64_t begin = memmap->map[i].addr, end = begin + memmap->map[i].size;
  197. if (memmap->map[i].type == E820_ARM) {
  198. if (begin < freemem) {
  199. begin = freemem;
  200. }
  201. if (end > KMEMSIZE) {
  202. end = KMEMSIZE;
  203. }
  204. if (begin < end) {
  205. begin = ROUNDUP(begin, PGSIZE);
  206. end = ROUNDDOWN(end, PGSIZE);
  207. if (begin < end) {
  208. init_memmap(pa2page(begin), (end - begin) / PGSIZE);
  209. }
  210. }
  211. }
  212. }
  213. }
  214. static void
  215. enable_paging(void) {
  216. lcr3(boot_cr3);
  217. // turn on paging
  218. uint32_t cr0 = rcr0();
  219. cr0 |= CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP;
  220. cr0 &= ~(CR0_TS | CR0_EM);
  221. lcr0(cr0);
  222. }
  223. //boot_map_segment - setup&enable the paging mechanism
  224. // parameters
  225. // la: linear address of this memory need to map (after x86 segment map)
  226. // size: memory size
  227. // pa: physical address of this memory
  228. // perm: permission of this memory
  229. static void
  230. boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, uintptr_t pa, uint32_t perm) {
  231. assert(PGOFF(la) == PGOFF(pa));
  232. size_t n = ROUNDUP(size + PGOFF(la), PGSIZE) / PGSIZE;
  233. la = ROUNDDOWN(la, PGSIZE);
  234. pa = ROUNDDOWN(pa, PGSIZE);
  235. for (; n > 0; n --, la += PGSIZE, pa += PGSIZE) {
  236. pte_t *ptep = get_pte(pgdir, la, 1);
  237. assert(ptep != NULL);
  238. *ptep = pa | PTE_P | perm;
  239. }
  240. }
  241. //boot_alloc_page - allocate one page using pmm->alloc_pages(1)
  242. // return value: the kernel virtual address of this allocated page
  243. //note: this function is used to get the memory for PDT(Page Directory Table)&PT(Page Table)
  244. static void *
  245. boot_alloc_page(void) {
  246. struct Page *p = alloc_page();
  247. if (p == NULL) {
  248. panic("boot_alloc_page failed.\n");
  249. }
  250. return page2kva(p);
  251. }
  252. //pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism
  253. // - check the correctness of pmm & paging mechanism, print PDT&PT
  254. void
  255. pmm_init(void) {
  256. //We need to alloc/free the physical memory (granularity is 4KB or other size).
  257. //So a framework of physical memory manager (struct pmm_manager)is defined in pmm.h
  258. //First we should init a physical memory manager(pmm) based on the framework.
  259. //Then pmm can alloc/free the physical memory.
  260. //Now the first_fit/best_fit/worst_fit/buddy_system pmm are available.
  261. init_pmm_manager();
  262. // detect physical memory space, reserve already used memory,
  263. // then use pmm->init_memmap to create free page list
  264. page_init();
  265. //use pmm->check to verify the correctness of the alloc/free function in a pmm
  266. check_alloc_page();
  267. // create boot_pgdir, an initial page directory(Page Directory Table, PDT)
  268. boot_pgdir = boot_alloc_page();
  269. memset(boot_pgdir, 0, PGSIZE);
  270. boot_cr3 = PADDR(boot_pgdir);
  271. check_pgdir();
  272. static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0);
  273. // recursively insert boot_pgdir in itself
  274. // to form a virtual page table at virtual address VPT
  275. boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_W;
  276. // map all physical memory to linear memory with base linear addr KERNBASE
  277. //linear_addr KERNBASE~KERNBASE+KMEMSIZE = phy_addr 0~KMEMSIZE
  278. //But shouldn't use this map until enable_paging() & gdt_init() finished.
  279. boot_map_segment(boot_pgdir, KERNBASE, KMEMSIZE, 0, PTE_W);
  280. //temporary map:
  281. //virtual_addr 3G~3G+4M = linear_addr 0~4M = linear_addr 3G~3G+4M = phy_addr 0~4M
  282. boot_pgdir[0] = boot_pgdir[PDX(KERNBASE)];
  283. enable_paging();
  284. //reload gdt(third time,the last time) to map all physical memory
  285. //virtual_addr 0~4G=liear_addr 0~4G
  286. //then set kernel stack(ss:esp) in TSS, setup TSS in gdt, load TSS
  287. gdt_init();
  288. //disable the map of virtual_addr 0~4M
  289. boot_pgdir[0] = 0;
  290. //now the basic virtual memory map(see memalyout.h) is established.
  291. //check the correctness of the basic virtual memory map.
  292. check_boot_pgdir();
  293. print_pgdir();
  294. }
  295. //get_pte - get pte and return the kernel virtual address of this pte for la
  296. // - if the PT contians this pte didn't exist, alloc a page for PT
  297. // parameter:
  298. // pgdir: the kernel virtual base address of PDT
  299. // la: the linear address need to map
  300. // create: a logical value to decide if alloc a page for PT
  301. // return vaule: the kernel virtual address of this pte
  302. pte_t *
  303. get_pte(pde_t *pgdir, uintptr_t la, bool create) {
  304. /* LAB2 EXERCISE 2: YOUR CODE
  305. *
  306. * If you need to visit a physical address, please use KADDR()
  307. * please read pmm.h for useful macros
  308. *
  309. * Maybe you want help comment, BELOW comments can help you finish the code
  310. *
  311. * Some Useful MACROs and DEFINEs, you can use them in below implementation.
  312. * MACROs or Functions:
  313. * PDX(la) = the index of page directory entry of VIRTUAL ADDRESS la.
  314. * KADDR(pa) : takes a physical address and returns the corresponding kernel virtual address.
  315. * set_page_ref(page,1) : means the page be referenced by one time
  316. * page2pa(page): get the physical address of memory which this (struct Page *) page manages
  317. * struct Page * alloc_page() : allocation a page
  318. * memset(void *s, char c, size_t n) : sets the first n bytes of the memory area pointed by s
  319. * to the specified value c.
  320. * DEFINEs:
  321. * PTE_P 0x001 // page table/directory entry flags bit : Present
  322. * PTE_W 0x002 // page table/directory entry flags bit : Writeable
  323. * PTE_U 0x004 // page table/directory entry flags bit : User can access
  324. */
  325. #if 0
  326. pde_t *pdep = NULL; // (1) find page directory entry
  327. if (0) { // (2) check if entry is not present
  328. // (3) check if creating is needed, then alloc page for page table
  329. // CAUTION: this page is used for page table, not for common data page
  330. // (4) set page reference
  331. uintptr_t pa = 0; // (5) get linear address of page
  332. // (6) clear page content using memset
  333. // (7) set page directory entry's permission
  334. }
  335. return NULL; // (8) return page table entry
  336. #endif
  337. pde_t *pdep = &pgdir[PDX(la)];
  338. if (!(*pdep & PTE_P)) {
  339. struct Page *page;
  340. if (!create || (page = alloc_page()) == NULL) {
  341. return NULL;
  342. }
  343. set_page_ref(page, 1);
  344. uintptr_t pa = page2pa(page);
  345. memset(KADDR(pa), 0, PGSIZE);
  346. *pdep = pa | PTE_U | PTE_W | PTE_P;
  347. }
  348. return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)];
  349. }
  350. //get_page - get related Page struct for linear address la using PDT pgdir
  351. struct Page *
  352. get_page(pde_t *pgdir, uintptr_t la, pte_t **ptep_store) {
  353. pte_t *ptep = get_pte(pgdir, la, 0);
  354. if (ptep_store != NULL) {
  355. *ptep_store = ptep;
  356. }
  357. if (ptep != NULL && *ptep & PTE_P) {
  358. return pa2page(*ptep);
  359. }
  360. return NULL;
  361. }
  362. //page_remove_pte - free an Page sturct which is related linear address la
  363. // - and clean(invalidate) pte which is related linear address la
  364. //note: PT is changed, so the TLB need to be invalidate
  365. static inline void
  366. page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep) {
  367. /* LAB2 EXERCISE 3: YOUR CODE
  368. *
  369. * Please check if ptep is valid, and tlb must be manually updated if mapping is updated
  370. *
  371. * Maybe you want help comment, BELOW comments can help you finish the code
  372. *
  373. * Some Useful MACROs and DEFINEs, you can use them in below implementation.
  374. * MACROs or Functions:
  375. * struct Page *page pte2page(*ptep): get the according page from the value of a ptep
  376. * free_page : free a page
  377. * page_ref_dec(page) : decrease page->ref. NOTICE: ff page->ref == 0 , then this page should be free.
  378. * tlb_invalidate(pde_t *pgdir, uintptr_t la) : Invalidate a TLB entry, but only if the page tables being
  379. * edited are the ones currently in use by the processor.
  380. * DEFINEs:
  381. * PTE_P 0x001 // page table/directory entry flags bit : Present
  382. */
  383. #if 0
  384. if (0) { //(1) check if page directory is present
  385. struct Page *page = NULL; //(2) find corresponding page to pte
  386. //(3) decrease page reference
  387. //(4) and free this page when page reference reachs 0
  388. //(5) clear second page table entry
  389. //(6) flush tlb
  390. }
  391. #endif
  392. if (*ptep & PTE_P) {
  393. struct Page *page = pte2page(*ptep);
  394. if (page_ref_dec(page) == 0) {
  395. free_page(page);
  396. }
  397. *ptep = 0;
  398. tlb_invalidate(pgdir, la);
  399. }
  400. }
  401. //page_remove - free an Page which is related linear address la and has an validated pte
  402. void
  403. page_remove(pde_t *pgdir, uintptr_t la) {
  404. pte_t *ptep = get_pte(pgdir, la, 0);
  405. if (ptep != NULL) {
  406. page_remove_pte(pgdir, la, ptep);
  407. }
  408. }
  409. //page_insert - build the map of phy addr of an Page with the linear addr la
  410. // paramemters:
  411. // pgdir: the kernel virtual base address of PDT
  412. // page: the Page which need to map
  413. // la: the linear address need to map
  414. // perm: the permission of this Page which is setted in related pte
  415. // return value: always 0
  416. //note: PT is changed, so the TLB need to be invalidate
  417. int
  418. page_insert(pde_t *pgdir, struct Page *page, uintptr_t la, uint32_t perm) {
  419. pte_t *ptep = get_pte(pgdir, la, 1);
  420. if (ptep == NULL) {
  421. return -E_NO_MEM;
  422. }
  423. page_ref_inc(page);
  424. if (*ptep & PTE_P) {
  425. struct Page *p = pte2page(*ptep);
  426. if (p == page) {
  427. page_ref_dec(page);
  428. }
  429. else {
  430. page_remove_pte(pgdir, la, ptep);
  431. }
  432. }
  433. *ptep = page2pa(page) | PTE_P | perm;
  434. tlb_invalidate(pgdir, la);
  435. return 0;
  436. }
  437. // invalidate a TLB entry, but only if the page tables being
  438. // edited are the ones currently in use by the processor.
  439. void
  440. tlb_invalidate(pde_t *pgdir, uintptr_t la) {
  441. if (rcr3() == PADDR(pgdir)) {
  442. invlpg((void *)la);
  443. }
  444. }
  445. static void
  446. check_alloc_page(void) {
  447. pmm_manager->check();
  448. cprintf("check_alloc_page() succeeded!\n");
  449. }
  450. static void
  451. check_pgdir(void) {
  452. assert(npage <= KMEMSIZE / PGSIZE);
  453. assert(boot_pgdir != NULL && (uint32_t)PGOFF(boot_pgdir) == 0);
  454. assert(get_page(boot_pgdir, 0x0, NULL) == NULL);
  455. struct Page *p1, *p2;
  456. p1 = alloc_page();
  457. assert(page_insert(boot_pgdir, p1, 0x0, 0) == 0);
  458. pte_t *ptep;
  459. assert((ptep = get_pte(boot_pgdir, 0x0, 0)) != NULL);
  460. assert(pa2page(*ptep) == p1);
  461. assert(page_ref(p1) == 1);
  462. ptep = &((pte_t *)KADDR(PDE_ADDR(boot_pgdir[0])))[1];
  463. assert(get_pte(boot_pgdir, PGSIZE, 0) == ptep);
  464. p2 = alloc_page();
  465. assert(page_insert(boot_pgdir, p2, PGSIZE, PTE_U | PTE_W) == 0);
  466. assert((ptep = get_pte(boot_pgdir, PGSIZE, 0)) != NULL);
  467. assert(*ptep & PTE_U);
  468. assert(*ptep & PTE_W);
  469. assert(boot_pgdir[0] & PTE_U);
  470. assert(page_ref(p2) == 1);
  471. assert(page_insert(boot_pgdir, p1, PGSIZE, 0) == 0);
  472. assert(page_ref(p1) == 2);
  473. assert(page_ref(p2) == 0);
  474. assert((ptep = get_pte(boot_pgdir, PGSIZE, 0)) != NULL);
  475. assert(pa2page(*ptep) == p1);
  476. assert((*ptep & PTE_U) == 0);
  477. page_remove(boot_pgdir, 0x0);
  478. assert(page_ref(p1) == 1);
  479. assert(page_ref(p2) == 0);
  480. page_remove(boot_pgdir, PGSIZE);
  481. assert(page_ref(p1) == 0);
  482. assert(page_ref(p2) == 0);
  483. assert(page_ref(pa2page(boot_pgdir[0])) == 1);
  484. free_page(pa2page(boot_pgdir[0]));
  485. boot_pgdir[0] = 0;
  486. cprintf("check_pgdir() succeeded!\n");
  487. }
  488. static void
  489. check_boot_pgdir(void) {
  490. pte_t *ptep;
  491. int i;
  492. for (i = 0; i < npage; i += PGSIZE) {
  493. assert((ptep = get_pte(boot_pgdir, (uintptr_t)KADDR(i), 0)) != NULL);
  494. assert(PTE_ADDR(*ptep) == i);
  495. }
  496. assert(PDE_ADDR(boot_pgdir[PDX(VPT)]) == PADDR(boot_pgdir));
  497. assert(boot_pgdir[0] == 0);
  498. struct Page *p;
  499. p = alloc_page();
  500. assert(page_insert(boot_pgdir, p, 0x100, PTE_W) == 0);
  501. assert(page_ref(p) == 1);
  502. assert(page_insert(boot_pgdir, p, 0x100 + PGSIZE, PTE_W) == 0);
  503. assert(page_ref(p) == 2);
  504. const char *str = "ucore: Hello world!!";
  505. strcpy((void *)0x100, str);
  506. assert(strcmp((void *)0x100, (void *)(0x100 + PGSIZE)) == 0);
  507. *(char *)(page2kva(p) + 0x100) = '\0';
  508. assert(strlen((const char *)0x100) == 0);
  509. free_page(p);
  510. free_page(pa2page(PDE_ADDR(boot_pgdir[0])));
  511. boot_pgdir[0] = 0;
  512. cprintf("check_boot_pgdir() succeeded!\n");
  513. }
  514. //perm2str - use string 'u,r,w,-' to present the permission
  515. static const char *
  516. perm2str(int perm) {
  517. static char str[4];
  518. str[0] = (perm & PTE_U) ? 'u' : '-';
  519. str[1] = 'r';
  520. str[2] = (perm & PTE_W) ? 'w' : '-';
  521. str[3] = '\0';
  522. return str;
  523. }
  524. //get_pgtable_items - In [left, right] range of PDT or PT, find a continuous linear addr space
  525. // - (left_store*X_SIZE~right_store*X_SIZE) for PDT or PT
  526. // - X_SIZE=PTSIZE=4M, if PDT; X_SIZE=PGSIZE=4K, if PT
  527. // paramemters:
  528. // left: no use ???
  529. // right: the high side of table's range
  530. // start: the low side of table's range
  531. // table: the beginning addr of table
  532. // left_store: the pointer of the high side of table's next range
  533. // right_store: the pointer of the low side of table's next range
  534. // return value: 0 - not a invalid item range, perm - a valid item range with perm permission
  535. static int
  536. get_pgtable_items(size_t left, size_t right, size_t start, uintptr_t *table, size_t *left_store, size_t *right_store) {
  537. if (start >= right) {
  538. return 0;
  539. }
  540. while (start < right && !(table[start] & PTE_P)) {
  541. start ++;
  542. }
  543. if (start < right) {
  544. if (left_store != NULL) {
  545. *left_store = start;
  546. }
  547. int perm = (table[start ++] & PTE_USER);
  548. while (start < right && (table[start] & PTE_USER) == perm) {
  549. start ++;
  550. }
  551. if (right_store != NULL) {
  552. *right_store = start;
  553. }
  554. return perm;
  555. }
  556. return 0;
  557. }
  558. //print_pgdir - print the PDT&PT
  559. void
  560. print_pgdir(void) {
  561. cprintf("-------------------- BEGIN --------------------\n");
  562. size_t left, right = 0, perm;
  563. while ((perm = get_pgtable_items(0, NPDEENTRY, right, vpd, &left, &right)) != 0) {
  564. cprintf("PDE(%03x) %08x-%08x %08x %s\n", right - left,
  565. left * PTSIZE, right * PTSIZE, (right - left) * PTSIZE, perm2str(perm));
  566. size_t l, r = left * NPTEENTRY;
  567. while ((perm = get_pgtable_items(left * NPTEENTRY, right * NPTEENTRY, r, vpt, &l, &r)) != 0) {
  568. cprintf(" |-- PTE(%05x) %08x-%08x %08x %s\n", r - l,
  569. l * PGSIZE, r * PGSIZE, (r - l) * PGSIZE, perm2str(perm));
  570. }
  571. }
  572. cprintf("--------------------- END ---------------------\n");
  573. }