Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grammar and prose updates for Chapters 1-9 #119

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Chapter-1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@

> The term x86 denotes a family of backward compatible instruction set architectures based on the Intel 8086 CPU.

The x86 architecture is the most common instruction set architecture since its introduction in 1981 for the IBM PC. A large amount of software, including operating systems (OS's) such as DOS, Windows, Linux, BSD, Solaris and Mac OS X, function with x86-based hardware.
Since its introduction in 1981 for the IBM PC, x86 has become the most common instruction set architecture. A large amount of software, including operating systems (OS), function with x86-based hardware. Examples of these include DOS, Windows, Linux, BSD, Solaris and macOS.

In this course we are not going to design an operating system for the x86-64 architecture but for x86-32, thanks to backward compatibility, our OS will be compatible with our newer PCs (but take caution if you want to test it on your real machine).
In this course, we are not going to design an operating system for the x86/64 architecture, but for x86-32. Thanks to backward compatibility, our OS will be compatible with newer PCs (but take caution if you want to test it on your real machine).

### Our Operating System

The goal is to build a very simple UNIX-based operating system in C++, but the goal is not to just build a "proof-of-concept". The OS should be able to boot, start a userland shell and be extensible.
The goal is to build a very simple UNIX-based operating system in C++. However, the goal is not to just build a "proof-of-concept". The OS should be able to boot, start a userland shell and be extensible.

The OS will be built for the x86 architecture, running on 32 bits, and compatible with IBM PCs.
To clarify, the OS will be built for the x86 architecture, running as 32-bit, and should be compatible with IBM PCs.

**Specifications:**

* Code in C++
* x86, 32 bit architecture
* Boot with Grub
* Coded in C++
* x86 and 32 bit architecture
* Boot with GRUB
* Kind of modular system for drivers
* Kind of UNIX style
* Multitasking
* Multitasking possible
* ELF executable in userland
* Modules (accessible in userland using /dev/...) :
* IDE disks
Expand Down
29 changes: 13 additions & 16 deletions Chapter-2/README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
## Chapter 2: Setup the development environment
## Chapter 2: Set Up the Development Environment

The first step is to setup a good and viable development environment. Using Vagrant and Virtualbox, you'll be able to compile and test your OS from all the OSs (Linux, Windows or Mac).
The first step is to setup an effective development environment. Using Vagrant and VirtualBox, you'll be able to compile and test your OS from any platform.

### Install Vagrant

> Vagrant is free and open-source software for creating and configuring virtual development environments. It can be considered a wrapper around VirtualBox.

Vagrant will help us create a clean virtual development environment on whatever system you are using.
The first step is to download and install Vagrant for your system at http://www.vagrantup.com/.
Vagrant will help us create a clean virtual environment on whatever system you are using. To get started, download and install Vagrant for your system [here](http://www.vagrantup.com).

### Install Virtualbox
### Install VirtualBox

> Oracle VM VirtualBox is a virtualization software package for x86 and AMD64/Intel64-based computers.

Vagrant needs Virtualbox to work, Download and install for your system at https://www.virtualbox.org/wiki/Downloads.
As a prerequisite, Vagrant needs VirtualBox to function properly. Download and install the VirtualBox package from [here](https://www.virtualbox.org/wiki/Downloads).

### Start and test your development environment

Once Vagrant and Virtualbox are installed, you need to download the ubuntu lucid32 image for Vagrant:
Once Vagrant and VirtualBox have been installed, you need to download the Ubuntu `lucid32` image for Vagrant:

```
vagrant box add lucid32 http://files.vagrantup.com/lucid32.box
```

Once the lucid32 image is ready, we need to define our development environment using a *Vagrantfile*, [create a file named *Vagrantfile*](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/Vagrantfile). This file defines what prerequisites our environment needs: nasm, make, build-essential, grub and qemu.
Once the lucid32 image is ready, we need to define our development environment using a *Vagrantfile*. [Create a file named *Vagrantfile*](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/Vagrantfile). This file defines what prerequisites our environment needs: nasm, make, build-essential, grub and qemu.

Start your box using:
Now, spin up your box using:

```
vagrant up
```

You can now access your box by using ssh to connect to the virtual box using:
You can now access your environment by using ssh. Connect to the virtual box using:

```
vagrant ssh
Expand All @@ -45,20 +44,18 @@ cd /vagrant

#### Build and test our operating system

The file [**Makefile**](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/Makefile) defines some basics rules for building the kernel, the user libc and some userland programs.
The [**Makefile**](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/Makefile) defines some basic rules for building the kernel, the user libc and some userland programs.

Build:
To build, run:

```
make all
```

Test our operating system with qemu:
We can test our operating system with qemu:

```
make run
```

The documentation for qemu is available at [QEMU Emulator Documentation](http://wiki.qemu.org/download/qemu-doc.html).

You can exit the emulator using: Ctrl-a.
The documentation for qemu is available at [QEMU Emulator Documentation](http://wiki.qemu.org/download/qemu-doc.html). You can exit the emulator using: Ctrl-a.
28 changes: 15 additions & 13 deletions Chapter-3/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
## Chapter 3: First boot with GRUB

#### How the boot works?
#### How does boot work?

When an x86-based computer is turned on, it begins a complex path to get to the stage where control is transferred to our kernel's "main" routine (`kmain()`). For this course, we are only going to consider the BIOS boot method and not it's successor (UEFI).
When an x86-based computer is turned on, it starts on a complex path to get to the stage where control is transferred to our kernel's "main" routine (`kmain()`). For this course, we are only going to consider the BIOS boot method and not any successors (e.g. UEFI).

The BIOS boot sequence is: RAM detection -> Hardware detection/Initialization -> Boot sequence.

The most important step for us is the "Boot sequence", where the BIOS is done with its initialization and tries to transfer control to the next stage of the bootloader process.
The most important step for us is the "boot sequence"where the BIOS finishes initialization and attempts to transfer control to the next stage of the bootloader process.

During the "Boot sequence", the BIOS will try to determine a "boot device" (e.g. floppy disk, hard-disk, CD, USB flash memory device or network). Our Operating System will initially boot from the hard-disk (but it will be possible to boot it from a CD or a USB flash memory device in future). A device is considered bootable if the bootsector contains the valid signature bytes `0x55` and `0xAA` at offsets 511 and 512 respectively (called the magic bytes of the Master Boot Record, also known as the MBR). This signature is represented (in binary) as 0b1010101001010101. The alternating bit pattern was thought to be a protection against certain failures (drive or controller). If this pattern is garbled or 0x00, the device is not considered bootable.
During the boot sequence, the BIOS will try to determine a boot device (e.g. floppy disk, hard disk, CD, USB flash memory device or network). Our operating system will initially boot from the hard disk (but it will be possible to boot it from a CD or a USB flash memory device in future).

A device is considered bootable if the bootsector contains the valid signature bytes `0x55` and `0xAA` at offsets 511 and 512 respectively (called the magic bytes of the Master Boot Record, also known as the MBR). This signature is represented (in binary) as 0b1010101001010101. The alternating bit pattern was thought to be a protection against certain failures (drive or controller). If this pattern is garbled or 0x00, the device is not considered bootable.

BIOS physically searches for a boot device by loading the first 512 bytes from the bootsector of each device into physical memory, starting at the address `0x7C00` (1 KiB below the 32 KiB mark). When the valid signature bytes are detected, BIOS transfers control to the `0x7C00` memory address (via a jump instruction) in order to execute the bootsector code.

Expand All @@ -18,22 +20,22 @@ Throughout this process the CPU has been running in 16-bit Real Mode, which is t

> GNU GRUB (short for GNU GRand Unified Bootloader) is a boot loader package from the GNU Project. GRUB is the reference implementation of the Free Software Foundation's Multiboot Specification, which provides a user the choice to boot one of multiple operating systems installed on a computer or select a specific kernel configuration available on a particular operating system's partitions.

To make it simple, GRUB is the first thing booted by the machine (a boot-loader) and will simplify the loading of our kernel stored on the hard-disk.
Essentially, GRUB is the first thing booted by the machine (a bootloader). This will simplify the loading of our kernel stored on the hard disk.

#### Why are we using GRUB?

* GRUB is very simple to use
* Make it very simple to load 32bits kernels without needs of 16bits code
* Multiboot with Linux, Windows and others
* GRUB is very simple to use and implement
* Make it very simple to load 32-bit kernels without needing 16-bit code
* GRUB allows you to multi-boot with Linux, Windows and others
* Make it easy to load external modules in memory

#### How to use GRUB?
#### How do we use GRUB?

GRUB uses the Multiboot specification, the executable binary should be 32bits and must contain a special header (multiboot header) in its 8192 first bytes. Our kernel will be a ELF executable file ("Executable and Linkable Format", a common standard file format for executables in most UNIX system).
GRUB uses the multi-boot specification; the executable binary should be 32-bit and must contain a special header (multiboot header) in its 8192 first bytes. Our kernel will be a ELF executable file ("Executable and Linkable Format", a common standard file format for executables in most UNIX system).

The first boot sequence of our kernel is written in Assembly: [start.asm](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/start.asm) and we use a linker file to define our executable structure: [linker.ld](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/linker.ld).

This boot process also initializes some of our C++ runtime, it will be described in the next chapter.
This boot process also initializes some of our C++ runtime; this will be described in the next chapter.

Multiboot header structure:

Expand Down Expand Up @@ -70,7 +72,7 @@ struct multiboot_info {

You can use the command ```mbchk kernel.elf``` to validate your kernel.elf file against the multiboot standard. You can also use the command ```nm -n kernel.elf``` to validate the offset of the different objects in the ELF binary.

#### Create a disk image for our kernel and grub
#### Create a disk image for our kernel and GRUB

The script [diskimage.sh](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/sdk/diskimage.sh) will generate a hard disk image that can be used by QEMU.

Expand Down Expand Up @@ -168,7 +170,7 @@ And finally we detach the loop device:
losetup -d /dev/loop1
```

#### See Also
#### See also

* [GNU GRUB on Wikipedia](http://en.wikipedia.org/wiki/GNU_GRUB)
* [Multiboot specification](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html)
2 changes: 1 addition & 1 deletion Chapter-4/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ typedef signed long long s64;

#### Compile our kernel

Compiling a kernel is not the same thing as compiling a linux executable, we can't use a standard library and should have no dependencies to the system.
Compiling a kernel is not the same thing as compiling a Linux executable. We can't use a standard library and should have no dependencies to the system.

Our [Makefile](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/Makefile) will define the process to compile and link our kernel.

Expand Down
2 changes: 1 addition & 1 deletion Chapter-6/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void init_gdt_desc(u32 base, u32 limite, u8 acces, u8 other, struct gdtdesc *des
}
```

And the function **init_gdt** initialize the GDT, some parts of the below function will be explained later and are used for multitasking.
The function **init_gdt** initializes the GDT. Some parts of the below function will be explained later and are used for multitasking.

```cpp
void init_gdt(void)
Expand Down
12 changes: 6 additions & 6 deletions Chapter-7/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
## Chapter 7: IDT and interrupts

An interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention.
An interrupt is a signal to the processor, emitted by hardware or software indicating an event that needs immediate attention.

There are 3 types of interrupts:
There are three types of interrupts:

- **Hardware interrupts:** are sent to the processor from an external device (keyboard, mouse, hard disk, ...). Hardware interrupts were introduced as a way to reduce wasting the processor's valuable time in polling loops, waiting for external events.
- **Software interrupts:** are initiated voluntarily by the software. It's used to manage system calls.
- **Hardware interrupts:** are sent to the processor from an external device (keyboard, mouse, hard disk etc). Hardware interrupts were introduced as a way to reduce wasting the processor's valuable time in polling loops, waiting for external events.
- **Software interrupts:** are initiated voluntarily by the software. These are used to manage system calls.
- **Exceptions:** are used for errors or events occurring during program execution that are exceptional enough that they cannot be handled within the program itself (division by zero, page fault, ...)

#### The keyboard example:
Expand All @@ -14,7 +14,7 @@ When the user pressed a key on the keyboard, the keyboard controller will signal

#### What is the PIC?

The [PIC](http://en.wikipedia.org/wiki/Programmable_Interrupt_Controller) (Programmable interrupt controller)is a device that is used to combine several sources of interrupt onto one or more CPU lines, while allowing priority levels to be assigned to its interrupt outputs. When the device has multiple interrupt outputs to assert, it asserts them in the order of their relative priority.
The [PIC](http://en.wikipedia.org/wiki/Programmable_Interrupt_Controller) (Programmable Interrupt Controller) is a device that is used to combine several sources of interrupt onto one or more CPU lines, while allowing priority levels to be assigned to its interrupt outputs. When the device has multiple interrupt outputs to assert, it asserts them in the order of their relative priority.

The best known PIC is the 8259A, each 8259A can handle 8 devices but most computers have two controllers: one master and one slave, this allows the computer to manage interrupts from 14 devices.

Expand Down Expand Up @@ -247,4 +247,4 @@ _asm_int_%1:
%endmacro
```

These macros will be used to define the interrupt segment that will prevent corruption of the different registries, it will be very useful for multitasking.
These macros will be used to define the interrupt segment that will prevent corruption of the different registries; it will be very useful for multitasking.
18 changes: 6 additions & 12 deletions Chapter-8/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
## Chapter 8: Theory: physical and virtual memory

In the chapter related to the GDT, we saw that using segmentation a physical memory address is calculated using a segment selector and an offset.
In the chapter related to the GDT, we saw that segmentation with a physical memory address can be calculated using a segment selector and an offset.

In this chapter, we are going to implement paging, paging will translate a linear address from segmentation into a physical address.
In this chapter, we are going to implement paging. Paging will translate a linear address from segmentation into a physical address.

#### Why do we need paging?

Expand All @@ -12,7 +12,7 @@ Paging will allow our kernel to:
* to have a unique memory space for each process
* to allow and unallow memory space in a dynamic way

In a paged system, each process may execute in its own 4gb area of memory, without any chance of effecting any other process's memory, or the kernel's. It simplifies multitasking.
In a paged system, each process may execute in its own area of memory, without any chance of affecting any other process' memory or the kernel's – it simplifies multitasking.

![Processes memories](./processes.png)

Expand All @@ -29,7 +29,7 @@ The translation of a linear address to a physical address is done in multiple st

#### Format for pages table and directory

The two types of entries (table and directory) look like the same. Only the field in gray will be used in our OS.
The two types of entries (table and directory) look like the same. Only the field in gray will be used in our particular OS.

![Page directory entry](./page_directory_entry.png)

Expand All @@ -44,7 +44,7 @@ The two types of entries (table and directory) look like the same. Only the fiel
* 0 = 4kb
* 1 = 4mb

**Note:** Physical addresses in the pages diretcory or pages table are written using 20 bits because these addresses are aligned on 4kb, so the last 12bits should be equal to 0.
**Note:** Physical addresses in the pages directory or pages table are written using 20 bits because these addresses are aligned on 4kb, so the last 12 bits should be equal to 0.

* A pages directory or pages table used 1024*4 = 4096 bytes = 4k
* A pages table can address 1024 * 4k = 4 Mb
Expand All @@ -69,10 +69,4 @@ With the identity mapping model, the page will apply only to the kernel as the f

![Identity Mapping](identitymapping.png)

This model is simple: the first virtual memory page coincide to the first page in physical memory, the second page coincide to the second page on physical memory and so on ...






This model is simple: the first virtual memory page coincide to the first page in physical memory, the second page coincide to the second page on physical memory and so on...
4 changes: 2 additions & 2 deletions chapter9/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Memory management: physical and virtual
## Memory management: physical and virtual

The kernel knows the size of the physical memory available thanks to [GRUB](../Chapter-3/README.md).

Expand Down Expand Up @@ -31,4 +31,4 @@ This is implemented by pointing the first 256 entries of the task page directory
*/
for (i=0; i<256; i++)
pdir[i] = pd0[i];
```
```