paging.c
资源名称:tizos.rar [点击查看]
上传用户:qddsws
上传日期:2022-06-22
资源大小:723k
文件大小:15k
源码类别:
操作系统开发
开发平台:
C/C++
- #include <i386/paging.h>
- int avmem;
- /* -----------------------------------------------
- *
- * PHYSICAL ALLOCATOR
- *
- * ----------------------------------------------*/
- /* PHYSICAL MEMORY STACK
- * Gives free physical memory page address
- * from a stack of free memory pages
- *
- */
- /* Free physical memory stack pointers */
- unsigned long* bottom_phys_stack; /* pointer to bottom */
- unsigned long* act_phys_stack; /* pointer to actual address */
- /* Initialize the stack */
- void init_stack_up() {
- /* Push all physical address after the 16Mb point */
- long int address=0x1000000; /*(16Mb)*/
- long int end_address=avmem*1024*1024;
- int structure_size=((end_address-address)/PAGE_SIZE)*sizeof(long int);
- /* Prevent from adding reserved region
- * to the stack */
- address=address+structure_size;
- /* Align start and end to page size */
- address=PAGE_ALIGN_UP(address);
- end_address=PAGE_ALIGN(end_address);
- char text[200];
- snprintf (text,"%x first usable page. Last usable address %xn",address,end_address);
- kprint (text);
- /* Set stack pointers */
- bottom_phys_stack= (unsigned long*)TEMP_MAP_16_20M;
- act_phys_stack = bottom_phys_stack;
- /* For the whole range of physical address
- * push them to the stack.
- */
- while (end_address>=address) {
- push_up_phys(end_address&0xfffff000);
- end_address=end_address-PAGE_SIZE;
- }
- }
- /* Push a free address to the stack */
- void push_up_phys (unsigned long address) {
- act_phys_stack[0]=address;
- act_phys_stack=(unsigned long*)((unsigned long)act_phys_stack+(unsigned long)sizeof(unsigned long));
- }
- /* Pop an address from the stack */
- unsigned long pop_up_phys () {
- act_phys_stack=(unsigned long*)((unsigned long)act_phys_stack-(unsigned long)sizeof(unsigned long));
- unsigned long ret_val=act_phys_stack[0];
- return ret_val;
- }
- /*
- * PAGING INITIALIZATION
- *
- */
- void initialize_paging(int availmem)
- {
- unsigned long *page_directory;
- unsigned long *page_table;
- avmem=availmem;
- init_stack_up();
- /* Get a physical page for the page directory */
- page_directory=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
- /* Set the page directory empty */
- empty_page_table (page_directory);
- /* LOW MEMORY MAP */
- /* Fill page table with map Phys 0x00-4Mb to virtual 0x00-4Mb */
- page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
- fill_page_table (page_table,0x00,1024,0x03);
- /* Do the mapping */
- set_page_table_entry (page_directory,VIRT_TO_PDE(0x00),PRE_VIRTTOPHYS(page_table),0x03);
- /* KERNEL MAP */
- /* Fill page table with map Phys 1Mb-5Mb to virtual 0xC000000 */
- page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
- fill_page_table (page_table,0x100000,1024,0x03);
- /* Insert the table into the page directory */
- set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_KERNEL_BASE), PRE_VIRTTOPHYS(page_table),0x03);
- /* PHYSICAL STACK MAP */
- /* Fill page table with map Phys 16Mb-20Mb to virtual 0xFF000000 */
- page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
- fill_page_table (page_table,0x1000000,1024,0x03);
- /* Insert the table into the page directory */
- set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_PHYS_STACK_BASE),PRE_VIRTTOPHYS(page_table),0x03);
- /* VIDEO TEMP MAP */
- /* Fill page table with map Phys 0xF0000000 to virtual 0xD0800000 */
- page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
- fill_page_table (page_table,0xF0000000,1024,0x03);
- /* Insert the table into the page directory */
- set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_VIDEO),PRE_VIRTTOPHYS(page_table),0x03);
- /* TEMP MAP MAP */
- /* We give a physical address to PDE virtual address
- * VIRT_TEMP_MAP
- */
- /* Insert the PDE for this mapping */
- page_table=(unsigned long*)PRE_PHYSTOVIRT(pop_up_phys());
- /* Set all PTE to unused */
- empty_page_table (page_table);
- /* Insert the table into the page directory */
- set_page_table_entry (page_directory,VIRT_TO_PDE(VIRT_TEMP_MAP),PRE_VIRTTOPHYS(page_table),0x03);
- /* PD TO PDE MAP */
- /* Insert the PD into the page directory */
- set_page_table_entry (page_directory,1023,PRE_VIRTTOPHYS(page_directory),0x03);
- /****************************
- * Commit changes to the PD *
- ****************************/
- /* The processor flushes page_directory variable */
- write_cr3(PRE_VIRTTOPHYS(page_directory)); // put that page directory address into CR3
- write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
- }
- void fill_page_table (unsigned long* page_table, unsigned long base_physical_address, int number_of_pages, int attributes) {
- int i;
- number_of_pages=number_of_pages%1025;
- for(i=0; i<number_of_pages; i++)
- {
- page_table[i] = base_physical_address | attributes;
- base_physical_address = base_physical_address + PAGE_SIZE;
- }
- }
- void set_page_table_entry (unsigned long* page_table, int PTE_number,unsigned long phys_addr, int attributes) {
- page_table[PTE_number] = phys_addr | attributes;
- }
- void empty_page_table (unsigned long* page_table) {
- int i;
- for(i=0; i<1024; i++)
- {
- page_table[i] = 0x02;
- }
- }
- /* Returns the physical address to a physical
- * page mapped at virtual address base VIRT_TEMP_MAP
- *
- * */
- unsigned long get_temp_page_table () {
- unsigned long* phys_page_table;
- unsigned long* temp_pde;
- phys_page_table=(unsigned long*)pop_up_phys();
- /* Get virtual address of the PDE for
- * temporal mapping */
- temp_pde=(unsigned long *)VIRT_TO_PTE_VIRT(VIRT_TEMP_MAP);
- set_page_table_entry (temp_pde,0,(unsigned long)phys_page_table,0x03);
- /****************************
- * Commit changes to the PD *
- ****************************/
- /* The processor flushes page_directory variable */
- write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
- write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
- return (unsigned long)phys_page_table;
- }
- void allocate_page(unsigned long virtualbase) {
- /*Search for the entry for this address at the PD. */
- unsigned long *page_directory;
- page_directory=VIRT_PAGE_DIRECTORY;
- virtualbase=PAGE_ALIGN(virtualbase);
- if( (page_directory[VIRT_TO_PDE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
- // kprint ("USED PDEn");
- /* If the PDE exists, look for the PTE for the
- * corresponding virtual address
- */
- unsigned long* pte_table=(unsigned long*)VIRT_TO_PTE_VIRT(virtualbase);
- if( (pte_table[VIRT_TO_PTE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
- // kprint ("USED PTE, errorn");
- }
- else {
- // kprint ("FREE PTEn");
- unsigned long* phys_page;
- /* Allocate the desired page */
- phys_page=(unsigned long*)pop_up_phys();
- /* Map the physical page into the table */
- set_page_table_entry(pte_table,VIRT_TO_PTE(virtualbase),(unsigned long)phys_page,0x03);
- write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
- write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
- }
- }
- else {
- // kprint ("FREE PDEn");
- /* Get a table page mapped to TEMP_VIRT*/
- /* This page holds the PT , is the PTE*/
- unsigned long* phys_table=(unsigned long*)get_temp_page_table ();
- unsigned long* virt_table=(unsigned long*)VIRT_TEMP_MAP;
- unsigned long* phys_page;
- /* Map the allocated table page to the virtual address space */
- set_page_table_entry(page_directory,VIRT_TO_PDE(virtualbase),(unsigned long)phys_table,0x03);
- /* Allocate the desired page */
- phys_page=(unsigned long*)pop_up_phys();
- /* Map the physical page into the table */
- empty_page_table (virt_table);
- set_page_table_entry(virt_table,VIRT_TO_PTE(virtualbase),(unsigned long)phys_page,0x03);
- write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
- write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
- }
- }
- void allocate_pages(unsigned long virtualbase, int pages) {
- int i=0;
- for (i=0;i<pages;i++) {
- allocate_page(virtualbase+(i*PAGE_SIZE));
- }
- }
- void deallocate_page(unsigned long virtualbase) {
- unsigned long *page_directory =VIRT_PAGE_DIRECTORY;
- /* Seatch for the PD entry for the virtualbase */
- page_directory=VIRT_PAGE_DIRECTORY;
- virtualbase=PAGE_ALIGN(virtualbase);
- if( (page_directory[VIRT_TO_PDE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
- /* The PDE exist , now search the PTE */
- unsigned long* pte_table=(unsigned long*)VIRT_TO_PTE_VIRT(virtualbase);
- if( (pte_table[VIRT_TO_PTE(virtualbase)]&0x00000fff) != (unsigned long)0x02 ){
- push_up_phys(PAGE_ALIGN(pte_table[VIRT_TO_PTE(virtualbase)]));
- pte_table[VIRT_TO_PTE(virtualbase)]=0x02;
- write_cr3((unsigned long)PHYS_PAGE_DIRECTORY); // put that page directory address into CR3
- write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
- }
- else {
- kprint ("The PTE does not existn");
- }
- }
- else {
- kprint ("The PDE does not existn");
- }
- }
- void deallocate_pages(unsigned long virtualbase, int pages) {
- int i=0;
- for (i=0;i<pages;i++) {
- deallocate_page(virtualbase+(i*PAGE_SIZE));
- }
- }
- /* -----------------------------------------------
- *
- * DYNAMIC ALLOCATOR
- *
- * ----------------------------------------------*/
- heap_struct heap_info;
- void kfree(unsigned long base) {
- struct list_node_head *p;
- struct list_node_head *mover;
- struct heap_member* region;
- struct heap_member* new_region;
- region = (struct heap_member*)(list_entry (&(heap_info.usedlist->list), struct heap_member, list));
- if ((base>=region->base)&&(base<region->base+region->size)) {
- new_region=(struct heap_member*)kmalloc(sizeof(struct heap_member));
- new_region->base=region->base;
- new_region->size=region->size;
- region->base=0;
- region->size=0;
- list_add(&(new_region->list),&(heap_info.freelist->list));
- }
- else {
- list_for_each (p,&(heap_info.usedlist->list)) {
- region = (struct heap_member*)list_entry (p, struct heap_member, list);
- if ((base>=region->base)&&(base<region->base+region->size)) {
- list_del (p);
- mover=p;
- }
- }
- }
- list_add(mover,&(heap_info.freelist->list));
- }
- void initialize_dynamic_allocator() {
- heap_info.heap_top=KERNEL_HEAP_START;
- /* Add a page to the heap that will be used to get memory */
- allocate_page(KERNEL_HEAP_START);
- heap_info.heap_top=heap_info.heap_top+PAGE_SIZE;
- /* The first 2 reserverd regions in the heap are for the
- * freelist and usedlist */
- heap_info.freelist=(struct heap_member*)KERNEL_HEAP_START;
- heap_info.usedlist=heap_info.freelist+sizeof(struct heap_member);
- struct heap_member* first_free=heap_info.usedlist+sizeof(struct heap_member);
- /* Add this page to the free list */
- first_free->base=first_free+sizeof(struct heap_member);
- first_free->size=PAGE_SIZE-4*sizeof(struct heap_member);
- heap_info.freelist->base=0;
- heap_info.freelist->size=0;
- INIT_LIST_HEAD (&(heap_info.freelist->list));
- INIT_LIST_HEAD (&(heap_info.usedlist->list));
- list_add(&(first_free->list),&(heap_info.freelist->list));
- }
- unsigned long kmalloc (int bytes) {
- unsigned long base=0;
- /* Search the list for a big enough entry */
- struct heap_member* region;
- char text[200];
- /* returns a pointer to the base
- * of a free region and a pointer
- * to the list item that points to it
- */
- bytes=bytes+sizeof(struct heap_member);
- struct list_node_head* heap_list_p=get_free_heap_base(bytes);
- if (heap_list_p!=0) {
- /* A piece at least of the requested size has
- * been found, the size that we are requesting is
- * bytes + sizeof (struct heap_member) which
- * will hold the used heap_member structure
- * for the used fraction.
- * */
- region=(struct heap_member*)list_entry (heap_list_p,struct heap_member, list);
- // snprintf (text,"new heap base %x size %dn",region->base,region->size);
- // kprint (text);
- base=region->base;
- /* Substract the needed bytes from the piece */
- region->size=(region->size)-bytes;
- region->base=(region->base)+bytes;
- /* Heap member has been given the last bytes
- * of the requested region.
- * */
- struct heap_member* used_region=(struct heap_member*)(base+bytes-(sizeof(struct heap_member)));
- /* Set up the used region entry */
- used_region->base=base;
- used_region->size=bytes;
- /* Put the region into the list */
- list_add(&(used_region->list),&(heap_info.usedlist->list));
- }
- else {
- /* The heap is too small */
- /* More core needed */
- morecore (bytes);
- base=kmalloc (bytes);
- }
- return base;
- }
- unsigned long morecore(int bytes) {
- /* The beginning will be used to store
- * the entry to the free list */
- bytes=bytes+sizeof(struct heap_member);
- unsigned long base=PAGE_ALIGN(heap_info.heap_top);
- int pages=(bytes/PAGE_SIZE)+1;
- allocate_pages(base,pages);
- /* Increment the top address of heap */
- heap_info.heap_top=heap_info.heap_top+pages*PAGE_SIZE;
- struct heap_member* free_entry;
- free_entry=(struct heap_member*)base;
- free_entry->base=base+sizeof(struct heap_member);
- free_entry->size=pages*PAGE_SIZE-sizeof(struct heap_member);
- list_add(&(free_entry->list),&(heap_info.freelist->list));
- return base;
- }
- void debug_print_used_list () {
- struct list_node_head *p;
- struct heap_member* region;
- char text[200];
- region = (struct heap_member*)list_entry (&(heap_info.usedlist->list), struct heap_member, list);
- snprintf (text,"1Used at base %x size %dn",region->base,region->size);
- kprint (text);
- list_for_each (p,&(heap_info.usedlist->list)) {
- region = (struct heap_member*)list_entry (p, struct heap_member, list);
- snprintf (text,"2Used at base %x size %dn",region->base,region->size);
- kprint (text);
- }
- }
- void debug_print_free_list () {
- struct list_node_head *p;
- struct heap_member* region;
- char text[200];
- region = (struct heap_member*)(list_entry (&(heap_info.freelist->list), struct heap_member, list));
- snprintf (text,"1Free at base %x size %dn",region->base,region->size);
- kprint (text);
- list_for_each (p,&(heap_info.freelist->list)) {
- region = (struct heap_member*)list_entry (p, struct heap_member, list);
- snprintf (text,"2Free at base %x size %dn",region->base,region->size);
- kprint (text);
- }
- }
- struct list_node_head* get_free_heap_base (int bytes) {
- struct list_node_head *p;
- struct heap_member* region;
- region = (struct heap_member*)list_entry (&(heap_info.freelist->list), struct heap_member, list);
- if ( (region!=0) && region->size > bytes ) {
- p=&(heap_info.freelist->list);
- /* There is enough space here */
- return p;
- }
- else {
- list_for_each (p,(&(heap_info.freelist->list))) {
- region = (struct heap_member*)list_entry (p, struct heap_member, list);
- if ( region->size >= bytes ) {
- /* There is enough space here */
- return p;
- }
- }
- }
- return 0;
- }