There are two runtime environments: isolated and non-isolated.

  • Isolated Environment. This is inside an Intel VT-x hardware virtual machine, in an address space (physical and virtual) separate from the host kernel. Code running inside the isolated environment is strongly isolated from the rest of the machine, and it cannot exit this isolated environment.
  • Non-Isolated Environment. This is the environment the rest of the host kernel runs in. It's no different than it was before LCDs came into the picture. Threads in the non-isolated environment function just as before. (In other microkernel projects, the rest of the kernel is "deprivileged", but that's not the case here. The LCD microkernel runs alongside other non-isolated code, rather than below it as in a true hypervisor. Think: KVM.)

As discussed in the overview, threads in both environments use a capability-mediated interface to interact with each other, configure their environment, and create other LCDs. This common interface is called the LIBLCD interface. The interface is defined in the headers in lcd-domains/include/liblcd and lcd-domains/arch/x86/include/asm/liblcd.

There are two implementations of the LIBLCD interface, corresponding to the two environments:

  • liblcd - the isolated implementation
  • kliblcd - the non-isolated implementation

For example, there is an implementation for lcd_enter in liblcd (in lcd-domains/liblcd/lcd-domains/enter_exit.c) and in kliblcd (in lcd-domains/kliblcd/enter_exit.c). Code that will run inside an LCD is linked at compile time with liblcd. Code that will run in the non-isolated environment is linked at kernel module load time with kliblcd.

LIBLCD Interface Initialization and Tear Down

Before invoking any other functions in the LIBLCD interface, a thread must invoke:

      int lcd_enter(void);

(This was motivated by Capsicum's CAP_ENTER.) This gives liblcd and kliblcd a chance to initialize the calling thread's environment so that it can use the LIBLCD interface. liblcd also uses this opportunity to initialize the page and slab allocators that are used inside the LCD.

For non-isolated threads, we say the non-isolated thread has entered "LCD mode" when it invokes this function.

When a thread is finished using the LIBLCD interface, it must invoke:

     void lcd_exit(int retval);

This is motivated by the "exit" libc function. For isolated code, this function does not return, and the LCD is dead. For non-isolated code, this gives kliblcd a chance to tear down LCD-related data structures that are part of the thread's context, but it doesn't kill the thread itself (the function returns).

Note: It is strongly recommended that, for non-isolated code, you wrap the beginning and ending of LCD-related code with LCD_MAIN. This modifies the non-isolated code's stack so that libasync works properly in the non-isolated environment. See the enter_exit.h header for more information.

The LIBLCD Interface

Here is a summary of the rest of the functions, broken down into categories. (Some functions are not described here, like the generalized page allocator and glue code-related functions. See the liblcd documentation and kliblcd documentation for more information.)

Capabilities (libcap)

Creating LCDs

Resource Trees and Address -> Cptr Translation

Allocating and Mapping Memory

Volunteering Memory

Synchronous IPC

Asynchronous Programming (libasync/thc)

Shared Memory IPC / Ring Buffers (libfipc)