导航:首页 > 科技大全 > mips系统调用

mips系统调用

发布时间:2023-03-05 03:34:49

linux设备驱动程序如何与硬件通信

LINUX设备驱动程序是怎么样和硬件通信的?下面将由我带大家来解答这个疑问吧,希望对大家有所收获!

LINUX设备驱动程序与硬件设备之间的通信

设备驱动程序是软件概念和硬件电路之间的一个抽象层,因此两方面都要讨论。到目前为止,我们已经讨论详细讨论了软件概念上的一些细节,现在讨论另一方面,介绍驱动程序在Linux上如何在保持可移植性的前提下访问I/O端口和I/O内存。

我们在需要示例的场合会使用简单的数字I/O端口来讲解I/O指令,并使用普通的帧缓冲区显存来讲解内存映射I/O。

I/O端口和I/O内存

计算机对每种外设都是通过读写它的寄存器进行控制的。大部分外设都有几个寄存器,不管是在内存地址空间还是在I/O地址空间,这些寄存器的访问地址都是连续的。

I/O端口就是I/O端口,设备会把寄存器映射到I/O端口,不管处理器是否具有独立的I/O端口地址空间。即使没有在访问外设时也要模拟成读写I/O端口。

I/O内存是设备把寄存器映射到某个内存地址区段(如PCI设备)。这种I/O内存通常是首先方案,它不需要特殊的处理器指令,而且CPU核心访问内存更有效率。

I/O寄存器和常规内存

尽管硬件寄存器和内存非常相似,但程序员在访问I/O寄存器的时候必须注意避免由于CPU或编译器不恰当的优化而改变预期的I/O动作。

I/O寄存器和RAM最主要的区别就是I/O操作具有边际效应,而内存操作则没有:由于内存没有边际效应,所以可以用多种 方法 进行优化,如使用高速缓存保存数值、重新排序读/写指令等。

编译器能够将数值缓存在CPU寄存器中而不写入内存,即使储存数据,读写操作也都能在高速缓存中进行而不用访问物理RAM。无论是在编译器一级或是硬件一级,指令的重新排序都有可能发生:一个指令序列如果以不同于程序文本中的次序运行常常能执行得更快。

在对常规内存进行这些优化的时候,优化过程是透明的,而且效果良好,但是对I/O操作来说这些优化很可能造成致命的错误,这是因为受到边际效应的干扰,而这却是驱动程序访问I/O寄存器的主要目的。处理器无法预料某些 其它 进程(在另一个处理器上运行,或在在某个I/O控制器中发生的操作)是否会依赖于内存访问的顺序。编译器或CPU可能会自作聪明地重新排序所要求的操作,结果会发生奇怪的错误,并且很难调度。因此,驱动程序必须确保不使用高速缓冲,并且在访问寄存器时不发生读或写指令的重新排序。

由硬件自身引起的问题很解决:只要把底层硬件配置成(可以是自动的或是由Linux初始化代码完成)在访问I/O区域(不管是内存还是端口)时禁止硬件缓存即可。

由编译器优化和硬件重新排序引起的问题的解决办法是:对硬件(或其他处理器)必须以特定顺序的操作之间设置内存屏障(memory barrier)。Linux提供了4个宏来解决所有可能的排序问题:

#include <linux/kernel.h>

void barrier(void)

这个函数通知编译器插入一个内存屏障,但对硬件没有影响。编译后的代码会把当前CPU寄存器中的所有修改过的数值保存到内存中,需要这些数据的时候再重新读出来。对barrier的调用可避免在屏障前后的编译器优化,但硬件完成自己的重新排序。

#include <asm/system.h>

void rmb(void);

void read_barrier_depends(void);

void wmb(void);

void mb(void);

这些函数在已编译的指令流中插入硬件内存屏障;具体实现方法是平台相关的。rmb(读内存屏障)保证了屏障之前的读操作一定会在后来的读操作之前完成。wmb保证写操作不会乱序,mb指令保证了两者都不会。这些函数都是barrier的超集。

void smp_rmb(void);

void smp_read_barrier_depends(void);

void smp_wmb(void);

void smp_mb(void);

上述屏障宏版本也插入硬件屏障,但仅仅在内核针对SMP系统编译时有效;在单处理器系统上,它们均会被扩展为上面那些简单的屏障调用。

设备驱动程序中使用内存屏障的典型形式如下:

writel(dev->registers.addr, io_destination_address);

writel(dev->registers.size, io_size);

writel(dev->registers.operation, DEV_READ);

wmb();

writel(dev->registers.control, DEV_GO);

在这个例子中,最重要的是要确保控制某种特定操作的所有设备寄存器一定要在操作开始之前已被正确设置。其中的内存屏障会强制写操作以要求的顺序完成。

因为内存屏障会影响系统性能,所以应该只用于真正需要的地方。不同类型的内存屏障对性能的影响也不尽相同,所以最好尽可能使用最符合需要的特定类型。

值得注意的是,大多数处理同步的内核原语,如自旋锁和atomic_t操作,也能作为内存屏障使用。同时还需要注意,某些外设总线(比如PCI总线)存在自身的高速缓存问题,我们将在后面的章节中讨论相关问题。

在某些体系架构上,允许把赋值语句和内存屏障进行合并以提高效率。内核提供了几个执行这种合并的宏,在默认情况下,这些宏的定义如下:

#define set_mb(var, value) do {var = value; mb();} while 0

#define set_wmb(var, value) do {var = value; wmb();} while 0

#define set_rmb(var, value) do {var = value; rmb();} while 0

在适当的地方,<asm/system.h>中定义的这些宏可以利用体系架构特有的指令更快的完成任务。注意只有小部分体系架构定义了set_rmb宏。

使用I/O端口

I/O端口是驱动程序与许多设备之间的通信方式——至少在部分时间是这样。本节讲解了使用I/O端口的不同函数,另外也涉及到一些可移植性问题。

I/O端口分配

下面我们提供了一个注册的接口,它允允许驱动程序声明自己需要操作的端口:

#include <linux/ioport.h>

struct resource *request_region(unsigned long first, unsigned long n, const char *name);

它告诉内核,我们要使用起始于first的n个端口。name是设备的名称。如果分配成功返回非NULL,如果失败返回NULL。

所有分配的端口可从/proc/ioports中找到。如果我们无法分配到我们要的端口集合,则可以查看这个文件哪个驱动程序已经分配了这些端口。

如果不再使用这些端口,则用下面函数返回这些端口给系统:

void release_region(unsigned long start, unsigned long n);

下面函数允许驱动程序检查给定的I/O端口是否可用:

int check_region(unsigned long first, unsigned long n);//不可用返回负的错误代码

我们不赞成用这个函数,因为它返回成功并不能确保分配能够成功,因为检查和其后的分配并不是原子操作。我们应该始终使用request_region,因为这个函数执行了必要的锁定,以确保分配过程以安全原子的方式完成。

操作I/O端口

当驱动程序请求了需要使用的I/O端口范围后,必须读取和/或写入这些端口。为此,大多数硬件都会把8位、16位、32位区分开来。它们不能像访问系统内存那样混淆使用。

因此,C语言程序必须调用不同的函数访问大小不同的端口。那些只支持映射的I/O寄存器的计算机体系架构通过把I/O端口地址重新映射到内存地址来伪装端口I/O,并且为了易于移植,内核对驱动程序隐藏了这些细节。Linux内核头文件中(在与体系架构相关的头文件<asm/io.h>中)定义了如下一些访问I/O端口的内联函数:

unsigned inb(unsigned port);

void outb(unsigned char byte, unsigned port);

字节读写端口。

unsigned inw(unsigned port);

void outw(unsigned short word, unsigned port);

访问16位端口

unsigned inl(unsigned port);

void outl(unsigned longword, unsigned port);

访问32位端口

在用户空间访问I/O端口

上面这些函数主要是提供给设备驱动程序使用的,但它们也可以用户空间使用,至少在PC类计算机上可以使用。GNU的C库在<sys/io.h>中定义了这些函数。如果要要用户空间使用inb及相关函数,则必须满足正下面这些条件:

编译程序时必须带有-O选项来强制内联函数的展开。

必须用ioperm(获取单个端口的权限)或iopl(获取整个I/O空间)系统调用来获取对端口进行I/O操作的权限。这两个函数都是x86平台特有的。

必须以root身份运行该程序才能调用ioperm或iopl。或者进程的祖先进程之一已经以root身份获取对端口的访问。

如果宿主平台没有以上两个系统调用,则用户空间程序仍然可以使用/dev/port设备文件访问I/O端口。不过要注意,该设备文件的含义与平台密切相关,并且除PC平台以处,它几乎没有什么用处。

串操作

以上的I/O操作都是一次传输一个数据,作为补充,有些处理器实现了一次传输一个数据序列的特殊指令,序列中的数据单位可以是字节、字、双字。这些指令称为串操作指令,它们执行这些任务时比一个C语言编写的循环语句快得多。下面列出的宏实现了串I/O:

void insb(unsigned port, void *addr, unsigned long count);

void outsb(unsigned port, void *addr, unsigned long count);从内存addr开始连续读/写count数目的字节。只对单一端口port读取或写入数据

void insw(unsigned port, void *addr, unsigned long count);

void outsw(unsigned port, void *addr, unsigned long count);对一个16位端口读写16位数据

void insl(unsigned port, void *addr, unsigned long count);

void outsl(unsigned port, void *addr, unsigned long count);对一个32位端口读写32位数据

在使用串I/O操作函数时,需要铭记的是:它们直接将字节流从端口中读取或写入。因此,当端口和主机系统具有不同的字节序时,将导致不可预期的结果。使用inw读取端口将在必要时交换字节,以便确保读入的值匹配于主机的字节序。然而,串函数不会完成这种交换。

暂停式I/O

在处理器试图从总线上快速传输数据时,某些平台(特别是i386)就会出现问题。当处理器时钟比外设时钟(如ISA)快时就会出现问题,并且在设备板上特别慢时表现出来。为了防止出现丢失数据的情况,可以使用暂停式的I/O函数来取代通常的I/O函数,这些暂停式的I/O函数很像前面介绍的那些I/O函数,不同之处是它们的名字用_p结尾,如inb_p、outb_p等等。在linux支持的大多数平台上都定义了这些函数,不过它们常常扩展为非暂停式I/O同样的代码,因为如果不使用过时的外设总线就不需要额外的暂停。

平台相关性

I/O指令是与处理器密切相关的。因为它们的工作涉及到处理器移入移出数据的细节,所以隐藏平台间的差异非常困难。因此,大部分与I/O端口相关的源代码都与平台相关。

回顾前面函数列表可以看到有一处不兼容的地方,即数据类型。函数的参数根据各平台体系架构上的不同要相应地使用不同的数据类型。例如,port参数在x86平台上(处理器只支持64KB的I/O空间)上定义为unsigned short,但在其他平台上定义为unsigned long,在这些平台上,端口是与内存在同一地址空间内的一些特定区域。

感兴趣的读者可以从io.h文件获得更多信息,除了本章介绍的函数,一些与体系架构相关的函数有时也由该文件定义。

值得注意的是,x86家族之外的处理器都不为端口提供独立的地址空间。

I/O操作在各个平台上执行的细节在对应平台的编程手册中有详细的叙述;也可以从web上下载这些手册的PDF文件。

I/O端口示例

演示设备驱动程序的端口I/O的示例代码运行于通用的数字I/O端口上,这种端口在大多数计算机平台上都能找到。

数字I/O端口最常见的一种形式是一个字节宽度的I/O区域,它或者映射到内存,或者映射到端口。当把数字写入到输出区域时,输出引脚上的电平信号随着写入的各位而发生相应变化。从输入区域读取到的数据则是输入引脚各位当前的逻辑电平值。

这类I/O端口的具体实现和软件接口是因系统而异的。大多数情况下,I/O引脚由两个I/O区域控制的:一个区域中可以选择用于输入和输出的引脚,另一个区域中可以读写实际的逻辑电平。不过有时情况简单些,每个位不是输入就是输出(不过这种情况下就不能称为“通用I/O"了);在所有个人计算机上都能找到的并口就是这样的非通用的I/O端口。

并口简介

并口的最小配置由3个8位端口组成。第一个端口是一个双向的数据寄存器,它直接连接到物理连接器的2~9号引脚上。第二个端口是一个只读的状态寄存器;当并口连接打印机时,该寄存器 报告 打印机状态,如是否是线、缺纸、正忙等等。第三个端口是一个只用于输出的控制寄存器,它的作用之一是控制是否启用中断。

如下所示:并口的引脚

示例驱动程序

while(count--) {

outb(*(ptr++), port);

wmb();

}

使用I/O内存

除了x86上普遍使的I/O端口之外,和设备通信的另一种主要机制是通过使用映射到内存的寄存器或设备内存,这两种都称为I/O内存,因为寄存器和内存的差别对软件是透明的。

I/O内存仅仅是类似RAM的一个区域,在那里处理器可以通过总线访问设备。这种内存有很多用途,比如存放视频数据或以太网数据包,也可以用来实现类似I/O端口的设备寄存器(也就是说,对它们的读写也存在边际效应)。

根据计算机平台和所使用总线的不同,i/o内存可能是,也可能不是通过页表访问的。如果访问是经由页表进行的,内核必须首先安排物理地址使其对设备驱动程序可见(这通常意味着在进行任何I/O之前必须先调用ioremap)。如果访问无需页表,那么I/O内存区域就非常类似于I/O端口,可以使用适当形式的函数读取它们。

不管访问I/O内存是否需要调用ioremap,都不鼓励直接使用指向I/O内存的指针。相反使用包装函数访问I/O内存,这一方面在所有平台上都是安全的,另一方面,在可以直接对指针指向的内存区域执行操作的时候,这些函数是经过优化的。并且直接使用指针会影响程序的可移植性。

I/O内存分配和映射

在使用之前,必须首先分配I/O区域。分配内存区域的接口如下(在<linux/ioport.h>中定义):

struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);

该函数从start开始分配len字节长的内存区域。如果成功返回非NULL,否则返回NULL值。所有的I/O内存分配情况可从/proc/iomem得到。

不再使用已分配的内存区域时,使用如下接口释放:

void release_mem_region(unsigned long start, unsigned long len);

下面函数用来检查给定的I/O内存区域是否可用的老函数:

int check_mem_region(unsigned long start, unsigned long len);//这个函数和check_region一样不安全,应避免使用

分配内存之后我们还必须确保该I/O内存对内存而言是可访问的。获取I/O内存并不意味着可引用对应的指针;在许多系统上,I/O内存根本不能通过这种方式直接访问。因此,我们必须由ioremap函数建立映射,ioremap专用于为I/O内存区域分配虚拟地址。

我们根据以下定义来调用ioremap函数:

#include <asm/io.h>

void *ioremap(unsigned long phys_addr, unsigned long size);

void *ioremap_nocache(unsigned long phys_addr, unsigned long size);在大多数计算机平台上,该函数和ioremap相同:当所有I/O内存已属于非缓存地址时,就没有必要实现ioremap的独立的,非缓冲版本。

void iounmap(void *addr);

记住,由ioremap返回的地址不应该直接引用,而应该使用内核提供的accessor函数。

访问I/O内存

在某些平台上我们可以将ioremap的返回值直接当作指针使用。但是,这种使用不具有可移植性,访问I/O内存的正确方法是通过一组专用于些目的的函数(在<asm/io.h>中定义)。

从I/O内存中读取,可使用以下函数之一:

unsigned int ioread8(void *addr);

unsigned int ioread16(void *addr);

unsigned int ioread32(void *addr);

其中,addr是从ioremap获得的地址(可能包含一个整数偏移量);返回值是从给定I/O内存读取到的值。

写入I/O内存的函数如下:

void iowrite8(u8 value, void *addr);

void iowrite16(u16 value, void *addr);

void iowrite32(u32 value, void *addr);

如果必须在给定的I/O内存地址处读/写一系列值,则可使用上述函数的重复版本:

void ioread8_rep(void *addr, void *buf, unsigned long count);

void ioread16_rep(void *addr, void *buf, unsigned long count);

void ioread32_rep(void *addr, void *buf, unsigned long count);

void iowrite8_rep(void *addr, const void *buf, unsigned long count);

void iowrite16_rep(void *addr, const void *buf, unsigned long count);

void iowrite32_rep(void *addr, const void *buf, unsigned long count);

上述函数从给定的buf向给定的addr读取或写入count个值。count以被写入数据的大小为单位。

上面函数均在给定的addr处执行所有的I/O操作,如果我们要在一块I/O内存上执行操作,则可以使用下面的函数:

void memset_io(void *addr, u8 value, unsigned int count);

void memcpy_fromio(void *dest, void *source, unsigned int count);

void memcpy_toio(void *dest, void *source, unsigned int count);

上述函数和C函数库的对应函数功能一致。

像I/O内存一样使用I/O端口

某些硬件具有一种有趣的特性:某些版本使用I/O端口,而其他版本则使用I/O内存。导出给处理器的寄存器在两种情况下都是一样的,但访问方法却不同。为了让处理这类硬件的驱动程序更加易于编写,也为了最小化I/O端口和I/O内存访问这间的表面区别,2.6内核引入了ioport_map函数:

void *ioport_map(unsigned long port, unsigned int count);

该函数重新映射count个I/O端口,使其看起来像I/O内存。此后,驱动程序可在该函数返回的地址上使用ioread8及其相关函数,这样就不必理会I/O端口和I/O内存之间的区别了。

当不需要这种映射时使用下面函数一撤消:

void ioport_unmap(void *addr);

这些函数使得I/O端口看起来像内存。但需要注意的是,在重新映射之前,我们必须通过request_region来分配这些I/O端口。

为I/O内存重用short

前面介绍的short示例模块访问的是I/O端口,它也可以访问I/O内存。为此必须在加载时通知它使用I/O内存,另外还要修改base地址以使其指向I/O区域。

下例是在MIPS开发板上点亮调试用的LED:

mips.root# ./short_load use_mem=1 base = 0xb7ffffc0

mips.root# echo -n 7 > /dev/short0

下面代码是short写入内存区域时使用的循环:

while(count--) {

iowrite8(*ptr++, address);

wmb();

}

1MB地址空间之下的ISA内存

最广为人知的I/O内存区之一就是个人计算机上的ISA内存段。它的内存范围在64KB(0xA0000)到1MB(0x100000)之间,因此它正好出现在常规系统RAM的中间。这种地址看上去有点奇怪,因为这个设计决策是20世纪80年代早期作出的,在当时看来没有人会用到640KB以上的内存。

❷ 操作系统的主要性能指标有哪些

微型计算机的主要性能指标和基本系统配置
(1)微型计算机主要性能指标

字长:CPU能够同时处理的比特(bit)数目。它直接关系到计算机的计算精度、功能和速度。字长越长,计算精度越高,处理能力越强。常见的微型机字长有8位、16位、32位。
主频(时钟频率):时钟脉冲发生器所产生的时钟信号频率(MHz)。它在很大程度上决定了计算机的运行速度。
内存容量:内存储器中能够存储信息的总字节数,一般以KB、MB为单位,反映了内存储器存储数据的能力。
运算速度:计算机每秒运算的次数(MIPS
-
每秒百万条指令)。
系统的可靠性:系统在正常条件下不发生故障或失效的概率。
外设配置:外设是指计算机的输入、输出设备以及外存储器等,其中,显示器有单色、彩色之分,也有高、中、低分辨率之分,,磁盘有软盘与硬盘之分,软盘有高密、低密之分。
软件配置:软件配置包括操作系统、计算机语言、数据库管理系统、网络通信软件、汉字软件及其他各种应用软件等。
存取周期:对内存进行一次访问(存取)操作所需的时间。

❸ linux,unix.windows三大操作系统的区别在哪

1、操作

linux区分大小写,windows在dos界面命令下不区分大小写;

linux所有内容均以文件形式保存包括硬件,用户,而windows文件和硬件没什么关系,两个之间没有关联;

windows用扩展名区分文件如.exe代表执行文件,.txt代表文本文件,而linux无扩展名的概念,当然为了管理员区分方便会有部分扩展名如.gz , .bz2 ,.tar.bz2代表压缩包。

.html ,,php代表网页文件,这些纯粹是给管理员看的便于区分,但是linux本身是没有扩展名的,linux是以权限区分文件的,文件权限总共有十位。

windows下的.exe文件不能直接在linux下安装与运行,同时linux大部分是字符界面,大大增加了linux系统的安全性,减少了木马攻击的可能性,同时linux字符界面占用的系统资源要小于windows下的图形界面所占的资源。

2、系统概念

UNIX操作系统:

是一个强大的多用户、多任务操作系统,支持多种处理器架构。

整个UNIX系统可分为五层:

最底层是裸机,即硬件部分;

第二层是UNIX的核心,它直接建立在裸机的上面,实现了操作系统重要的功能,如进程管理、存储管理、设备管理、文件管理、网络管理等。

用户不能直接执行UNIX内核中的程序,而只能通过一种称为”系统调用”的指令,以规定的方法访问核心,以获得系统服务;

第三层系统调用构成了第四层应用程序层和第二层核心层之间的接口界面;

应用层主要是UNIX系统的核外支持程序,如文本编辑处理程序、编译程序、系统命令程序、通信软件包和窗口图形软件包、各种库函数及用户自编程序;

UNIX系统的最外层是Shell解释程序,它作为用户与操作系统交互的接口,分析用户键入的命令和解释并执行命令,Shell中的一些内部命令可不经过应用层,直接通过系统调用访问核心层。

Linux操作系统:

是基于UNIX操作系统发展而来的一种克隆系统,是一套免费使用和自由传播的类Unix操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。

Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。其目的是建立不受任何商品化软件的版权制约的、全世界都能自由使用的Unix兼容产品。

Windows操作系统:

Windows1.0是微软第一次对个人电脑操作平台进行用户图形界面的尝试。Windows 1.0基于MS-DOS操作系统,实际上其本身并非操作系统,至多只是基于DOS的应用软件。

之后的 Windows 2.x,3.x 和 95,98,ME仍是基于DOS的操作系统。 而Windows NT则宣告了DOS操作系统的终结,并成为流行至今的主流操作系统。

3、发展背景

Linux与其他操作系统的区别是,Linux是从一个比较成熟的操作系统发展而来的,而其他操作系统,如Windows NT等,都是自成体系,无对应的相依托的操作系统。这一区别使得Linux的用户能大大地从Unix团体贡献中获利。

因为Unix是世界上使用最普遍、发展最成熟的操作系统之一,它是七十年代中期发展起来的微机和巨型机的多任务系统,虽然有时接口比较混乱,并缺少相对集中的标准,但还是发展壮大成为了最广泛使用的操作系统之一。

无论是Unix的作者还是Unix的用户,都认为只有Unix才是一个真正的操作系统,许多计算机系统(从个人计算机到超级计算机)都存在Unix版本,Unix的用户可以从很多方面得到支持和帮助。

因此,Linux做为Unix的一个克隆,同样会得到相应的支持和帮助,直接拥有Unix在用户中建立的牢固的地位。

4、使用费用

从使用费用上看,Linux与其他操作系统的区别在于Linux是一种开放、免费的操作系统,而其他操作系统都是封闭的系统,需要有偿使用。

这一区别使得我们能够不用花钱就能得到很多Linux的版本以及为其开发的应用软件。当我们访问Internet时,会发现几乎所有可用的自由软件都能够运行在Linux系统上。

有来自很多软件商的多种Unix实现,Unix的开发、发展商以开放系统的方式推动其标准化,但却没有一个公司来控制这种设计。

因此,任何一个软件商(或开拓者)都能在某种Unix实现中实现这些标准。

OS/2和WindowsNT等操作系统是具有版权的产品,其接口和设计均由某一公司控制,而且只有这些公司才有权实现其设计,它们是在封闭的环境下发展的。

❹ 基于MIPS指令集的Linux系统与基于X86指令集的Linux系统有什么区别

MIPS和x86是两种不同的处理器架构,属于硬件范畴;
Linux 则是操作系统软件,它支持包括 MIPS , x86, arm 等各种各样的处理器架构平台。换句话说,它可以跑在依据不同处理器架构规范实作出来的各种处理器上面。
Linux 大部分的代码都是由C语言写成,因为C语言是一种高级别的语言,用它写的程序可以被编译成各种指令集中指令所构成的二进制可执行程序。C语言虽然高级别,但是有时候在没办法使用C语言的场合(比方为了访问处理器内不同寄存器就需要使用汇编而非C语言),或者有时候为了追求效率的提升,我们必须得用汇编来写程序。Linux内核为了支持不同的处理器架构,所以在其代码中包括了少量的汇编代码。所以我们可以认为,就内核源代码级别来说,基于不同指令集的Linux内核是没有太多区别的。
这是内核,对于不同应用程序来说,我们也可以认为是没什么区别,因为应用程序基于C函数库导出的不同函数,以及Linux内核所提供的系统调用,这些都是C语言接口,所以应用程序都用高级语言写成,基本上不会使用汇编语言。
如果要真说有什么区别,那就体现在编译后出来的二进制代码上。我们认为那是完全不同的。因为完成同一个功能的二进制代码,里面包含的是来自不同指令集内的不同指令。

就这么多了,您还需要多少详细的解答?:)
(该解答来自JulianTec - 您在 arm 架构下学习嵌入式Linux的上佳指导。)

❺ Windows NT采用了怎样内核结构

Windows NT 内核基本结构和特征

尽管大部分人每天在Windows系统上工作学习娱乐,但是对于其内核结构很多人仍然是不了解的。一方面是由于其内核源代码不开源,另一方面则是由于相关资料的奇缺。我大二基本上花了一学期来学习和探究NT内核。虽然不敢说自己对其有很深入的了解,但至少其基本结构还算是清楚的。但是我毕竟才学有限,肯定会有不完善的地方,还请各位不吝赐教。

目前微软所有的主流操作系统均是基于NT内核,比如:
Windows 2000/XP/Server 2003(基于NT5)
Windows Vista (基于NT6)

Windows 7(基于NT6.1, 我没装过Win7,不过据说是这样的)

尽管很多人责备Windows在一些方面存在很多问题,但是这并不是内核的错,总的来说,NT的是一个成熟稳定且先进的内核,我认为在今后相当长的一段时期内,NT内核仍将是主流,且不会有很大变化(当然,局部的升级是完全毫无疑问的)
微软早期希望把NT做成一个纯微内核结构,关于微内核和单一内核的区别,各位如有不清楚的,可以去网上搜索一下。后来为了提高图形子系统的性能,避免大量的内核态和用户态切换,微软便将其移入内核之中,使其成为内核一部分(类似的还有后来的DirectX技术)。由此可见,NT并不是一个完全的微内核,它也具有单一内核的某些特征。

NT内核具有以下几个特征(摘自Undocumented Windows NT)

Portability (可移植性)
如你所知,Windows NT 可以运行在多种平台上,即 Intel、MIPS、Power PC 和 DEC Alpha。众多厂商都为 Windows NT 的可移植性做出了贡献。 其中最为重要的因素可能是其实现所使用的语言。Windows NT 大部分是用 C 语言编写的,也有一部分用的是 C++。 平台相关的汇编语言只在必需的地方才用到。Windows NT 团队还将操作系统中硬件相关的部分与其它部分隔离开,单独放进了 HAL.DLL。 如此一来,Windows NT 中与硬件无关的部分的代码就可以用 C 之类的高级语言来编写,也因此可以很容易地移植到各种平台。

Extensibility(可扩展性)
Windows NT 具有很高的可扩展性,但因为缺少文档,其可扩展的特性却极少得到发掘。未公开的特性的名单中,子系统首当其冲。子系统在操作系统中提供了多种操作系统接口。只需添加新的子系统程序就可以为 Windows NT 扩展新的操作系统接口,但是对于公开添加新子系统过程的要求微软却一直打马虎眼。

Windows NT 的内核是高可扩展的,因为可以将内核模块作为驱动程序动态加载。对于 Windows NT,微软提供了足够的文档来编写硬件设备驱动——即硬盘驱动、网卡驱动、磁带机驱动等等。在 Windows NT 下还可以编写不控制设备的驱动程序。甚至连文件系统也是作为驱动程序加载的。
Windows NT 的可扩展性的另一个例子就是系统调用接口的实现。 开发者要修改操作系统行为,一般都需要钩挂或添加系统调用。 Windows NT 的开发团队实际了良好的系统调用接口以方便钩挂和添加系统调用。但是微软还是没有公开这些机制。

Compatibility(兼容性)
长久以来,向下兼容性都是 Intel 处理器和微软操作系统的一大特征,也是这两位巨人成功的关键。Windows NT 必须能运行 DOS、Win16 和 OS/2 的程序。兼容性是 Windows NT 开发团队使用子系统概念的另一个原因。除二进制兼容之外(执行不同格式的可执行文件),Windows NT 还为符合 POSIX 的程序提供了源代码级的兼容。增强兼容性的其他方面还表现在除自己本身的 NTFS 外,Windows NT 支持其它的文件系统,如 DOS 的 FAT 和 OS/2 的 HPFS。

Maintainability(可维护性)
Windows NT 的代码量很大,维护着些代码的工作量也相当大。NT 的开发团队通过使用面向对象的设计实现了高可维护性。再有,将操作系统的功能分成各个层也提高了可维护性。最上面的一层,也就是用户见到的操作系统层面,是子系统层。子系统提供系统调用接口来为外界提供应用程序编程接口。在系统调用接口层之下的是 NT 的 executive,executive 又建立在内核之上,而内核又依赖于硬件抽象层(HAL),硬件抽象层与硬件直接通讯。
NT 的开发团队所选的编程语言也与 Windows NT 的可维护性有关。正如我们前面提到的,整个操作系统都是用 C 和 C++ 来编写的,只有极少数不用不行的地方用了汇编语言。

Security(安全性)
Windows NT 是一个安全的操作系统,是因为它有以下几点特征:用户在使用系统之前必须先登陆。 系统中的资源都被视为对象,而每一个对象都相应由一个安全描述符。安全描述符有一个安全列表来指示那些用户可以访问该对象。

尽管有这些,要是没有一个安全的文件系统,操作系统也不能说是安全的。 DOS 时的 FAT 文件系统没有预见到任何的安全问题,其作为一个单用户的系统,也不用防范安全问题。

为了克服此缺陷,Windows NT 团队推出了一种新的文件系统,这种文件系统基于 OS/2 的文件系统 HPFS。这种新的 Windows NT 的自有文件系统叫 NTFS。它支持访问控制,用户可以为 NTFS 下创建的文件或目录指定访问权限,NTFS 只允许有访问权限的进程访问该文件或目录。

Multiprocessing(多进程)
Windows NT 支持对称多处理,Windows NT 的工作站版本可以支持两个处理器,服务器版可以支持到4个。为支持多处理,操作系统需要特殊的同步机制。在单处理器系统中,通过禁用中断,临界区中的代码执行时不会被打断。这对于维护内核数据结构的完整性来说是必需的。在多处理器环境下,就不可能在所有的处理器上都禁用中断。在多处理环境中,Windows NT 使用自旋锁来保护内核数据结构。

注:多处理可分为对称的和非对称的。在非对称多处理中,有一个处理器为主处理器,其它的处理器都为从处理器。只有主处理器运行在内核模式,其它从处理器都只运行在用户线程。只要运行在用户线程的从处理器一调用系统服务,主处理器就接管此线程并执行所需的内核服务。调度程序,一个内核程序,之运行在主处理器上。因此,主处理扮演者调度员的角色,将用户模式线程分派给从处理器。很自然,与所有处理器都可在内核或用户模式运行的对称多处理相比,主处理器负担很重,系统不均衡。

International Language Support(国际化语言支持)
如今众多的 PC 用户都使用英语之外的其它语言。与这些用户能很好交互的关键就是使操作系统能支持用户们的语言。Windows NT 通过使用 Unicode 标准的字符集实现了这一目标。Unicode 标准规定了一个16位的字符集,而ASCII 使用的是8位字符集。 Unicode 的前256个字符的编码与 ASCII 的相同。这就为非拉丁语的语言留出了充足的空间。Win32 API 能接受 Unicode 和 ASCII 两种字符集,而 Windows NT 的内核则只能使用 Unicode。尽管应用程序程序员可以不去了解 Unicode,但驱动程序的开发者必须熟悉 Unicode,因为内核接口函数只接受 Unicode 字符串而且驱动的入口点都用的是 Unicode。

Windows NT 从 MACH 操作系统那里借用了核心体系,MACH 操作系统是在卡耐基梅隆大学开发的。MACH 操作系统的基本理念就是通过将复杂的操作系统功能交给用户级进程而将内核减至最小。这种客户机-服务器的操作系统体系还有另外一个目的:允许在同一操作系统上使用多种 APIs。通过在服务器进程中实现 APIs 就可以做到。

MACH 操作系统的内核提供了非常简单的一组接口函数。服务器进程使用这组接口函数实现出某种 API 来提供一组更复杂的接口函数。Windows NT 从 MACH 那里借用了这个理念。Windows NT 中的服务器进程被称作子系统。模块化和结构化的程序设计都是优秀软件管理的原则,NT 选择使用客户机-服务器的体系结构显示了它对这种原则的服从。Windows NT 本可以将所需的 APIs 在内核实现,也可以在内核上加上不同的层来实现不同的 APIs。出于维护性和扩展性的目的,NT 团队选择了子系统的办法。

Windows NT 中有两种子系统: integral subsystems 和 environment subsystems。Integral subsystems,如安全管理子系统,完成基本的操作系统任务。 Environment subsystems 则使得一台 Windows NT 机器能使用不同种类的 APIs。Windows NT 的子系统能支持以下的 APIs:

Win32 子系统。Win32 子系统提供 Win32 API。使用 Win32 API 的应用程序可以运行在微软 提供的所有平台上—

WOW 子系统。Windows on Windows (WOW) 子系统提供了对 16-bit Windows 应用程序的兼容,使得 Win16 的应用程序可以在 Windows NT 上运行。只要没有使用 Windows NT 不支持的未公开函数,这些应用程序都可以运行。

NTVDM 子系统。NT Virtual DOS Machine (NTVDM) 提供了一个基于文本的环境,DOS 程序可以在这个环境中运行。

OS/2 子系统。OS/2 子系统能运行 OS/2 应用程序。WOW、NTVDM 和 OS/2 都只能用在 Intel 平台上,因为他们都对应用程序提供二进制兼容性。而用于一种处理器的可执行文件或二进制文件就不能用在另一种处理器上,因为处理器间的机器指令格式不同。

POSIX 子系统。POSIX 子系统提供符合 POSIX 1003.1 标准的 API。

应用程序并不知道所调用的 API 是由相应的子系统处理的。这种隐藏是通过每种子系统各自的客户端 DLL 来实现的。这种 DLL 将 API 调用转换为本地过程调用(local procere call,LPC)。本地过程调用类似于联网的 UNIX 上的远程过程调用(RPC)。使用 RPC,客户应用程序可以调用运行在网络上另一台机器上的服务器进程。 LPC 对运行在同一台计算机上的客户机与服务器进行了优化。

NT内核主要包含以下几个重要文件:
Ntoskrnl.exe(或者Ntkrnlpa.exe)
HAL.Dll
NTDll.Dll
Win32k.Sys

NT内核的核心是NT EXECUTIVE。对应的文件是Ntoskrnl.exe。如果是机器是多处理器的,则是Ntkrnlpa.exe。非常可笑的是,这个文件可以直接删除,其后果就是重启后Windows无法启动,甚至连滚动条都看不到。该文件只有2MB左右的大小,但可谓是麻雀虽小五脏俱全,它作为整个Windows中最核心的部分,向外界提供了复杂的接口。

与之相辅相成的是HAL.Dll文件,即Hardware Abstraction Layer 硬件抽象层 。它直接与机器的硬件打交道,将硬件的差异对其之上的层隐藏起来。Windows NT 是一个有高可移植性的操作系统,运行在多种平台上。HAL.DLL 包含的代码向核心的其它部分隐藏了处理器和机器相关的细节。因此平台之间只有 HAL.DLL 不同,剩下的使用 HAL 接口的核心代码都有很高的可移植性。

NTDll.Dll模块。导出了大部分的Native API函数,提供了由用户态至内核态的切换的功能。做过Windows平台开发的人都知道,Windows API主要由Kernel32.Dll, User32.Dll, GDI32.Dll构成。其实对WindowsAPI的调用最终会被转接到NTDll。即所谓Native API,命名上基本上就是在原API前面加上Nt或者Zw(比如CreateFile就变成了NtCreateFile)。而Kernel32.Dll, User32.Dll, GDI32.Dll三个文件则组成了Win32子系统,它们本身不实现API,它导出的函数被称为stub 函数(尽管名称上看起来很迷惑人)

Win32K.sys模块。实现了Windows的图形处理部分。USER32 和 GDI32 使用系统调用接口来调用 WIN32K.SYS 中的服务。由于其工作与内核态,所以具有很高的性能,这也成就了Windows系统的强大的图形处理能力。

阅读全文

与mips系统调用相关的资料

热点内容
网络云盘大小 浏览:420
去美国准备什么app 浏览:461
米8如何复制u盘文件 浏览:523
导航的o文件是什么 浏览:435
Re旧版本下载 浏览:416
电子血压表怎么读数据 浏览:610
软件开发和编程哪个前景好 浏览:30
手机保存图片在相册里找不到文件 浏览:42
xp桌面图案保存哪个文件夹 浏览:136
dnf70版本红眼 浏览:484
越来越不懂两个版本 浏览:258
javabigdecimal位数 浏览:316
学好编程需要学哪些东西 浏览:186
概预算教程 浏览:893
90版本国服第一驱魔 浏览:436
手机qq音乐启动程序 浏览:840
口袋妖怪破解版12版本 浏览:632
数据研究的岗位有哪些 浏览:124
今日头条网站怎么改名 浏览:663
信口袋app什么系列口子 浏览:374

友情链接