Thursday, January 28, 2010
linux-0.11-RW
{
struct file * file;
struct m_inode * inode;
if (fd>=NR_OPEN || count<0 file="current-">filp[fd]))
return -EINVAL;
if (!count)
return 0;
verify_area(buf,count);
inode = file->f_inode;
if (inode->i_pipe)
return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; /* pipe mode hadn't been added in stat.h*/
if (S_ISCHR(inode->i_mode))
return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return block_read(inode->i_zone[0],&file->f_pos,buf,count); /*
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
if (count+file->f_pos > inode->i_size)
count = inode->i_size - file->f_pos; /*truncate to the boundary*/
if (count<=0)
return 0;
return file_read(inode,file,buf,count);
}
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
1.what does inode->i_zone[0] contain ?
it stores character/block's logical device number as oppose of logical block number in regular file.
2.file points to a global file entry, if the offset was modified in this process, will other processes be affected ?
3. we can treat directory as regular file.
To summarize this function, in linux there're basic 4 types of readable things: 1.pipe 2.character device 3.block device 4.directory and regular file.
pipe resides on memory area, it normally has two ends. one for reading, one for writing.
4. some perpheral apparatus have its own buffer, which could facilitate the data transmission. how to fetch data out of the buffer ?
5.why the code verifies the buf ?
buf value assigns to the function is the logical address. get_base(current->ldt[2]); translates logical address to virtual address.
void verify_area(void * addr,int size)
{
unsigned long start;
start = (unsigned long) addr;
size += start & 0xfff; /* fully align to block boundary*/
start &= 0xfffff000; /* locate which block the addr is belonging to */
start += get_base(current->ldt[2]);
while (size>0) {
size -= 4096;
write_verify(start);
start += 4096;
}
}
int read_pipe(struct m_inode * inode, char * buf, int count)
{
int chars, size, read = 0;
while (count>0) {
while (!(size=PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
if (inode->i_count != 2) /* are there any writers? */
return read;
sleep_on(&inode->i_wait);
}
chars = PAGE_SIZE-PIPE_TAIL(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
count -= chars;
read += chars;
size = PIPE_TAIL(*inode);
PIPE_TAIL(*inode) += chars;
PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
while (chars-->0)
put_fs_byte(((char *)inode->i_size)[size++],buf++);
}
wake_up(&inode->i_wait);
return read;
}
1.what if count is greater than chars ?
in such case, the reading action will repeat.
2.what i_zone[0] and i_zone[1] represent in pipe inode ? an memory address or an integer ?
Theoretically speaking, i_zone[0/1] only could contain integre, which is used to index in array.
PIPE_TAIL(*inode) &= (PAGE_SIZE-1); if reading or writing operation exceeds the upper side boundary, the pointer will wrap around to the beginning of the pipe buffer.
this piece code is much like
while (PIPE_TAIL(*inode) > ( PAGE_SIZE-1 ) )
PIPE_TAIL(*inode) = PIPE_TAIL(*inode) - (PAGE_SIZE-1 ) ;
size : the available amount
chars : represent the distance of tail or head to the upper side of pipe buffer. Note, it doesn't stand for the amount of pipe data.
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 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;
}