Saturday, March 28, 2009

linux-0.11-mm-3

void do_wp_page(unsigned long error_code,unsigned long address)

{

#if

/* we cannot do this yet: the estdio library writes to code space */

/* stupid, stupid. I really want the libc.a from GNU */

if (CODE_SPACE(address))

do_exit(SIGSEGV);

#endif

un_wp_page((unsigned long *)

(((address>>10) & 0xffc) + (0xfffff000 &

*((unsigned long *) ((address>>20) &0xffc)))));


}


void un_wp_page(unsigned long * table_entry) // *table_entry is the entry in page table

{

unsigned long old_page,new_page;


old_page = 0xfffff000 & *table_entry; /*old_page is refer to the physical address */

/*MAP_NR-->>calculate the INDEX and guarantee that this page is only being referenced by one */

if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {

*table_entry |= 2; // set R/W bit , clear exception protection.

invalidate();

return;

}

/*if there're two or more references, just decrease one and copy the orginal content to new area*/

if (!(new_page=get_free_page()))

oom();

if (old_page >= LOW_MEM)

mem_map[MAP_NR(old_page)]--;

*table_entry = new_page | 7;

invalidate();

copy_page(old_page,new_page);

/*

#define copy_page(from,to) \

__asm__("cld ; rep ; movsl" movsl: move from %esi to %edi

:

:"S" (from),"D" (to),"c" (1024) %esi %edi

:"cx","di","si")


*/


}

int copy_page_tables(unsigned long from,unsigned long to,long size)

{

unsigned long * from_page_table;

unsigned long * to_page_table;

unsigned long this_page;

unsigned long * from_dir, * to_dir;

unsigned long nr;


if ((from&0x3fffff) || (to&0x3fffff))

panic("copy_page_tables called with wrong alignment");

from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */

to_dir = (unsigned long *) ((to>>20) & 0xffc);

size = ((unsigned) (size+0x3fffff)) >> 22;

for( ; size-->0 ; from_dir++,to_dir++) {

if (1 & *to_dir)

panic("copy_page_tables: already exist");

if (!(1 & *from_dir))

continue; /*source doesn't exist, just skip it*/

from_page_table = (unsigned long *) (0xfffff000 & *from_dir);/* get the pointer of page table*/

/*allocate physical memory with a page size to destination table*/

if (!(to_page_table = (unsigned long *) get_free_page()))

return -1; /* Out of memory, see freeing */

*to_dir = ((unsigned long) to_page_table) | 7; /*record the preceding page table to directory table*/

nr = (from==0)?0xA0:1024;

for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {

this_page = *from_page_table;

if (!(1 & this_page))

continue;

this_page &= ~2; /*this_page & 0xfffff000 ==>> the begining of page in physical memory*/

*to_page_table = this_page;

if (this_page > LOW_MEM) {

*from_page_table = this_page;

this_page -= LOW_MEM;

this_page >>= 12;

mem_map[this_page]++; /*increase the count of reference.*/

}

}

}

invalidate();

return 0;

}

No comments: