Linux 下设置端口权限的系统调用有两个: ioperm 和 iopl 。
一、 ioperm 和 iopl 介绍。 1.ioperm 该系统调用的介绍参考了以下链接中的内容: http://blog./u2/76419/showart_1404294.html
功能描述: 为调用进程设置 I/O 端口访问权能。 ioperm 的使用需要具有超级用户的权限,只有低端的 [0-0x3ff] I/O 端口可被设置,要想指定更多端口的权能,可使用 iopl 函数。这一调用只可用于 i386 平台。
用法: #include <unistd.h> /* for libc5 */ int ioperm(unsigned long from, unsigned long num, int turn_on); 参数: from :起始端口地址。 num :需要修改权能的端口数。 turn_on :端口的新权能位。 1 为开启, 0 为关闭。
成功执行时,返回 0 。失败返回 -1 , errno 被设为以下的某个值 EINVAL :参数无效
2. iopl 功能描述:该调用用于修改当前进程的操作端口的权限。可以用于所有 65536 个端口的权限。因此, ioperm 相当于该调用的子集。和 ioperm 一样,这一调用仅适用于 i386 平台。
用法: #include <sys/io.h> int iopl(int level); 参数: level : 端口的权限级别 。为 3 时可以读写端口。默认权能级别为 0 ,用户空间不可读写。 返回说明:成功执行时,返回 0 。失败返回 -1 , errno 被设为以下的某个值 EINVAL : level 值大于 3 EPERM :调用进程权能不足。
二、程序示例 1. ioperm.c 操作低于 0x3FF 的端口 该程序首先设置 0x3FF 端口的读写权限,然后读出原先的值,然后将原值的 LSB 翻转并写回端口,并在此读取端口值。 /*Godbach. Dec 18, 2008 Description:This function is used to test ioperm()*/ #include <stdio.h> #include <unistd.h> #include <sys/io.h>
#define PORT_ADDR 0x3FF
int main(void) { int ret; char port_val;
/*set r/w permission of port_addr on, only one port*/ ret = ioperm(PORT_ADDR, 1, 1); if(ret < 0){ perror("ioperm set error"); return 0; } port_val = inb(PORT_ADDR); printf("Original value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);
/*reverse the least significant bit */ outb(port_val^0x01, PORT_ADDR); port_val = inb(PORT_ADDR); printf("Current value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);
/*set r/w permission of PORT_ADDR off, only one port*/ ret = ioperm(PORT_ADDR, 1, 0); if(ret < 0){ perror("ioperm set error"); return 0; } return 0; }
程序执行的结果是: [root@localhost misc-progs]# ./a.out Original value of port 0x3ff is : 00 Current value of port 0x3ff is : 01 [root@localhost misc-progs]# ./a.out Original value of port 0x3ff is : 01 Current value of port 0x3ff is : 00 该程序执行几次,将进行几次的 LSB 翻转。 这里有一个问题值得注意:在 2.4 ( RH9 )的内核上,当端口值大于 0x3FF 时,执行该程序则会报错: ioperm set error: Invalid argument 。即 IO 端口的值设置有问题,超出了限制。但是在 2.6 内核下并没有报错,而且执行结果也符合程序既定的结果。但是 man ioperm 中仍然说明了 0x3FF 的限制。暂且存疑。
2. iopl.c 该程序可以操作所有 65536 个端口。 该程序首先设置 0x3FF 端口的读写权限,然后读出原先的值,然后将原值的 LSB 翻转并写回端口,并在此读取端口值。 代码如下: /*Godbach. Dec 18, 2008 Description:This function is used to test iopl()*/ #include <stdio.h> #include <unistd.h> #include <sys/io.h>
#define PORT_ADDR 0x3FF
int main(void) { int ret; char port_val;
/*set r/w permission of all 65536 ports*/ ret = iopl(3); if(ret < 0){ perror("iopl set error"); return 0; } port_val = inb(PORT_ADDR); printf("Original value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);
/*reverse the least significant bit */ outb(port_val^0x01, PORT_ADDR); port_val = inb(PORT_ADDR); printf("Current value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);
/*set r/w permission of all 65536 ports*/ ret = iopl(0); if(ret < 0){ perror("iopl set error"); return 0; } return 0; } 程序执行结果: [root@linux misc-progs]# ./a.out Original value of port 0x3ff is : 01 Current value of port 0x3ff is : 00 [root@linux misc-progs]# ./a.out Original value of port 0x3ff is : 00 Current value of port 0x3ff is : 01 该程序执行几次,将进行几次的 LSB 翻转。 注:这里再次使用 0x3FF 端口,主要个人对端口的理解还不很深入,其他高于 0x3FF 的端口进行测试的时候,没有得到既定的结果。这里权且还使用这个端口,借此对 iopl 的用法熟悉一下即可。至于在真正使用中,如果系统的某个端口是可以进行配置的,那么执行这个程序应该是可以得到既定结果的。 区别: 必须用ioperm或iopl来获取对端口进行I/O操作的权限。ioperm用来获取对指定端口的 |
|