Let's first get familiar with the processor related terms:
Processor Related Terms
Clock Speed
Clock speed refers to the frequency at which the processor executes instructions, measured in Hertz (HZ).
It determines the number of instructions a CPU can process per second.
Higher clock speeds generally result in faster processing and better overall performance.
Cores
Cores are individual processing units within a CPU.
Modern CPUs often contain multiple cores, allowing them to handle multiple tasks simultaneously.
More cores means better multitasking capabilities and improved performance specially for tasks that can be parallelized.
Cache Memory
Cache memory is a small, high-speed memory located within the CPU.
It stores frequently accessed data and instructions to reduce access time and improve performance.
Cache memory comes in multiple levels (L1, L2, L3), with each level providing progressively larger but slower storage.
Instruction Set Architecture (ISA)
ISA defines the set of instructions and operations that a CPU can execute.
It includes instructions like arithmetic, logical, data movement, and control operations.
Different CPUs may use different ISAs, such as x86, ARM, MIPS, and RISC-V.
Fetch-Decode-Execute Cycle
The instructions that CPUs execute are just binary data: a byte or two to represent what instruction is being run (the opcode), followed by whatever data is needed to run the instruction. What we call machine code is nothing but a series of these binary instructions in a row. Assembly is a helpful syntax for reading and writing machine code that's easier for humans to read and write than raw bits; it is always compiled to the binary that your CPU knows how to read.
RAM is your computer's main memory bank, a large multi-purpose space which stores all the data used by programs running on your computer. That includes the program code itself as well as the code at the core of the operating system. The CPU always reads machine code directly from RAM, and code can't be run if it isn't loaded into RAM.
The CPU has a special register called the instruction pointer, which tells it where to find the next instruction in memory.
During each cycle, the CPU fetches the next instruction pointed to by the instruction pointer, decodes it to understand what to do, and then executes it. This process repeats over and over again. This is called fetch-decode-execute cycle.
After executing an instruction, the pointer moves forward to immediately after the instruction in RAM so that it now points to the next instruction. That's why code runs! The instruction pointer just keeps going forward, executing machine code in the order in which in has been stored in memory. Some instruction can tell the instruction pointer to jump somewhere else instead, or jump different places depending on a certain condition; this makes reusable code and conditional logic possible.
Some registers are directly accessible from machine code, like ebx
in the earlier example. Other registers are only used internally by the CPU, but can often be updated or read using specialized instructions. One example is the instruction pointer, which can't be read directly byt can be updated with, for example, a jump instruction.
Think of the CPU (Central Processing Unit) as the brain of your computer. It follows a simple cycle called fetch-decode-execute:
- Fetch: The CPU fetches instructions from memory (RAM), like reading a recipe from a cookbook.
- Decode: It figures out what each instruction means, like understanding the steps of a recipe.
- Execute: Then it carries out those instructions, like following the steps of the recipe to cook a meal.
What happens when you run the program
When you run a program on your computer, several key processes occur behind the scenes to ensure that the program executes smoothly.
1. Loading:
When you initiate a program by clicking on its icon or typing its name into the command line, the operating system (OS) locates the program's executable file on your storage device (such as a hard drive or SSD).
2. Memory Allocation:
The OS allocates memory space for the program to run. This includes reserving space for the program's code, data, and stack.
3. Process Creation:
The OS creates a new process for the program. A process is an instance of a running program that has its own memory space and resources. The OS assigns a unique process ID (PID) to the new process for identification purposes.
4. Program Execution:
The OS loads the program's code into memory and transfers control to the program's entry point, typically the main() function in languages like C or C++. The CPU fetches instructions from memory and executes them sequentially.
5. Fetch-Decode-Execute Cycle:
As mentioned earlier, the CPU follows the fetch-decode-execute cycle to execute each instruction in the program. It fetches instructions from memory, decodes them to determine their meaning, and executes them accordingly.
6. Resource Allocation:
During program execution, the OS manages resources such as CPU time, memory, and input/output (I/O) devices. It allocates CPU time to the program, ensures that it has access to the necessary memory, and handles requests for I/O operations.
7. Interaction:
The program may interact with the user through input/output operations. For example, it may display information on the screen, accept user input from the keyboard or mouse, or communicate with other devices.
8. Termination:
When the program completes its execution or encounters an error, it terminates. The OS releases the resources allocated to the program, closes any open files or connections, and deallocates memory.
9. Cleanup:
The OS may perform additional cleanup tasks, such as removing temporary files created by the program or updating system logs to record the program's execution.
10. Return to OS:
Once the program has terminated, control returns to the OS, which may resume its normal operations or wait for the next user command.
Privilege Levels (Modes/ ring)
The mode (sometimes called privilege level or ring) a processor is in controls what it's allowed to do. Modern architectures have at least two options: kernel/supervisor mode and user mode. While an architecture might support more than two modes, only kernel mode and user mode are commonly used these days.
1 Kernel Mode (Supervisor Mode, Ring 0):
Kernel mode is the highest privilege level, often referred to as ring 0. In this mode, the operating system kernel has full access to the hardware resources of the system and can execute privileged instructions. Kernel mode is used for critical system operations, such as managing memory, handling interrupts, and controlling hardware devices. Only the operating system kernel and device drivers run in kernel mode.
- It is the most privileged state that a processor can operate in.
- It grants unrestricted access to system resources and allows execution of privileged instructions.
- Generally, the kernel and drivers run in kernel mode while applications run in user mode.
Processors start in kernel mode. Before executing a program, the kernel executing a program, the kernel initiates the switch to user mode.
2 User Mode (Ring 3):
User mode is the lowest privilege level, often referred to as ring 3. Most applications and user-level processes run in user mode, where they have restricted access to system resources and cannot execute privileged instructions directly. User mode provides a protected environment for applications, preventing them from interfering with critical system functions and other processes.
- User mode is the least privileged state in which software can operate.
- It restricts direct access to system resources and rely on the operating system to manage hardware interactions on their behalf.
- Restricts access to critical system resources and sensitive hardware components.
- User mode provides a secure and isolated environment for running applications, preventing them from disrupting system operations or accessing sensitive data belonging to other processes.
- When a user-level process encounters an error or attempts to perform a privileged operation, the OS intervenes and handles the exception in kernel mode. This ensures that the system remains stable and protected from unauthorized activities.
Aspect | Kernel Mode | User Mode |
---|---|---|
Privilege Level | Highest privilege level, often referred to as ring 0. | Lowest privilege level, often referred to as ring 3. |
Access | Full access to system resources and execution of privileged instructions. | Restricted access to system resources and prohibits execution of privileged instructions. |
Operating System Operations | Kernel mode allows the operating system kernel to perform critical system operations, such as memory management, device I/O, process scheduling, and handling interrupts. | User mode relies on the operating system to manage hardware interactions on behalf of user-level applications. |
Direct Access to Hardware | Allows direct access to hardware components, enabling communication with peripherals, memory allocation, and process control. | Prohibits direct manipulation of hardware registers and critical system resources by user-level processes. |
Environment | Operates in a protected environment, isolated from user-level processes. | Provides a secure and isolated environment for running applications, preventing disruptions to system operations. |
Exception Handling | Handles exceptions and errors encountered by user-level processes to ensure system stability. | Intervenes and handles exceptions in kernel mode when user-level processes attempt privileged operations or encounter errors. |
Responsibility | Responsible for managing system operations, enforcing security policies, and maintaining system stability. | Focuses on executing user applications, interacting with users, and ensuring application isolation. |
Current Privilege Level (CPL) and Code Segment (CS) Register
- In the x86-64 architecture, the CPL is a two-bit field that represents the current privilege level of the CPU. CPL is contained in the two least significant bits of the cs register.
- The CPL determines the privilege level of the currently executing code, with values ranging from 0 to 3. These two bits can store four possible rings.
- The CS register, or Code Segment register, is a segment register in the x86 architecture that holds information about the current code segment.
- Specifically, the two least significant bits of the CS register contain the CPL.
Privilege Rings
- The x86-64 architecture supports four privilege levels, known as rings: 0, 1, 2, and 3.
- Ring 0 is the most privileged level, also known as kernel mode, where the operating system kernel and device drivers operate.
- Ring 3 is the least privileged level, also known as user mode, where user-level applications and processes run.
- Rings 1 and 2 were originally intended for running device drivers or other system-level software but are not commonly used in modern operating systems.
Interpreting CPL in CS Register
- When the CPU is running code, the CPL bits in the CS register indicate the current privilege level of the CPU.
- If the CPL bits are set to '11' (binary), it indicates that the CPU is running in ring 3, which is user mode.
- In contrast, if the CPL bits are set to '00' (binary), it indicates that the CPU is running in ring 0, which is kernel mode.
- Intermediate privilege levels (rings 1 and 2) are rarely used in modern operating systems and are typically reserved for specialized purposes or legacy systems.
Example
- Suppose the CPL bits in the CS register are set to '11'. In this case, the CPU is running in ring 3, which is user mode.
- In user mode, the CPU executes user-level applications and processes, which have limited access to system resources and cannot execute privileged instructions directly.
- The operating system kernel, running in ring 0 (kernel mode), manages system operations, handles hardware interactions, and ensures system stability and security.
What is a Syscall (System Call)?
Programs run in user mode because they can’t be trusted with full access to the computer. User mode does its job, preventing access to most of the computer — but programs need to be able to access I/O, allocate memory, and interact with the operating system somehow! To do so, software running in user mode has to ask the operating system kernel for help. The OS can then implement its own security protections to prevent programs from doing anything malicious.
If you’ve ever written code that interacts with the OS, you’ll probably recognize functions like open, read, fork, and exit. Below a couple of layers of abstraction, these functions all use system calls to ask the OS for help. A system call is a special procedure that lets a program start a transition from user space to kernel space, jumping from the program’s code into OS code.
User space to kernel space control transfers are accomplished using a processor feature called software interrupts:
- During the boot process, the operating system stores a table called an interrupt vector table (
IVT
; x86-64 calls this the interrupt descriptor table) in RAM and registers it with the CPU. TheIVT
maps interrupt numbers to handler code pointers. - Then, userland programs can use an instruction like
INT
which tells the processor to look up the given interrupt number in theIVT
, switch to kernel mode, and then jump the instruction pointer to the memory address stored in theIVT
.
When this kernel code finishes, it uses an instruction like IRET
to tell the CPU to switch back to user mode and return the instruction pointer to where it was when the interrupt was triggered.
(If you were curious, the interrupt ID used for system calls on Linux is 0x80
.
Thus we can say that, Syscalls serve as a bridge between user mode and kernel mode, enabling user-level programs to invoke operating system functions or services. When a program makes a syscall, it triggers a controlled transition from user space to kernel space, where the operating system can perform the requested operation on behalf on the program.