如何模拟内存映射I/O

7

我有一些硬件想要模拟; 我想知道是否可以像这样在低级别上进行。硬件有许多寄存器,我将它们排列在一个结构体中:

#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这样的函数来抽象访问硬件,这样一切都会很容易(也许),但我想了解是否可以按照这种确切的方式安排对我的硬件的访问。

1
你的“低级”太高了...在Windows和Linux中,硬件访问都是从内核模式进行的。你需要考虑更多的实现细节 - 如何与硬件通信。例如,你可以编写真正的驱动程序和驱动程序仿真。 - Alex F
那么,在用户模式下使用预定义的内存地址是不可能的吗? - anatolyg
1
在用户模式的Windows/Linux中,您无法直接通过直接内存访问与硬件设备通信。这只有在内核模式下才能实现。因此,我建议您首先考虑实现细节。如果没有它们,您实际上不知道应该模拟什么。 - Alex F
只有一个评论,mmap() 对你的问题没有帮助。它为您的进程分配一个新的线性地址间隔,并根据需要将其与空闲页面框架链接起来。就我理解你想要做的事情而言,你希望在用户空间中的一个内存位置更改值为1时发送信号,正如Alex指出的那样,我不熟悉任何简单的方法来实现这一点。 - gnometorule
只熟悉Linux,不太了解Windows。 - gnometorule
这是在Windows中使用SEH的方法。 - Alexey Frunze
3个回答

4

原则上,你可以编写(不可移植的)SIGSEGV处理程序,用于捕获和处理对不需要访问的页面的访问,并检查是否访问了指定的地址。

要在Linux下完成这个操作,你需要使用sigaction系统调用,使用SA_SIGINFO,并使用你的信号处理程序的第三个参数ucontext_t*

这是极度不可移植的:你必须为不同的Unix操作系统编写不同的代码(甚至可能版本号也会有影响),而且当更换处理器时也需要修改代码。

我听说Linux内核在这样的处理方面不太快。

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


2

我最初误解了你的问题。你有一块内存映射硬件,并且希望你的仿真具有二进制兼容性。在Windows上,你可以使用VirtualAlloc为结构体分配内存,并将其设置为守护页,然后使用SEH捕获对它的任何访问。


1

实际上,你的模拟器可以(相当粗糙地)在Linux上使用纯用户空间代码实现。

要构建模拟器,只需有第二个线程或进程(使用共享内存,或者可能是一个mmap'd文件和inotify)监视模拟内存映射设备的内存即可。

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接