超越抽象的好奇心:字节码是如何执行的?设备驱动程序如何工作?
我在 *nix 上看到的一切都是硬件的一组抽象,但我很好奇硬件是如何工作的。
我已经用汇编进行了编程,但这仍然只是一组抽象。
处理器如何理解汇编操作码(作为字节码)?
设备驱动程序如何工作(带有较低级别(抽象)的解释)?
Everything I've seen on *nix has been a set of abstractions off hardware, but I'm curious as to how the hardware works.
I've programmed in assembly, but that's still only a set of abstractions.
How does a processor understand assembly opcodes (as bytecode)?
How do device drivers work (with an explanation at a lower level (of abstraction))?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
设备驱动程序形成操作系统的设备 API 和实际硬件寄存器之间的接口。
Linux 设备 API 模型是更广泛的 Linux 概念的延续,即一切都是文件,并且应用程序可以使用 open()、read()、write()、ioctl() 和 close( ) 界面。在底层,有一个 install() 例程,但操作系统决定何时调用它。
硬币的另一面是硬件。 CPU 使用特殊 I/O 指令访问设备寄存器,或者使用普通内存访问连接到硬件的特殊内存位置。虽然硬件寄存器可以像内存一样工作,但它们可以做内存不能做的事情。通常,写入设备的一个寄存器可以更改其其他一些寄存器的值,并且可以更改或被连接硬件中的电气活动更改。
设备驱动程序弥补了这一差距。由于设备类型的可能性几乎是无限的,因此除了几点之外,很难概括功能的映射方式。 install() 例程在系统启动时启动,配置寄存器以实现正确操作,通常这包括设置中断服务和处理; open() 例程为应用程序提供了与设备的逻辑连接;通常会努力使 read() 和 write() 以某种合理的方式移动数据,尽管有时您会看到这些实现为无操作;动态设备设置通过 ioctl() 进行操作。当然,close() 的主要工作是撤消 open() 的工作,特别注意释放 open() 占用的任何系统资源。
无论如何,这就是以 Linux 为中心的观点。 Windows 模型,至少是我熟悉的模型(可能已经过时了),倾向于提供特定于设备的函数调用库。
Device drivers form an interface between an OS's device API and actual hardware registers.
The linux device API model is a continuation of the broader linux concept that everything is a file, and that an application can accomplish anything it needs to with the open(), read(), write(), ioctl(), and close() interface. Under the hood, there's an install() routine, but the OS decides when to call that.
The other side of the coin is hardware. The CPU accesses device registers either with special I/O instructions, or ordinary memory accesses to special memory locations that are connected to hardware. While hardware registers can act like memory, they can do things that memory cannot. Quite frequently, writing to one of a device's registers can change values some of its other registers, and to the point, can change or be changed by electrical activity in the connected hardware.
Device drivers bridge this gap. Since the possibilities for devices types are almost unlimited, it's hard to generalize about how functions are mapped, beyond just a few points. The install() routine is hit at system start up time, configures registers for proper operation, normally this includes setting up interrupt service and handling; the open() routine gives an application a logical connection to the device; there's usually an effort to make read() and write() move data in some sensible way, though sometimes you see these implemented as no-ops; and on-the-fly device settings are operated through ioctl(). And of course, the main job of close() is to undo the work of open(), taking special care to release any system resources grabbed by open().
Well, that's the linux-centric take, anyway. The windows model, at least the one I'm familiar with (probably dated), tends to offer libraries of device-specific function calls.
设备有一个“中断”——这就是它们发出信号希望处理器注意的方式。
设备驱动程序有一个“中断服务例程”——这是当该设备上发生中断时执行的代码。
然后,设备驱动程序以映射到设备的低级形式读取或写入数据——通常是字符或数据块。设备驱动程序的较高级别管理打包、解包、缓冲以及从较低级别数据到较高级别数据的转换,例如文本字符行。
其基础知识非常简单,但当您在基本的面向块的设备 I/O 之上添加多个设备、多个用户、跟踪两者的状态以及许多其他抽象(如文件系统)时,它会变得非常复杂。
Devices have an "interrupt" -- which is how they signal that they want the processor's attention.
Device drivers have an "interrupt service routine" -- which is the code that gets executed when an interrupt occurs on that device.
Device drivers then read or write data in a low level form that maps to the device -- typically either characters or blocks of data. The higher levels of the device driver manage packing, unpacking, buffering and translating from the lower level data to higher level data, like lines of text characters, for example.
Pretty simple in it's basics, but it gets complicated real fast when you add multiple devices, multiple users, keeping track of state for both, and lots of other abstractions, like a file system, on top of basic block oriented device I/O.
《组装的艺术》是一本很好的书,但有点过时了,它对几乎所有硬件和底层都有解释。你应该读一下。
它可以合法地在线获取并以印刷形式获取。
这本书,在线
在亚马逊
编辑:评论者 Samoz 提到了新版本,所以现在它可能是最新的!
"The Art of Assembly" is a good, yet kind of outdated book with explanations on pretty much everything hardware and low-level. You should give it a read.
It's available legally online and in print form.
The book, online
On amazon
EDIT: Commenter Samoz mentions a new edition, so now it's probably up to date!
哇......大问题!在最底层,处理器可以通过特殊指令(例如 x86 硬件上的 I/O 端口的 IN 和 OUT 和/或某种形式的内存映射 I/O 区域)与硬件进行通信。
不同的硬件对于如何通过这些通道进行通信有非常不同的协议/规则,如果不遵循这些规则,通常可能会严重失败。例如,输出设备每秒只能处理有限数量的传输,因此驱动程序需要在尝试传输任何内容之前检查硬件是否准备好发送更多数据。您通常还需要确保没有并发尝试访问同一设备,这是操作系统不允许用户模式程序随时直接访问硬件的众多充分理由之一。
为什么不看看 Linux 源代码来满足你的好奇心呢?
Linux 内核驱动程序
请注意,其中大部分是用 C 语言编写的,而不是汇编语言。没有严格要求使用汇编语言编写设备驱动程序,只要您有可用于与硬件通信的指令(这在 C 中是正确的,但在某些高级语言中可能并非如此)。
Wow.... huge question! At the very root level the processor can communicate with the hardware through special instructions e.g. IN and OUT to I/O ports on x86 hardware and/or some form of memory mapped I/O regions.
Different hardware then has very different protocols / rules as to how to communicate over these channels and in general will probably fail horribly if these rules are not followed. An example would be an output device that can only handle a limited number of transmits per second, so the driver needs to check whether the hardware is ready to send more data before trying to transmit anything. You also usually need to ensure that there are no concurrent attempts to access the same device, which is one of many good reasons why operating systems do not allow user mode programs to directly access the hardware whenever they feel like it.
Why not have a look at the Linux source code to satisfy your curiosity?
Linux kernel drivers
Note that most of this is written in C, not assembly language. There's no strict requirement to use assembly language to write device drivers providing you have the instructions available to communicate with the hardware (which is true in C, but might not be true in some higher level languages).