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,一切都会很容易(也许),但我想知道我是否可以以这种确切的方式安排对我的硬件的访问。

4

3 回答 3

3

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

要在 Linux 下做到这一点,您需要使用sigaction系统调用SA_SIGINFO并使用ucontext_t*信号处理程序的第三个参数。

这是非常不可移植的:你必须为不同的 Unix 编写不同的代码(甚至你的 Linux 内核的版本号可能很重要)以及在更改处理器时。

而且我听说 Linux 内核在这种处理上不是很快。

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

于 2011-10-26T17:05:20.253 回答
2

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

于 2018-01-12T05:41:51.197 回答
1

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

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

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

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

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

于 2011-11-07T14:09:56.283 回答