[Mesa-dev] How to memory map the framebuffer

Daniele Tessaro tessaro.daniele at gmail.com
Wed Apr 18 05:56:13 PDT 2012


Hi everybody,
first of all I apologize if this is not the right place for this
question but I couldn't find
any answer in other places and I think this is a good question about
DRI. I also apologize
for the length of the question!

For a security application I'm developing I need direct access to the
framebuffer on the
graphic device under X on both linux and freebsd.
My goal is to memory map the portion of the graphic device memory
where pixel values
are stored just before they are read by the monitor. I need to achieve
this for a couple of
well known architectures that will not change in time (say an ati and
an nvidia specific card).

This would be the best scenario even if it is not really clear to me
if it is really possible at all.

I've spent days trying to figure out how to do that and I've seen that
DRI2 / DRM is probably
what I should use.

By now I've found 3 possible solutions (sorry if two of these
solutions are not DRI related, but maybe
some of you have an answer!). If you are not interested in anything
but DRI you should jump to point 3.

1. Use of the kernel fbdev (/dev/fb0).
  Issues:
  - 1.a What am I really accessing when reading from /dev/fb0? Is
that really the videocard memory
  or some system memory the kernel allocates and keep updated?
  - 1.b Capturing /dev/fb0 is not working under X unless fbdev is
specified as videodriver for X. And that is
    really really slow!


2. Use of X API and shm extension. This is what screenshot grabber are
usually doing. Basically ask X to get
  the pixmap of the screen root drawable and retrieve it by using a
shared memory.
  Issues:
  - This is working fine actually but it is using X. I would like
something of more low level (that is more reliable
    for the security applications). Also I'm not sure of the
pipeline involved in this process.
    I guess it is something like: X gets the backbuffer reading
directly from the graphic device and copies it to the
    shared memory. Or is it possible that X is accessing some buffer
in system memory that it keeps updated?
   (Note that I'm supposing DRI2 and hardware acceleration are
active and runinng).


3. Use of DRI2 infrastructure and DRM. This would be my favourite
solution since I would have the biggest control
  over what is happening.
  I've made some test and I failed but I feel I'm close to the
solution...but sadly it is not working!
  I would really appreciate if you validated this procedure and/or
if you suggested any possible mistake I've made.

  So first, DRM seems to be the key...and more precisely, drmMap
function seems to be exactly what I need!

  int drmMap(int fd, drmHandle handle, drmSize size, drmAddressPtr address)

  I have fd here (I got it by open("/dev/dri/card0")), I need the
handle and the size. After a long search and try
  this is what I've found that should work for getting this information:

 - I setup a DRI connection using xcb_dri2_connect() and
xcb_dri2_authenticate(). This is working.

 - I call xcb_dri2_get_buffers(...) passing as input drawable the
root window of the screen and XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT
  as the attachment.This is half working. I receive an answer, width
and height are correct but, the count attribute is 0!
  If I call   xcb_dri2_create_drawable() with the same drawable,
then the xcb_dri2_get_buffers call returns a good answer, where
  count is 5! I can't really understand this..why 5?..but then I go
on with buffer[0] and

 - I need to convert the buffer name to an handle to be used for the
drmMap call. So I execute this code I've found googling and
  that makes sense to me:

  struct drm_gem_open open;
  int ret;

  open.name = buffer[0].name;
  open.handle = 0;
  open.size = 0;

  do {
      ret = ioctl (drmFD, DRM_IOCTL_GEM_OPEN, &open);
  } while (ret == -1 && errno == EINTR);

 This code is working with no error and at the end I get open.handle
with a (seems) good value.

 - At the end of this I call drmMap(fd, open.handle, open.size,
pointer); but this is returning a negative value :-(

 So, Is this a correct way of doing things? The key could really be
that xcb_dri2_get_buffers() is returning count == 0 when
 called and I need to call xcb_dri2_create_drawable()...but I think
that this is wrong since X should have created that at the beginning
 of the times! Isn't there any other way of retrieving the name of
the root drawable of X?

 Last question: even If I'll manage to read the buffer memory mapping
it...will that memory be the final step before
 monitor, or there will be some other piece of software moving it
around to some other buffer?

 Sorry for the very long post, but I really thing this could be an
instructive thread for a lot of people!

Thanks!


More information about the mesa-dev mailing list