Let’s begin with the arithmetic unit (ALU) and how we access it from a central viewpoint, commonly referred to as the CPU. Before the ALU can perform calculations, it must know where to fetch data and initiate the task (memory) and thread (ALU opcodes). This entails pre-setting registers along with program counter. This preparation is what we term the context-switch (aka resource mapping, scheduling).
In the realm of operating systems (OS), a fundamental role of the kernel involves the mentioned CPU context switching. This entails
- saving the CPU context of the current task,
- loading the context of the new task into these registers and program counters, and
- ultimately transitioning to the new location specified by the program counter.
But how does the kernel achieve this? The kernel comprises a set of handlers that respond to both hardware and software interrupts, coupled with a library designed for hardware abstraction and management. The interrupt triggers the handler, that does the necessary register and program counter operations.
Besides the context-switch, the kernel also abstracts and manage the hardware access (multiplexing). All the management tasks are also called objects, see e.g., here. The access uncovers memory and the I/O devices. The access is managed while specific e.g., target specific c libraries such as “libc” and “posix libraries”, that are calling/ mapping the kernel functions.
As management structure – how we keep the data between different tasks – various concepts are applied
- Unix: everything is a file
- Mach (L3 microkernel, 1st generation microkernel): everything is inter-process-communication (IPC) = memory buffer as messages
- L4 microkernel (the 2nd generation of microkernel): can we put it outside the kernel, as explained below
Memory usage is regulated by the addresses of the available memory, logically assigned to a task within the kernel management structure (except for most extended L4 approaches). These addresses are overseen through what we call address spaces (aka task), often organized in a page-like structure. A memory page essentially constitutes a set of addresses. Mayor difference between Mach and L4 is how the messages are passed between threads/ tasks. Mach does a copy between pages. In comparison L4 just copies references to shared memory pages.
Here is where we usually distinguish between user and kernel space. The kernel has memory pages and each and every other tasks, the so called “user” one, has assigned memory pages. With L4 the kernel has a fixed not growing amount of assigned memory (aka static), because driver and other non mandatory tasks are just managed as every “user-space” task/ thread. For example the memory management is a so called “pager thread” that is just one out of many
A good example how a kernel is abstracted can be found e.g., here. It is the Linux kernel that has been adapted (“ported”) to the L4Re kernel APIs.