Discussion:
Writing to two different dataspaces at the same time
David Werner
2016-01-20 22:42:01 UTC
Permalink
Hello Genode Community,

i am new to Genode and i have two questions.

1) Is it somehow possible to back a virtual address range with two
different dataspaces (attaching two different dataspaces at the same
virtual address is obviously not possible) ? What i want to achieve is
that writing to a virtual address results in writing to two dataspaces
at the same time, so that the dataspaces have the same content.

2) As far as i know a thread has to be added to a rm session as a client
in order to be able to use it as layout for its virtual address space.
Is it possible for a thread to operate on two different rm_sessions at
the same time?

Best Regards,
David
Martin Stein
2016-01-21 11:25:07 UTC
Permalink
Hi David,
Post by David Werner
1) Is it somehow possible to back a virtual address range with two
different dataspaces (attaching two different dataspaces at the same
virtual address is obviously not possible) ? What i want to achieve is
that writing to a virtual address results in writing to two dataspaces
at the same time, so that the dataspaces have the same content.
The only way I see to do this is by using a managed dataspace combined
with instruction emulation. But before going deeper into this: I wonder
why you want to access two dataspace at a time anyway?

A managed dataspace is not backed by physical memory but by another
virtual address range (see [2]). So, you can install your own region
manager implementation that is then called each time someone causes a
page fault on the managed dataspace. In your region manager you could
then resolve the faulting instruction to a double access. In order to do
so, your region manager would have to be able to access the text segment
of the component that uses the managed dataspace.
Post by David Werner
2) As far as i know a thread has to be added to a rm session as a client
in order to be able to use it as layout for its virtual address space.
Not exactly. A thread can access any virtual address in the address
space of its component, without the need for a registration at the
corresponding RM session, *as long as the accessed address is already
mapped*. Rm_session::add_client is only needed to enable the handling of
page faults for a thread. It requests the RM session to create a a pager
for the thread and returns a capability that references this pager (see
[3]). To ensure that page faults of the thread are actually forwarded to
this pager, you have to call Cpu_session::set_pager(thread_cap,
pager_cap) additionally.

However, as virtual addresses are normally mapped on demand, one should
assume to cause page faults when accessing virtual addresses and thus
register its thread for page-fault handling in advance.
Post by David Werner
Is it possible for a thread to operate on two different rm_sessions at
the same time?
Yes and no. You can call Rm_session::add_client for one thread on two
different RM sessions. What this does is that both RM sessions keep
ready a pager for the thread but the thread is linked to neither of them
yet. The linkage is done by Cpu_session::set_pager. As you can see for
example in [1], Cpu_session::set_pager simply overwrites the previous
configuration. So, if you call it twice with different pagers, your
thread will be linked to the pager you stated last.

But yes, you can incorporate multiple RM sessions into one address space
by the means of the already mentioned managed dataspaces. You would then
have to register your thread at the top-level RM session. However, also
in this case, each address goes down to exactly one "leaf" RM session
that is responsible for the corresponding faults.

Cheers,
Martin

[1]
https://github.com/genodelabs/genode/blob/master/repos/base-hw/src/core/platform_thread.cc#L190

[2] http://genode.org/documentation/genode-foundations-15-05.pdf Page
63, "Realizing managed dataspaces"

[3]
https://github.com/genodelabs/genode/blob/master/repos/base/src/core/rm_session_component.cc#L568
David Werner
2016-01-21 13:14:32 UTC
Permalink
Hi Martin,

thank you for your answer!
Post by Martin Stein
The only way I see to do this is by using a managed dataspace combined
with instruction emulation. But before going deeper into this: I wonder
why you want to access two dataspace at a time anyway?
My goal is to have access to the memory content of a component at a
certain point of time without stopping the component (the threads of the
component). So my idea was to maintain a second dataspace (same size,
same content) for each dataspace that is attached to the RM session of
the component as a copy. So when i want to inspect the memory content i
just stop writing to the second dataspace and inspect this dataspace
instead of the "main" dataspaces. This way the component would be able
to keep running.

Regards,
David
Martin Stein
2016-01-21 13:57:22 UTC
Permalink
Hi David,
Post by David Werner
My goal is to have access to the memory content of a component at a
certain point of time without stopping the component (the threads of the
component). So my idea was to maintain a second dataspace (same size,
same content) for each dataspace that is attached to the RM session of
the component as a copy. So when i want to inspect the memory content i
just stop writing to the second dataspace and inspect this dataspace
instead of the "main" dataspaces. This way the component would be able
to keep running.
I wonder why you don't want to pause the component? You would have to
stop your carbon-copy code anyway to get a consistent state.

In general, I think the problem with your idea is not Genode but the
hardware. Genode only manages the mapping from physical to virtual
memory. As soon as this mapping is available to the MMU, the access to a
virtual address is completely handled by hardware and there is no way
for Genode to interpose itself except by removing the mapping again. So,
as long as the hardware doesn't provide such multi-accesses, Genode
can't change this for mapped addresses.

That said, the instruction-emulation solution I mentioned uses the fact
that you can interpose every memeory access to a virtual address if you
never map it. So, on every access you get a fault that is forwarded to
the code that does the carbon-copy.

Another solution would be a second component that polls for the memory
state of the supervised component. This might be efficient if your
interest is restricted to a small range of the target address space.

Cheers,
Martin
Norman Feske
2016-01-22 11:53:38 UTC
Permalink
Hello,
Post by Martin Stein
Another solution would be a second component that polls for the memory
state of the supervised component. This might be efficient if your
interest is restricted to a small range of the target address space.
I think that Martin's suggestion of managed dataspaces points in the
right direction. But in contrast to Martin, I don't think that there is
the need for an instruction emulator. How about the following approach?

* In line with Martin's suggestions, instead of obtaining RAM
dataspaces from core, there is a new RAM service (let's call it VRAM
for now) that hands out managed dataspaces instead of real RAM
dataspaces. Managed dataspaces represent a mechanism for implementing
virtual memory in user space. You can find an example at [1]. Note
however that this mechanism requires a kernel that supports the
remote manipulation of address spaces. This is the case for all of
Genode's base platforms except Linux.

[1] repos/base/src/test/rm_fault/main.cc

* Initially, when handing out a dataspace, the VRAM server attaches a
real RAM dataspace within the managed dataspace. So the client can
access it as usual. It would not notice any difference from a
regular RAM dataspace.

* From time to time, the VRAM server, detaches the RAM dataspace from
the managed dataspace.

* The next time the client tries to access the dataspace, it would
stop executing. Under the hood, a page fault occurs, which is
reflected by the kernel (and Genode's core) to the VRAM server as a
signal (RM-fault signal). The VRAM server wakes up upon the reception
of the signal and thereby knows that the dataspace was accessed. It
can even determine the fault address via the Rm_session::state
operation. It can respond to the signal be re-attaching the RAM
dataspace to the managed dataspace. This operation will implicitly
resume the execution of the client.

In principle, this approach implements a mechanism similar to the
dirty-bits in the MMU page tables. The VRAM server becomes able to track
the accesses to the dataspace and may copy its content. From the
client's perspective, the monitoring is completely transparent. If you
want to track the usage of the managed dataspace at a fine granularity,
the VRAM server might attach the RAM dataspace as several pieces to the
managed dataspace (by using the offset, size, and local_addr arguments
to the Rm_session::attach operation).

The only open question left is how to pick a suitable interval of
detaching the RAM dataspace from the managed dataspace?

Cheers
Norman
--
Dr.-Ing. Norman Feske
Genode Labs

http://www.genode-labs.com · http://genode.org

Genode Labs GmbH · Amtsgericht Dresden · HRB 28424 · Sitz Dresden
Geschäftsführer: Dr.-Ing. Norman Feske, Christian Helmuth
David Werner
2016-01-25 11:27:22 UTC
Permalink
Hi Martin, Hi Norman,
Post by Martin Stein
I wonder why you don't want to pause the component? You would have to
stop your carbon-copy code anyway to get a consistent state.
I am currently doing my Bachelor thesis at the Chair of Operating
Systems at TU München. My goal is to develop a real-time capable
checkpoint-restore mechanism on Genode. Therefore i dont want to stop my
component.
Post by Martin Stein
The only open question left is how to pick a suitable interval of
detaching the RAM dataspace from the managed dataspace?
I thought about using the point of time of the preempt (scheduler) of
the component.

Regards,
David

Loading...