实验内容
实验环境
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; }
解释下代码出现的几个陌生变量和函数。
-
/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; }
-
编译、运行结果
-
F5打开调试,编写应用程序
编写代码输出页目录和页表信息
-
添加系统调用
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 | 无 |