paging.c
上传用户:qddsws
上传日期:2022-06-22
资源大小:723k
文件大小:15k
源码类别:

操作系统开发

开发平台:

C/C++

  1. #include <i386/paging.h>
  2. int avmem;
  3. /* -----------------------------------------------
  4.  * 
  5.  * PHYSICAL ALLOCATOR
  6.  *
  7.  * ----------------------------------------------*/
  8. /* PHYSICAL MEMORY STACK
  9.  * Gives free physical memory page address
  10.  * from a stack of free memory pages
  11.  *
  12.  */
  13. /* Free physical memory stack pointers */
  14. unsigned long* bottom_phys_stack; /* pointer to bottom */
  15. unsigned long* act_phys_stack; /* pointer to actual address */
  16. /* Initialize the stack */
  17. void init_stack_up() {
  18. /* Push all physical address after the 16Mb point */
  19.         long int address=0x1000000; /*(16Mb)*/
  20. long int end_address=avmem*1024*1024;
  21. int structure_size=((end_address-address)/PAGE_SIZE)*sizeof(long int);
  22. /* Prevent from adding reserved region
  23.  * to the stack */
  24. address=address+structure_size;
  25. /* Align start and end to page size */
  26. address=PAGE_ALIGN_UP(address);
  27. end_address=PAGE_ALIGN(end_address);
  28. char text[200];
  29. snprintf (text,"%x first usable page. Last usable address %xn",address,end_address);
  30. kprint (text);
  31. /* Set stack pointers */
  32. bottom_phys_stack= (unsigned long*)TEMP_MAP_16_20M;
  33. act_phys_stack = bottom_phys_stack;
  34. /* For the whole range of physical address 
  35.  * push them to the stack.
  36.  */
  37.         while (end_address>=address) {
  38.                push_up_phys(end_address&0xfffff000);
  39.                end_address=end_address-PAGE_SIZE;
  40.         }
  41. }
  42. /* Push a free address to the stack */
  43. void push_up_phys (unsigned long address) {
  44. act_phys_stack[0]=address;
  45. act_phys_stack=(unsigned long*)((unsigned long)act_phys_stack+(unsigned long)sizeof(unsigned long));
  46. }
  47. /* Pop an address from the stack */
  48. unsigned long pop_up_phys () {
  49. act_phys_stack=(unsigned long*)((unsigned long)act_phys_stack-(unsigned long)sizeof(unsigned long));
  50. unsigned long ret_val=act_phys_stack[0];
  51. return ret_val;
  52. }
  53. /*
  54.  * PAGING INITIALIZATION
  55.  * 
  56.  */
  57. void initialize_paging(int availmem)
  58. {
  59. unsigned long *page_directory;
  60.         unsigned long *page_table;
  61. avmem=availmem;
  62. init_stack_up();
  63. /* Get a physical page for the page directory */
  64. page_directory=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
  65. /* Set the page directory empty */
  66. empty_page_table (page_directory);
  67.   
  68. /* LOW MEMORY MAP */
  69. /* Fill page table with map Phys 0x00-4Mb to virtual 0x00-4Mb */
  70. page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
  71. fill_page_table (page_table,0x00,1024,0x03);
  72. /* Do the mapping */
  73. set_page_table_entry (page_directory,VIRT_TO_PDE(0x00),PRE_VIRTTOPHYS(page_table),0x03);
  74. /* KERNEL MAP */
  75. /* Fill page table with map Phys 1Mb-5Mb to virtual 0xC000000 */
  76. page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
  77. fill_page_table (page_table,0x100000,1024,0x03);
  78. /* Insert the table into the page directory */
  79. set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_KERNEL_BASE), PRE_VIRTTOPHYS(page_table),0x03);
  80. /* PHYSICAL STACK MAP */
  81. /* Fill page table with map Phys 16Mb-20Mb to virtual 0xFF000000 */
  82. page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
  83. fill_page_table (page_table,0x1000000,1024,0x03);
  84. /* Insert the table into the page directory */
  85. set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_PHYS_STACK_BASE),PRE_VIRTTOPHYS(page_table),0x03);
  86. /* VIDEO TEMP MAP */
  87. /* Fill page table with map Phys 0xF0000000 to virtual 0xD0800000 */
  88. page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
  89. fill_page_table (page_table,0xF0000000,1024,0x03);
  90. /* Insert the table into the page directory */
  91. set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_VIDEO),PRE_VIRTTOPHYS(page_table),0x03);
  92. /* TEMP MAP MAP */
  93. /* We give a physical address to PDE virtual address 
  94.  * VIRT_TEMP_MAP
  95.  */
  96. /* Insert the PDE for this mapping */
  97. page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
  98. /* Set all PTE to unused */
  99. empty_page_table (page_table);
  100. /* Insert the table into the page directory */
  101. set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_TEMP_MAP),PRE_VIRTTOPHYS(page_table),0x03);
  102. /* PD TO PDE MAP */
  103. /* Insert the PD into the page directory */
  104. set_page_table_entry (page_directory,1023,PRE_VIRTTOPHYS(page_directory),0x03);
  105. /****************************
  106.  * Commit changes to the PD *
  107.  ****************************/
  108. /* The processor flushes page_directory variable */
  109. write_cr3(PRE_VIRTTOPHYS(page_directory)); // put that page directory address into CR3
  110. write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
  111. }
  112. void fill_page_table (unsigned long* page_table, unsigned long base_physical_address, int number_of_pages, int attributes) {
  113. int i;
  114. number_of_pages=number_of_pages%1025;
  115. for(i=0; i<number_of_pages; i++)
  116. {
  117. page_table[i] = base_physical_address | attributes; 
  118. base_physical_address = base_physical_address + PAGE_SIZE; 
  119. }
  120. }
  121. void set_page_table_entry (unsigned long* page_table, int PTE_number,unsigned long phys_addr, int attributes) {
  122.  page_table[PTE_number] = phys_addr | attributes;
  123. }
  124. void empty_page_table (unsigned long* page_table) {
  125. int i;
  126. for(i=0; i<1024; i++)
  127. {
  128. page_table[i] = 0x02; 
  129. }
  130. }
  131. /* Returns the physical address to a physical
  132.  * page mapped at virtual address base VIRT_TEMP_MAP
  133.  * 
  134.  * */
  135. unsigned long get_temp_page_table () {
  136.   unsigned long* phys_page_table;
  137.   unsigned long* temp_pde;
  138.   phys_page_table=(unsigned long*)pop_up_phys();
  139. /* Get virtual address of the PDE for
  140.  * temporal mapping */
  141. temp_pde=(unsigned long *)VIRT_TO_PTE_VIRT(VIRT_TEMP_MAP);
  142. set_page_table_entry (temp_pde,0,(unsigned long)phys_page_table,0x03);
  143. /****************************
  144.  * Commit changes to the PD *
  145.  ****************************/
  146. /* The processor flushes page_directory variable */
  147. write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
  148. write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
  149. return (unsigned long)phys_page_table;
  150. }
  151. void allocate_page(unsigned long virtualbase) {
  152. /*Search for the entry for this address at the PD. */
  153. unsigned long *page_directory;
  154. page_directory=VIRT_PAGE_DIRECTORY;
  155. virtualbase=PAGE_ALIGN(virtualbase);
  156.   if( (page_directory[VIRT_TO_PDE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
  157. // kprint ("USED PDEn");
  158. /* If the PDE exists, look for the PTE for the 
  159.  * corresponding virtual address
  160.  */
  161. unsigned long* pte_table=(unsigned long*)VIRT_TO_PTE_VIRT(virtualbase);
  162. if( (pte_table[VIRT_TO_PTE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
  163. // kprint ("USED PTE, errorn");
  164. }
  165. else {
  166. // kprint ("FREE PTEn");
  167. unsigned long* phys_page;
  168. /* Allocate the desired page */
  169. phys_page=(unsigned long*)pop_up_phys();
  170. /* Map the physical page into the table */
  171. set_page_table_entry(pte_table,VIRT_TO_PTE(virtualbase),(unsigned long)phys_page,0x03);
  172. write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
  173. write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
  174. }
  175. }
  176. else {
  177. // kprint ("FREE PDEn");
  178. /* Get a table page mapped to TEMP_VIRT*/
  179. /* This page holds the PT , is the PTE*/
  180. unsigned long* phys_table=(unsigned long*)get_temp_page_table ();
  181. unsigned long* virt_table=(unsigned long*)VIRT_TEMP_MAP;
  182. unsigned long* phys_page;
  183. /* Map the allocated table page to the virtual address space */
  184. set_page_table_entry(page_directory,VIRT_TO_PDE(virtualbase),(unsigned long)phys_table,0x03);
  185. /* Allocate the desired page */
  186. phys_page=(unsigned long*)pop_up_phys();
  187. /* Map the physical page into the table */
  188. empty_page_table (virt_table);
  189. set_page_table_entry(virt_table,VIRT_TO_PTE(virtualbase),(unsigned long)phys_page,0x03);
  190. write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
  191. write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
  192. }
  193. }
  194. void allocate_pages(unsigned long virtualbase, int pages) {
  195.    int i=0;
  196.    for (i=0;i<pages;i++) {
  197.    allocate_page(virtualbase+(i*PAGE_SIZE));
  198. }
  199. }
  200. void deallocate_page(unsigned long virtualbase) {
  201. unsigned long *page_directory =VIRT_PAGE_DIRECTORY;
  202. /* Seatch for the PD entry for the virtualbase */
  203. page_directory=VIRT_PAGE_DIRECTORY;
  204. virtualbase=PAGE_ALIGN(virtualbase);
  205. if( (page_directory[VIRT_TO_PDE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
  206. /* The PDE exist , now search the PTE */
  207. unsigned long* pte_table=(unsigned long*)VIRT_TO_PTE_VIRT(virtualbase);
  208. if( (pte_table[VIRT_TO_PTE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
  209. push_up_phys(PAGE_ALIGN(pte_table[VIRT_TO_PTE(virtualbase)]));
  210. pte_table[VIRT_TO_PTE(virtualbase)]=0x02;
  211. write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
  212. write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
  213. }
  214. else {
  215. kprint ("The PTE does not existn");
  216. }
  217. }
  218. else {
  219. kprint ("The PDE does not existn");
  220. }
  221. }
  222. void deallocate_pages(unsigned long virtualbase, int pages) {
  223.    int i=0;
  224.    for (i=0;i<pages;i++) {
  225.    deallocate_page(virtualbase+(i*PAGE_SIZE));
  226. }
  227. }
  228. /* -----------------------------------------------
  229.  * 
  230.  * DYNAMIC ALLOCATOR
  231.  *
  232.  * ----------------------------------------------*/
  233. heap_struct heap_info;
  234. void kfree(unsigned long base) {
  235. struct list_node_head *p;
  236. struct list_node_head *mover;
  237. struct heap_member* region;
  238. struct heap_member* new_region;
  239. region = (struct heap_member*)(list_entry (&(heap_info.usedlist->list), struct heap_member, list));
  240. if ((base>=region->base)&&(base<region->base+region->size)) {
  241. new_region=(struct heap_member*)kmalloc(sizeof(struct heap_member));
  242. new_region->base=region->base;
  243. new_region->size=region->size;
  244. region->base=0;
  245. region->size=0;
  246. list_add(&(new_region->list),&(heap_info.freelist->list));
  247. }
  248. else {
  249. list_for_each (p,&(heap_info.usedlist->list)) {
  250. region = (struct heap_member*)list_entry (p, struct heap_member, list);
  251. if ((base>=region->base)&&(base<region->base+region->size)) {
  252. list_del (p);
  253. mover=p;
  254. }
  255. }
  256. }
  257. list_add(mover,&(heap_info.freelist->list));
  258. }
  259. void initialize_dynamic_allocator() {
  260. heap_info.heap_top=KERNEL_HEAP_START;
  261. /* Add a page to the heap that will be used to get memory */
  262. allocate_page(KERNEL_HEAP_START);
  263. heap_info.heap_top=heap_info.heap_top+PAGE_SIZE;
  264. /* The first 2 reserverd regions in the heap are for the
  265.  * freelist and usedlist */
  266. heap_info.freelist=(struct heap_member*)KERNEL_HEAP_START;
  267. heap_info.usedlist=heap_info.freelist+sizeof(struct heap_member);
  268. struct heap_member* first_free=heap_info.usedlist+sizeof(struct heap_member);
  269. /* Add this page to the free list */
  270. first_free->base=first_free+sizeof(struct heap_member);
  271. first_free->size=PAGE_SIZE-4*sizeof(struct heap_member);
  272. heap_info.freelist->base=0;
  273. heap_info.freelist->size=0;
  274. INIT_LIST_HEAD (&(heap_info.freelist->list));
  275. INIT_LIST_HEAD (&(heap_info.usedlist->list));
  276. list_add(&(first_free->list),&(heap_info.freelist->list));
  277. }
  278. unsigned long kmalloc (int bytes) {
  279. unsigned long base=0;
  280. /* Search the list for a big enough entry */
  281. struct heap_member* region;
  282. char text[200];
  283. /* returns a pointer to the base
  284.  * of a free region and a pointer
  285.  * to the list item that points to it
  286.  */
  287. bytes=bytes+sizeof(struct heap_member);
  288. struct list_node_head* heap_list_p=get_free_heap_base(bytes);
  289. if (heap_list_p!=0) {
  290. /* A piece at least of the requested size has
  291.  * been found, the size that we are requesting is
  292.  * bytes + sizeof (struct heap_member) which
  293.  * will hold the used heap_member structure
  294.  * for the used fraction.
  295.  * */
  296. region=(struct heap_member*)list_entry (heap_list_p,struct heap_member, list);
  297. // snprintf (text,"new heap base %x size %dn",region->base,region->size);
  298. // kprint (text);
  299. base=region->base;
  300. /* Substract the needed bytes from the piece */
  301. region->size=(region->size)-bytes;
  302. region->base=(region->base)+bytes;
  303. /* Heap member has been given the last bytes
  304.  * of the requested region.
  305.  * */
  306. struct heap_member* used_region=(struct heap_member*)(base+bytes-(sizeof(struct heap_member)));
  307. /* Set up the used region entry */
  308. used_region->base=base;
  309. used_region->size=bytes;
  310. /* Put the region into the list */
  311. list_add(&(used_region->list),&(heap_info.usedlist->list));
  312. }
  313. else {
  314. /* The heap is too small */
  315. /* More core needed */
  316. morecore (bytes);
  317. base=kmalloc (bytes);
  318. }
  319. return base;
  320. }
  321. unsigned long morecore(int bytes) {
  322. /* The beginning will be used to store
  323.  * the entry to the free list */
  324. bytes=bytes+sizeof(struct heap_member);
  325.    unsigned long base=PAGE_ALIGN(heap_info.heap_top);
  326. int pages=(bytes/PAGE_SIZE)+1;
  327. allocate_pages(base,pages);
  328. /* Increment the top address of heap */
  329.    heap_info.heap_top=heap_info.heap_top+pages*PAGE_SIZE;
  330. struct heap_member* free_entry;
  331. free_entry=(struct heap_member*)base;
  332. free_entry->base=base+sizeof(struct heap_member);
  333. free_entry->size=pages*PAGE_SIZE-sizeof(struct heap_member);
  334. list_add(&(free_entry->list),&(heap_info.freelist->list));
  335. return base;
  336. }
  337. void debug_print_used_list () {
  338. struct list_node_head *p;
  339. struct heap_member* region;
  340. char text[200];
  341. region = (struct heap_member*)list_entry (&(heap_info.usedlist->list), struct heap_member, list);
  342. snprintf (text,"1Used at base %x size %dn",region->base,region->size);
  343. kprint (text);
  344. list_for_each (p,&(heap_info.usedlist->list)) {
  345. region = (struct heap_member*)list_entry (p, struct heap_member, list);
  346. snprintf (text,"2Used at base %x size %dn",region->base,region->size);
  347. kprint (text);
  348. }
  349. }
  350. void debug_print_free_list () {
  351. struct list_node_head *p;
  352. struct heap_member* region;
  353. char text[200];
  354. region = (struct heap_member*)(list_entry (&(heap_info.freelist->list), struct heap_member, list));
  355. snprintf (text,"1Free at base %x size %dn",region->base,region->size);
  356. kprint (text);
  357. list_for_each (p,&(heap_info.freelist->list)) {
  358. region = (struct heap_member*)list_entry (p, struct heap_member, list);
  359. snprintf (text,"2Free at base %x size %dn",region->base,region->size);
  360. kprint (text);
  361. }
  362. }
  363. struct list_node_head* get_free_heap_base (int bytes) {
  364. struct list_node_head *p;
  365. struct heap_member* region;
  366. region = (struct heap_member*)list_entry (&(heap_info.freelist->list), struct heap_member, list);
  367. if ( (region!=0) && region->size > bytes ) {
  368. p=&(heap_info.freelist->list);
  369. /* There is enough space here */
  370. return p;
  371. }
  372. else {
  373. list_for_each (p,(&(heap_info.freelist->list))) {
  374. region = (struct heap_member*)list_entry (p, struct heap_member, list);
  375. if ( region->size >= bytes ) {
  376. /* There is enough space here */
  377. return p;
  378. }
  379. }
  380. }
  381. return 0;
  382. }