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;

}

Friday, March 27, 2009

linux-0.11-mm-2

unsigned long put_page(unsigned long page,unsigned long address)
{
unsigned long tmp, *page_table;

/* NOTE !!! This uses the fact that _pg_dir=0 */

if (page <>= HIGH_MEMORY)
printk("Trying to put page %p at %p\n",page,address);
if (mem_map[(page-LOW_MEM)>>12] != 1) //this element should be marked as used before invoking this function
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) ((address>>20) & 0xffc);
/*address>>20: address>>22 locate the INDEX in directory table.the pointer of each entry equals to INDEX x 4, because each entry occupies 4 bytes. finally, simplify the expression to "address>>20", least but not last, the last 2 bits must be set to 0.*/
if ((*page_table)&1)
page_table = (unsigned long *) (0xfffff000 & *page_table);// *page_table is page table entry.
else {
if (!(tmp=get_free_page())) //get the physical address of a new page from main memory.
return 0;
*page_table = tmp|7;
page_table = (unsigned long *) tmp;
}
page_table[(address>>12) & 0x3ff] = page | 7; /*save the pointer pointing to the begining of page to page table. 7 means:P=1.
R/W=1 read-and-write . U/S = 1 for application procedures and data. */
/* no need for invalidate */
return page;
}

linux-0.11-mm-1

unsigned long get_free_page(void)
{
register unsigned long __res asm("ax");// AS(16bit) consists of AH(8bit) and AL (8bit)
// repne: %cx is decremented by 1 each cycle.
__asm__("std ; repne ; scasb\n\t" //"scasb"compare 0(%1) with %edi:end of mem_map(%4) repne: repeat if ZF=0.doesn't find empty page
"jne 1f\n\t" // JUMP IF ZF(zero flag in EFLAGS) =0. when reach here, ZF=1.(No more page ZF=0)
"movb $1,1(%%edi)\n\t"//Found empty page.Mark used.after executed "scasb",pointed to next position.so need to add 1 before set
"sall $12,%%ecx\n\t" // multiple %ecs 12 times. %edi is the destination of string operation.4MbX (target page)=relative ADD.
"addl %2,%%ecx\n\t" //%2 LOW_MEM. LOW_MEM + relative address = absolute address
"movl %%ecx,%%edx\n\t" // save to %edx
"movl $1024,%%ecx\n\t" // set counts
"leal 4092(%%edx),%%edi\n\t" // move to the end point of target page.
"rep ; stosl\n\t" // move %eax // copy AL = 0 to %edi and %edi decrement. initialize this page.
"movl %%edx,%%eax\n" // %edx the begining of this page. send to output.
"1:"
:"=a" (__res) // %eax
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), // "c"--> %ecx "i"-->> a constant value
"D" (mem_map+PAGING_PAGES-1) // D -->>> %edi
:"di","cx","dx");
return __res;
}