In the world of operating systems, there exist two fundamental realms that govern the behavior of the operating system: Userspace and Kernelspace. Understanding the distinction between Userspace and Kernelspace is vital for kernel developers. Knowing their roles and responsibilities allows us to develop efficient, secure, and reliable operating systems. Once you understand this concept, you can unlock the full potential of your system.

Why it Matters

To a kernel developer, testing is incredibly important. While looking at making testcases for my code, I ran into a couple cases where triggering those pathways through Userspace made more sense than Kernelspace (and vice-versa). That made me ask: why would one make sense over the other? And how do we get them to communicate with each other? As I looked into it more, it seemed like an valuable topic to learn and write about.

Userspace: The Realm of the Users

Userspace, sometimes referred to as Userland, can simply be thought of as “the space controlled by a user.” Most of the system’s functionality is implemented in Userspace, including (but not limited to): – Application execution: i.e. web browsers, office software, and games. – Library and framework support: i.e. graphics, audio, and networking libraries. – System services: i.e. init systems, system logging, and device management.

Userspace programs are executed in user mode. In Linux, the kernel provides userspace with a sandboxed environment, called user mode, that users can freely act in. Each userspace process gets its own independent memory region, called its address space. In order to get access to any memory areas, userspace must go through the kernel. If the kernel refuses, the users are helpless. By default each process can only see the memory in its own address space – in fact they don’t even know others exist.

Kernelspace: The Realm of the Kernel

Kernelspace, on the other hand, is the domain of the Kernel itself. The kernel can be thought of as “the bridge between hardware and software.” In Linux, the kernel gets its own address space, independent from all user processes, and can see all other memory in the system. This is called supervisor mode.

In supervisor mode, the kernel performs critical tasks such as: – Process management: Creating, scheduling, and terminating processes. – Memory management: Allocating and deallocating memory for applications. – Device management: Interacting with hardware devices, such as disks, network cards, and graphics cards. – Security enforcement: Enforcing access control, authentication, and authorization.

Although the kernel has unrestricted access to system resources, it doesn’t do much unless prompted. To the average user, a kernel isn’t very useful on its own: its primary function is to ensure userspace applications can execute in a secure and stable environment.

The Divide: Userspace-Kernelspace Interaction

The boundary between Userspace and Kernelspace [1] is a critical aspect of operating system design. To ensure system stability and security, the kernel must carefully control interactions between userspace applications and the kernel itself.

On the software side, to facilitate userspace interaction with the kernel, Linux provides a set of userspace application programming interfaces (UAPIs) [2]. When a userspace application needs to access a kernel-provided service, such as reading from a file or sending a network packet, it must use one of those UAPIs: a system call [3]. Whenever a system call is triggered, Linux switches from executing code in user mode to executing code in supervisor mode.

On the hardware side, to enforce the divide, CPU architectures implement a protection ring system [4]. Ring 0, synonymous with supervisor mode, allows code to execute any and all instructions. Ring 3, synonymous with user mode, has many limitations to prevent users from causing harm to the system.

Benefits of a Divide

The separation between Userspace and Kernelspace has significant effects on system design, performance, and security: – Security: The divide prevents userspace applications from accessing sensitive kernel data or code, reducing the risk of system compromise. – Stability: Separation limits userspace applications’ access to kernel resources, making the system more resilient to application crashes or misbehavior. – Performance: The kernel can optimize system calls and kernel interfaces to minimize overhead, improving overall system performance.

What a Divide Means for Developers

The divide introduces complexity for developers. From a developer standpoint, we must be cognizant of which side of the divide we’re on and identify two common differences: – Codebase Coding Standards: Userspace and Kernelspace are different codebases, so they tend to have different coding standards. – Intended Users: Userspace is made for users, while Kernelspace is made for Userspace (not userspace’s users).

Kernelspace developers must carefully design and implement UAPIs, while userspace developers must use these UAPIs to access kernel services and get user tasks done. Any misuse of these systems could have disasterous consequences.

Furthermore, kernel developers must be cognizant of the fact that each architecture and operating system are unique. Developing features for monolithic kernels (i.e. Linux) is different compared to microkernels (i.e. Minix) and different compared to hybrid kernels (i.e Windows)[5].

A Real World Example

Consider common Linux virtualization tools: Kernel-based Virtual Machine (KVM) [6] and Quick Emulator (QEMU) [7]. KVM is a kernel module, running in ring 0. On its own KVM doesn’t accomplish much. QEMU is a userspace process running in ring 3. QEMU is what actually spins up virtual machines [8].

A user can run multiple QEMU instances, and KVM ensures they are all isolated from one another. Whenever a QEMU instance needs more resources, it uses the provided UAPI to request more resources from the KVM. The KVM then provides QEMU with the requested hardware resources.

The QEMU coding standards differ from KVM’s. Since the tools serve fundamentally different purposes, their development goals differ as well. KVM focuses on instructing the kernel to provide services QEMU desires, such as mapping guest memory to host hardware. QEMU focuses on features users want, such as guest monitors like the QEMU Monitor.

Conclusion

I hope you learned something valuable. If any of these topics piqued your interest, take a look at the further readings below.

Further Reading:

  1. Userspace and Kernelspace Wiki
  2. Linux UAPI Wiki
  3. Linux Syscalls
  4. Protection Rings Wiki
  5. Overview of Operating System Architecture
  6. KVM Wiki
  7. QEMU Wiki
  8. KVM userspace stack