Background
I'm writing a framework to enable co-simulation of RTL running in a simulator and un-modified host software. The host software is written to control actual hardware and typically works in one of two ways:
- Read/Write calls through a driver
- Memory mapped access using mmap
The former case is pretty straightforward - write a library that implements the same read / write calls as the driver and link against that when running a simulation. This all works wonderfully and I can run un-modified production software as stimulus for my RTL simulations.
The second case is turning out to be far more difficult than the first...
Trapping mmap
Initially I thought I could use LD_PRELOAD
to intercept the mmap call. In my implementation of mmap
I'd allocate some page-aligned memory and then mprotect
it and set a signal handler to trap SIGSEGV
.
There are numerous problems with this approach:
Read vs Write
I can determine the address of the access from siginfo_t->si_addr
but not whether the access was read or write.
Catching repeat accesses
In the signal handler I need to un-protect the memory region, otherwise the I'll get repeat SIGSEGV
s as soon as my handler exits and the host code can never continue. However if I unprotect the region then my signal handler won't trap subsequent accesses.
Signal handler nastiness
To block in a signal handler while the simulator drives the RTL and returns a result violates all sorts of programming rules - particularly given the simulator could trigger all sorts of other events and execute arbitrary code before returning a result from this access.
Other approaches
I was wondering if it's possible to create a file-like object that behaves like a disk rather than using mprotect
on a buffer. I haven't found any information suggesting this is feasible.
Questions
Is it possible to trap all accesses to an mmap region and how?
- Accesses need to block for an indeterminate period of time (while simulator runs)
- Read accesses need to retrieve a new value placed by my trap
Assuming LD_PRELOAD
and mprotect
is the best route:
- Can I determine whether the access was a read or a write call?
- How do I trap subsequent accesses since I have to un-
mprotect
the region?
SIGSEGV
which will be inefficient for writes (and may make the modelled behaviour different to real hardware) – Atlantes