Driver Reuse In The L4 Environment
Thomas Friebel, Christian Helmuth
2006-03-13
 
 The Dream
  
   The microkernel approach relocates all functionality from privileged (kernel)
   to unprivileged (user) CPU mode that need not to stay in the kernel for strong
   security or performance reasons. This paradigm effectively revokes unlimited
   access to the system's resources from components that do not neccessarily need
   this access.
   
  
   One category of components considered are device drivers which account for
   the major portion of the complexity of modern operating systems. From
   security-related point of view, device drivers are considered
   less trustworthy than core OS components because they are provided by
   third-party (hardware) vendors. Against this background, device drivers reside
   in distinct protection domains above the microkernel and are constrained to use
   well-defined interfaces.
   
  
   The resulting advantages are:
   
  
   - Controlled Interference Of Drivers
 
   - 
    
     The separation into protection domains
     (i.e. address spaces) forces device drivers to use microkernel mechanisms
     for interaction with other system components like file systems. This
     effectively prevents malicious or defective drivers from accessing arbitrary
     memory locations. Leakage or integrity violations of information can be
     limited to the specific driver's domain. Also crashes of one driver can be
     restricted and do not neccessarily interfere with other system components.
     
    
   - Ease Of Debugging
 
   - 
    
     As drivers run as ordinary tasks on-top of the microkernel,
     debugging becomes as easy as debugging normal programs.
     
    
   
  
   The open question is: How do we get device drivers for all the fancy devices
   around? This demonstration details our approach to reuse existing device
   drivers.
   
 
 DSweeper
  
   DSweeper is a simple application for overwriting the data on your hard disk
   (i.e., sweeping data from your drives).
   
  
   Be careful what you do! YOU presumably WILL LOSE YOUR DATA!
   This is the purpose of DSweeper!
   
  
  A short manual
   
    In the upper part of the main window you can choose the task to be done:
    First, if the data written to the selected partition are zeros or random.
    Additionally, verification of writes can be switched on. Below the options
    resides a list of partitions on your IDE hard drives. You may select the
    partitions you wish to sweep and press "Start" to begin.
    
   
    The window title may read "DSweeper (readonly)", which is the default case in
    this demo, and no data will be written to your hard disk. If you intend to
    erase data from your disks, you have to edit the GRUB boot entry for DSweeper.
    
   
    That's easy: Simply press the "e" button on the proper boot menu entry after
    GRUB comes up, select the line referencing dsweeper, press "e" again to edit
    this line, and remove the –readonly commandline switch. Then press "Enter"
    to accept your changes and "b" to boot the modified entry.
    
  
  What's behind it?
   
    There are three main invisible parts involved:
    First there is the block device driver framework (bddf), a central task
    managing all i/o requests and sending them to the appropriate disk driver,
    the second invisible part. In this example setup we use l4ata as the
    disk driver, which is the FreeBSD ATA driver compiled with dde_fbsd described
    later. The third main part is the i/o server (l4io). It manages the computer's
    i/o resources as interrupts, i/o ports, mapped device memory, and the pci bus
    configuration and it gives the required access rights to the responsible device
    drivers.
    
 
 About Three Ways For Getting Drivers For A New OS
  
   There are three main ways to get drivers for a new OS (let's call it the
   target OS).
   
  
  Writing Drivers From Scratch
   
    First, implementation from scratch with the help of device specifications is
    a way. (Driver source code for other operating systems—legacy OS from here
    on—may help a lot.) Using just the specifications is evidently the hardest
    way. Often they are incomplete, imprecise or not available at all. Sometimes
    the hardware simply doesn't behave as expected. So the aid (i.e., reuse) of
    other driver sources is very welcome.
    
   
    If legacy drivers form the basis, we must be able to follow updates and bug
    fixes. The best way to achieve this goal is prevention of divergency or keeping
    changes small. This is achieved by the approaches described next.
    
  
  Reusing Drivers With Their Kernels
   
    Leaving legacy drivers in their environment by running a slightly modified
    legacy kernel as driver container in the target OS is an interesting
    alternative. For example, The DD/OS approach runs multiple linux kernels as
    driver hosts in an L4 environment. These Linuxes are called device driver
    operating systems (DD/OSs).
    
   
    Now you have access to a galore of drivers with little effort once the legacy
    kernel is adapted to run on the target OS. Per device class you just need one
    stub on the legacy side accessing the driver and one on the target side
    offering access to it to the target applications, both communicating with each
    other.
    
   
    The main drawback of this design originates from the legacy kernel.
    Higher independency between the drivers may be possible, if they all ran in
    their own driver container. This produces a higher memory footprint with DD/OS.
    Another drawback is the late switch to the target environment: Most of the work
    is done in the modified legacy kernel and features provided by
    the target system are not exploited. This is addressed by the next approach,
    device driver environments.
    
  
  Reusing Drivers In A Rebuilt Environment (DDE)
   
    This approach does not use the legacy kernel as the driver's environment.
    Instead we emulate the driver interface of the legacy
    kernel. This requires a clean interface definition and well-behaving drivers.
    Once having a DDE you get almost the whole bunch of legacy drivers, just by
    implementing an access stub per device class. At TU Dresden, we chose the DDE
    approach and will explain it in detail later.
    
  
  Reusing Binary Drivers
   
    All three approaches shown more or less involve access to
    legacy driver sources. But there is a multitude of drivers e.g. for the
    Microsoft Windows operating system which are only available as binary. A couple
    of projects out there struggle with emulation environments for MS Windows
    drivers with some success, but a sufficient emulation environment is always
    hard to achieve.
    
 
 DDE Development At TU Dresden
  
   TU Dresden's work with device drivers on microkernels dates back to the mid-90s
   when the L3 microkernel was still in use. Our work continued while we changed our
   research basis from L3 to L4 and supported more and more devices (e.g., SCSI
   drives and video cards). In 2001, we combined our experiences with results from
   the IBM Sawmill project and developed DDE Linux. After 4 years and a whole
   bunch of Linux 2.4 and 2.6 versions, we reviewed our code evolution and think
   it's time to take the next step.
   
  
  First Approach: DDE Linux
   
    In DDE Linux we implemented a very thin wrapping layer around Linux 2.4
    drivers. The resulting framework allowed to compile and run unmodified source
    code drivers. It consists of two parts: a library and header files for the
    basic environment interfaces used by most drivers; and one library per device
    class satisfying its special requirements.
    
   
    To date, we have implemented libraries for ATA (IDE), USB, network, input and
    simple sound (OSS) devices. We even have a DDE-based port of the Linux 2.4
    TCP/IP stack.
    
   
    For example, the (binary) sizes of the ATA framework's individual parts are
    about 40 kB for the basic environment common to all drivers, about 10 kB for
    ATA specific support, and about 100 kB for the Linux ATA driver. As you see,
    the biggest part of the DDE Linux is the common library, which is used by all
    drivers (for other device classes too). The class specific library is only very
    small.
    
   
    We achieved porting the Linux ATA driver to L4 at a small fraction of the
    effort writing one from scratch. The small special library hints that the costs
    for supporting further device classes is expected to be very small!
    
  
  Next step: DDE Kit / DDE FreeBSD
   
    Currently, we work on support for drivers from another legacy system
    (we chose FreeBSD) to review our Linux work and compare it to the effort for
    FreeBSD. During this work, the idea of making it better somehow arises. We
    found two new paradigms as described in the next sections.
    
   
    - Cut At The Weakest Spot
 
    - 
    
 
    
   
    This paradigm is: Prevent the implementation of the driver-to-kernel interface
    in the common library and use some of FreeBSD's kernel code where convenient.
    This means a little step into the direction of DD/OS but without having major
    parts of the legacy kernel attached to each driver.
    
   
    In DDE FreeBSD frequently the legacy implemention of a driver-to-kernel
    interface is reused. This results in having to implement interfaces which are
    less special. And as about the half of them are not FreeBSD-specific the idea of
    a DDE Kit arose.
    
   
    - Encapsulate Services Needed By All Drivers (DDE Kit)
 
    - 
    
 
    
   
    The DDE Kit provides the foundation of a DDE. It comprises all required
    functionality of the underlying system. This includes device access,
    resource reservation, interrupt handling, threads support, and more.
    
   
    We now can leverage the DDE Kit for easier development of frameworks for other
    systems or for the development of L4 drivers from scratch. Combined with binary
    driver reuse the DDE Kit provides a proper basis for a DDE Windows as the
    next step.
    
   
    - ...And The Benefits?
 
    - 
    
 
    
   
    Figure codesizes shows the binary code sizes of the individual DDE
    components. As mentioned above nearly half of the code written for DDE FreeBSD
    was moved to the unspecific DDE Kit. This are 21 kB of (binary) code. About
    190 kB of code reused from FreeBSD plus 25 kB newly developed for FreeBSD
    specifics (or wrapping to the DDE Kit) remain in the DDE FreeBSD common
    library. Taken together this is far more than the DDE Linux common library,
    which has a size of 43 kB.
    
   
      
    | 
     Sizes of the particular DDE components.
    |   
   
    What makes DDE FreeBSD large is the huge amount of legacy FreeBSD code. But
    this is mature code which should contain very few bugs. And as it is
    contributed it means no additional effort for us.
    When just comparing the size of code especially written for the DDEs we see
    it is only 2/3 (25 kB) compared to DDE Linux (43 kB). A 1/3 lower code
    complexity means 1/3 less time needed to develop and 1/3 less places for bugs
    to hide.
    
 
 Summary
  
   Our demonstration shows that the advantages of the microkernel approach can be
   exploited for secure and performant user-level device drivers. DDE keeps the
   engineering effort reasonably small and opens the wide range of drivers
   available as source code.
   
  
   Next steps to go are:
   
  
   - 
    
     Design and implementation of a complete driver framework with support for
     hotplugging, power management, and on-demand loading of drivers.
     
    
   - 
    
     Deeper look into binary driver reuse.
     
    
   - 
    
     Improvement of robustness and fault resilience of the framework.
     
    
   
  
   We hope you enjoyed our demo and want to invite you to contact us.
   
  
   drivers@tudos.org
   
  
   http://www.tudos.org
   
 
 Reboot the machine
  
   Click here (in the Demo-CD version of this document) to reboot your machine.
   
   |