作为用户程序的设备驱动程序是如何被其它用户程序调用的?

80386的权限机制中规定:
操作系统数据只能由操作系统代码或核心代码来访问;
内核的系统调用函数也只能由用户程序或权限等于或小于它的用户程序调用;

QNX中的设备驱动程序作为用户程序来运行,调用其功能的用户级代码想必得通过系统调用接口来访问其代码,而如果通过系统调用,则必然出现核心代码反过来调用用户程序(设备驱动程序)的情况.这个问题QNX是怎样解决的呢?

还有,如果设备驱动程序作为用户级程序来运行,它必然要访问硬件端口或者是其它核心内存空间,这又与以上权限机制相违背.

思量好久不得其法,请问QNX是如何处理这两个问题的呢?

QNX是微内核,注意这个“微”字。
你的问题是将一体化内核的思想套到QNX上。
驱动程序访问硬件为什么一定要靠系统调用???
想想以前DOS下对硬件的操作,访问硬件不一定必须经过操作系统内核来完成。

前面的部份是正确的。80386有4个保护机制,RING0可以运行内核代码,RING3是通常的用户程序。

注意在QNX上,内核不会去“调用”用户程序。(唯一例外是中断服务程序)内核只提供了数据传递机制(消息传递)。一个用户程序,它需要使用某一设备时,是将它的请求,封装到一个数据块里,然后请求内核将数据块传给指定的设备驱动程序。对于内核来说,数据块里的内容它是不关心的,只负责将数据从一个进程(用户程序)传给另一个进程(设备驱动)。设备驱动负责解释数据块的含义,找出用户的请求,对硬件进行相应操作,并返回结果。

另一方面,设备驱动程序,因为要进行一些硬件操作,in/out,所以它如果只有普通的RING3的权限是不够的。所以在每一个需要进行硬件操作的程序里,它都需要先向内核申请取得“IO特权”。有个专门的 ThreadCtl()内核调用让你做这件事。申请成功后,每次这个设备驱动进程被调度到时,内核会把CPU置在RING2上,以允许设备驱动进程进行硬件操作。

这就是为什么“用户态”的进程可以进行硬件操作。当然,如果随便什么进程都可以取得IO权限,会对系统安全造成威胁。所以规定只有root权限的用户程序才可以取得IO特权。

楼上的,在不重构中断描述符表的情况下,直接使用INT指令调用BIOS能否算是系统调用??这是我一直迷惑的地方。另外,如In/Out在DOS中是否会引起操作系统的调用呢?

Intel从80286开始就介绍”保护模式“了。386时达到32位保护模式。在保护模式下,是不能”直接使用INT指令调用BIOS“的。(至少我没听说过可以在保护模式下运行的BIOS)

In/Out是80x86的IO指令,跟操作系统,系统调用没有什么直接联系。

并不是在保护模式下不能调用BIOS,而是大多数操作系统会重构中断描述符表。
在我的记忆里,在保护模式的DOS,DPMI上是可以调用BIOS中断的。

离题了,其实我的意思就是告诉楼主,访问硬件并不是一定要经过操作系统。
使用In/OUT这样的指令一样可以访问硬件,不用操作系统调用一样能编驱动程序。但是在大多数保护很好的操作系统中,这样做是一件很困难的事。

也许。。。。DOS根本不算是操作系统,毕竟没有任务管理机制。

to xtang:
是不是可以这样理解:用户程序通过消息机制,把对硬件的数据请求发给设备驱动程序,设备驱动程序从硬件取得数据后,又通过消息机制把结果发回来.

而这个设备驱动程序,因为有ROOT权限,因此可以通过系统调用threadCTL,把自已置于ring2之上,从而被允许访问硬件.

如果是的话,那么,用户程序的系统调用接口同普通的UNIX一样吗?还是open/write/close等等? 或是使用其它不同的函数调用?

如果使用不同与UNIX的函数调用格式,源程序是不是已不能做到与UNIX源码级兼容?如果是这样的话,还符合POSIX吗?

是。

“调用接口”或者更准确的说是"数据请求及应答格式“。

对一个驱动的调用,是不是open/read/write/close,取决于驱动。UNIX的理念是把设备当成文件来操作。所以有些驱动,比如串口,就是一个 /dev/ser1,然后用户程序可以 open/read/write/close它。另一些驱动,比如网卡,用户程序通常不是直接去使用这设备的。而是由TCPIP协议栈来与其交互的。这时候,网卡驱动提供的,是供TCPIP协议栈与其交互的API。

POSIX并没有如何调用驱动的规定,POSIX只规定了一些API。比如POSIX规定了open(),至于你Open的是个驱动,还是个普通文件,都没有区别。

IN/OUT是I/O敏感指令,只能在CPL<=IOPL时才能执行,否则就会产生异常.

显然,QNX不会把IOPL置为3(它究竟是几呢?从XTANG所述,应当是2),而用户程序的CPL显然只能是3,因此,如果用户程序在用户态执行IN/OUT明显不可能.

我想,多任务操作系统设立驱动程序机制的目的除了为程序员建立一个通用的调用格式外,还是为了保护.而作为驱动程序来说,放在内核显然是不明智的,因为外设是经常变化的,大内核操作系统每增加一个外设都要链接一次内核,况且在设备驱动由使用者编制的情况下,更增加了对内核产生破坏的可能. QNX把设备驱动放在核外的确令人欣赏.

可问题是,设备驱动程序即要作为用户程序来运行,又要访问硬件,其权限置为0,1,3均不合适.置为0可以访问核心,置为1可以访问系统,置为3又无效.于是只能是2了.是这样的吗???


而用户程序如果没有ROOT权限而又想执行诸如IN/OUT之类的特权指令,显然只好通过系统调用降低CPL值(还有其它方法吗?)而一但执行了系统调用,那么控制权就交给了操作系统代码.X86以此方式实现了对核心数据的保护.

---------------以上论述是否正确呢?UNIX V R4 只用了0,3两个权限,QNX是否0123几个权限全用了呢?

呵呵,当然也是有办法的。我记得进程的TSS里是有IO允许位图的,打开之。
然后将EFLAG里的IOPL值改掉即可。不过在Windows下是没法成功的,它的保护比较完善,在QNX下没有试过。

如何才能打开呢?

用内联汇编吧,呵呵

Tss存在于全局地址空间,也即核心数据段,位于线性地址0~1000H以内,用户代码无论什么汇编都不能访问得到.

真的这样还要黑客技术干什么,都不用进内核态了

TSS在GDT里面,以前在DOS下很轻松可以访问GDT,从而访问TSS.
QNX不知有没有保护,只要能访问GDT,就有办法。
还有,你说的TSS无法修改是说的当前任务的TSS,其他任务的TSS不一定不能改。。。。。用当前任务修改其他任务的TSS,然后。。。

保护机制是80386的内存保护机制提供的,与是否QNX无关.用户进程的用户态不能访问GDT.

当前任务的TSS在核心地址空间,其它任务的TSS描述符在进程的U区,同样在核心地址空间.如果不巧被交换了出去,也须被交换进内存后才可能找到,因此,如果当前进程的TSS不能访问,其它进程的TSS同样不能访问.

看你的QNX Startup Code怎么做的。呵呵,说用户不能访问GDT是不确切的。
GDT的第二项里的是指向自己的,所以当然可以在Startup Code里设置权限。
只要Startup放开权限,当然可以访问任意GDT。

不要把操作系统总和80386保护机制扯在一起,不是任何操作系统都完全用到保护机制。QNX 6.4.0下的X86 BSP提供了Startup Code的源码,改一改嘛。

另,U区指的是什么?

“保护机制”,讨论的是在操作系统如何利用硬件提供的功能,对普通用户程序进行“保护”的问题。

如果需要修改操作系统,面使普通用户无法保护,那是另一个范畴的安全问题了。

本贴的标题突出“用户程序”和“设备”
如果有权限修改操作系统,何必绕那么大弯子。

而且我想我们侧重于讨论正常发布的QNX操作系统,严格保护下的用户程序及系统核心对设备的访问问题。旨在探讨QNX与众不同的设备驱动实现机制。

Startup code也算操作系统么?那时QNX 的Protno还不知道在什么地址呢。