DEV Community

Draevich Matthew
Draevich Matthew

Posted on

Virtualization & Emulation explained in a top-down fashion

It took much time for me to find and comprehend the difference between virtualization & emulation. Since the understanding may require a broad knowledge of how software and hardware are coupled together, I decided to describe all components you need in a single article.

Case #1 — Running OS on a bare-metal server

It’s important to know how the things are working in a traditional way.
So, we'll discuss in a top-down fashion how the following components are coupled together:

  1. Hardware — you can’t run anything without CPU & RAM.
  2. OS — a set of processes that helps us to manage & utilize the power of hardware.
  3. Application — there is nothing useful if OS isn’t able to run applications.

All the magic begins with a CPU — it defines a set of instructions available for execution. Instruction can be simply represented as an action with arguments. Available instructions are defined by CPU architecture. Thus, instructions for ARMv7 and x86_64 will be different.

When it comes to OS it's worth to describe it as a set of processes which are responsible for managing & utilizing hardware (e.g. screen updates, keyboard events, network data sending & receiving). Under the hood all the processes are described as an order of instructions that a particular CPU understands.

Finally, the installed application is also an order of instructions that a particular CPU understands.

We're ready to state that instructions can be different from the permissions perspective. In general we divide available instructions to:

  1. privileged — OS-level instructions (to get all keyboard events as an example);
  2. unprivileged — application-level instructions (to sum up two integers as an example).

The permission level of an instruction is defined by the means of protections rings. Permissions in turn allow us to prevent a single application seizing the control over the hardware in a selfish manner.

But what if an application needs to access a data that requires execution of a privileged instruction? As an example, sending a network packet or catching some keyboard events?

As far as we know an application is not allowed to execute any privileged instruction... That’s a point where interaction with an OS comes into play — an application is able to interact with OS by API calls to request the data.

Let’s display it with a scheme:

Case #1 — Running OS on a bare-metal server

Case #2 — Emulation approach

The first question I would like to speak about is the problem that emulation solves.

Generally speaking we need emulation when an application executes instructions the underlying hardware doesn't support. A quick example would be running ARMv7 application on top of x86_64 platform.

In general this issue is resolved by placing a kind of translator between an application and CPU to translate instructions — the translator would be referred as an interpretator.

Pay great attention that an emulated application is deployed as a general user application so it's not allowed to execute any privileged instruction. The solution for that is simply converting privileged instructions to API calls to the underlying OS.

Emulation enables you to emulate either a single application or an entire OS.

Let's take a look how an entire OS can be emulated:

Case #2 — Emulation

Case #3 — Full virtualization approach

What’s the problem virtualization solves?

Virtualization allows us to run a separate OS (referred as a virtual machine) as a general user application. Besides, a virtual machine is allowed to execute instructions directly on hardware CPU without any interpretator between. That's dramatically increases performance however a virtual machine should use supported CPU instructions.

You must ask: “whoa, wait a minute, is a virtual machine allowed to execute privileged instructions in this case?”. Yeah, it’s a good question to ask.

To answer the question it’s worth to know how CPU behaves if a privileged instruction is executed from user space (where a virtual machine sits).
If CPU gets a privileged instruction from user space it will not silently drop it. Instead, it will raise an exception to kernel space (where underlying OS sits). Underlying OS is now responsible for handling & resolving the exceptions. The described technique is called Trap-and-Emulate.

Let’s display it with a scheme:

Case #3 — Full virtualization

Case #4 — Paravirtualization approach

Finally, let’s take a look at paravirtualization.

Trap-and-Emulate technique is a working solution but its performance leaves something to be desired due to unnecessary exceptions. Paravirtualization comes into play to provide more performance by eliminating the need of exceptions.

Paravirtualization implies that you modify virtual machine OS to make it directly execute API calls to the underlying OS instead of executing privileged instructions on a CPU. But once again — paravirtualization requires you to modify virtual machine OS by installing additional software what can be a great limitation.

A scheme illustrating what I’ve just said:

Case #4 — Paravirtualization

To sum up

In this article we've completed a journey to understand the following:

  • what are CPU instructions and how they can be different;
  • how OS and applications are coupled together and how they use CPU;
  • how emulation allows you to run applications on unsupported hardware;
  • how virtualization overtakes emulation in performance and what paravirtualization is.

I really hope you'll find this article useful.
Let me know if you have any recommendations how to make it better.

Have a nice day!

Top comments (0)