Topics

User Mode Drivers #driver


Jett ✈ Rink
 

Hey all,

Do all "drivers" need to be run in supervisor mode (within the kernel)? I am specifically thinking about external ICs that are connected to an embedded controller running Zephyr via i2c/SPI/etc.

Take, for example, the drivers for certain EEPROMs. The EEPROM drivers do not actually need to run within the kernel, but only need permission for the SPI kernel device that the EEPROM is attached to.

Within the principle of least privilege, should these drivers for external ICs that communicate over buses actually be kernel-level drivers, or should they be "user mode drivers" instead? Just for clarity, the drivers for hardware modules on the actual embedded controller should remain in the kernel.

Lastly, should "user mode devices" be present in the device tree or not? If we wanted to use the device tree to express how external ICs were connected, does that force us to make all drivers in the kernel or would there be flexibility to use the device tree for "user mode devices"?

Thank you for any input!

-Jett


Bolivar, Marti
 

Hi,

Jett ✈ Rink via lists.zephyrproject.org
<jettrink=google.com@...> writes:

Lastly, should "user mode devices" be present in the device tree or not? If
we wanted to use the device tree to express how external ICs were
connected, does that force us to make all drivers in the kernel or would
there be flexibility to use the device tree for "user mode devices"?
The devicetree describes the hardware. Whether or not a particular
software driver runs in user mode or not is an orthogonal question IMO.

If you are able to write a user mode driver as you describe, I don't see
why the hardware shouldn't be in the DT. You'll still want the device
labels in there to pass to device_get_binding(), for instance.

Martí


Boie, Andrew P
 

Hi Jett,

 

It should certainly be possible to do this, where you implement driver logic as just code which makes other system calls at a lower-level bus abstraction to interact with the hardware. It would be hard to get this to play along with Zephyr's current driver abstraction infrastructure though.

 

However, a current limitation of the driver subsystems in Zephyr is that they unconditionally implement system calls at the subsystem level. And there is also the question on how to manage access to any global data associated with the higher-level driver, as the contents of data structures like `struct device` are considered private kernel data.

 

So using EEPROM as an example, you could in principle implement eeprom_read(), eeprom_write() etc as just some library code which makes system calls into the underlying SPI subsystem code to talk to the hardware. What currently happens right now is that the system call boundary is at the EEPROM subsystem level, and the implementation of the EEPROM APIs will call into the SPI driver already in supervisor mode. From a performance perspective the infrastructure is smart enough to skip all the syscall overhead when it calls into SPI from the EEPROM driver code, but from a least privilege standpoint it's not ideal.

 

The challenges are, as I see it:

  • struct device and supporting data structures are currently considered private kernel data, can't really provide a 'struct device' at the EEPROM level, just SPI
  • Callers into a user mode driver, if the driver code used any read-write global data, would have to also have access to this data otherwise you'd get a fault when making an API call
  • The subsystem code would need some idea of what devices are user mode and what aren't, and how to manage access to data that is kernel-private (like API vtables)

 

However, if you wanted to do this outside of the Zephyr driver abstraction model, it shouldn't be too bad. Write everything in terms of SPI driver calls, add a memory partition for any globals it has to manage, and enforce that any callers have both permissions on the underlying SPI device and also the memory partition active in the caller's memory domain.

 

Devicetree is AFAIK just our ontology of hardware characteristics so I wouldn't see a problem with getting HW values and stuff out of DTS regardless of what mode it runs in.

 

HTH,

Andrew

 

 

From: Jett Rink <jettrink@...>
Sent: Wednesday, September 9, 2020 1:21 PM
To: devel@...
Cc: Boie, Andrew P <andrew.p.boie@...>
Subject: User Mode Drivers #driver

 

Hey all,

 

Do all "drivers" need to be run in supervisor mode (within the kernel)? I am specifically thinking about external ICs that are connected to an embedded controller running Zephyr via i2c/SPI/etc.

 

Take, for example, the drivers for certain EEPROMs. The EEPROM drivers do not actually need to run within the kernel, but only need permission for the SPI kernel device that the EEPROM is attached to.

 

Within the principle of least privilege, should these drivers for external ICs that communicate over buses actually be kernel-level drivers, or should they be "user mode drivers" instead? Just for clarity, the drivers for hardware modules on the actual embedded controller should remain in the kernel.

 

Lastly, should "user mode devices" be present in the device tree or not? If we wanted to use the device tree to express how external ICs were connected, does that force us to make all drivers in the kernel or would there be flexibility to use the device tree for "user mode devices"?

 

Thank you for any input!

 

-Jett


Jett ✈ Rink
 

Thank you both for detailed answers! We will continue to consider this idea for user mode drivers with the previously mentioned caveats, and we will see if implementing them is too onerous or not. Thanks again for the input!

-Jett

On Wed, Sep 9, 2020 at 2:51 PM Boie, Andrew P <andrew.p.boie@...> wrote:

Hi Jett,

 

It should certainly be possible to do this, where you implement driver logic as just code which makes other system calls at a lower-level bus abstraction to interact with the hardware. It would be hard to get this to play along with Zephyr's current driver abstraction infrastructure though.

 

However, a current limitation of the driver subsystems in Zephyr is that they unconditionally implement system calls at the subsystem level. And there is also the question on how to manage access to any global data associated with the higher-level driver, as the contents of data structures like `struct device` are considered private kernel data.

 

So using EEPROM as an example, you could in principle implement eeprom_read(), eeprom_write() etc as just some library code which makes system calls into the underlying SPI subsystem code to talk to the hardware. What currently happens right now is that the system call boundary is at the EEPROM subsystem level, and the implementation of the EEPROM APIs will call into the SPI driver already in supervisor mode. From a performance perspective the infrastructure is smart enough to skip all the syscall overhead when it calls into SPI from the EEPROM driver code, but from a least privilege standpoint it's not ideal.

 

The challenges are, as I see it:

  • struct device and supporting data structures are currently considered private kernel data, can't really provide a 'struct device' at the EEPROM level, just SPI
  • Callers into a user mode driver, if the driver code used any read-write global data, would have to also have access to this data otherwise you'd get a fault when making an API call
  • The subsystem code would need some idea of what devices are user mode and what aren't, and how to manage access to data that is kernel-private (like API vtables)

 

However, if you wanted to do this outside of the Zephyr driver abstraction model, it shouldn't be too bad. Write everything in terms of SPI driver calls, add a memory partition for any globals it has to manage, and enforce that any callers have both permissions on the underlying SPI device and also the memory partition active in the caller's memory domain.

 

Devicetree is AFAIK just our ontology of hardware characteristics so I wouldn't see a problem with getting HW values and stuff out of DTS regardless of what mode it runs in.

 

HTH,

Andrew

 

 

From: Jett Rink <jettrink@...>
Sent: Wednesday, September 9, 2020 1:21 PM
To: devel@...
Cc: Boie, Andrew P <andrew.p.boie@...>
Subject: User Mode Drivers #driver

 

Hey all,

 

Do all "drivers" need to be run in supervisor mode (within the kernel)? I am specifically thinking about external ICs that are connected to an embedded controller running Zephyr via i2c/SPI/etc.

 

Take, for example, the drivers for certain EEPROMs. The EEPROM drivers do not actually need to run within the kernel, but only need permission for the SPI kernel device that the EEPROM is attached to.

 

Within the principle of least privilege, should these drivers for external ICs that communicate over buses actually be kernel-level drivers, or should they be "user mode drivers" instead? Just for clarity, the drivers for hardware modules on the actual embedded controller should remain in the kernel.

 

Lastly, should "user mode devices" be present in the device tree or not? If we wanted to use the device tree to express how external ICs were connected, does that force us to make all drivers in the kernel or would there be flexibility to use the device tree for "user mode devices"?

 

Thank you for any input!

 

-Jett