简体   繁体   English

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

[英]How to emulate memory-mapped I/O

I have some hardware that i want to emulate; 我有一些我想模仿的硬件; i wonder if i can do it at a low level like this. 我想知道我是否可以在这样的低水平上做到这一点。 The hardware has many registers, which i arrange in a struct: 硬件有很多寄存器,我将它们排列在一个结构中:

#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;

So, i want to support the following syntax for hardware access on Windows and linux: 因此,我想为Windows和linux上的硬件访问支持以下语法:

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

When the last line of code is executed, i want the hardware emulator to "wake up" and do some stuff. 当执行最后一行代码时,我希望硬件仿真器“唤醒”并做一些事情。 Can i implement this on Windows and/or linux? 我可以在Windows和/或Linux上实现此功能吗? I thought about somehow catching the "segmentation fault" signal, but not sure whether this can be done on Windows, or at all. 我考虑过以某种方式捕获“分段故障”信号,但不确定是否可以在Windows上完成,或者根本不行。

I looked at the manual page of mmap ; 我看了mmap的手册页; it seems like it can help, but i couldn't understand how i can use it. 看来它可以提供帮助,但是我不明白如何使用它。

Of course, i could abstract the access to hardware by defining functions like WriteToMyDevice , and everything would be easy (maybe), but i want to understand if i can arrange access to my hardware in this exact way. 当然,我可以通过定义WriteToMyDevice函数来抽象化对硬件的访问,并且一切都会变得容易(也许),但是我想了解是否可以以这种确切的方式安排对硬件的访问。

In principle, you could code (unportably) a handler for SIGSEGV which would trap and handle access to unwanted pages, and which could check that a specified address is accessed. 原则上,您可以为SIGSEGV编码(不重要地)一个处理程序,该处理程序将捕获并处理对不需要的页面的访问,并可以检查是否访问了指定的地址。

To do that under Linux, you'll need to use the sigaction system call with SA_SIGINFO and use the ucontext_t* third argument of your signal handler. 为此,您需要在Linux中使用sigaction系统调用和SA_SIGINFO并使用信号处理程序的ucontext_t*第三个参数。

This is extremely unportable: you'll have to code differently for different Unixes (perhaps even the version number of your Linux kernel could matter) and when changing processors. 这是极其不可移植的:在不同的Unix(甚至Linux内核的版本号可能很重要)以及更改处理器时,您都必须编写不同的代码。

And I've heard that Linux kernels are not very quick on such handling. 而且我听说Linux内核在这种处理方面不是很快。

Other better kernels (Hurd, Plan9) offer user-level pagination, which should help. 其他更好的内核(Hurd,Plan9)提供用户级别的分页,这应该有所帮助。

I initially misunderstand your question. 我最初误解了您的问题。 You have a piece of memory mapped hardware and you want your emulation to be binary compatible. 您有一块内存映射的硬件,并且您希望仿真是二进制兼容的。 On Windows you could allocate the memory for the structure using VirtualAlloc and make it a guard page and catch any access to it using SEH. 在Windows上,您可以使用VirtualAlloc为该结构分配内存,并使其成为保护页,并使用SEH捕获对其的任何访问。

In actuality your emulator is (rather crudely) possible on linux with pure user space code. 实际上,在纯用户空间代码的Linux上,您的仿真器是(而不是粗略的)可能的。

To build the emulator, simply have a second thread or process (using shared memory, or perhaps an mmap'd file and inotify) watching the memory which is emulating the memory mapped device 要构建仿真器,只需让第二个线程或进程(使用共享内存,或者可能是mmap'd文件并进行inotify)来监视正在模拟内存映射设备的内存。

For the real hardware driver, you will need a tiny bit of kernel code, but that could simply be something that maps the actual hardware addresses into user space with appropriate permissions. 对于真正的硬件驱动程序,您只需要一点点内核代码,但这可能只是将实际的硬件地址映射到具有适当权限的用户空间中的东西。 In effect this regresses a modern multiuser operating environment down to acting like an old dos box or a simple micro-controller - not great practice, but workable at least where security is not a concern. 实际上,这会使现代的多用户操作环境退化为像旧的dos box或简单的微控制器一样工作-不是很好的做法,但是至少在不考虑安全性的情况下才可行。

Another thing you could consider would be running the code in a virtual machine. 您可能考虑的另一件事是在虚拟机中运行代码。

If the code you will be exercising is your own, it's probably better to write it in a portable manner to begin with, abstracting out the hardware access into functions that you can re-write for each platform (ie, OS, hardware version or physical/emulated). 如果您要执行的代码是您自己的代码,则最好以可移植的方式开始编写,将硬件访问权限抽象为可以为每个平台重写的功能(例如,操作系统,硬件版本或物理/模拟)。 These techniques are more useful if it's someone else's existing code you need to create an environment for. 如果您需要其他人的现有代码来创建环境,那么这些技术将更加有用。 Another thing you can consider (if the original isn't too tightly integrated) is using dynamic-library level interception of specific functions, for example with LD_PRELOAD on linux or a wrapper dll on windows. 您可以考虑考虑的另一件事(如果原始文档没有太紧密地集成在一起)是使用特定功能的动态库级拦截,例如在Linux上使用LD_PRELOAD或在Windows上使用包装dll。 Or for that matter, patching the binary. 或为此,修补二进制文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM