On Sun, Jun 13, 2004 at 08:47:37PM +0100, Matt Sealey wrote:
> 
> Having a capable accelerated 2D and 3D architecture, something
> like DirectFB but at more of a "core" and "commercial" level
> would benefit everyone. Building a single DDX driver to 
> interface with this would simplify support for X - no drivers
> in the X tree but one! "Console Framebuffers" could be built
> on top of the same low-level graphics API. In the end losing
> the 4-driver system for each card would both simplify and
> optimise the Linux graphics experience.
[..]

> We need a low-level "kernel" graphics API (much like Windows
> has, although Windows favours microkernels with high-level
> kernel functionality, rather than monolithic kernels with
> user-level functionality.. the two philosophies are at odds)
> which can perform and accelerate the expected functionality of
> everything from router to PDA, past desktop to display of
> remote-served apps.

Careful.  I think it is wise to consider the difference between what
needs to be in the kernel, versus what is convenient to have an API for.

For instance, it is possible to have a mode setting API without it being
in the kernel -- just have a library that talks to a trusted userspace
arbiter.  Same for a 3D locking and command serialization.  The only
real difference between implementing such an API over a trusted
userspace process or over kernel ioctls is that the userspace process
might crash (and leave the system running, unlike a kernel crash) or be
killed by the kernel; so you would need to plan for such a scenario and
be able to recover from it.

I don't particularly like the 1 driver to rule them all approach,
especially if it's going in the kernel.  I like the idea of nailing down
exactly what resources the multiple drivers would be in competition for,
and providing methods for permitted entities to cooperatively share
those resources and to recover from failure.  Putting everything in the
kernel would enforce a lot of policy and doesn't guarantee it will all
work right anyway.  otoh, doing everything by disparate userland
processes which each assume the hardware is their own doesn't work too
well either, because graphics hardware has too much state.  It seems
like the sanest thing to do is to provide a userland server which maps
the hardware and which graphical programs can talk to via a socket or
library to get things done.  That way all the policy ends up in
userland, and all the server does regarding the kernel is to lock the
hardware so i.e. two servers can't accidentally run at the same time.

The problem with this approach is not only that the process could be
killed, but what about scheduling?  If I dispatch a command to it, what
guarantees me that it gets done reasonably soon?  Because of that it
would probably have to run at realtime priority like jack does for audio
processes.  This still doesn't save you the overhead of a context switch
compared to a uniform userspace driver, unfortunately.  But you can use
shared memory to e.g. dispatch big DMA lists or maintain a ring buffer.

Like I said, this is also a cooperative approach.  This has its
advantages but its drawbacks as well.  For instance, I ask the arbiter
what the physical address of the framebuffer for the primary display is
and to lock other people out from it.  Its policy is to only give me the
address if nobody else has said they are going to map the framebuffer
directly.  If someone else has already and it returns false, there is
nothing to stop me from just finding the fb address and mapping it
myself, possibly scrambling someone else's display or locking up the
hardware.  So the users of this arbiter need to not be hostile, which
means there needs to be a security policy.

I think the current DRM idea of having a device node for security would
suffice for that security policy.  Open /dev/display/*, then talk to the
arbiter.  If it believes you should get the access you want, it tells
that to the kernel (via its own interface), then when you ioctl(..
MMAP_FB) the kernel can just look up whether or not the arbiter has
granted your process access for that or not, and if so, mmap the
framebuffer (or MMIO registers, or BIOS, or whatever) and give you a
pointer.  This way, direct hardware access need not be done as root
(meaning less opportunity to abuse the system), but the user of the
kernel API only gets access depending on the arbiter's policy, not
policy embedded in the kernel.

The great thing is that the arbiter's policy can be based on intimate
knowledge of the hardware and arbitrarily complicated.  For instance, it
can know the state of the 3D engine while a game is running (via
Mesa/DRI), and if another process (such as a XAA driver) requests an
operation that is unsafe if the 3D engine is in a particular state, it
can defer that until the time is right.  Or maybe it knows that there
must be a delay after a particular operation, so it defers any other
accesses until then.  This is stuff that is trivial to do in userspace
compared to the kernel.  One problem compared to a kernel approach I see
is locking.  If some process is waiting for a lock and its thread with
the arbiter is sleeping, and the resource becomes free, how do I wake it
up?  Send it a signal?

So the idea is that the kernel has nothing at all to do with graphics
besides some security related stuff if necessary.  Instead of a bunch of
processes competing for the hardware without having knowledge of what
the others are doing or what state the hardware is in, place a trusted
userspace arbiter in control of access to the hardware.  Root-owned
processes could circumvent the arbiter, and individual processes are not
obligated to share low-level resources (like FB or MMIO registers) if
they are granted access, so it is a cooperative approach.  But for
normal processes using abstract resources, the arbiter can enforce
whatever policy it feels like for a particular piece of hardware to
ensure that it cannot be caused to fail by numerous processes competing
for its resources.

A library would be wrapped around the arbiter to make access to it
transparent as well as provide mid level APIs for various common
graphics tasks.  Individual applications like Mesa would still have
control over e.g. the structure of DMA buffers, and then they call a
arbiter library function to dispatch a buffer, competely ignoring the
state of the hardware because the arbiter is taking care of
serialization and locking as well as checking the validity of the
buffers if desired.

I just mashed this down so its probably half baked.  Any thoughts?

-- 
Ryan Underwood, <[EMAIL PROTECTED]>

Attachment: signature.asc
Description: Digital signature

Reply via email to