如何模拟内存映射的I / O.

时间:2011-10-26 13:28:58

标签: c hardware-interface memory-mapping

我有一些我想模仿的硬件;我想知道我是否可以在这样的低水平做到这一点。硬件有很多寄存器,我在一个结构中安排:

#include <stdint.h>
struct MyControlStruct
{
    uint32_t data_reg_1;
    uint32_t data_reg_2;
    uint32_t dummy[2]; // to make the following registers have certain addresses
    uint32_t control_reg_1;
    uint32_t control_reg_2;
};
volatile struct MyControlStruct* MyDevice = (struct MyControlStruct*)0xDeadF00;

所以,我想在Windows和Linux上支持以下硬件访问语法:

MyDevice->data_reg_1 = 42;
MyDevice->data_reg_2 = 100;
MyDevice->control_reg_1 = 1;

当执行最后一行代码时,我希望硬件模拟器“唤醒”并执行一些操作。我可以在Windows和/或Linux上实现这个吗?我想过以某种方式捕获“分段错误”信号,但不确定这是否可以在Windows上完成,或者根本不能。

我查看了mmap的手册页;它似乎可以帮助,但我无法理解我如何使用它。

当然,我可以通过定义WriteToMyDevice之类的函数来抽象对硬件的访问,一切都很简单(也许),但我想知道我是否可以按照这种方式安排访问我的硬件。

3 个答案:

答案 0 :(得分:3)

原则上,您可以编码(不可移植)SIGSEGV的处理程序,该处理程序将陷阱和处理对不需要的页面的访问,并且可以检查是否访问了指定的地址。

要在Linux下执行此操作,您需要使用sigaction系统调用SA_SIGINFO并使用信号处理程序的ucontext_t*第三个参数。

这非常难以置信:对于不同的Unix(甚至Linux内核的版本号可能很重要)以及更换处理器时,您必须采用不同的代码。

我听说Linux内核的处理速度不是很快。

其他更好的内核(Hurd,Plan9)提供了用户级别的分页,这应该会有所帮助。

答案 1 :(得分:2)

我最初误解了你的问题。你有一块内存映射硬件,你希望你的仿真是二进制兼容的。在Windows上,您可以使用VirtualAlloc为结构分配内存,并使其成为一个保护页面,并使用SEH捕获对它的任何访问权。

答案 2 :(得分:1)

实际上,您的模拟器(在相当粗略的情况下)可以在Linux上使用纯用户空间代码。

要构建模拟器,只需要第二个线程或进程(使用共享内存,或者mmap'd文件和inotify),观察模拟内存映射设备的内存

对于真正的硬件驱动程序,您将需要一些内核代码,但这可能只是将实际硬件地址映射到具有适当权限的用户空间。实际上,这会使现代多用户操作环境回归到像旧的dos盒或简单的微控制器一样 - 不是很好的做法,但至少在安全性不是问题的情况下是可行的。

您可以考虑的另一件事是在虚拟机中运行代码。

如果您要执行的代码是您自己的代码,最好以可移植的方式编写代码,将硬件访问抽象为可以为每个平台重写的函数(即OS,硬件)版本或物理/模拟)。如果这是其他人创建环境所需的现有代码,那么这些技术会更有用。您可以考虑的另一件事(如果原始版本没有太紧密集成)是使用特定函数的动态库级别拦截,例如在Linux上使用LD_PRELOAD或在Windows上使用包装器DLL。或者就此而言,修补二进制文件。