linux shell 宏定义_linux内核修炼之系统调用

d129033fac3b3f5615336a4da1bdbe3b.png

fork()这个系统调用是有两个返回值的,在子进程中的返回值是0,在父进程中的返回值是PID,如下

5fb05376ceeee8e49ea7cc8960b21bad.png
图 fork一次 返回两次

关于0x80中断和特权级检查

在mian函数的sched_init()函数中调用宏:set_system_gate(0x80,&system_call);将0x80号中断安装到中断表里。可见将0x80中断安装进了head.s中定义的IDT表中的第0x80项,将中断函数入口偏移地址设置为system_call,将特权级设置为3。至于为什么没有看见可以自定义段描述符的地方,因为set_system_gate这个宏的作用是用来安装系统调用中断,而系统调用函数是内核函数,内核所在的代码段描述符值是0x8,这个是已经定死了的。安装描述符时不需要修改。

IDT表项安装好后,一旦用户程序执行0x80中断,则首先进行特权检查,用户程序的CPL为3,0x80中断的DPL也为3,因此可以执行该中断,中断将跳入内核函数中执行,硬件会自动得将0x8写入CS,将偏移地址写入EIP,从而执行systemcall,且CPL此时也已被修改为0,从而完成了特权级切换。

当使用jumpi指令进行段间跳转的时候会对比CS中的CPL和目标GDT中的代码段的DPL,段内跳转不对比;当使用mov的指令进行段间内存访问会对比DS中的CPL和目标GDT中的代码段的DPL,段内内存访问不对比,使用中断跳到中断服务程序的时候也会发生段间跳转,此时会对比CS中的CPL和IDT表项中的DPL。

8fc01fa60e7158937319117e3db2cf62.png

e1d8b1ab46aec4a71eaf0fd13fa9da13.png

d4e18eae44f591433e7abf60c3dc4b37.png
图 安装中断的宏

eab337395440d176418e256e6d81a8a4.png

使用bochs进行实验时,需要关注两个文件,一个是源码文件夹linux-0.11下的image文件,一个是oslab文件夹下的hdc-0.11-new.img 文件,源码文件夹下的image文件每次编译源码时都会重新生成,是内核代码文件;而.img是一个根文件系统镜像,他与/linux-0.11文件夹下的源码无关。

Bochs会虚拟出一个软盘和一个硬盘,软盘中放image,硬盘中放.img,bochs在启动是会从软盘启动,从而将image中的之前讲的bootset 、setup、 head和 sys内核程序按照之前讲过的顺序边读入内存边执行。当执行到main()中的init()函数时,这个函数的第一句话 setup((void *) &drive_info); 就是调用setup系统调用,安装根目录文件系统,如果此时没有.img文件,则可以在虚拟机页面中看到loading system…之后便报错,报错的语句是printk("Unable to read partition table of drive %dnr", 可以在代码中搜到,即在执行setup系统调用时报错。

文件系统加载完成后,就可以在shell中用ls查看各种文件和目录。当然也可以不启动linux0.11,而是在Ubuntu中将.img文件mount到某个目录下,则点进去看到的东西跟启动linux0.11后的根文件目录ls后看到的一样。

李志军老师的系统调用试验新增三个文件:who.c 、iam.c和whoami.c三个文件。其中who.c是新增的内核文件,写好放在源码的kernel文件夹下,至于为什么要用get_fs_byte来实现内存的访问,因为内核中的ds描述符默认是内核数据段,而我们实际也需要访问用户数据段,需要用到fs描述符,因此要加一层封装,这点在李老师书里详细说明。

who.c 写好后需要重新编译内核然后bochs加载进入shell,在shell中新建iam.c和whoami.c然后进行编译。编译出来的是用户程序,这两个c文件在编译的时候需要 编译一个_syscall2(int, whoami, char*, name, unsigned int, size);这种宏,宏中有一个变量是在unistd.h中定义的,要修改这个文件不应该在linux0.11的源码中找,而应该需要在文件系统中的/usr/include文件夹中找到并修改,因为源码此时已经编译成内核转载软驱载入内存中在跑,修改源码的源文件无意义。在shell的环境中找到include的文件,并进行修改。

#include <string.h>
#include <errno.h>
#include <asm/segment.h>
 
char msg[24];
 
int sys_iam(const char * name)
{
 char tep[26];
 int i = 0;
 for(; i < 26; i++)
    {
        tep[i] = get_fs_byte(name+i);
 if(tep[i] == '0')  break;
    }
 
 if (i > 23) return -(EINVAL);
 
 strcpy(msg, tep);
 return i;
}
 
int sys_whoami(char * name, unsigned int size)
{
 int len = 0;
 for (;msg[len] != '0'; len++);
 
 if (len > size) 
    {
 return -(EINVAL);
    }
 
 int i = 0;
 for(i = 0; i < size; i++)
    {
 put_fs_byte(msg[i], name+i);
 if(msg[i] == '0') break;
    }
 return i;
}

图 who.c代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值