<?xml version="1.0" encoding="UTF-8"?>
<chapter id="hardware">
<?dbhtml filename="hardware.html"?>
<title>Device Drivers</title>
<para>Since HelenOS is a microkernel, a framework for supporting userspace
device drivers has been implemented. A typical userspace task acting as a
device driver might need to:</para>
<itemizedlist>
<listitem>
<para>receive notifications about interrupts sent by its device,</para>
</listitem>
<listitem>
<para>access physical memory address space,</para>
</listitem>
<listitem>
<para>access I/O space and</para>
</listitem>
<listitem>
<para>control preemption.</para>
</listitem>
</itemizedlist>
<section>
<title>Interrupt Notifications</title>
<para>Userspace tasks that are in hold of the
<constant>CAP_IRQ_REG</constant> capability can register themselves via
the <code>ipc_register_irq()</code> to be notified about occurrences of a
given interrupt. The registration call takes two arguments. The first
argument is the IRQ number and the second is the pointer to special
pseudocode that instructs the kernel interrupt handler how to process the
IRQ. Currently the pseudocode language supports reading and writing
physical memory, reading from and writing to I/O space and actions related
to running HelenOS in virtual environments.</para>
<para>When the interrupt comes after its handler has been registered by a
userspace task, the kernel interrupt handler interprets the pseudocode
program and sends an IPC notification to the respective task. The
userspace task can get certain information about the interrupt (e.g. what
key was pressed) by issuing memory or I/O space reads in the pseudocode
program. The read values are wrapped into the IPC notification sent to the
task. The write operations are also very essential because some interrupts
are level-sensitive and need to be processed in the kernel interrupt
routine. In many situations, the interrupt is considered serviced only
when the interrupt handler performs certain reads or writes of memory or
I/O space.</para>
</section>
<section>
<title>Accessing Memory and I/O Space</title>
<para>When a task has the <constant>CAP_MEM_MANAGER</constant> capability,
it can use the <constant>SYS_MAP_PHYSMEM</constant> to map regions of
physical memory to its address space. When successful, the syscall creates
an address space area for the physical memory region. The address space
area can be further shared by other tasks. Similarily, when a task has the
<constant>CAP_IOSPACE_MANAGER</constant> capability, it is entitled to
request access to the I/O space by using the
<constant>SYS_IOSPACE_ENABLE</constant>. However, this syscall is relevant
only on architectures that have separate I/O space (e.g. amd64 and
ia32).</para>
</section>
<section>
<title>Disabling Preemption</title>
<para>It might be desirable for a device driver to temporarily disable
preemption. Tasks that can do this are required to have the
<constant>CAP_PREEMPT_CONTROL</constant> capability. Preemption could be theoretically disabled
by disabling interrupts on the current processor, but disabling preemption
is more lightweight as interrupt processing remains enabled.</para>
</section>
</chapter>