Minix添加系统调用(带参数)

本文详细介绍了如何在Minix3系统中增加新的系统调用。从内核到库函数,逐步指导如何定义和实现新的系统调用,并提供了一个具体的例子进行验证。

主要是根据以下步骤来的,不过原网页有些错误,少了些步骤,我加上了,经试验在我的Minix3.1.2a中可以成功了~

参考:http://www.phien.org/ucdavis/ta/ecs150-f03/syscall.html
           《MINIX on Linux/VMware》 Silvia Figueira – Fall 2007 Lab 3
           《How to Add a New System Call for Minix 3》 Karthick Jayaraman
                            Department of Electrical Engineering & Computer Science  Syracuse University, Syracuse, New York
           《System Call Implementation on Minix 3》  Felipe Caballero
                            Universidad Adolfo Ibá?ez, Santiago de Chile   Sistemas Operativos 2006-Segundo Semestre

以下为http://www.phien.org/ucdavis/ta/ecs150-f03/syscall.html按我的步骤的修改版:

Example Specifics

We want to add a system call int foo( long num ) to Minix. The specifics for foo are below:

Function: Print message 'syscall foo( <#> ) called! ' to screen, where <#> is the value of parameter num .
Returns: If num is a long integer greater than 0, do_foo returns 0 . Otherwise, foo fails and returns -1 .

Please note that foo is actually the interface to the system call do_foo that we will implement. Remember, the user calls a library function (in our case foo ). The library function then makes the actual system call (do_foo ).

Step 1: Kernel Modifications

All system calls in Minix correspond to a specific integer, as defined in /usr/include/minix/callnr.h . So, the first thing we should do is associate our new system call to an integer value.

  1. Open /usr/include/minix/callnr.h
  2. Increase the value of NCALLS by one
  3. At the bottom of the document, add the line '#define FOO 78 '. This assigns the value of 78 to our system call foo
  4. At the botton of /usr/src/include/minix/callnr.h, add '#define FOO 78'.
  5. Save changes and exit

Now we must modify the system call tables for FS and PM (file system, process manager).

Lets take care of the system call table in FS first. Since we want to implement this code in PM , we do not want FS to do anything for our system call. However, we will need to add an entry in the FS call table. This is done as follows:

  1. Open /usr/src/servers/fs/table.c
  2. Go to the end of the call_vec array
  3. Add the line no_sys, /* 78 = FOO */ at the end of call_vec
  4. Save and exit

Our new call_vec should look like this:

PUBLIC _PROTOTYPE( int (*call_vec[]), (void) ) = {
no_sys, /* 0 = unused */
do_exit, /* 1 = exit */

/* ... omitted code ... */

do_svrctl, /* 77 = SVRCTL */
no_sys, /* 78 = FOO */
};

Next we must modify the system call table in PM . Since this is where we want our system call to actually be implemented, we must do the following:

  1. Open /usr/src/servers/pm/table.c
  2. Go to the end of the call_vec array
  3. Add the line do_foo, /* 78 = FOO */ at the end of call_vec
  4. Save and exit

Our new call_vec should look like this:

PUBLIC _PROTOTYPE( int (*call_vec[]), (void) ) = {
no_sys, /* 0 = unused */
do_mm_exit, /* 1 = exit */

/* ... omitted code ... */

do_svrctl, /* 77 = SVRCTL */
do_foo, /* 78 = FOO */
};

 

Now that FS and PM know about our new system call, we should implement it. This can be done in a couple of ways, but only one is presented here:

  1. Open /usr/src/servers/pm/misc.c
  2. Add the line #include <stdio.h> with the other #include lines.
  3. Go to the bottom of the file, and add the following code:
PUBLIC int do_foo()
{
        long num;

      num = m_in.m4_l1;

        if( num > 0 )
{
printf( "syscall foo( %d ) called!/n", num );
return 0;
}
else
{
return -1;
}
}

Now, we should give PM the prototype for our new system call. This is done as follows:

  1. Open /usr/src/servers/pm/proto.h
  2. Go to the /* misc.c */ section (on line 41)
  3. Add the line _PROTOTYPE( int do_foo, (void) );
  4. Save changes and exit

The misc.c section should look like this:

/* misc.c */
_PROTOTYPE( int do_reboot, (void) );
_PROTOTYPE( int do_svrctl, (void) );
_PROTOTYPE( int do_foo, (void) );

At this point, we have made all the necessary kernel modifications. More information on the passing of parameter num from user space to kernel space can be found towards the bottom of this document.

Step 2: Library Modifications

Now we must make a library function call foo() , so that users can call our new do_foo system call. (This is just like how users call the fork() library function call to indirectly call the do_fork system call.) Again, there are multiple ways to do this, but only one is given here.

  1. Open /usr/include/unistd.h
  2. Add _PROTOTYPE( int foo, (long _num) ); at the end of the /* Function Prototypes*/ section (around line 126)
  3. Save and exit

The end of the /* Function Prototypes */ section should look like:

/* Function Prototypes. */
_PROTOTYPE( void _exit, (int _status) );

/* ... omitted code ... */

_PROTOTYPE( int foo, (long _num) );

Now we must create a small user library for our foo function call. This is done as follows:

  1. Create file /usr/src/include/foolib.h
  2. Add the following code:
#include <lib.h> 
#include <unistd.h>

PUBLIC int foo( long _num )
{
message m;

m.m4_l1 = _num;

return( _syscall( PM_PROC_NR, FOO, &m ) );
}

This completes all modifications we must make to add the do_foo system call. Please notice the underscores in the variable name!

Recompile Kernel

To compile the kernel, do the following commands in Minix (will take awhile):

  • cd /usr/src/tools/
  • make includes
  • make hdboot
  • sync

Finally, type shutdown and restart Minix. (Note: You might be able to find a faster way to compile the kernel.)

Testing New System Call

Here is some sample test code (foo.c ) that will test to make sure our new system call works properly.

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <foolib.h>
void main( int argc, char* argv )
{
        long rval1;
        long rval2;

rval1 = foo( -5 );
printf( "called foo( -5 )... rval was %d/n", rval1 );

rval2 = foo( 2 );
printf( "called foo( 2 )... rval was %d/n", rval2 );

return;
}

This program should output the following:

called foo( -5 )... rval was -1
syscall foo( 2 ) called!
called foo( 2 )... rval was 0
### Minix 操作系统技术注释 Minix 是一个小型的类 Unix 操作系统,最初由 Andrew S. Tanenbaum 于 1987 年开发,主要用于教学目的。它被设计成模块化和可移植的形式,以便学生和研究人员可以更好地理解操作系统的基本原理[^2]。Minix 的简单性和清晰的代码结构使其成为学习操作系统概念的理想平台。 #### 文件系统 Minix 使用了一种相对简单的文件系统结构,这使得它非常适合用于教学和研究。该文件系统的布局包括引导块、超级块、i 节点区、数据区等部分。其中,超级块包含了文件系统的全局信息,如文件系统的大小、可用空间等;i 节点区存储了每个文件的元数据;数据区则用来存放文件的实际内容[^1]。 - **超级块**:位于文件系统的起始位置之后,包含有关文件系统的关键参数,例如文件系统的总大小、空闲块的数量以及根目录的位置等。 - **i 节点**:每个文件都有一个对应的 i 节点,其中保存了文件的所有者、权限、时间戳及指向数据块的指针等信息。 - **数据区**:这是实际存储文件内容的地方,通常会被划分为固定大小的数据块。 #### 进程管理 在 Minix 中,进程管理是通过内核来处理的,而为了保证系统的稳定性与安全性,Minix 实现了特权级别保护机制。应用程序运行在较低的特权级(用户模式),当它们需要执行某些受限制的操作时,必须通过系统调用来请求内核服务。这些系统调用最终会触发中断,比如 `int 0x80`,然后控制权转移到内核中的中断处理程序,进而根据具体的系统调用号去查找并执行相应的处理函数[^4]。 #### 微内核架构 Minix 的一个显著特点是其采用的微内核架构。这种架构将核心的服务尽量减少,并且把更多的服务放在用户空间中作为独立的服务进程运行。这样做的好处是可以提高系统的稳定性和可靠性,因为如果某个服务失败了,不会直接影响到整个内核。此外,这也增加了系统的灵活性和可扩展性,便于添加新的功能而不必修改内核本身[^5]。 #### 系统调用接口 Minix 提供了一系列丰富的系统调用接口,允许应用程序与操作系统进行交互。这些接口覆盖了从文件操作到网络通信等多个方面。对于开发者来说,了解这些接口的工作方式及其背后的实现细节是非常重要的,因为它们构成了应用程序与底层硬件之间的桥梁。 ```c // 示例:使用 int 0x80 触发系统调用 #include <unistd.h> int main() { // write(1, "Hello, world\n", 13); __asm__("movl $4, %%eax\n\t" // sys_write "movl $1, %%ebx\n\t" // file descriptor 1 = stdout "movl $message, %%ecx\n\t" // address of string "movl $13, %%edx\n\t" // number of bytes "int $0x80" ); return 0; } ``` 以上代码片段演示了如何直接利用汇编指令在 Minix 或类似环境中调用 `write` 系统调用来输出字符串到标准输出设备上。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值