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:
Post a Comment