Linux系统内存管理实验

  • Post author:
  • Post category:linux




实验内容

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述



实验环境


Engintime Linux Lab 实验平台

所有修改过的文件都贴在文末,以便对照,点击前往:

sys.c



memory.c



printk.c



unistd.h



sys.h



kernel.h



system_call.s




编写代码实现页式管理分配物理页和释放物理页的过程


  • 添加系统调用内核函数

    int dump_physical_mem()

    • 新建

      Linux011 Kernel

      项目


    • /include/unistd.h

      中定义系统调用符号

      在162行插入

      #define __NR_dump_physical_mem 87


      在这里插入图片描述


    • /include/linux/sys.h

      中声明系统调用函数

      88行插入

      extern int sys_dump_physical();


      在这里插入图片描述

      179行插入

      sys_dump_physical_mem


      在这里插入图片描述


    • /kernel/system_call.s

      中修改系统调用总数

      73行令

      nr_system_calls

      的值加一

      在这里插入图片描述


    • /kernel/sys.c

      末尾定义

      dump_physical_mem

      函数

      在这里插入图片描述

      显然,todo就是实验内容的核心部分,它要完成以下功能:

      在这里插入图片描述

      但是,

      /kernel/sys.c

      无法直接访问内存信息,

      /mm/memory.c

      可以。todo要干的事在

      /mm/memory.c

      中很容易完成,所以可以把todo的内容封装成函数在

      /mm/memory.c

      完成,供

      /kernel/sys.c

      调用。


    • /mm/memory.c

      中定义

      physical_mem()

      实现todo

      在文(在)件(哪)末(都)尾(行)添加函数定义:

      int physical_mem(){
      	int i, free=0;	/* free表示空闲页的总数 */
      	unsigned long addr; /*分配的物理内存页地址*/
      	
      	for(i=0 ; i<PAGING_PAGES ; i++)
      	{
      		if (0 == mem_map[i])
      		{
      			free++;
      		}
      	}
      	printk("Page Count : %d\n", PAGING_PAGES);
      	//计算内存,kernel默认物理页大小为4K
      	printk("Memory Count : %d * 4096 = %d Byte\n\n", PAGING_PAGES, PAGING_PAGES * 4096); 
      	printk("Free Page Count : %d\n", free);
      	printk("Used Page Count : %d\n", PAGING_PAGES - free);
      	
      	//申请一个空闲页后的内存情况
      	printk("****************After Allocate One Page****************\n");
      	addr = get_free_page();
      	if(!addr){
      		printk("get free page error!\n");
      		return 1;
      	}
      	printk("Allocate One Page : 0x%X\n", addr );
      	free = 0;
      	for(i=0 ; i<PAGING_PAGES ; i++)
      	{
      		if (0 == mem_map[i])	//为0即mem_map[i]为空闲页
      		{
      			free++;
      		}
      	}
      	printk("Free Page Count : %d\n", free);
      	printk("Used Page Count : %d\n", PAGING_PAGES - free);
      	
      	//释放掉申请的内存页后的内存情况
      	printk("****************After Free One Page****************\n");
      	free_page(addr);
      	printk("Free One Page : 0x%X\n", addr );
      	free = 0;
      	for(i=0 ; i<PAGING_PAGES ; i++)
      	{
      		if (0 == mem_map[i])
      		{
      			free++;
      		}
      	}
      	printk("Free Page Count : %d\n", free);
      	printk("Used Page Count : %d\n", PAGING_PAGES - free);
      	
      	return 0;
      }
      

      解释下代码出现的几个陌生变量和函数。


      PAGING_PAGES



      mem_map[]



      get_free_page()



      free_page()


    • /include/linux/kernel.h

      中声明

      physical_mem()



      kernel.h

      定义了一些常用函数的原型,sys.c和memory.c都include了它。在文件中插入

      int physical_mem();

      在这里插入图片描述


    • /kernel/sys.c

      调用

      /mm/memory.c



      physical_mem()


      直接调用就好了

      在这里插入图片描述

      F7编译就完事了。

      在这里插入图片描述



  • 应用程序调用系统调用
    • F5打开调试,编写应用程序


      vi main.c

      #define __LIBRARY__
      #include <unistd.h>
      #define __NR_dump_physical_mem 87
      _syscall0( int, dump_physical_mem )
      int main( int argc, char** argv ){
      	dump_physical_mem();
      	return 0;
      }
      
    • 编译、运行结果

      在这里插入图片描述



编写代码输出页目录和页表信息


  • 添加系统调用

    table_mapping()

    没必要新建项目,我们直接在这个项目上工作就好了。添加系统调用上文已经介绍过了,那这里我偷偷懒,只放图了。


    • /include/unistd.h


      在这里插入图片描述


    • /kernel/system_call.s


      在这里插入图片描述


    • /include/linux/sys.h


      在这里插入图片描述

      在这里插入图片描述


    • /kernel/sys.c

      末尾添加

      sys_table_mapping()

      定义

      int sys_table_mapping(){
      	unsigned long index_of_dir,  index_of_table;
      	unsigned long entry;
      	unsigned long page_table_base;
      	unsigned long page_dir_base = 0;
      	__asm("cli");
      	calc_mem();	// 显示内存空闲页面数。
      	// 首先打印输出页目录信息
      	fprintk(1,"Page Directory(PFN:0x0 | LA:0x00000000)\n");
      	// 第一层循环,遍历页目录中的所有 PDE
      	for(index_of_dir = 0; index_of_dir < 1024; index_of_dir++){
      		entry = ((unsigned long*)page_dir_base)[index_of_dir];
      		if(!(entry & 1))	/* 跳过无效的 PDE */
      			continue;
      		// 输出 PDE 信息
      		fprintk(1,"\tPDE: 0x%X -> Page Table(PFN:0x%X | LA:0x%08X)\n", index_of_dir,  entry >> 12, 0xFFFFF000 & entry);
      		/* 页目录项的高20位即为页表的物理地址,页表的物理地址即为页表的逻辑地址 */
      		page_table_base = 0xFFFFF000 & entry;
      		/* 第二层循环,遍历页表中的所有 PTE */
      		for(index_of_table = 0; index_of_table < 1024; index_of_table++){
      			entry = ((unsigned long*)page_table_base)[index_of_table];
      			if(!(entry & 1))	/* 跳过无效的 PTE */
      				continue;	
      			// 输出 PTE 信息
      			fprintk(1,"\t\tPTE: 0x%X -> Physical Page(PFN:0x%X | LA:0x%08X)\n", index_of_table, 
      				entry >> 12, (index_of_dir << 22) | (index_of_table << 12));
      		}
      	 }
      	 __asm("sti");
      	return 0;
      }
      

      呃,咋一看是不是一脸懵。没关系,让我们来分析一下实验内容。

      在这里插入图片描述

      实验要求显示系统空闲页面(

      calc_mem()

      干的就是这个)和当前页目录、PDE、PTE 。没错,

      sys_table_mapping

      的定义中calc_mem()用来输出系统空闲页面数,剩下的就是输出页目录、PDE、PTE用的。你一定还发现了,代码里出现了陌生的未定义的函数,比如fprintk,实验要求输出到

      文本文件

      中,



      不是屏幕



      。来看看指导书的解释。

      在sys_table_mapping函数中调用了一个名称为fprintk的函数用于向标准输出打印信息,而没有使用printk函数,这是由于本实验需要输出的内容较多,需要输出到文件中以便查看,但是printk虽然可以在屏幕上进行输出,但是却不能输出到文件中,所以需要实现一个fprintk函数。


      所以,我们的思路就是,实现函数fprintk,将要输出的内容通过fprintk推到标准输出流stdout中,再将流中的内容保存到文本文档内。

    • 实现

      fprintk()




      /kernel/printk.c

      末添加fprintk的定义,还要添加两个头文件,一个静态声明。

      int fprintk( int fd, const char * fmt, ... )
      {
      	va_list args;
      	int i;
      	struct file * file;
      	struct m_inode * inode;
      	va_start (args, fmt);		
        	i = vsprintf (logbuf, fmt, args);
        	va_end (args);
        	
        	if( fd<3 )
        	{
        		__asm__ ("push %%fs\n\t"		
      	   	"push %%ds\n\t"
      	   	"pop %%fs\n\t"	
      	  	"pushl %0\n\t"					
      	   	"pushl $_logbuf\n\t"			
      	   	"pushl %1\n\t"					
      	   	"call _sys_write\n\t"			
      	   	"addl $8,%%esp\n\t"				
      	   	"popl %0\n\t"					
      	   	"pop %%fs"						
      		::"r" (i),"r" (fd):"ax",  "dx");
        	}
        	else
        	{
        		if( !( file=task[0]->filp[fd] ) )
        			return 0;
        		inode=file->f_inode;
        		__asm__ ("push %%fs\n\t"		
      	   	"push %%ds\n\t"
      	   	"pop %%fs\n\t"	
      	  	"pushl %0\n\t"					
      	   	"pushl $_logbuf\n\t"			
      	   	"pushl %1\n\t"					
      	   	"pushl %2\n\t"					
      	   	"call _file_write\n\t"			
      	   	"addl $12,%%esp\n\t"			
      	   	"popl %0\n\t"					
      	   	"pop %%fs"						
      		::"r" (i), "r" (file), "r" (inode)   );	
        	}
        	return i;// 返回字符串长度
      }
      

      在这里插入图片描述


      include/linux/kernel.h

      中添加fprintk声明

      在这里插入图片描述

      calc_mem()的输出对象也是屏幕,我们要把它改成向流输出,把printk全部改成fprintk。这个函数定义在memory.c的760行。

      在这里插入图片描述

      F7编译,冒得错误。

      在这里插入图片描述

  • 编写应用程序调用

    table_mapping



    vi meminfo.c

    #define __LIBRARY__
    #include <unistd.h>
    #define __NR_table_mapping 88
    _syscall0( int, table_mapping )
    int main( int argc, char** argv ){
    	table_mapping();
    	return 0;
    }
    


  • 结果


    gcc meminfo.c -o meminfo

    编译


    meminfo > a.txt

    执行并将标准输出流stdout中的内容输出到文本文件a.txt


    sync

    同步


    mcopy -n a.txt b:a.txt

    将a.txt拷贝到软盘b

    在这里插入图片描述

    打开软盘b

    在这里插入图片描述

    在这里插入图片描述


以下为所有修改过的文件和一些说明

  • sys.c

...

int sys_dump_physical_mem(){
	physical_mem();
	return 0;
}

int sys_table_mapping(){
	unsigned long index_of_dir,  index_of_table;
	unsigned long entry;
	unsigned long page_table_base;
	unsigned long page_dir_base = 0;

	__asm("cli");
	
	calc_mem();	// 显示内存空闲页面数。
	
	// 首先打印输出页目录信息。格式为:Page Directory(页目录的物理页框号 | 所在线性地址)
	fprintk(1,"Page Directory(PFN:0x0 | LA:0x00000000)\n");
	
	// 第一层循环,遍历页目录中的所有 PDE
	for(index_of_dir = 0; index_of_dir < 1024; index_of_dir++)
	{
		entry = ((unsigned long*)page_dir_base)[index_of_dir];
		
		if(!(entry & 1))	/* 跳过无效的 PDE */
			continue;
		
		// 输出 PDE 信息,格式如下:  
		// PDE: 下标 -> Page Table(页表的物理页框号 | 所在的线性地址)
		fprintk(1,"\tPDE: 0x%X -> Page Table(PFN:0x%X | LA:0x%08X)\n", index_of_dir,  entry >> 12, 0xFFFFF000 & entry);

		/* 页目录项的高20位即为页表的物理地址,页表的物理地址即为页表的逻辑地址 */
		page_table_base = 0xFFFFF000 & entry;
		
		/* 第二层循环,遍历页表中的所有 PTE */
		for(index_of_table = 0; index_of_table < 1024; index_of_table++)
		{
			entry = ((unsigned long*)page_table_base)[index_of_table];
			
			if(!(entry & 1))	/* 跳过无效的 PTE */
				continue;	
			
			// 输出 PTE 信息,格式如下:
			// PTE: 下标 -> Physical Page(物理页框号 | 所在的线性地址)
			fprintk(1,"\t\tPTE: 0x%X -> Physical Page(PFN:0x%X | LA:0x%08X)\n", index_of_table, 
				entry >> 12, (index_of_dir << 22) | (index_of_table << 12));
		}
	 }
	__asm("sti");
	return 0;
}


回到目录

  • memory.c

...

// 计算内存空闲页面数并显示。
void calc_mem(void)
{
	int i,j,k,free=0;
	long * pg_tbl;

	// 扫描内存页面映射数组mem_map[],获取空闲页面数并显示。
	for(i=0 ; i<PAGING_PAGES ; i++)
		if (!mem_map[i]) free++;
	fprintk(1,"%d pages free (of %d)\n\r",free,PAGING_PAGES);
	// 扫描所有页目录项(除0,1 项),如果页目录项有效,则统计对应页表中有效页面数,并显示。
	for(i=2 ; i<1024 ; i++) {
		if (1&pg_dir[i]) {
			pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
			for(j=k=0 ; j<1024 ; j++)
				if (pg_tbl[j]&1)
					k++;
			fprintk(1,"Pg-dir[%d] uses %d pages\n",i,k);
		}
	}
}

int physical_mem(){
	int i, free=0;	/* free表示空闲页的总数 */
	unsigned long addr; /*分配的物理内存页地址*/
	
	/* PAGING_PAGES 是在本文件第 137 行处定义,表示分页后的物理内存页数。*/
	/* mem_map[] 是在第 152 行定义的内存映射字节图(1 字节代表 1 页内存),
		每个页面对应的字节用于标志页面当前被引用(占用)次数。*/
	for(i=0 ; i<PAGING_PAGES ; i++)
	{
		if (0 == mem_map[i])
		{
			free++;
		}
	}
	
	printk("Page Count : %d\n", PAGING_PAGES);
	printk("Memory Count : %d * 4096 = %d Byte\n\n", PAGING_PAGES, PAGING_PAGES * 4096); /*kernel 物理内存页的默认大小是4K*/
	
	printk("Free Page Count : %d\n", free);
	printk("Used Page Count : %d\n", PAGING_PAGES - free);
	
	printk("****************After Allocate One Page****************\n");
	addr = get_free_page();
	if(!addr){
		printk("get free page error!\n");
		return 1;
	}
	printk("Allocate One Page : 0x%X\n", addr );
	free = 0;
	for(i=0 ; i<PAGING_PAGES ; i++)
	{
		if (0 == mem_map[i])
		{
			free++;
		}
	}
	printk("Free Page Count : %d\n", free);
	printk("Used Page Count : %d\n", PAGING_PAGES - free);
	
	printk("****************After Free One Page****************\n");
	free_page(addr);
	printk("Free One Page : 0x%X\n", addr );
	free = 0;
	for(i=0 ; i<PAGING_PAGES ; i++)
	{
		if (0 == mem_map[i])
		{
			free++;
		}
	}
	printk("Free Page Count : %d\n", free);
	printk("Used Page Count : %d\n", PAGING_PAGES - free);
	
	return 0;
}


回到目录

  • printk.c

/*
 * 当处于内核模式时,我们不能使用printf,因为寄存器fs 指向其它不感兴趣的地方。
 * 自己编制一个printf 并在使用前保存fs,一切就解决了。
 */
#include <stdarg.h>			// 标准参数头文件。以宏的形式定义变量参数列表。主要说明了-个
							// 类型(va_list)和三个宏(va_start, va_arg 和va_end),用于
							// vsprintf、vprintf、vfprintf 函数。
#include <stddef.h>			// 标准定义头文件。定义了NULL, offsetof(TYPE, MEMBER)。

#include <linux/kernel.h>	// 内核头文件。含有一些内核常用函数的原形定义。

#include<linux/sched.h>
#include<sys/stat.h>


static char buf[1024];
static char logbuf[1024];

// 下面该函数vsprintf()在linux/kernel/vsprintf.c 中
extern int vsprintf(char * buf, const char * fmt, va_list args);

// 内核使用的显示函数。
int printk(const char *fmt, ...)
{
	va_list args;
	int i;

	va_start (args, fmt);				// 参数处理开始函数。在(include/stdarg.h)
  	i = vsprintf (buf, fmt, args);		// 使用格式串fmt 将参数列表args 输出到buf 中。
										// 返回值i 等于输出字符串的长度。
  	va_end (args);						// 参数处理结束函数。
 	 __asm__ ("push %%fs\n\t"			// 保存fs。
	   	"push %%ds\n\t" "pop %%fs\n\t"	// 令fs = ds。
	  	"pushl %0\n\t"					// 将字符串长度压入堆栈(这三个入栈是调用参数)。
	   	"pushl $_buf\n\t"				// 将buf 的地址压入堆栈。
	   	"pushl $0\n\t"					// 将数值0 压入堆栈。是通道号channel。
	   	"call _tty_write\n\t"			// 调用tty_write 函数。(kernel/chr_drv/tty_io.c)。
	   	"addl $8,%%esp\n\t"				// 跳过(丢弃)两个入栈参数(buf,channel)。
	   	"popl %0\n\t"					// 弹出字符串长度值,作为返回值。
	   	"pop %%fs"						// 恢复原fs 寄存器。
	::"r" (i):"ax", "cx", "dx");		// 通知编译器,寄存器ax,cx,dx 值可能已经改变。
  return i;								// 返回字符串长度。
}

int fprintk( int fd, const char * fmt, ... )
{
	va_list args;
	int i;
	struct file * file;
	struct m_inode * inode;
	va_start (args, fmt);		
  	i = vsprintf (logbuf, fmt, args);
  	va_end (args);
  	
  	if( fd<3 )
  	{
  		__asm__ ("push %%fs\n\t"		
	   	"push %%ds\n\t"
	   	"pop %%fs\n\t"	
	  	"pushl %0\n\t"					
	   	"pushl $_logbuf\n\t"			
	   	"pushl %1\n\t"					
	   	"call _sys_write\n\t"			
	   	"addl $8,%%esp\n\t"				
	   	"popl %0\n\t"					
	   	"pop %%fs"						
		::"r" (i),"r" (fd):"ax",  "dx");
  	}
  	else
  	{
  		if( !( file=task[0]->filp[fd] ) )
  			return 0;
  		inode=file->f_inode;
  		__asm__ ("push %%fs\n\t"		
	   	"push %%ds\n\t"
	   	"pop %%fs\n\t"	
	  	"pushl %0\n\t"					
	   	"pushl $_logbuf\n\t"			
	   	"pushl %1\n\t"					
	   	"pushl %2\n\t"					
	   	"call _file_write\n\t"			
	   	"addl $12,%%esp\n\t"			
	   	"popl %0\n\t"					
	   	"pop %%fs"						
		::"r" (i), "r" (file), "r" (inode)   );	
  	}
  	return i;// 返回字符串长度
}


回到目录

  • unistd.h

...

#define __NR_dump_physical_mem 87
#define __NR_table_mapping 88

...


回到目录

  • sys.h

extern int sys_setup ();		// 系统启动初始化设置函数。 (kernel/blk_drv/hd.c)
extern int sys_exit ();			// 程序退出。 (kernel/exit.c)
extern int sys_fork ();			// 创建进程。 (kernel/system_call.s)
extern int sys_read ();			// 读文件。 (fs/read_write.c)
extern int sys_write ();		// 写文件。 (fs/read_write.c)
extern int sys_open ();			// 打开文件。 (fs/open.c)
extern int sys_close ();		// 关闭文件。 (fs/open.c)
extern int sys_waitpid ();		// 等待进程终止。 (kernel/exit.c)
extern int sys_creat ();		// 创建文件。 (fs/open.c)
extern int sys_link ();			// 创建一个文件的硬连接。 (fs/namei.c)
extern int sys_unlink ();		// 删除一个文件名(或删除文件)。 (fs/namei.c)
extern int sys_execve ();		// 执行程序。 (kernel/system_call.s)
extern int sys_chdir ();		// 更改当前目录。 (fs/open.c)
extern int sys_time ();			// 取当前时间。 (kernel/sys.c)
extern int sys_mknod ();		// 建立块/字符特殊文件。 (fs/namei.c)
extern int sys_chmod ();		// 修改文件属性。 (fs/open.c)
extern int sys_chown ();		// 修改文件宿主和所属组。 (fs/open.c)
extern int sys_break ();		// (-kernel/sys.c)
extern int sys_stat ();			// 使用路径名取文件的状态信息。 (fs/stat.c)
extern int sys_lseek ();		// 重新定位读/写文件偏移。 (fs/read_write.c)
extern int sys_getpid ();		// 取进程id。 (kernel/sched.c)
extern int sys_mount ();		// 安装文件系统。 (fs/super.c)
extern int sys_umount ();		// 卸载文件系统。 (fs/super.c)
extern int sys_setuid ();		// 设置进程用户id。 (kernel/sys.c)
extern int sys_getuid ();		// 取进程用户id。 (kernel/sched.c)
extern int sys_stime ();		// 设置系统时间日期。 (-kernel/sys.c)
extern int sys_ptrace ();		// 程序调试。 (-kernel/sys.c)
extern int sys_alarm ();		// 设置报警。 (kernel/sched.c)
extern int sys_fstat ();		// 使用文件句柄取文件的状态信息。(fs/stat.c)
extern int sys_pause ();		// 暂停进程运行。 (kernel/sched.c)
extern int sys_utime ();		// 改变文件的访问和修改时间。 (fs/open.c)
extern int sys_stty ();			// 修改终端行设置。 (-kernel/sys.c)
extern int sys_gtty ();			// 取终端行设置信息。 (-kernel/sys.c)
extern int sys_access ();		// 检查用户对一个文件的访问权限。(fs/open.c)
extern int sys_nice ();			// 设置进程执行优先权。 (kernel/sched.c)
extern int sys_ftime ();		// 取日期和时间。 (-kernel/sys.c)
extern int sys_sync ();			// 同步高速缓冲与设备中数据。 (fs/buffer.c)
extern int sys_kill ();			// 终止一个进程。 (kernel/exit.c)
extern int sys_rename ();		// 更改文件名。 (-kernel/sys.c)
extern int sys_mkdir ();		// 创建目录。 (fs/namei.c)
extern int sys_rmdir ();		// 删除目录。 (fs/namei.c)
extern int sys_dup ();			// 复制文件句柄。 (fs/fcntl.c)
extern int sys_pipe ();			// 创建管道。 (fs/pipe.c)
extern int sys_times ();		// 取运行时间。 (kernel/sys.c)
extern int sys_prof ();			// 程序执行时间区域。 (-kernel/sys.c)
extern int sys_brk ();			// 修改数据段长度。 (kernel/sys.c)
extern int sys_setgid ();		// 设置进程组id。 (kernel/sys.c)
extern int sys_getgid ();		// 取进程组id。 (kernel/sched.c)
extern int sys_signal ();		// 信号处理。 (kernel/signal.c)
extern int sys_geteuid ();		// 取进程有效用户id。 (kenrl/sched.c)
extern int sys_getegid ();		// 取进程有效组id。 (kenrl/sched.c)
extern int sys_acct ();			// 进程记帐。 (-kernel/sys.c)
extern int sys_phys ();			// (-kernel/sys.c)
extern int sys_lock ();			// (-kernel/sys.c)
extern int sys_ioctl ();		// 设备控制。 (fs/ioctl.c)
extern int sys_fcntl ();		// 文件句柄操作。 (fs/fcntl.c)
extern int sys_mpx ();			// (-kernel/sys.c)
extern int sys_setpgid ();		// 设置进程组id。 (kernel/sys.c)
extern int sys_ulimit ();		// (-kernel/sys.c)
extern int sys_uname ();		// 显示系统信息。 (kernel/sys.c)
extern int sys_umask ();		// 取默认文件创建属性码。 (kernel/sys.c)
extern int sys_chroot ();		// 改变根系统。 (fs/open.c)
extern int sys_ustat ();		// 取文件系统信息。 (fs/open.c)
extern int sys_dup2 ();			// 复制文件句柄。 (fs/fcntl.c)
extern int sys_getppid ();		// 取父进程id。 (kernel/sched.c)
extern int sys_getpgrp ();		// 取进程组id,等于getpgid(0)。(kernel/sys.c)
extern int sys_setsid ();		// 在新会话中运行程序。 (kernel/sys.c)
extern int sys_sigaction ();	// 改变信号处理过程。 (kernel/signal.c)
extern int sys_sgetmask ();		// 取信号屏蔽码。 (kernel/signal.c)
extern int sys_ssetmask ();		// 设置信号屏蔽码。 (kernel/signal.c)
extern int sys_setreuid ();		// 设置真实与/或有效用户id。 (kernel/sys.c)
extern int sys_setregid ();		// 设置真实与/或有效组id。 (kernel/sys.c)
extern int sys_sigpending();
extern int sys_sigsuspend();
extern int sys_sethostname();
extern int sys_setrlimit();
extern int sys_getrlimit();
extern int sys_getrusage();
extern int sys_gettimeofday();
extern int sys_settimeofday();
extern int sys_getgroups();
extern int sys_setgroups();
extern int sys_select();
extern int sys_symlink();
extern int sys_lstat();
extern int sys_readlink();
extern int sys_uselib();
extern int sys_dump_physical_mem();
extern int sys_table_mapping();
// 系统调用函数指针表。用于系统调用中断处理程序(int 0x80),作为跳转表。
// 数组元素为系统调用内核函数的函数指针,索引即系统调用号
fn_ptr sys_call_table[] = { 
sys_setup,			//0 
sys_exit,           //1   
sys_fork,           //2
sys_read,           //3
sys_write,          //4
sys_open,           //5
sys_close,          //6
sys_waitpid,        //7
sys_creat,          //8
sys_link,           //9
sys_unlink,         //10 
sys_execve,         //11
sys_chdir,          //12
sys_time,           //13
sys_mknod,          //14
sys_chmod,          //15 
sys_chown,          //16 
sys_break,          //17
sys_stat,           //18
sys_lseek,          //19
sys_getpid,         //20
sys_mount,          //21
sys_umount,         //22 
sys_setuid,         //23
sys_getuid,         //24
sys_stime,          //25
sys_ptrace,         //26
sys_alarm,          //27
sys_fstat,          //28 
sys_pause,          //29
sys_utime,          //30
sys_stty,           //31
sys_gtty,           //32 
sys_access,         //33
sys_nice,           //34
sys_ftime,          //35
sys_sync,           //36
sys_kill,           //37
sys_rename,         //38
sys_mkdir,          //39
sys_rmdir,          //40
sys_dup,            //41   
sys_pipe,           //42
sys_times,          //43
sys_prof,           //44
sys_brk,            //45
sys_setgid,         //46
sys_getgid,         //47
sys_signal,         //48
sys_geteuid,        //49
sys_getegid,        //50
sys_acct,           //51
sys_phys,           //52
sys_lock,           //53
sys_ioctl,          //54
sys_fcntl,          //55
sys_mpx,            //56
sys_setpgid,        //57
sys_ulimit,         //58
sys_uname,          //59
sys_umask,          //60
sys_chroot,         //61
sys_ustat,          //62
sys_dup2,           //63
sys_getppid,        //64
sys_getpgrp,        //65
sys_setsid,         //66
sys_sigaction,      //67
sys_sgetmask,       //68
sys_ssetmask,       //69
sys_setreuid,       //70
sys_setregid,       //71
sys_sigsuspend, 	//72
sys_sigpending, 	//73
sys_sethostname,	//74
sys_setrlimit, 		//75
sys_getrlimit, 		//76
sys_getrusage, 		//77
sys_gettimeofday,	//78 
sys_settimeofday, 	//79
sys_getgroups, 		//80
sys_setgroups, 		//81
sys_select, 		//82
sys_symlink,		//83
sys_lstat, 			//84
sys_readlink, 		//85
sys_uselib, 		//86
sys_dump_physical_mem,//87
sys_table_mapping	//88 
};


回到目录

  • kernel.h

/*
 * 'kernel.h' contains some often-used function prototypes etc
 */
/*
 * 'kernel.h'定义了一些常用函数的原型等。
 */
// 验证给定地址开始的内存块是否超限。若超限则追加内存。( kernel/fork.c)。
void verify_area (void *addr, int count);
// 显示内核出错信息,然后进入死循环。( kernel/panic.c)。
volatile void panic (const char *str);
// 标准打印(显示)函数。( init/main.c)。
int printf (const char *fmt, ...);
// 内核专用的打印信息函数,功能与printf()相同。( kernel/printk.c)。
int printk (const char *fmt, ...);
// 往tty 上写指定长度的字符串。( kernel/chr_drv/tty_io.c)。
int tty_write (unsigned ch, char *buf, int count);
// 通用内核内存分配函数。( lib/malloc.c)。
void *malloc (unsigned int size);
// 释放指定对象占用的内存。( lib/malloc.c)。
void free_s (void *obj, int size);
//
int physical_mem();
//
int fprintk( int fd, const char * fmt, ... );

#define free(x) free_s((x), 0)

/*
 * This is defined as a macro, but at some point this might become a
 * real subroutine that sets a flag if it returns true (to do
 * BSD-style accounting where the process is flagged if it uses root
 * privs). The implication of this is that you should do normal
 * permissions checks first, and check suser() last.
 */
/*
 * 下面函数是以宏的形式定义的,但是在某方面来看它可以成为一个真正的子程序,
 * 如果返回是true 时它将设置标志(如果使用root 用户权限的进程设置了标志,则用
 * 于执行BSD 方式的计帐处理)。这意味着你应该首先执行常规权限检查,最后再
 * 检测suser()。
 */
#define suser() (current->euid == 0)	// 检测是否是超级用户。


回到目录

  • system_call.s

...

nr_system_calls = 89	# Linux 0.11 版内核中的系统调用总数。

...
  • 变量

变量 描述 定义在where
PAGING_PAGES 分页后的物理内存页数 /mm/memory.c:137行
mem_map 内存映射字节图(1 字节代表1 页内存),每个页面对应的字节用于标志页面当前被引用(占用)次数 /mm/memory.c:151行
  • 函数

函数 描述 参数 返回值
get_free_page 在主内存中取空闲页面 返回空闲页面地址(如果无空闲也则返回0)
free_page 释放物理地址addr 开始的一页面内存 unsigned long addr


我要回去



版权声明:本文为Liaojj_原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。