Obtaining and accessing device abstractions in L4Re

Paul Boddie paul at boddie.org.uk
Thu Jul 6 01:05:58 CEST 2017


On Wednesday 5. July 2017 22.53.35 Matthias Lange wrote:
> 
> On 07/04/2017 11:11 PM, Paul Boddie wrote:
> > 
> > It appears that if I just declare the device appropriately in my board's
> > hw_devices.io file, I should be able to get a handle for it using code
> > like the above. And all access can apparently be done via the
> > l4vbus_gpio functions with this handle.
> 
> That's not the whole story. Devices declared in e.g. hw_devices.io
> describe physical (real) devices and their resources. The device handle
> that you obtain via the Vbus API points to a virtual device and only
> virtual devices can be assigned to a client's virtual bus. A virtual
> device can wrap a physical one but e.g. in the case of GPIOs it can be
> composed of individual (or ranges) of physical GPIO resources (= pins).

My understanding of this is that the hw_devices.io file, although I used the 
term "declare", is actually instantiating device objects using a Lua interface 
to the underlying C++ code. I hope that is correct.

Then, with regard to the virtual bus, my understanding of that is that it 
exposes functionality via the IPC mechanism. So, all invocations have to be 
marshalled via that mechanism to the Io server.

So, I define my GPIO devices (one per "port", similar to the OMAP 
functionality) in the hw_devices.io file, plus other devices (CPM, LCD) like 
this:

Io.hw_add_devices(function()

  CPM = Hw.Cpm_jz4740_chip(function()
    Property.hid = "jz4740-cpm";
    Property.exclk_freq = 12000000; -- 12 MHz
    compatible = {"mips,jz4740-cpm"};
    Resource.regs = Res.mmio(0x10000000, 0x10000fff);
  end);

  GPIO = Hw.Device(function()
    Property.hid = "JZ4740 GPIO";

    PORTA = Hw.Gpio_jz4740_chip(function()
      Property.hid = "jz4740-gpio-PORTA";
      Property.pins = 32;
      compatible = {"mips,jz4740-gpio"};
      Resource.regs = Res.mmio(0x10010000, 0x100100ff);
      Resource.irq = Res.irq(28, Io.Resource.Irq_type_level_high);
    end);

    ... -- PORTB, PORTC, PORTD

  end);

  LCD = Hw.Device(function()
    Property.hid = "jz4740-lcd";
    compatible = {"mips,jz4740-lcd"};
    Resource.regs = Res.mmio(0x13050000, 0x1305ffff);
  end);

end)

I guess that this now means that the Io server will expose each of these 
devices, but that the APIs to access them will vary: the GPIO devices will be 
accessible via the l4vbus_gpio API, but the other devices will only support a 
more limited API, maybe access to resource details and perhaps "raw" 
communication, but nothing specific to the device type.

At the moment, I'm not even sure whether it makes sense to expose the LCD 
device, but I assume that this initialisation does some work to map the region 
defined for the "regs" resource (or to offer the capability of mapping this 
region), and this is necessary for the LCD driver to be able to obtain this 
region and access its contents.

> > (I was also wondering if it was possible to actually instantiate or
> > obtain a device directly instead of obtaining a handle, for code written
> > in C++, but the above is easily good enough at the moment.)
> > 
> > But now I want to make another, non-GPIO, driver abstraction, instead of
> > directly accessing the mapped memory regions concerned (which I see that
> > some of the drivers do). It seems like I should be able to...
> 
> The first question that should be answered is, whether the driver
> (abstraction) has to be implemented inside io.

I don't really know! The "device tree" aspect of it might be convenient, and 
it arguably lets me specify all the various device parameters in one place. I 
had thought that Io perhaps made devices available as separate servers, but I 
get the impression that this isn't the case.

> Maybe a standalone driver with an appropriate API is better suited for your
> use case, because the Vbus API has its limitations and most likely you need
> to extend it anyways. Also from a security standpoint it is maybe worthwile
> to implement the driver in its own component.

I'm still not really very clear about how I would achieve this. Thinking about 
the LCD driver, which is merely following the form of the other LCD drivers in 
the L4Re distribution, I would only be using this other driver to access 
various peripheral registers.

I suppose that the simplest approach would be to define a generic device (as 
done above but using Hw.Device instead of Hw.Cpm_jz4740_chip), and then just 
use the memory mapping support to obtain the register memory region. Then I 
would just access the memory directly in the LCD driver. This is, after all, 
what I do to access the LCD registers in the LCD driver, and something has to 
access the memory directly.

But to make a better abstraction would either involve another Io-based device 
or, as you suggest, making a standalone driver in some form. Having seen the 
GPIO drivers, I was led along that route, but maybe it isn't the right one.

(I also get the impression that the LCD drivers are actually just combined 
with fb-drv and used as libraries, but maybe I misunderstood something in that 
regard.)

> Currently L4Re is lacking a proper device driver framework and we are
> still learning and exploring different directions. Maybe you would like
> to discuss your use case further so that we can guide you through that
> process?

Well, briefly, all I'm trying to do at the moment is to add LCD panel support 
for a MIPS-based board, and this also seems to need GPIO and "CPM" (clock and 
power management) peripheral support. I've adapted code that was originally 
written as a Linux driver, deploying it in a standalone payload on this board, 
and the code does work in a minimal environment. So, I aim to work from that 
limited success by trying to get it to work in the L4 runtime environment.

Initially, I saw the following general advice about writing drivers:

http://os.inf.tu-dresden.de/pipermail/l4-hackers/2015/007475.html
(define devices in hw_devices.io, query the vbus, map the memory)

http://os.inf.tu-dresden.de/pipermail/l4-hackers/2015/007489.html
(mentions the client configuration and mapping the memory)

I previously also got some general advice myself:

http://os.inf.tu-dresden.de/pipermail/l4-hackers/2016/007755.html
(mentions the vbus and mapping mechanisms)

So, I got the impression that the "device tree" approach was a sound one. I 
couldn't really find much other guidance about writing drivers, at least not 
particularly conveniently. If you know of some good resources to help settle 
my conceptual model, I would appreciate it.

Sorry if this is a bit confused, but I do feel that I have made some progress 
this time round, at least!

Paul




More information about the l4-hackers mailing list