# Module 3 - Operating System Booting
## Prerequisite
- Using **VMware Player**, with nested virtualization enabled.
- Install Linux Ubuntu 22.04 with at least 4GB memory and 4 vCPU.
## Learning Outcomes
- Understand the Linux operating system booting process.
- Understand the basic concepts of the Linux kernel and creating a root filesystem (initramfs).
- Be able to compile the Linux kernel and create a root filesystem using BusyBox.
- Be able to emulate an operating system using QEMU.
- Be able to create a bootable ISO disk and run emulation using the ISO.
## Table of Contents
- [i. Prerequisite](#prerequisite)
- [ii. Learning Outcomes](#learning-outcomes)
- [iii. Table of Contents](#table-of-contents)
- [1. Introduction](#introduction)
- [1.1 Definition of Booting](#definition-of-booting)
- [2. Linux Kernel](#linux-kernel)
- [2.1 Definition of Linux Kernel](#definition-of-linux-kernel)
- [2.2 Preparing the Linux Kernel](#preparing-the-linux-kernel)
- [3. Creating a Root Filesystem](#creating-a-root-filesystem)
- [3.1 Definition of Root Filesystem](#definition-of-root-filesystem)
- [3.2 Single User vs Multi User](#single-user-vs-multi-user)
- [3.3 Single User](#single-user)
- [3.4 Multi User](#multi-user)
- [4. Emulation with QEMU](#emulation-with-qemu)
- [4.1 Understanding QEMU](#understanding-qemu)
- [4.2 Steps for Emulation with QEMU](#steps-for-emulation-with-qemu)
- [4.3 Testing Inside the Shell](#testing-inside-the-shell)
- [4.4 Restarting the Boot Process](#restarting-the-boot-process)
- [5. Creating a Bootable ISO Disk](#creating-a-bootable-iso-disk)
- [6. Emulating ISO File Execution](#emulating-iso-file-execution)
## Introduction
Imagine you are about to start a car. When you turn the key or press the start button, the engine starts, the electronic systems activate, and within seconds, the car is ready to use. But have you ever wondered what actually happens before the car is ready to drive?
The same thing happens when you turn on a computer or laptop. When you press the power button, the system does not immediately become "ready to use." There is a long process happening behind the scenes, and this is called the booting process.
### Definition of Booting
**Booting** is the process that occurs from the moment a computer is powered on until the operating system is fully active and ready to use. This is a crucial initial stage in the life of an operating system because without a successful booting process, no applications can run.
#### General Booting Stages
The booting process can be divided into several main stages:
1. **Power-On Self Test (POST)**
Once the power button is pressed, the computer's firmware (such as BIOS or UEFI) will perform a POST. This is an initial check to ensure that key components like RAM, processor, and storage devices are functioning properly. If there is an issue, this process will display an error message or emit a beep sound.
2. **Searching for Boot Device & Executing Bootloader**
After POST is complete, the firmware will search for a **boot device**, which is the storage medium containing the operating system, based on a configured order (e.g., hard disk, USB, or CD). Within the boot device, the firmware will execute a small program called the **bootloader**, such as GRUB (on Linux) or bootmgr (on Windows). The bootloader is responsible for selecting and loading the operating system kernel into memory.
3. **Loading Kernel**
The kernel is the core of the operating system. It is responsible for managing communication between hardware and software, memory, processes, file systems, and more. Once loaded, the kernel will begin initializing all the system's essential components.
4. **Running Init**
After the kernel completes initialization, control of the system is handed over to the first process: **init**. This process then starts various other processes, such as network services, login shells, and desktop environments. Init can be a traditional system like SysVinit or a more modern system like systemd.
#### Types of Booting
There are two commonly known types of booting processes:
- **Cold Boot (Hard Boot)**
This is the booting process from a completely powered-off state. For example, when you turn on a laptop that is completely off, the process is called a cold boot.
- **Warm Boot (Soft Boot)**
This is the rebooting process of a system that is already running. This can be done, for example, by pressing the restart button or using the `reboot` command. Warm booting is often performed after a system update or when there is a minor issue that requires a restart.
#### Importance of the Booting Process and the Role of the Kernel
Without a proper booting process, the operating system **cannot be run**. No matter how advanced or complete the hardware is, without the booting process, a computer is just a pile of components that cannot do anything. The booting process is the **gateway** that opens the way for all operating system functions, from user login, running applications, to managing networks and external devices.
Each stage in the booting process has an important responsibility:
- **Firmware** ensures that the hardware is ready.
- **Bootloader** determines which operating system to run.
- **Kernel** initializes all the essential elements of the system.
- **Init** (the first process) runs the system's basic services.
Failure at any of these stages can cause the system to **fail to boot**, be unable to enter the operating system, or even crash. Therefore, understanding how the booting process works is very important, especially when developing operating systems or troubleshooting.
One of the most vital parts of this process is the **kernel**. The kernel acts as a bridge between hardware and software, managing communication between the processor, memory, input/output devices, and running programs. In Linux-based systems, this kernel is called the **Linux Kernel**.
Due to its central role, the booting process heavily depends on whether the kernel can be loaded and run properly. Therefore, in the next chapter, you will learn how to prepare the Linux kernel as the foundational element of a simple operating system that you will build and emulate yourself.
## Linux Kernel
### Definition of Linux Kernel
The Linux Kernel is the core of the Linux operating system. It manages the interaction between hardware and software and handles critical tasks such as memory management, processes, file systems, and input/output devices. The kernel is the first component to run after the bootloader loads it into memory.
One of the advantages of the Linux kernel is its **open-source and modular nature**. Anyone can view, modify, and recompile the kernel according to their needs. This makes it ideal for learning, experimentation, and developing customized operating systems, as you will do in this module.
In practice, we do not need to write a kernel from scratch. We simply take the **official Linux kernel source code**, then compile it into a binary file `bzImage` that can be executed by the bootloader and emulated by QEMU. The kernel compilation process requires several system dependencies and initial configurations to determine the features to include in the compiled kernel.
### Preparing the Linux Kernel
At this stage, we will prepare the Linux kernel to be used for building a minimal operating system using **QEMU**.
QEMU is an open-source emulator that allows us to run operating systems in a virtual environment. With QEMU, we can test the kernel we have built without installing it directly on hardware. Further explanation about QEMU will be discussed in a separate section.
The steps to be performed include updating and installing supporting software, downloading the kernel source code, configuring the kernel as needed, and compiling the kernel to produce the `bzImage` file.
1. Update and Install Supporting Software
Before starting, ensure the system is updated and all necessary software for this process is installed. We will use several tools such as `qemu`, `build-essential`, `bison`, `flex`, and others.
```bash
sudo apt -y update
sudo apt -y install qemu-system build-essential bison flex libelf-dev libssl-dev bc grub-common grub-pc libncurses-dev libssl-dev mtools grub-pc-bin xorriso tmux
```
2. Prepare the Directory
Create a directory for this project and navigate to it. All kernel building and configuration processes will be performed within this directory.
```bash
mkdir -p osboot
cd osboot
```
3. Download and Extract the Linux Kernel
The next step is to download the Linux kernel source code version 6.1.1. After downloading, we will extract it into the `linux-6.1.1` directory.
```bash
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.1.tar.xz
tar -xvf linux-6.1.1.tar.xz
cd linux-6.1.1
```
4. Configure the Kernel
The Linux kernel needs to be configured before being compiled. We will start by using a minimal configuration with `make tinyconfig`. After that, we can further customize the configuration using `make menuconfig` to enable features required by the operating system we are building. Some important settings to enable include support for virtualization, file systems, device drivers, and networking.
```
64-Bit Kernel
General Setup > Configure standard kernel features > Enable support for printk
General Setup > Configure standard kernel features > Enable futex support
General Setup > Initial RAM filesystem and RAM disk (initramfs/initrd) support
General Setup > Control Group Support
Enable the block layer > Legacy autoloading support
Enable the block layer > Partition type > Advanced Partition Selection
Device Drivers > Character devices > Enable TTY
Device Drivers > Character devices > Virtio console
Device Drivers > Character devices > /dev/mem virtual device support
Device Drivers > Network device support > Virtio Network Driver
Device Drivers > Serial Ata / Paralel ATA
Device Drivers > Block Devices > Virtio block driver
Device Drivers > Block Devices > loopback device support
Device Drivers > Block Devices > RAM block device support
Device Drivers > Virtio drivers
Device Drivers > Virtualization Drivers
Device Drivers > Generic Driver Options > Maintain a devtmpfs at filesystems
Device Drivers > Generic Driver Options > Automount devtmpfs at /dev
Executable file formats > Kernel Support for ELF binaries
Executable file formats > Kernel Support scripts starting with #!
File Systems > FUSE support
File Systems > The extended 3 filesystem
File Systems > The extended 4 filesystem
File Systems > Second extended fs support
File Systems > Virtio Filesystem
File Systems > Kernel automounter support
File Systems > Pseudo File Systems > /proc file system support
File Systems > Pseudo File Systems > sysctl support
File Systems > Pseudo File Systems > sysfs file system support
Networking Support > Networking options > Unix domain sockets
Networking Support > Networking options > TCP/IP Networking
```
or you can use this script
```
make tinyconfig
./scripts/config --enable CONFIG_64BIT --enable CONFIG_PRINTK --enable CONFIG_FUTEX \
--enable CONFIG_BLK_DEV_INITRD --enable CONFIG_CGROUPS --enable CONFIG_TTY \
--enable CONFIG_VIRTIO_CONSOLE --enable CONFIG_DEVMEM --enable CONFIG_VIRTIO_NET \
--enable CONFIG_ATA --enable CONFIG_VIRTIO_BLK --enable CONFIG_BLK_DEV_LOOP \
--enable CONFIG_BLK_DEV_RAM --enable CONFIG_VIRTIO --enable CONFIG_VIRTUALIZATION \
--enable CONFIG_DEVTMPFS --enable CONFIG_DEVTMPFS_MOUNT --enable CONFIG_BINFMT_ELF \
--enable CONFIG_BINFMT_SCRIPT --enable CONFIG_FUSE_FS --enable CONFIG_EXT4_FS \
--enable CONFIG_VIRTIO_FS --enable CONFIG_PROC_FS --enable CONFIG_SYSFS \
--enable CONFIG_UNIX --enable CONFIG_INET
make olddefconfig
```
This configuration ensures that the resulting kernel can work well in a virtual environment and supports the basic operations required.
```bash
make tinyconfig
make menuconfig
```
After completing the configuration, you can save the `.config` file and proceed to the next step.
5. Compile the Kernel
With the configuration ready, we can now start the kernel compilation process. This process will produce the `bzImage` file, which is the kernel file ready for booting.
```bash
make -j$(nproc)
```
The command above compiles the kernel using all available CPU cores on the system.
6. Generate the `bzImage` File
After the compilation is complete, we will obtain the `bzImage` file in the `arch/x86/boot/` directory. Move this file to the `osboot` directory in preparation for the next step, which is creating the root filesystem and emulating it using QEMU.
```bash
cp arch/x86/boot/bzImage ..
```
## Creating a Root Filesystem
### Definition of Root Filesystem
Imagine an operating system as a house. The **root filesystem** is the _foundation and basic framework of that house_. All rooms (directories like `/bin`, `/etc`, `/dev`, etc.) are built on top of this rootfs, and all activities of the inhabitants (applications and services) depend on it for the house to function properly. Without rootfs, the house is like a structure without an entrance, tools, or rules.
#### What is a Root Filesystem?
- The **Root Filesystem** is the file structure used by the operating system to store essential files required to run the system, such as configurations, hardware, and basic applications.
- It is the **first filesystem loaded** after the booting process begins and serves as the central storage for all critical files needed by the system.
#### Components in a Root Filesystem
The root filesystem typically contains several important directories, including:
- **`/bin`** – Stores basic applications and programs used to run the system.
- **`/etc`** – Stores system and application configuration files.
- **`/lib`** – Contains system libraries required by programs to run.
- **`/dev`** – Stores device files needed to access hardware.
- **`/home`** – Directory for storing user data.
#### Initial RAM Filesystem (initramfs)
Before the main root filesystem can be mounted, the system requires a temporary filesystem called **initramfs** to start the operating system. Initramfs is a **lightweight filesystem image** loaded into memory during the initial booting phase.
**Functions of Initramfs**:
- Provides basic tools and scripts to prepare the system.
- Configures hardware and checks storage devices.
- Supplies the kernel with the information needed to mount the main root filesystem.
#### BusyBox
To simplify tasks within initramfs, **BusyBox** is used as a collection of lightweight yet comprehensive tools. BusyBox provides various **system utilities** used to configure hardware, manipulate the filesystem, and perform other critical tasks during the booting process.
**Functions of BusyBox**:
- Replaces many standard Linux commands in the operating system with lighter and simpler versions.
- Functions in resource-constrained environments (such as embedded systems or the early booting stage).
- Provides utilities like `ls`, `cp`, `mv`, `mount`, and many others, which are used by initramfs to perform various tasks.
**Installing BusyBox**
BusyBox can be installed using the following command:
```bash
sudo apt install -y busybox-static
```
You can check if BusyBox is installed with the command:
```bash
whereis busybox
```
Typically, **BusyBox** will be located in the `/usr/bin/busybox` directory.
### Single User vs Multi User
The Linux operating system can run in two main modes based on user needs and system complexity: **Single User** and **Multi User**. Both use the root filesystem as the system's foundation but have different approaches, structures, and booting processes.
The **Single User** mode is suitable for system maintenance or debugging as it only allows one user (usually root) to access the system. Meanwhile, the **Multi User** mode is designed to allow multiple users to log in and work simultaneously, with access rights, accounts, and system services management.
#### Comparison: Single User vs Multi User
1. From a Functional Perspective
| Aspect | Single User | Multi User |
| --------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| **Purpose** | Used for maintenance, debugging, or minimal systems. | Used for daily use, servers, or systems with multiple users. |
| **User Access** | Only one user (usually root) can log in. | Multiple users can log in simultaneously with different access rights. |
| **Interaction** | No interaction between users, focused on basic system tasks. | Supports interaction between users and parallel processes. |
| **Security** | Minimal security settings as only root has access. | Requires authentication systems, user management, and access rights for each user. |
| **Use Case** | Practical for recovery, boot testing, or very lightweight embedded systems. | Common in desktop systems, servers, or work environments involving multiple users. |
2. From a System Creation Perspective
**Single User**
- **Root Filesystem Structure:**
- Minimal: `/bin`, `/dev`, `/proc`, `/sys`, and the `init` file.
- No user directories (`/home`, `/etc/passwd`, etc.).
- **`init` File:**
- Simple. Usually contains:
```sh
#!/bin/sh
echo "Init started"
exec /bin/sh
```
- After mounting, directly enters the shell as root without a login process.
- **User Management:** Not required, as only root runs the shell.
- **Booting Process:** Fast and simple, no login daemon or access rights management.
**Multi User**
- **Root Filesystem Structure:**
- More complete: Includes `/etc/passwd`, `/etc/group`, `/etc/shadow`, `/home/user1`, etc.
- Uses BusyBox for `login`, `adduser`, `getty`, and other system management tools.
- **`init` File:**
- More complex, as it must run the login process via `getty`:
```sh
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
/bin/hostname multiuser
setsid /bin/getty -n -l /bin/login 115200 tty1 &
exec /bin/sh
```
- Login process active on `tty1`, and can be added for `tty2`, `tty3`, etc.
- **User Management:**
- Users and groups must be created using `adduser` or manually editing `/etc/passwd`.
- Passwords can be encrypted or left blank depending on BusyBox configuration.
- **Booting Process:** The system runs a login prompt on multiple terminals (multi-console). After logging in, each user gets their own shell according to their access rights.
3. Summary of Differences
| Aspect | Single User | Multi User |
| -------------------------- | ---------------------------------------- | ----------------------------------------------------- |
| **Main Purpose** | Maintenance / minimal system | System ready for use by multiple users |
| **Access** | Root only | Multiple users with login |
| **Filesystem Complexity** | Simple | Complete with user configuration |
| **`init` File** | Direct shell | Login process via getty |
| **Additional Directories** | No need for `/etc/passwd`, `/home`, etc. | Must include directories and user configuration files |
| **User Management** | None | Requires authentication system |
| **Use Case Example** | Rescue mode, embedded systems | Server, multi-user workstation |
Conclusion
The main difference between **single user** and **multi user** lies not only in the number of users who can log in but also in the level of system complexity. The **single user** mode offers simplicity and speed, ideal for emergencies or lightweight embedded systems. Meanwhile, the **multi user** mode requires additional configuration but provides greater flexibility and scalability, suitable for production systems.
### Single User
After preparing the kernel and root filesystem, we will proceed to create a simpler filesystem for the initial booting stage, known as Single User Mode. In **Single User** mode, the prepared root filesystem will run with only one user who has full control over the system. This mode is useful in the early stages of booting or for simpler systems, such as embedded systems, where only one user is needed to configure or manage the system. Below is a further explanation of how the root filesystem works in single user mode, along with steps to create this root filesystem.
#### Concept of Root Filesystem in Single User Mode
1. **Role of the `init` Program**
- After the Linux kernel starts the booting process, the first step is to run the **init** program. This **init** program is the first program executed by the kernel with Process ID (PID) 1.
- **init** is responsible for setting up the environment needed by the system and starting other processes in the correct order.
- The root filesystem initially loaded by the kernel will include the **init** program, which is usually located in the root directory (`/`).
2. **Using Initramfs in Single User Mode**
- To simplify the booting process, the root filesystem can be loaded using **initramfs**. Initramfs is a **temporary filesystem** loaded into memory and serves to prepare the system before the main root filesystem is mounted.
- In this case, **initramfs** is used to configure the system and provide minimal tools, such as BusyBox, to run the **init** program in single user mode.
3. **Why Use BusyBox**
- In more complex operating systems, the root filesystem is usually stored on permanent storage such as a hard drive or SSD. However, during the initial booting process or on resource-constrained systems, we use **BusyBox**.
- **BusyBox** is a collection of Unix/Linux utilities packaged into a single executable file. It enables a lighter system by providing various essential commands like `ls`, `cp`, `mount`, and `sh`, which are used to configure and manage the filesystem.
#### Steps to Create a Root Filesystem for Single User Mode
The steps to create a root filesystem using initramfs and BusyBox to provide a minimal yet functional system environment are as follows:
1. **Enter Superuser Mode**
To make changes to the system, we will work in superuser (root) mode. Use the following command to enter the shell as root:
```bash
sudo bash
```
2. **Create a Directory for Initramfs**
Next, create a `myramdisk` directory and several subdirectories for the filesystem:
```bash
mkdir -p myramdisk/{bin,dev,proc,sys}
```
The directory structure will look like this:
```
myramdisk/
├── bin/
├── dev/
├── proc/
└── sys/
```
3. **Copy Device Files to the `dev` Directory**
The `/dev` directory in Linux contains important device files like `null`, `tty`, `zero`, and `console`. We will copy them from the host system into the `dev` directory in `myramdisk`.
```bash
cp -a /dev/null myramdisk/dev
cp -a /dev/tty* myramdisk/dev
cp -a /dev/zero myramdisk/dev
cp -a /dev/console myramdisk/dev
```
4. **Copy BusyBox to the `bin` Directory**
Next, copy the **BusyBox** file into the `bin` directory created inside `myramdisk`. Then, install all utilities provided by BusyBox:
```bash
cp /usr/bin/busybox myramdisk/bin
cd myramdisk/bin
./busybox --install .
```
This command will add various Unix/Linux commands like `ls`, `cp`, `mv`, `mount`, and many others to the `bin` directory.
5. **Create the `init` File**
Inside the `myramdisk` directory, create an **init** file that will be executed first during booting. Populate this file with instructions to mount the filesystem and start an interactive shell.
```bash
#!/bin/sh
/bin/mount -t proc none /proc
/bin/mount -t sysfs none /sys
exec /bin/sh
```
This file will mount `proc` and `sysfs`, enabling the system to communicate with the kernel. After that, it will start the `/bin/sh` shell for user interaction.
6. **Grant Execution Permission to the `init` File**
To make the `init` file executable, grant it execution permission using the command:
```bash
chmod +x init
```
7. **Compress and Create the `initramfs` File**
After preparing all the necessary files, the next step is to package them using the `cpio` command and compress them with `gzip` to create the initramfs image.
```bash
find . | cpio -oHnewc | gzip > ../myramdisk.gz
```
This command will produce the **myramdisk.gz** file, which contains the minimal filesystem for the initial booting stage.
With the above steps, we have successfully created a root filesystem in single user mode using BusyBox and initramfs.
### Multi User
After successfully running the system in **single user** mode, the next step is to build the system in **multi user** mode using **initramfs**. In this mode, more than one user can log in and use the system simultaneously, making it suitable for general use that requires account and access management.
To support multi user, we will construct a more complete root filesystem. We use **BusyBox** as the provider of basic Linux utilities and **initramfs** as the root filesystem loaded into memory during booting. Unlike single user mode, which only provides a direct shell for root, this mode requires a login process on the terminal, necessitating files like `/etc/passwd`, `/etc/group`, and services like `getty`.
#### Steps to Create a Root Filesystem for Multi User Mode
1. **Enter Privileged Mode (Superuser)**
To make changes to the system, we will work in **superuser** (root) mode using the command:
```bash
sudo bash
```
2. **Create a Directory for Initramfs**
Create a directory named `myramdisk` and several subdirectories required by the root filesystem.
```bash
mkdir -p myramdisk/{bin,dev,proc,sys,etc,root,home/user1}
```
3. **Copy Device Files to the `dev` Directory**
The `/dev` directory contains important devices like `null`, `tty`, `zero`, and `console`. We will copy these device files from the host system into the `dev` directory in `myramdisk`.
```bash
cp -a /dev/null myramdisk/dev
cp -a /dev/tty* myramdisk/dev
cp -a /dev/zero myramdisk/dev
cp -a /dev/console myramdisk/dev
```
4. **Copy BusyBox to the `bin` Directory**
Copy the **BusyBox** file into the `bin` directory and run the BusyBox utility installation:
```bash
cp /usr/bin/busybox myramdisk/bin
cd myramdisk/bin
./busybox --install .
```
5. **Create Root Password**
Use the `openssl` command to create an encrypted root password:
```bash
openssl passwd -1 myrootpassword
```
Copy the output of the above command, as it will be used to create the user and password database.
6. **Create the `passwd` File in the `etc` Directory**
Create a `passwd` file in the `etc` directory to store information about the root account and the user we will create (e.g., `user1`):
```bash
root:<>:0:0:root:/root:/bin/sh
user1:<>:1001:100:user1:/home/user1:/bin/sh
```
7. **Create the `group` File in the `etc` Directory**
Create a `group` file in the `etc` directory containing group settings for the newly created user:
```bash
root:x:0:
bin:x:1:root
sys:x:2:root
tty:x:5:root,user1
disk:x:6:root
wheel:x:10:root,user1
users:x:100:user1
```
8. **Create the `init` File**
Return to the `myramdisk` directory and create an **init** file that will be called by the bootloader during system booting. Populate the `init` file with instructions to mount the filesystem and run the login process:
```bash
#!/bin/sh
/bin/mount -t proc none /proc
/bin/mount -t sysfs none /sys
while true
do
/bin/getty -L tty1 115200 vt100
sleep 1
done
```
This file will mount `proc` and `sysfs`, enabling communication between user space and the kernel. Then, the `getty` command will wait for login input from users via the console.
9. **Grant Execution Permission to the `init` File**
To make the `init` file executable, grant it execution permission:
```bash
chmod +x init
```
10. **Compress and Create the `initramfs` File**
After preparing all the necessary files, we will package them using the **cpio** utility and then compress them with **gzip** to create the **initramfs** image.
```bash
find . | cpio -oHnewc | gzip > ../myramdisk.gz
```
This command will produce the **myramdisk.gz** file, which contains the minimal filesystem for booting.
With the above steps, we have successfully created a root filesystem with multi-user capabilities using initramfs and BusyBox. This system allows multiple users to log in, with one main user (root) and one additional user (user1). When the system boots, users can log in using the credentials we have defined.
## Emulation with QEMU
### Understanding QEMU
**QEMU** (Quick Emulator) is a program used to run **operating systems** or **applications** in a **virtual environment** (similar to another computer) without requiring different physical hardware. With QEMU, you can run different operating systems, such as Linux on Windows, or try entirely different systems, like ARM or RISC-V, on an x86-based machine (a regular computer).
Imagine you want to try a different system, for example, testing **Windows 10** on a **Mac**. Instead of installing Windows directly on the Mac's hard drive (which can be time-consuming and risky), you can use QEMU to **"emulate"** a Windows machine inside the Mac, allowing you to test Windows 10 without changing anything on the original computer.
QEMU works by **emulating** (mimicking) components in a computer such as the **CPU** (processor), **memory**, and **hardware**. This allows you to run operating systems or applications that would normally only work on specific hardware, without needing the corresponding physical machine.
#### Difference Between QEMU and Virtual Machines (VM)
**QEMU** and **Virtual Machines (VM)** are often used for the same purpose, which is running different operating systems, but they differ in how they work.
1. **Virtual Machine (VM)**
- **What is a VM?** A VM is a **virtual machine** that runs on top of the main operating system. With a VM, you create a **virtual machine** that functions like a separate physical computer. You can run an operating system (e.g., Linux) on top of another operating system (e.g., Windows) using programs like **VirtualBox** or **VMware**.
- **How a VM Works:** A virtual machine uses **virtualization** to divide the physical computer's resources (like CPU, RAM) into multiple virtual machines. So, even though all virtual machines share the same physical computer, they work as if they have their own separate computer.
2. **QEMU**
- **What is QEMU?** QEMU is a **flexible emulator**. QEMU can perform **full emulation** of a computer, meaning it can mimic **hardware** (like CPUs and other devices) from another machine. This allows you to run operating systems designed for different hardware (e.g., ARM, MIPS) on top of a different machine (e.g., x86).
- **How QEMU Works:** QEMU not only supports **virtualization** but also **emulation**. This means QEMU can "mimic" hardware entirely, allowing you to run various types of operating systems without requiring the corresponding physical machine.
3. **Comparison Between QEMU and VM**
| **Aspect** | **QEMU** | **VM** |
| -------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
| **Technology Type** | Emulation (mimics hardware) | Virtualization (shares physical resources) |
| **Main Function** | Runs operating systems from different architectures | Runs multiple operating systems on one physical machine |
| **Use Case Example** | Running operating systems for different architectures (e.g., ARM on x86) | Running multiple operating systems on one machine (e.g., Windows and Linux on one computer) |
### Steps for Emulation with QEMU
After creating the `bzImage` (kernel) and `myramdisk.gz` (initramfs) files, you can run the operating system you built using **QEMU**. Here are the steps to follow:
1. Navigate to the `osboot` Directory
First, go to the directory where you saved the build files:
```bash
cd osboot
```
This directory should contain the following files:
- `bzImage` → the compiled kernel
- `myramdisk.gz` → the root filesystem you created
2. Run the Emulation with QEMU
Use the following command to run QEMU with specific configurations:
```bash
qemu-system-x86_64 \
-smp 2 \
-m 256 \
-display curses \
-vga std \
-kernel bzImage \
-initrd myramdisk.gz
```
Explanation of Options:
| Option | Function |
| ---------------------- | ---------------------------------------------------------------- |
| `-smp 2` | Provides 2 vCPUs (virtual CPUs) for the emulated system |
| `-m 256` | Allocates 256 MB of memory |
| `-display curses` | Displays output in text mode (can be used in a regular terminal) |
| `-vga std` | Sets standard VGA display (80x25), sufficient for text display |
| `-kernel bzImage` | Specifies the kernel to use for booting |
| `-initrd myramdisk.gz` | Specifies the root filesystem (initramfs) to load |
After running the above command, QEMU will start the booting process. If there are no errors, you will enter the BusyBox shell (if using an `init` script that launches a shell) or see a login process if using a multi-user configuration.
### Testing Inside the Shell
Once the system successfully boots through QEMU, you will see a shell or login prompt depending on whether you are using **single user** or **multi-user** mode.
#### **Single User**
You will directly enter the `sh` shell provided by **BusyBox**. This means the system only provides direct access to the terminal without a login process.
Example display:
```
/ #
```
Here, you can try some basic Linux commands like:
```sh
ls
cat /proc/cpuinfo
echo "Hello from QEMU!"
```
The goal is to ensure that:
- The file system is successfully loaded
- BusyBox is functioning correctly
- The system responds to input
#### **Multi User**
In this mode, you will see a login prompt. The system will ask you to log in using the username and password you configured earlier (e.g., in the `/etc/passwd` and `/etc/shadow` files).
Example display:
```
Welcome to Mini Linux
myos login: user1
Password:
```
After successfully logging in, you will enter the shell and can perform tests such as:
```sh
whoami
ls /home
```
Things to test:
- The login process works correctly
- User permissions are appropriate (cannot access root directories without permission)
- You can navigate directories and execute basic commands
### Restarting the Boot Process
If you want to **restart the boot process** of the system you emulated with QEMU, you need to stop the QEMU process first, then run it again as before.
1. **Stop the QEMU Process**
Use the following command to stop the QEMU process:
```sh
pkill -f qemu
```
This command will find processes containing the word "qemu" and terminate them. Ensure you are not running any other important processes with the same name.
2. **Run the System Again Using QEMU**
Repeat the same QEMU command as before:
```sh
qemu-system-x86_64 \
-smp 2 \
-m 256 \
-display curses \
-vga std \
-kernel bzImage \
-initrd myramdisk.gz
```
This will reboot the system from the beginning with the same settings, allowing you to test again whether the system runs stably and as expected.
## Creating a Bootable ISO Disk
A **bootable ISO disk** is a `.iso` file that contains a complete file system structure of an operating system and can be used for **booting**. This file can be run through emulators like QEMU, burned to a CD/DVD, or written to a USB drive to run the system directly (live system).
Creating an ISO is useful for:
- **Distributing a custom operating system**
- **Quick testing and deployment** to other machines
- Building a **custom minimal Linux live system**
To make the ISO bootable, we need a **bootloader**, which is the initial program executed when the computer starts. Here, we will use **GRUB** (GRand Unified Bootloader) as the bootloader and combine it with the kernel (`bzImage`) and root filesystem (`myramdisk.gz`) into a single ISO using the `grub-mkrescue` tool.
**Steps:**
1. **Navigate to the `osboot` directory**:
```bash
cd osboot
```
2. **Create the ISO directory structure**:
```bash
mkdir -p mylinuxiso/boot/grub
```
3. **Copy the kernel and root filesystem files**:
```bash
cp bzImage mylinuxiso/boot
cp myramdisk.gz mylinuxiso/boot
```
4. **Create the GRUB configuration file**:
Create a `grub.cfg` file in `mylinuxiso/boot/grub` with the following content:
```cfg
set timeout=5
set default=0
menuentry "MyLinux" {
linux /boot/bzImage
initrd /boot/myramdisk.gz
}
```
> This file creates a GRUB menu displaying a boot option named "MyLinux" and directs the system to use the provided kernel and initrd.
5. **Generate the bootable ISO file**:
Run the following command from the `osboot` directory:
```bash
grub-mkrescue -o mylinux.iso mylinuxiso
```
## Emulating ISO File Execution
After successfully creating the **bootable ISO file**, the next step is to **test the ISO using an emulator**. Here, we will use **QEMU** to run the system we built, simulating booting from a virtual CD-ROM.
This emulation allows us to:
- Verify that the bootable ISO system works correctly
- Run the BusyBox shell from the ISO
- Check the integration of the kernel and initramfs
**Steps for Emulation:**
1. **Navigate to the `osboot` directory**:
```bash
cd osboot
```
2. **Run the system with QEMU using the ISO file**:
```bash
qemu-system-x86_64 \
-smp 2 \
-m 256 \
-display curses \
-vga std \
-cdrom mylinux.iso
```
**Explanation of parameters**:
- `-smp 2` → uses 2 virtual CPUs
- `-m 256` → allocates 256 MB of RAM
- `-display curses` → displays output in the terminal (text mode)
- `-vga std` → standard VGA for 80x25 resolution display
- `-cdrom mylinux.iso` → specifies the ISO file to boot
**Results**
- The screen will display the booting process
- A **GRUB** menu will appear with the option: `MyLinux`
- After selecting, the system will load the kernel and `initrd`, then enter the **BusyBox shell**
**Testing in BusyBox Shell**
Once inside the shell, try the following commands to test the system environment:
```bash
ls -la
ls
whoami
ps
```
These commands will:
- Display the directory contents (`ls`)
- Show the active user (`whoami`)
- List running processes (`ps`)
**Restarting the Emulation**
If you want to rerun the emulation:
1. Stop QEMU with:
```bash
pkill -f qemu
```
2. Run the `qemu-system-x86_64` command again as shown above.