From 0e5f8442e08959d017cc8c62e37197653eb8eadf Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 21 Mar 2023 16:06:12 +0000 Subject: [PATCH 01/32] Add parts decorators --- .pandoc/decorators/appendix_section.tex | 3 +++ .pandoc/decorators/part_architecture.tex | 1 + .pandoc/decorators/part_build.tex | 1 + .pandoc/decorators/part_ipc.tex | 1 + .pandoc/decorators/part_memory.tex | 1 + .pandoc/decorators/part_scheduling.tex | 1 + .pandoc/decorators/part_userspace.tex | 1 + .pandoc/decorators/part_vfs.tex | 1 + .pandoc/pandoc.yaml | 2 +- 9 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 .pandoc/decorators/appendix_section.tex create mode 100644 .pandoc/decorators/part_architecture.tex create mode 100644 .pandoc/decorators/part_build.tex create mode 100644 .pandoc/decorators/part_ipc.tex create mode 100644 .pandoc/decorators/part_memory.tex create mode 100644 .pandoc/decorators/part_scheduling.tex create mode 100644 .pandoc/decorators/part_userspace.tex create mode 100644 .pandoc/decorators/part_vfs.tex diff --git a/.pandoc/decorators/appendix_section.tex b/.pandoc/decorators/appendix_section.tex new file mode 100644 index 00000000..95e18854 --- /dev/null +++ b/.pandoc/decorators/appendix_section.tex @@ -0,0 +1,3 @@ +\part*{Appendices} +\addcontentsline{toc}{part}{Appendices} +\appendix diff --git a/.pandoc/decorators/part_architecture.tex b/.pandoc/decorators/part_architecture.tex new file mode 100644 index 00000000..cba46ee2 --- /dev/null +++ b/.pandoc/decorators/part_architecture.tex @@ -0,0 +1 @@ +\part{The Architecture} diff --git a/.pandoc/decorators/part_build.tex b/.pandoc/decorators/part_build.tex new file mode 100644 index 00000000..57ee9f84 --- /dev/null +++ b/.pandoc/decorators/part_build.tex @@ -0,0 +1 @@ +\part{Build Process} diff --git a/.pandoc/decorators/part_ipc.tex b/.pandoc/decorators/part_ipc.tex new file mode 100644 index 00000000..a72b1c34 --- /dev/null +++ b/.pandoc/decorators/part_ipc.tex @@ -0,0 +1 @@ +\part{Inter Process Communication} diff --git a/.pandoc/decorators/part_memory.tex b/.pandoc/decorators/part_memory.tex new file mode 100644 index 00000000..973172d0 --- /dev/null +++ b/.pandoc/decorators/part_memory.tex @@ -0,0 +1 @@ +\part{Memory Management} diff --git a/.pandoc/decorators/part_scheduling.tex b/.pandoc/decorators/part_scheduling.tex new file mode 100644 index 00000000..5e00d26b --- /dev/null +++ b/.pandoc/decorators/part_scheduling.tex @@ -0,0 +1 @@ +\part{Scheduling and Processes} diff --git a/.pandoc/decorators/part_userspace.tex b/.pandoc/decorators/part_userspace.tex new file mode 100644 index 00000000..8c6bcb52 --- /dev/null +++ b/.pandoc/decorators/part_userspace.tex @@ -0,0 +1 @@ +\part{Userspace} diff --git a/.pandoc/decorators/part_vfs.tex b/.pandoc/decorators/part_vfs.tex new file mode 100644 index 00000000..862087b4 --- /dev/null +++ b/.pandoc/decorators/part_vfs.tex @@ -0,0 +1 @@ +\part{The Virtual File System} diff --git a/.pandoc/pandoc.yaml b/.pandoc/pandoc.yaml index fc1789e4..a7b3321d 100644 --- a/.pandoc/pandoc.yaml +++ b/.pandoc/pandoc.yaml @@ -5,7 +5,7 @@ author: - Dean T. header-includes: - \usepackage{fvextra} - - \usepackage{appendix} + - \usepackage[page,toc,titletoc,title]{appendix} - \DefineVerbatimEnvironment{Highlighting}{Verbatim}{breaklines,commandchars=\\\{\}} book: true --- From 0f4c36923ca89e2cc1f7eed1ff6d4e218d28dc15 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 21 Mar 2023 19:38:14 +0000 Subject: [PATCH 02/32] Start rearrangin chapter --- .pandoc/decorators/part_video_output.tex | 1 + {98_Drivers => 03_Video_Output}/DrawingTextOnFB.md | 0 {98_Drivers => 03_Video_Output}/Framebuffer.md | 0 {03_Memory_Management => 04_Memory_Management}/01_README.md | 0 .../02_Physical_Memory.md | 0 {03_Memory_Management => 04_Memory_Management}/03_Paging.md | 0 .../04_Virtual_Memory_Manager.md | 0 .../05_Heap_Allocation.md | 0 .../06_Memory_Protection.md | 0 {04_Scheduling => 05_Scheduling}/01_README.md | 0 {04_Scheduling => 05_Scheduling}/02_Scheduler.md | 0 {04_Scheduling => 05_Scheduling}/03_Processes_And_Threads.md | 0 {04_Scheduling => 05_Scheduling}/04_Locks.md | 0 {05_Userspace => 06_Userspace}/01_README.md | 0 {05_Userspace => 06_Userspace}/02_Switching_Modes.md | 0 {05_Userspace => 06_Userspace}/03_Handling_Interrupts.md | 0 {05_Userspace => 06_Userspace}/04_System_Calls.md | 0 {05_Userspace => 06_Userspace}/05_Example_ABI.md | 0 {06_IPC => 07_IPC}/01_README.md | 0 {06_IPC => 07_IPC}/02_Shared_Memory.md | 0 {06_IPC => 07_IPC}/03_Message_Passing.md | 0 {07_VirtualFileSystem => 08_VirtualFileSystem}/01_README.md | 0 .../02_VirtualFileSystem.md | 0 .../03_TarFileSystem.md | 0 {09_Going_Beyond => 10_Going_Beyond}/01_README.md | 0 25 files changed, 1 insertion(+) create mode 100644 .pandoc/decorators/part_video_output.tex rename {98_Drivers => 03_Video_Output}/DrawingTextOnFB.md (100%) rename {98_Drivers => 03_Video_Output}/Framebuffer.md (100%) rename {03_Memory_Management => 04_Memory_Management}/01_README.md (100%) rename {03_Memory_Management => 04_Memory_Management}/02_Physical_Memory.md (100%) rename {03_Memory_Management => 04_Memory_Management}/03_Paging.md (100%) rename {03_Memory_Management => 04_Memory_Management}/04_Virtual_Memory_Manager.md (100%) rename {03_Memory_Management => 04_Memory_Management}/05_Heap_Allocation.md (100%) rename {03_Memory_Management => 04_Memory_Management}/06_Memory_Protection.md (100%) rename {04_Scheduling => 05_Scheduling}/01_README.md (100%) rename {04_Scheduling => 05_Scheduling}/02_Scheduler.md (100%) rename {04_Scheduling => 05_Scheduling}/03_Processes_And_Threads.md (100%) rename {04_Scheduling => 05_Scheduling}/04_Locks.md (100%) rename {05_Userspace => 06_Userspace}/01_README.md (100%) rename {05_Userspace => 06_Userspace}/02_Switching_Modes.md (100%) rename {05_Userspace => 06_Userspace}/03_Handling_Interrupts.md (100%) rename {05_Userspace => 06_Userspace}/04_System_Calls.md (100%) rename {05_Userspace => 06_Userspace}/05_Example_ABI.md (100%) rename {06_IPC => 07_IPC}/01_README.md (100%) rename {06_IPC => 07_IPC}/02_Shared_Memory.md (100%) rename {06_IPC => 07_IPC}/03_Message_Passing.md (100%) rename {07_VirtualFileSystem => 08_VirtualFileSystem}/01_README.md (100%) rename {07_VirtualFileSystem => 08_VirtualFileSystem}/02_VirtualFileSystem.md (100%) rename {07_VirtualFileSystem => 08_VirtualFileSystem}/03_TarFileSystem.md (100%) rename {09_Going_Beyond => 10_Going_Beyond}/01_README.md (100%) diff --git a/.pandoc/decorators/part_video_output.tex b/.pandoc/decorators/part_video_output.tex new file mode 100644 index 00000000..359fb0b0 --- /dev/null +++ b/.pandoc/decorators/part_video_output.tex @@ -0,0 +1 @@ +\part{Video Output} diff --git a/98_Drivers/DrawingTextOnFB.md b/03_Video_Output/DrawingTextOnFB.md similarity index 100% rename from 98_Drivers/DrawingTextOnFB.md rename to 03_Video_Output/DrawingTextOnFB.md diff --git a/98_Drivers/Framebuffer.md b/03_Video_Output/Framebuffer.md similarity index 100% rename from 98_Drivers/Framebuffer.md rename to 03_Video_Output/Framebuffer.md diff --git a/03_Memory_Management/01_README.md b/04_Memory_Management/01_README.md similarity index 100% rename from 03_Memory_Management/01_README.md rename to 04_Memory_Management/01_README.md diff --git a/03_Memory_Management/02_Physical_Memory.md b/04_Memory_Management/02_Physical_Memory.md similarity index 100% rename from 03_Memory_Management/02_Physical_Memory.md rename to 04_Memory_Management/02_Physical_Memory.md diff --git a/03_Memory_Management/03_Paging.md b/04_Memory_Management/03_Paging.md similarity index 100% rename from 03_Memory_Management/03_Paging.md rename to 04_Memory_Management/03_Paging.md diff --git a/03_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md similarity index 100% rename from 03_Memory_Management/04_Virtual_Memory_Manager.md rename to 04_Memory_Management/04_Virtual_Memory_Manager.md diff --git a/03_Memory_Management/05_Heap_Allocation.md b/04_Memory_Management/05_Heap_Allocation.md similarity index 100% rename from 03_Memory_Management/05_Heap_Allocation.md rename to 04_Memory_Management/05_Heap_Allocation.md diff --git a/03_Memory_Management/06_Memory_Protection.md b/04_Memory_Management/06_Memory_Protection.md similarity index 100% rename from 03_Memory_Management/06_Memory_Protection.md rename to 04_Memory_Management/06_Memory_Protection.md diff --git a/04_Scheduling/01_README.md b/05_Scheduling/01_README.md similarity index 100% rename from 04_Scheduling/01_README.md rename to 05_Scheduling/01_README.md diff --git a/04_Scheduling/02_Scheduler.md b/05_Scheduling/02_Scheduler.md similarity index 100% rename from 04_Scheduling/02_Scheduler.md rename to 05_Scheduling/02_Scheduler.md diff --git a/04_Scheduling/03_Processes_And_Threads.md b/05_Scheduling/03_Processes_And_Threads.md similarity index 100% rename from 04_Scheduling/03_Processes_And_Threads.md rename to 05_Scheduling/03_Processes_And_Threads.md diff --git a/04_Scheduling/04_Locks.md b/05_Scheduling/04_Locks.md similarity index 100% rename from 04_Scheduling/04_Locks.md rename to 05_Scheduling/04_Locks.md diff --git a/05_Userspace/01_README.md b/06_Userspace/01_README.md similarity index 100% rename from 05_Userspace/01_README.md rename to 06_Userspace/01_README.md diff --git a/05_Userspace/02_Switching_Modes.md b/06_Userspace/02_Switching_Modes.md similarity index 100% rename from 05_Userspace/02_Switching_Modes.md rename to 06_Userspace/02_Switching_Modes.md diff --git a/05_Userspace/03_Handling_Interrupts.md b/06_Userspace/03_Handling_Interrupts.md similarity index 100% rename from 05_Userspace/03_Handling_Interrupts.md rename to 06_Userspace/03_Handling_Interrupts.md diff --git a/05_Userspace/04_System_Calls.md b/06_Userspace/04_System_Calls.md similarity index 100% rename from 05_Userspace/04_System_Calls.md rename to 06_Userspace/04_System_Calls.md diff --git a/05_Userspace/05_Example_ABI.md b/06_Userspace/05_Example_ABI.md similarity index 100% rename from 05_Userspace/05_Example_ABI.md rename to 06_Userspace/05_Example_ABI.md diff --git a/06_IPC/01_README.md b/07_IPC/01_README.md similarity index 100% rename from 06_IPC/01_README.md rename to 07_IPC/01_README.md diff --git a/06_IPC/02_Shared_Memory.md b/07_IPC/02_Shared_Memory.md similarity index 100% rename from 06_IPC/02_Shared_Memory.md rename to 07_IPC/02_Shared_Memory.md diff --git a/06_IPC/03_Message_Passing.md b/07_IPC/03_Message_Passing.md similarity index 100% rename from 06_IPC/03_Message_Passing.md rename to 07_IPC/03_Message_Passing.md diff --git a/07_VirtualFileSystem/01_README.md b/08_VirtualFileSystem/01_README.md similarity index 100% rename from 07_VirtualFileSystem/01_README.md rename to 08_VirtualFileSystem/01_README.md diff --git a/07_VirtualFileSystem/02_VirtualFileSystem.md b/08_VirtualFileSystem/02_VirtualFileSystem.md similarity index 100% rename from 07_VirtualFileSystem/02_VirtualFileSystem.md rename to 08_VirtualFileSystem/02_VirtualFileSystem.md diff --git a/07_VirtualFileSystem/03_TarFileSystem.md b/08_VirtualFileSystem/03_TarFileSystem.md similarity index 100% rename from 07_VirtualFileSystem/03_TarFileSystem.md rename to 08_VirtualFileSystem/03_TarFileSystem.md diff --git a/09_Going_Beyond/01_README.md b/10_Going_Beyond/01_README.md similarity index 100% rename from 09_Going_Beyond/01_README.md rename to 10_Going_Beyond/01_README.md From 7276427cd13969bccce291ec2ae3ad03aab3b339 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 28 Mar 2023 11:32:58 +0100 Subject: [PATCH 03/32] Adding new section, typo fixes and some expansions --- .pandoc/decorators/part_architecture.tex | 2 +- 01_Build_Process/01_README.md | 14 +- 01_Build_Process/02_Overview.md | 8 + 02_Architecture/01_README.md | 4 + .../04_Virtual_Memory_Manager.md | 2 +- 05_Scheduling/01_README.md | 6 +- 98_Drivers/ACPITables.md | 162 --------- 98_Drivers/APIC.md | 314 ------------------ 98_Drivers/PS2_Keyboard/01_README.md | 47 --- .../PS2_Keyboard/02_Interrupt_Handling.md | 111 ------- .../PS2_Keyboard/03_Driver_Implementation.md | 297 ----------------- 98_Drivers/Timers.md | 292 ---------------- 98_Drivers/test.pdf | Bin 0 -> 168665 bytes README.md | 47 +-- 14 files changed, 50 insertions(+), 1256 deletions(-) delete mode 100644 98_Drivers/ACPITables.md delete mode 100644 98_Drivers/APIC.md delete mode 100644 98_Drivers/PS2_Keyboard/01_README.md delete mode 100644 98_Drivers/PS2_Keyboard/02_Interrupt_Handling.md delete mode 100644 98_Drivers/PS2_Keyboard/03_Driver_Implementation.md delete mode 100644 98_Drivers/Timers.md create mode 100644 98_Drivers/test.pdf diff --git a/.pandoc/decorators/part_architecture.tex b/.pandoc/decorators/part_architecture.tex index cba46ee2..af3e919d 100644 --- a/.pandoc/decorators/part_architecture.tex +++ b/.pandoc/decorators/part_architecture.tex @@ -1 +1 @@ -\part{The Architecture} +\part{Architecture And Basic Driers} diff --git a/01_Build_Process/01_README.md b/01_Build_Process/01_README.md index d89a6158..1219d73f 100644 --- a/01_Build_Process/01_README.md +++ b/01_Build_Process/01_README.md @@ -1,11 +1,13 @@ # Kernel Build Process & Booting -This section covers some of the very first topics you'll need to know when building a kernel. Why you need a custom linker script, and how to write one, setting up a build system (we use make) and finally which boot protocol and bootloader to use. -- [General Overview](02_Overview.md) -- [Boot Protocols & Bootloaders](03_Boot_Protocols.md) -- [Makefiles](04_Gnu_Makefiles.md) -- [Linker Scripts](05_Linker_Scripts.md) -- [Generating A Bootable Iso](06_Generating_Iso.md) +An OS like any other project needs to be built, and packaged in a special way in order to be "booted". +This part will cover all the steps needed to have an initial set of building script for our os, and also explore some of the bootloader that can be used to load our kernel. + +- [General Overview](02_Overview.md) This chapter will a high level overview of the building process, introducing some of the basic concepts and tools that will be used in the following chapters and showing two possible compiler options +- [Boot Protocols & Bootloaders](03_Boot_Protocols.md) Here we will explore two possible solutions for booting our kernel: Multiboot2 and Stivale, explaining how they must be used and configured in order to boot our kernel +- [Makefiles](04_Gnu_Makefiles.md) The building script, we are going to use: Makefile. +- [Linker Scripts](05_Linker_Scripts.md) Probably one of the most _obscure_ parts of the building process, especially for beginners, this chapter explains what are the linker scripts, why they are important, an how to write one. +- [Generating A Bootable Iso](06_Generating_Iso.md) After building our kernel we want to run it too (yeah like the cake...) but for doing that we need a bootable support, only the kernel file is not enough, this chapter will show how to create a bootable iso and start to test it on emulators/real hardware. ## Useful Links diff --git a/01_Build_Process/02_Overview.md b/01_Build_Process/02_Overview.md index 07548d7c..ec14681d 100644 --- a/01_Build_Process/02_Overview.md +++ b/01_Build_Process/02_Overview.md @@ -132,6 +132,7 @@ For an explanation of the above linker flags used: One other linker option to keep in mind is `-M`, which displays the link map that was generated. This is a description of how and where the linker allocated everything in the final file. It can be seen as a manual symbol table. ### Building with Makefiles + Now compiling and building one file isn't so bad, but the same process for multiple files can quickly get out of hand. This is especially true when you only want to build files that have been modified, and use previously compiled versions of other files. Make is a common tool used for building many pieces of software due to how easy and commmon `make` is. Specifically GNU make. GNU make is also chosen as it comes installed by default in many linux distros, and is almost always available if it's not already installed. @@ -139,6 +140,7 @@ Make is a common tool used for building many pieces of software due to how easy There are other make-like tools out there (xmake, nmake) but these are less popular, and therefore less standardized. For the lowest common denominator we'll stick with the original GNU make, which is discussed later on in this chapter, in it's own section. ## Quick Addendum: Easily Generating a Bootable Iso + There are more details to this, however most bootloaders will provide a tool that lets you create a bootable iso, with the kernel, the bootloader itself and any other files you might want. For grub this is `grub-mkrescue` and limine provides `limine-install` for version 2.x or `limine-deploy` for version 3.x. While the process of generating an iso is straightforward enough when using something like xorisso, the process of installing a bootloader into that iso is usually bootloader dependent. This is covered more in detail in it's own section. @@ -146,6 +148,7 @@ While the process of generating an iso is straightforward enough when using some If you're just here for a quick reference, grub uses `grub-mkrescue` and a grub.cfg file, limine reqiures you to build the iso yourself with a limine.cfg on it, and then run `limine-deploy`. ## Testing with An Emulator + Now we have an iso with our bootloader and kernel installed onto it, how do we test this? Well there's a number of emulators out there, with varying levels of performance and debug utility. Generally the more debug functionality an emulator provides, the slower it will run. A brief comparison of some common x86 emulators is provided below. - Qemu is great middle ground between debugging and speed. By default your OS will run using software virtualization (qemu's implementation is called tcg), but you can optionally enable kvm with the `--enable-kvm` flag for hardware-assisted virtualization. Qemu also provides a wide range of supported platforms. @@ -177,6 +180,7 @@ There are a few other qemu flags you might want to be aware of: - `-no-shutdown` some configurations of qemu will shutdown if `-no-reboot` is specified, instead of pausing the VM. This flag forces qemu to stay open, but paused. ## Building and Using Debugging Symbols + You'll never know when you need to debug your kernel, especially when running in a virtualized environment. Having debug symbols included in your kernel will increase the file size, but can be useful. If you want to remove them from an already compiled kernel the `strip` program can be used to strip excess info from a file. Including debug info in the kernel is the same as any other program, simply compile with the `-g` flag. @@ -186,12 +190,15 @@ There are different versions of DWARF (the debugging format used by elf files), Getting access to these debug symbols is dependent on the boot protocol used: ### Multiboot 2 + Multiboot 2 provides the Elf-Symbols (section 3.6.7 of the spec) tag to the kernel which provides the elf section headers and the location of the string table. Using these is described below in the stivale section. ### Stivale 2 + Stivale2 uses a similar and slightly more complex (but more powerful) mechanism of providing the entire kernel file in memory. This means you're not limited to just using elf files, and can access debug symbols from a kernel in any format. This is because you have the file base address and length and have to do the parsing yourself. ### ELFs Ahead, Beware! + This section is included to show how elf symbols could be loaded and parsed, but it is not a tutorial on the elf format itself. If you're unfamiliar with the format, give the elf64 specification a read! It's quite straightforward, and written very plainly. This section makes refernce to a number a of structures and fields from the specification. With that warning out of the way, let's look at the two fields from the elf header we're interested in. If you're using the multiboot 2 info, you will be given these fields directly. For stivale 2, you will need to parse the elf header yourself. We're interested in `e_shoff` (the section header offset) and `e_shstrndx` (the section header string index). @@ -212,6 +219,7 @@ Now to get the name of a section, you'll need to find the matching symbol entry, Languages built around the C model will usually perform some kind of name mangling to enable features like function overloading, namespaces and so on. This is a whole topic on it's own. Name mangling can be through of as a translation that takes place, to allow things like function overloading and templates to work in the C naming model. ### Locating The Symbol Table + We'll need to access the data stored in the string table quite frequently for looking up symbols, so let's calculate that and store it in the variable `char* strtab_data`. For both protocols it's assumed that you have found the tag returned by the bootloader that contains the location of the elf file/elf symbols. ```c diff --git a/02_Architecture/01_README.md b/02_Architecture/01_README.md index f21c00b5..50caefe7 100644 --- a/02_Architecture/01_README.md +++ b/02_Architecture/01_README.md @@ -51,3 +51,7 @@ When an unexpected event happens, the cpu will immediately stop the current code The interrupted code is usually never aware that an interrupt even occured, and should continue on as normal. +# Drivers + +Not device drivers for graphic cards, network interfaces, and other hardware, but on early stages of development we will need some basic drivers to implement some of the future features, for example we will need to have at least one supported Timer to implement the scheduler, we will most likely want to add a basic support for a keyboard in order to implement a cli, these topics will be covered in this section, along with other architecture specific drivers required by the CPU. + diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index 7ffecdc8..345a66f8 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -121,7 +121,7 @@ vm_object* vm_objs = NULL; Now onto our alloc function. The first thing it will need to do is align the length up to the nearest page. This should look familiar. ```c -length = (length + (PAGE_SIZE - 1)) / PAGE_SIZE * PAGE_SIZE; +length = (length + (PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; ``` The next step is to find a space between two VM objects big enough to hold `length` bytes. We'll also want to handle the edge cases of allocating before the first object, after the last object, or if there are no VM objects in the list at all. diff --git a/05_Scheduling/01_README.md b/05_Scheduling/01_README.md index 5391a62e..7250255b 100644 --- a/05_Scheduling/01_README.md +++ b/05_Scheduling/01_README.md @@ -1,10 +1,10 @@ # Scheduling And Tasks -So far our kernel has been running a single stream of code, initializing various parts of the cpu and system hardware in sequence. While it is possible to go further, we'll begin to run into a handfuls of problems. Some hardware takes *time* to perform actions, and our code may need to wait. If we have a lot of devices this can lead to things becoming very slow. What if we want to start running multiple threads, or even multiple programs with multiple threads? This is a common scenario, and what the scheduler is responsible for. +So far our kernel has been running a single stream of code, initializing various parts of the cpu and system hardware in sequence and handling interrupts from few sources. While it is possible to go further, we'll begin to run into a handfuls of problems. Some hardware takes *time* to perform actions, and our code may need to wait. If we have a lot of devices this can lead to things becoming very slow. What if we want to start running multiple threads, or even multiple programs with multiple threads? This is a common scenario, and what the scheduler is responsible for. -The scheduler is similar to a hardware multiplexer (mux) in that it takes multiple inputs (programs or threads) and allows them to share a single output (the cpu executing the code). The scheduler does this by interrupting the current stream of code, saving it's state, selection the next stream, loading the new state and then returning. If done at a fast enough rate, all programs will get to spend a little time running, and to the user it will appear as if all programs are running at the same time. This whole operation is called a *context switch*. +The scheduler is similar to a hardware multiplexer (mux) in that it takes multiple inputs (programs or threads) and allows them to share a single output (the cpu executing the code). The scheduler does this by interrupting the current stream of code, saving it's state, selecting the next stream, loading the new state and then returning. If done at a fast enough rate, all programs will get to spend a little time running, and to the user it will appear as if all programs are running at the same time. This whole operation is called a *context switch*. -For our examples the scheduler is going to do it's selection inside of an interrupt handler, as that's the simplest way to get started. As always, there are other designs out there. +For our examples the scheduler is going to do its selection inside of an interrupt handler, as that's the simplest way to get started. As always, there are other designs out there. This section will cover two main areas: diff --git a/98_Drivers/ACPITables.md b/98_Drivers/ACPITables.md deleted file mode 100644 index 5cafcbc7..00000000 --- a/98_Drivers/ACPITables.md +++ /dev/null @@ -1,162 +0,0 @@ -# Acpi Tables - -ACPI (Advanced Configuration and Power Interface) is a Power Management and configuration standard for the PC, it allows operating systems to control many different hardware features, like amount of power on each device, thermal zones, fan control, IRQs, battery levels etc. - -We need to access the ACPI Tables in order to read the IO-Apic information, used to receive hardware interrupts (it will be explained later) - -## RSDP and RSDT/XSDT - -Many of the information are organized and accessible through different data structures, but since the ACPI specs are quite big, and cover so many different components, we focus only on what we just need to get the informations we need about the APIC. - -Before proceeding let's keep in mind that all address described below are physical, so if we will enable paging, keep in mind that we need to ensure they are properly mapped in the virtual memory spacea. - -### RSDP - -The RSDP (Root System Description Pointer) used in the ACPI programming interface is the pointer to the RSDT (Root System Descriptor Table) the full structure is depending if the version of ACPI used is 1 or 2, the newer version is just extending the previous one. - -The newer version is backward compatible with the older. - -#### Accessing the RSDP - -Accessing the RSDP register depends on the boot system used, if we are using grub, we get a copy of the RSDT/XSDT in one of the multiboot2 header tags. The specs contains two possible tags for the RSDP value, which one is used depend on the version: - -* For the version 1 the MULTIBOOT_TAG_TYPE_ACPI_OLD is used (type 14) -* For the version 2 the MULTIBOOT_TAG_TYPE_ACPI_NEW is used (type 15) - -Both headers are identical, with the only difference being in the type value, they are compoosed of just two fields: - -* The type field that can be 14 or 15 depending on the version -* The size of the RSDP - -And is followed by the RSDP itself. - -#### RSDP Structure - -As already mentioned there are two different version of RSDP, basic data structure for RSDP v1 is: - -```c -struct RSDPDescriptor { - char Signature[8]; - uint8_t Checksum; - char OEMID[6]; - uint8_t Revision; - uint32_t RsdtAddress; -} __attribute__ ((packed)); -``` - -Where the fields are: - -* *Signature*: Is an 8 byte string, that must contain: "RSDT PTR " **P.S. The string is not null terminated** -* *Checksum*: The value to add to all the other bytes (of the Version 1.0 table) to calculate the Checksum of the table. If this value added to all the others and casted to byte isn't equal to 0, the table must be ignored. -* *OEMID*: Is a string that identifies the OEM -* *Revision*: Is the revision number -* *RSDTAddress*: The address of the RSDT Table - -The structure for the v2 header is an extension of the previous one, so the fields above are still valid, but in addition it has also the following extra-fields: - -```c -struct RSDP2Descriptor -{ - //v1 fields - uint32_t Length; - uint64_t XSDTAddress; - uint8_t ExtendedChecksum; - uint8_t Reserved[3]; -}; -``` - -* *Length*: is the length of this data and its data, meaning the xsdt + all the other SDTs. -* *XSDTAddress*: Address of the XSDT table. If this is non-zero, the RSDT address **must** be ignored and the XSDT is to be used instead. -* *ExtendedChecksum*: Same as the previous checksum, just includes the new fields. - -#### RSDP Validation - -Before proceeding let's explain little bit better the validation. For both version what we need to check is that the sum of all bytes composing the descriptor structure have last byte equals to 0. How is possible to achieve that, and keep the same function for both? That is pretty easy, we just need cast the `RSDP*Descriptor` to a char pointer, and pass the size of the correct struct. Once we have done that is just mutter of cycling a byte array. Here the example code: - -```c -bool validate_RSDP(char *byte_array, size_t size) { - uint32_t sum = 0; - for(int i = 0; i < size; i++) { - sum += byte_array[i]; - } - return (sum & 0xFF) == 0; -} -``` - -Having last byte means that `result mod 0x100` is 0. Now there are two ways to test it: - -* Using the `mod` instruction, and check the result, if is 0 the structure is valid, otherwise it should be ignored -* Just checking the last byte of the result it can be achieved in several ways: for example is possible cast the result to `uint_8` if the content after casting is 0 the struct is valid, or use bitwise AND with `0xFF` value (`0xFF` is equivalent to the 0b11111111 byte) `sum & 0xFF`, if it is 0 the struct is valid otherwise it has to be ignored. - -The function above works perfectly with both versions of descriptors. -In the XSDT since it has more fields, the previous checksum field wont offset them properly (because it doesn't know about them), so this is why an extended checksum field is added. - -### RSDT Data structure and fields - -RSDT (Root System Description Table) is a data structure used in the ACPI programming interface. This table contains pointers to many different table descriptor (SDTs). Explaining all the tables is beyond of the scope of these notes, and for our purpose we are going to need only one of those table (the APIC table that we will enocunter later). - -Since every SDT table contains different type of information, they are all different from each other, we can define an RSDT table by the composition of two parts: - -* the first part is the header, common between all the SDTs with the following structure: - -```c -struct ACPISDTHeader { - char Signature[4]; - uint32_t Length; - uint8_t Revision; - uint8_t Checksum; - char OEMID[6]; - char OEMTableID[8]; - uint32_t OEMRevision; - uint32_t CreatorID; - uint32_t CreatorRevision; -}; -``` -* The second part is the table itself, every SDT has it's own table - -#### RSDT vs XSDT - -These 2 tables have the same purpose and are mutually exclusive. If the latter exists, the former is to be ignored, otherwise use the former. - -The RSDT is an SDT header followed by an array of `uint32_t`s, representing the address of another SDT header. - -The XSDT is the same, except the array is of `uint64_t`s. - -```c -struct RSDP -{ - ACPISDTHeader sdtHeader; //signature "RSDP" - uint32_t sdtAddresses[]; -}; - -struct XSDT -{ - ACPISDTHeader sdtHeader; //signature "XSDT" - uint64_t sdtAddresses[]; -}; -``` - -This means that if we want to get the n-th SDT table we just need to acces the corresponding item in the *SDT array: - -```c -//to get the sdt header at n index -ACPISDTHeader* header = (ACPISDTHeader*)(use_xsdt ? xsdt->sdtAddresses[n] : (uint64_t)rsdt->sdtAddresses[n]); -``` - -### Some useful infos - -* Be aware that the Signature in the RSD* structure is not null terminated. This means that if you try to print it, you will most likely end up in printing garbage in the best case scenario. -* The RSDT Data is an array of uint32_t addresses while the XSDT data is an array of uint64_t addresses. The number of items in the RSDT and XSDT can be computed in the following way: - -```c -//for the RSDT -size_t number_of_items = (rsdt->sdtHeader.Length - sizeof(ACPISDTheader)) / 4; -//for the XSDT -size_t number_of_items = (xsdt->sdtHeader.Length - sizeof(ACPISDTHeader)) / 8; -``` - -## Useful links - -* Osdev wiki page for RSDP: https://wiki.osdev.org/RSDP -* Osdev wiki page for RSDT: https://wiki.osdev.org/RSDT - diff --git a/98_Drivers/APIC.md b/98_Drivers/APIC.md deleted file mode 100644 index 9f95cba7..00000000 --- a/98_Drivers/APIC.md +++ /dev/null @@ -1,314 +0,0 @@ -# APIC - -## What is APIC - -APIC stands for *Advanced Programmable Interrupt Controller*, and it's the device used to manage incoming interrupts to a processor core. It replaces of the old PIC8259 (that remains still available), but it offers more functionality especially when dealing with SMP. In fact one of the limitations of the PIC was that it was able to deal with only one cpu at time, and this is also the main reason why the APIC was firstly introduced. - -It's worth noting that Intel later developed a version of the APIC called the SAPIC for the Itanium platform. These are referred to collectively as the *xapic*, so if you see this term used in documentation know that it just means the local APIC. - -## Types of APIC - -There are two types of APIC: - -* _Local APIC_: it is present in every processor core, it is responsible for handling incoming interrupts for *that core*. It can also be used for sending an IPI (inter-processor interrupt) to other cores, as well as generating some interrupts itself. Interrupts generated by the local APIC are controlled by the LVT (local vector table), which is part of the local APIC registers. The most interesting of these is the timer LVT, which we will take a closer look at in the timers chapter. -* _IO/APIC_: An IO APIC acts a 'gateway' for devices in the system to send interrupts to local APICs. Most personal computers will only have a single IO APIC, but more complex systems (like servers or industrial equipment) may contain multiple IO APICs. Each IO APIC has a number of input pins, which a connected device triggers when it wants to send an interrupt. When this pin is triggered, the IO APIC will send an interrupt to one (or many) local APICs, depending on the *redirection entry* for that pin. We can program these redirection entries, and they're presented as an array of memory-mapped registers. We'll look more at this later. In summary, an IO APIC allows us to route device interrupts to processor cores however we want. - -Both types of APIC are accessed by memory mapped registers, with 32-bit wide registers. They both have well-known base addresses, but rather than hardcoding these they should be fetched from the proper places as firmware (or even the bootloader) may move these around before our kernel boots. - -## Local APIC - -When a system boots up, the cpu starts in PIC8259A emulation mode for legacy reasons. This simply means that instead of having the LAPIC/IO-APIC up and running, we have them working to emulate the old interrupt controller, so before we can use them properly we should to disable the PIC8259 emulation. - -### Disabling The PIC8259 - -This part should be pretty straightforward, and we will not go deep into explaining the meaning of all command sent to it. The sequence of commands is: - -```c -void disable_pic() { - outportb(PIC_COMMAND_MASTER, ICW_1); - outportb(PIC_COMMAND_SLAVE, ICW_1); - outportb(PIC_DATA_MASTER, ICW_2_M); - outportb(PIC_DATA_SLAVE, ICW_2_S); - outportb(PIC_DATA_MASTER, ICW_3_M); - outportb(PIC_DATA_SLAVE, ICW_3_S); - outportb(PIC_DATA_MASTER, ICW_4); - outportb(PIC_DATA_SLAVE, ICW_4); - outportb(PIC_DATA_MASTER, 0xFF); - outportb(PIC_DATA_SLAVE, 0xFF); -} -``` - -The old x86 architecture had two PIC processor, and they were called "master" and "slave", and each of them has it's own data port and command port: - -* Master PIC command port: `0x20` and data port: `0x21`. -* Slave PIC command port: `0xA0` and data port `0xA1`. - -The ICW values are initialization commands (ICW stands for Initialization Command Words), every command word is one byte, and their meaning is: - -* ICW_1 (value `0x11`) is a word that indicates a start of inizialization sequence, it is the same for both the master and slave pic. -* ICW_2 (value `0x20` for master, and `0x28` for slave) are just the interrupt vector address value (IDT entries), since the first 31 interrupts are used by the exceptions/reserved, we need to use entries above this value (remember that each pic has 8 different irqs that can handle. -* ICW_3 (value `0x2` for master, `0x4` for slave) Is is used to indicate if the pin has a slave or not (since the slave pic will be connected to one of the interrupt pins of the master we need to indicate which one is), or in case of a slave device the value will be it's id. On x86 architectures the master irq pin connected to the slave is the second, this is why the value of ICW_M is 2 -* ICW_4 contains some configuration bits for the mode of operation, in our case we just tell that we are going to use the 8086 mode. -* Finally `0xFF` is used to mask all interrupts for the pic. - -### Discovering the Local APIC - -The first step needed to configure the LAPIC is getting access to it. The APIC registers are memory mapped, and to get their location we need to read the MSR (*model specific register*) that contains its base address, using the __rdmsr__ instruction. This instruction reads the content of the MSR specified in `ecx`, the result is placed in `eax` and `edx` (with `eax` containing the lower 32-bits, and `edx` container the upper 32-bits). - -In our case the MSR that we need to read is called IA32_APIC_BASE and its value is `0x1B`. - -This register contains the following information: - -* Bits 0:7: reserved. -* Bit 8: if set, it means that the processor is the Bootstrap Processor (BSP). -* Bits 9:10: reserved. -* Bit 11: APIC global enable. This bit can be cleared to disable the local APIC for this processor. Realistically there is no reason to do this on modern processors. -* Bits 12:31: Contains the base address of the local APIC for this processor core. -* Bits 32:63: reserved. - -Note that the registers are given as a *physical address*, so to access these you will need to map them somewhere in the virtual address space. This is true for the addresses of any IO APICs you obtain as well. When the system boots, the base address is usually `0xFEE0000` and often this is the value we read from `rdmsr`. - -A complete list of local APIC registers is available in the Intel/AMD software development manuals, but the important ones for now are: - -- Spurious Interrupt Vector: offset `0xF0`. -- EOI (end of interrupt): offset `0xB0`. -- Timer LVT: offset `0x320`. -- Local APIC ID: offset `0x20`. - -### Enabling the Local APIC, and The Spurious Vector - -The spurious vector register is also contains some miscellanious config for the local APIC, including the enable/disable flag. This register has the following format: - -| Bits | Value | -|-------|------------------------------| -| 0-7 | Spurious vector | -| 8 | APIC Software enable/disable | -| 9 | Focus Processor checking | -| 10-31 | Reserved | - -The functions of the fields in the registers are as follows: - -* Bits 0-7: They determine the vector number (IDT entry) for the spurious interrupt generated by the APIC. -* Bit 8: This bit acts a software toggle for enabling the local APIC, if set the local APIC is enabled. -* Bit 9: This is an optional feature not available on processors, but if set it indicates that some interrupts can be routed according to a list of priorities. This is an advanced topic and this bit can be safely left clear and ignored. - -The Spurious Vector register is writable only in the first 9 bits, the rest is read only. In order to enable the lapic we need to set bit 8, and set-up a spurious vector entry for the idt. In modern processors the spurious vector can be any vector, however old CPUs have the upper 4 bits of the spurious vector forced to 1, meaning that the vector must be between `0xF0` and `0xFF`. For compatibility it's best to place your spurious vector in that change. Of course we need to set-up the corresponding idt entry with a function to handle it, but for now printing an error message is enough. - -### Reading APIC Id and Version - -The ID register contains the *physical id* of the local APIC in the system. This is unique and assigned by the firmware when the system is first started. Often this ID is used to distinguish each processor from the others due to them being unique. This register is allowed to be read/write in some processors, but it's recommended to treat it as read-only. - -The version register contains some useful (if not really needed) information. Exploring this register is left as an exercise to the reader. - -### Local Vector Table - -The local vector table allows the software to specify how the local interrupts are delivered. -There are 6 items in the LVT starting from offset `0x320` to `0x370`: - -* *Timer*: used for controlling the local APIC timer. Offset: `0x320`. -* *Thermal Monitor*: used for configuring interrupts when certain thermal conditions are met. Offset: `0x330`. -* *Performance Counter*: allows an interrupt to be generated when a performance counter overflows. Offset: `0x340`. -* *LINT0*: Specifies the interrupt delivery when an interrupt is signaled on LINT0 pin. Offset: `0x350`. -* *LINT1*: Specifies the interrupt delivery when an interrupt is signaled on LINT1 pin. Offset: `0x360`. -* *Error*: configures how the local APIC should report an internal error, Offset `0x370`. - -The `LINT0` and `LINT1` pins are mostly used for emulating the legacy PIC, but they may also be used as NMI sources. These are best left untouched until you have parsed the MADT, which will tell you how you should program the LVT for these pins. - -Most LVT entries use the following format, with the timer LVT being the notable exception. It's format is explained in the timers chapter. The thermal sensor and performance entries ignore bits 15:13. - -| Bit | Description | -|----------|----------------------------------------------------------------------------------------------| -| 0:7 | Interrupt Vector. This is the IDT entry we want to trigger when for this interrupt. | -| 8:10 | Delivery mode (see below) | -| 11 | Destination Mode, can be either physical or logical. | -| 12 | Delivery Status **(Read Only)**, whether the interrupt has been served or not.| -| 13 | Pin polarity: 0 is active-high, 1 is active-low. | -| 14 | Remote IRR **(Read Only)** used by the APIC for managing level-triggered interrupts. | -| 15 | Trigger mode: 0 is edge-triggered, 1 is level-triggered. | -| 16 | Interrupt mask, if it is 1 the interrupt is disabled, if 0 is enabled. | - -The delivery mode field determines how the the APIC should present the interrupt to the processor. The fixed mode (0b000) is fine in almost all cases, the other modes are for specific functions or advanced usage. - -### X2 APIC - -The X2APIC is an extension of the XAPIC (the local APIC in it's regular mode). The main difference is the registers are now accessed via MSRs and some the ID register is expanded to use a 32-bit value (previously 8-bits). While we're going to look at how to use this mode, it's perfectly fine to not support it. - -Checking whether the current processor supports the X2APIC or not can be done via `cpuid`. It will be under leaf 1, bit 21 in `ecx`. If this bit is set, your processor supoorts the X2APIC. - -Enabling the X2APIC is done by setting bit 10 in the IA32_APIC_BASE MSR. It's important to note that once this bit is set, you cannot clear it to transition back to the regular APIC operation without resetting the system. - -Once enabled, the local APIC registers are no longer memory mapped (trying to access them there is now an error) and can instead be accessed as a range of MSRs starting at `0x800`. Since each MSR is 64-bits wide, the offset used to access an APIC register is shifted right by 4 bits. - -As an example, the spurious interrupt register is offset `0xF0`. To access the MSR version of this register we would shift it right by 4 (`0xF0 >> 4` = 0xF) and then add the base offset (`0x800`) to get the MSR we want. That means the spurious interrupt register is MSR `0x80F`. - -Since MSRs are 64-bits, the upper 32 bits are zero on reads and ignored on writes. As always there is an exception to this, which is the ICR register (used for sending IPIs to other cores) which is now a single 64-bit register. - -### Handling Interrupts - -Once an interrupt for the local APIC is served, it won't send any further interrupts until the end of interrupt signal is sent. To do this write a 0 to the EOI register, and the local APIC will resume sending interrupts to the processor. This is a separate mechanism to the interrupt flag (IF), which also disables interrupts being served to the processor. It is possible to send EOI to the local APIC while IF is cleared (disabling interrupts) and no futher interrupts will be served until IF is set again. - -There are few exceptions where sending an EOI is not needed, this is mainly spurious interrupts and NMIs. - -The EOI can be sent at any time when handling an interrupt, but it's important to do it before returning with `iret`. If you enable interrupts and only receive a single interrupt, forgetting to send EOI may be the reason. - -### Sending An IPI - -If you want to support SMP (multiple cores) in your kernel, you will need a way to inform other cores that an event has occured. This is typically done by sending an IPI. Note that IPIs don't carry any information about what event occureed, they simply indicate that *something* has happened. To send data about what the event is a struct is usually placed in memory somewhere, sometimes called a *mailbox*. - -To send an IPI we need to know the local APIC ID of the core we wish to interrupt. We will also need a vector in the IDT set up for handling IPIs. With these two things we can use the ICR (interrupt command register). - -The ICR is 64-bits wide and therefore we access it as two registers (a higher and lower half). The IPI is sent when the lower register is written to, so we should set up the destination in the higher half first, before writing the vector in the lower half. - -This register contains a few fields but most can be safely ignored and left to zero. We're interested in bits 63:56 which is the ID of the target local APIC (in X2APIC mode it's bits 63:32) and bits 7:0 which contain the interrupt vector that will be served on the target core. - -An example function might look like the following: - -```c -void lapic_send_ipi(uint32_t dest_id, uint8_t vector) { - lapic_write_reg(ICR_HIGH, dest_id << 24); - lapic_write_reg(ICR_LOW, vector); -} -``` - -At this point the target core would receive an interrupt with the vector we specified (assuming that core is setup correctly). - - -There is also a shorthand field in the ICR which overrides the destination id. It's available in bits 19:18 and has the following definition: - -- 0b00: no shorthand, use the destination id. -- 0b01: send this IPI to ourselves, no one else. -- 0b10: send this IPI to all lapics, including ourselves. -- 0b11: send this IPI to all lapics, but not ourselves. - -## IOAPIC - -The IOAPIC primary function is to receive external interrupt events from the systems, and is associated with I/O devices, and relay them to the local apic as interrupt messages, with the exception of the lapic timer, all external devices are going to use the IRQs provided by it (like it was done in the passt by the PIC8259). - -### Configure the IO-APIC - -To configure the IO-APIC we need to: - -1. Get the IO-APIC base address from the MADT -2. Read the IO-APIC Interrupt Source Override table -3. Initialize the IO Redirection table entries for the interrupt we want to enable - -### Getting IO-APIC address - -Read IO-APIC information from MADT table (the MADT table is available within the RSDT data (please refer here: https://github.com/dreamos82/Osdev-Notes/blob/master/RSDP_and_RSDT.md), you need to search for the MADT Table item type 1). The content of the MADT Table for the IO_APIC type is: - -| Offset | Length | Description | -|--------|--------|------------------------------| -| 2 | 1 | I/O Apic ID's | -| 3 | 1 | Reserved (should be 0) | -| 4 | 4 | I/O Apic Address | -| 8 | 4 | Global System Interrupt Base | - -The IO APIC ID field is mostly fluff, as you'll be accessing the io apic by it's mmio address, not it's ID. - -The Global System Interrupt Base is the first interrupt number that the I/O Apic handles. In the case of most systems, with only a single IO APIC, this will be 0. - -To check the number of inputs an IO APIC supports: - -```c -uint32_t ioapicver = read_io_apic_register(IOAPICVER); -size_t number_of_inputs = ((ioapicver >> 16) & 0xFF) + 1; -``` - -The number of inputs is encoded as bits 23:16 of the IOAPICVER register, minus one. - - -### IO-APIC Registers - -The IO-APIC has 2 memory mapped registers for accessing the other IO-APIC registers: - -| Memory Address | Mnemonic Name | Register Name | Description | -|----------------|---------------|--------------------|----------------------------------------------| -| FEC0 0000h | IOREGSEL | I/O Register Select| Is used to select the I/O Register to access | -| FEC0 0010h | IOWIN | I/O Window (data) | Used to access data selected by IOREGSEL | - -And then there are 4 I/O Registers that can be accessed using the two above: - -| Name | Offset | Description | Attribute | -|:------------:|----------|--------------------------------------------------------|-----------| -| IOAPICID | 00h | Identification register for the IOAPIC | R/W | -| IOAPICVER | 01h | IO APIC Version | RO | -| IOAPICARB | 02h | It contains the BUS arbitration priority for the IOAPIC| RO | -| IOREDTBL | 03h-3fh | The redirection tables (see the IOREDTBL paragraph) | RW | - - -### Reading data from IO-APIC - -There are basically two addresses that we need to use in order to write/read data from apic registers and they are: - -* IO_APIC_BASE address, that is the base address of the IOAPIC, called *register select* (or IOREGSEL) and used to select the offset of the register we want to read -* IO_APIC_BASE + 0x10, called *i/o window register* (or IOWIN), is the memory location mapped to the register we intend to read/write specified by the contents of the *Register Select* - -The format of the IOREGSEL is: - -| Bit | Description | -|---------|----------------------------------------------------------------------------------------------------------------------| -| 31:8 | Reserved | -| 7:0 | APIC Register Address, they specifies the IOAPIC Registers to be read or written via the IOWIN Register | - -So basically if we want to read/write a register of the IOAPIC we need to: - -1. write the register index in the IOREGSEL register -2. read/write the content of the register selected in IOWIN register - -The actual read or write operation is performed when IOWIN is accessed. -Accessing IOREGSEL has no side effects. - -### Interrupt source overrides -They contain differences between the IA-PC standard and the dual 8250 interrupt definitions. The isa interrupts should be identity mapped into the first IO-APIC sources, but most of the time there will be at least one exception. This table contains those exceptions. - -An example is the PIT Timer is connected to ISA IRQ 0, but when apic is enabled it is connected to the IO-APIC interrupt input pin 2, so in this case we need an interrupt source override where the Source entry (bus source) is 0 and the global system interrupt is 2 -The values stored in the IO Apic Interrupt source overrides in the MADT are: - -| Offset | Length | Description | -|--------|--------|------------------------------| -| 2 | 1 | bus source (it should be 0) | -| 3 | 1 | irq source | -| 4 | 4 | Global System Interrupt | -| 8 | 2 | Flags | - -* Bus source usually is constant and is 0 (is the ISA irq source), starting from ACPI v2 it is also a reserved field. -* Irq source is the source IRQ pin -* Global system interrupt is the target IRQ on the APIC - -Flags are defined as follows: - -* Polarity (*Lenght*: **2 bits**, *Offset*: *0* of the APIC/IO input signals, possible values are: - * 00 Use the default settings is active-low for level-triggered interrupts) - * 01 Active High - * 10 Reserved - * 11 Active Low -* Trigger Mode (*Length*: **2 bits**, *Offset*: *2*) Trigger mode of the APIC I/O Input signals: - * 00 Use the default settiungs (in the ISA is edge-triggered) - * 01 Edge-triggered - * 10 Reserved - * 11 Level-Triggered -* Reserved (*Length*: **12 bits**, *Offset*: **4**) this must be 0 - - -### IO Redirection Table (IOREDTBL) - -They can be accessed vie memory mapped registers. Each entry is composed of 2 registers (starting from offset 10h). So for example the first entry will be composed by registers 10h and 11h. - -The content of each entry is: - -* The lower double word is basically an LVT entry, for their definition check the LVT entry definition -* The upper double word contains: - - Bits 17 to 55: are Reserved - - Bits 56 to 63: are the Destitnation Field, In physical addressing mode (see the destination bit of the entry) it is the local apic id to forward the interrupts to, for more information read the IO-APIC datasheet. - -The number of items is stored in the IO-APIC MADT entry, but usually on modern architectures is 24. - -#### Delivery modes - - Do we need it? - -## Useful Resources - -* Intel Software developer's manual Vol 3A APIC Chapter -* IOAPIC Datasheet https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf -* http://www.brokenthorn.com/Resources/OSDevPic.html diff --git a/98_Drivers/PS2_Keyboard/01_README.md b/98_Drivers/PS2_Keyboard/01_README.md deleted file mode 100644 index 23e6b44b..00000000 --- a/98_Drivers/PS2_Keyboard/01_README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Adding keyboard support - -Writing an OS is great fun, but instead of only printing stuff to the screen, it would be better if we could interact with the user, right? - -In this section we will see how to interact with keyboard, and get the user input. - -The topics covered by this section are: - -* [Handling the keyboard interrupt](02_Interrupt_Handling.md) -* [Writing a driver](03_Driver_Implementation.md) - -## Keyboard Overview - -Before proceeding further let's have a quick high level overview of a keyboard. - -We'll be dealing with the PS/2 keyboard in this section, which communicates with us via the PS/2 controller in our system. Other keyboard running over more complex protocols (like USB) can be used to emulate a PS/2 keyboard, but this requires support from the device and motherboard. The good news for laptop developers is that most laptop keyboards (and trackpads) are actually still using PS/2 internally. - -Keyboards can accept several commands and generate interrupts, placing a byte on the communication port. - -Whenever a key is pressed or released the keyboard sends some data to us via the communication port, this data is called a *scancode*, and is composed of one or more bytes. - -There are three different sets of scancodes available (1, 2 and 3). Sets 1 and 2 are the most widely supported, set 3 was a later addition and is rare to see in the wild. Set 1 was the first, and a lot of software at the time was hardcoded to support it. This prevented an interesting problem when set 2 was introduced later on, and then standardized as being the default set for a keyboard. The solution was to keep set 2 as the default, but the ps/2 controller will translate set 2 scancodes into set 1 scancodes. To ensure compatability with older software, and confuse future os developers, this feature is enabled by default. - -The scancode that is generated when a key is pressed is called the **make** code, while the scancode generated by a key release is calle the **break** code. - -In order to develop our keyboard driver we'll need to do the following: - -* First identify the scancode set used by our keyboard, this is important because it is going to influence our mapping. -* Enable the Keyboard IRQ, how to do this depends if we are using the PIC or the IOAPIC, but in both cases we need to set up a handler and unmask the relevant entry into a IRQ table. -* Read the scancode byte. -* Once we have the full scancode, store it in a buffer along with any extra info we might need (any currently pressed modifers). - -As you can see translation the scancode to a printable character is not in the list above, we'll touch on how to do this briefly, although it's not really related to the keyboard driver. - -### Useful Links - -* [https://wiki.osdev.org/PS/2_Keyboard](https://wiki.osdev.org/PS/2_Keyboard) -* [https://wiki.osdev.org/IRQ#From_the_keyboard.27s_perspective](https://wiki.osdev.org/IRQ#From_the_keyboard.27s_perspective) -* [https://wiki.osdev.org/%228042%22_PS/2_Controller#Translation](https://wiki.osdev.org/%228042%22_PS/2_Controller#Translation) -* [https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#scancodesets](https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#scancodesets) -* [http://www.brokenthorn.com/Resources/OSDev19.html](http://www.brokenthorn.com/Resources/OSDev19.html) - - - - - - diff --git a/98_Drivers/PS2_Keyboard/02_Interrupt_Handling.md b/98_Drivers/PS2_Keyboard/02_Interrupt_Handling.md deleted file mode 100644 index 77acf3ff..00000000 --- a/98_Drivers/PS2_Keyboard/02_Interrupt_Handling.md +++ /dev/null @@ -1,111 +0,0 @@ -# Handling The Keyboard Interrupt - -Either the PIC or IOAPIC can be used to set up the keyboard irq. For this section we'll use the IOAPIC as it's more modern and the LAPIC + IOAPIC is the evolution of the PIC. However if you are using the PIC, most of the theory still applies, you'll need to adjust the irq routing code accordingly. - -To keep the examples below simple, we'll assume only a single IOAPIC is present in the system. This is true for most desktop systems, and is only something to worry about in server hardware. - -## IRQ and IOAPIC - -* The ps/2 keyboard is irq 1, this corresponds to pin 1 on the IOAPIC meaning we'll be accessing redirect entry 1. -* Redirection entries are accessed as 2x 32-bit registers, where the register number is defined as follows: - -``` -redtbl_offset = 0x10 + (entry_number * 2) -``` - -In this case then we have the offset for our entry at: `0x12` and `0x13` (called IOREDTBL1 in the spec), where `0x12` is the lower 32-bits of the table entry. - -Before unmasking the keyboard interrupt, we need an entry in the IDT, and a function (we can leave it empty for now) for the IDT entry to call. For this section we will call the function `keyboard_irq_handler`: - -```c -void keyboard_irq_handler() { - -} -``` - -Once we have a valid IDT entry, we can clear the mask bit in the IOAPIC redirect entry for the ps/2 keyboard. Be sure that the destination LAPIC id is set to the cpu you want to handle the keyboard interrupts. -This id can be read from the LAPIC registers. - - -## Driver Information - -The ps2 keyboard uses two IO ports for communication: - -| IO Port | Access Type | Purpose | -|---------|-------------|-----------------------------------------------------------------| -| 0x60 | R/W | Data Port | -| 0x64 | R/W | On read: status register. On Write: command register | - -* Since there are three different scancode sets, it's a good idea to check what set the keyboard is currently using. -* Usually the PS/2 controller (the device that the OS is actually talking to on ports `0x60` and `0x64`) converts set 2 scancodes into set 1 (for legacy reasons). -* To check if the translation is enabled, the command `0x20` must be sent on port `0x64`, and then read the byte on `0x60`. If the 6th bit is set than the translation is enabled. -* If we want to disable the translation we need: - - Read current controller configuration byte, by sending command `0x20` to port `0x64` (the reply byte will be sent on port `0x60`). - - Clear the 6th bit on the current controller configuration byte. - - To send the modified config byte back to the controller, send command `0x60` (to port `0x64`), then send the byte to port `0x60`. - - For our driver we will keep the translation enabled, since we'll be using set 1. -* The only scancode set guaranted to be supported by keyboards is the set 2. Keep in mind that most of the time the kernel communicate with the a controller compatible with the intel 8042 PS2 controller. In this case the scancodes can be translated into set 1. - - -### Sending Commands To The Keyboard - -To send commands to the PS/2 keyboard, we need to send the bytes directly to the data port (instead of the PS/2 controller command port). - -## Identifying The Scancode Set - -As mentioned in the introduction, we'll need to know to implement our keyboard support is what scancode set is being used by our system, and do one of the following things: - -* If we want to implement the support to all the three sets we will need to tell the driver what is the one being used by the keyboard. -* Try to set the keyboard to use a scancode we support (not all keyboard support all the sets, but it worth a try). -* If we're supporting set 1, we can try to enable translation on the PS2 controlle. -* Do nothing if it is the same set supported by our os. - -The keyboard command to get/set the scancode set used by the controller is `0x60` followed by another byte: - -| Value | Description | -|-------|-----------------------| -| 0 | Get current set | -| 1 | Set scancode set 1 | -| 2 | Set scancode set 2 | -| 3 | Set scancode set 3 | - -Now the keyboard will reply with 2 bytes: if we are setting the scancode, set the reply will be: `0xFA 0xFE`. If we are reading the current used set the response will be: `0xFA` followed by one of the below values: - -| Value | Description | -|-------|-------------------| -| 0x43 | Scancode set 1 | -| 0x41 | Scancode set 2 | -| 0x3f | Scancode set 3 | - -### About Scancode - -The scancode can be one of the following types: - -* A MAKE code, generated when a key is pressed. -* A BREAK code, generated when a key is released. - -The value of those code depends on the set in use. - -## Handling Keyboard Interrupts - -When a key is pressed/released the keyboard pushes the bytes that make up the scancode into the ps2 controller buffer, then triggers an interrupt. We'll need to read these bytes, and assemble them into a scancode. -If it's a simple scancode, only 1 byte in length then we can get onto the next step. - -```C -void keyboard_irq_handler() { - int scancode = inb(0x60); - //do_something_with_the_scancode(scancode); - - //Let's print the scancode we received for now - printf("Scancode read: %s\n", scancode); -} - -``` - -For set 1, the most significant bit of the scancode indicates whether it's a MAKE (MSB = 0) or BREAK (MSB = 1). -For set 2, a scancode is always a MAKE code, unless prefixed with the byte `0xF0`. - -Keep in mind that when we have multibyte scancodes (i.e. left ctrl, pause, and others), an interrupt is raised for every byte placed on the data buffer. - -*To be Continued...* - diff --git a/98_Drivers/PS2_Keyboard/03_Driver_Implementation.md b/98_Drivers/PS2_Keyboard/03_Driver_Implementation.md deleted file mode 100644 index b888d6f1..00000000 --- a/98_Drivers/PS2_Keyboard/03_Driver_Implementation.md +++ /dev/null @@ -1,297 +0,0 @@ -# Keyboard Driver Implementation - -Now that we can get scancodes from the keyboard (see [here](InterruptHandling.md)), we'll look at building a simple ps/2 keyboard driver. - -First of all, the driver is generally not responsible for translating the key presses and releases into printable characters, the driver's purpose is to deal with the specifics of the device (the ps2 keyboard) and provide a generic interface for getting key presses/releases. However it does usually involve translating from the keyboard-specific scancode into an os-specific one. The idea is that if more scancode sets or keyboards (like USB) are supported later on, these can be added without having to modify any code that uses the keyboard. Simply write a new driver that provides the same interface and it will work! - -Our keyboard driver does care about keeping track of any keyboard events (presses/releases), and making them available to any code that needs them. -Quite often these events will be consumed (that is, read by some other code and then removed from the driver's buffer). - -As already mentioned there are 3 scan code sets. We'll focus on just one (set 1, since by default the ps2 controller translates the other sets to set 1 when the system is powered). We'll implement the translate function in a generic fashion to make adding other scancode sets easier in the future. - -Now let's see what are the problems we need to solve when developing a keyboard driver: - -* We'll need to store the history of key press and their statuses somewhere. -* There are some special keys that also need to be handled, and some combinations that we should handle (was shift/alt/ctrl/super pressed at the same time as this key?). -* Handle the press/release status if needed (we don't care much when we release a normal key, but we do care when we release a key like shift or similar). -* Try to not lose sequence of key pressed/released. -* Handle the caps, num, and scroll lock keys (with the leds). -* We can optionally translate the scancode into a human readable character when needed. - -From now on we will assume that the scancode translation is enabled, so no matter what set is being used it will be translate to set 1. - -## High Level Overview - -In the previous section we have seen how an interrupt was generated and how to read data from the keyboard. Now we need to write a proper driver, one which addresses the issues listed above (well not all of them since some are an higher level than they will be implemented "using" the driver, not by it). - -We will try to build the driver in small steps adding one piece at time, so it will be easier to understand it. - -### Storing A History Of Pressed Keys - -The first thing we'll want to keep track of in the keyboard driver: what keys were pressed and in what order. For our example driver we're going to use a circular buffer because it has a fixed memory usage (does not require re-allocating memory) and is similar in speed to an array. The only downside is that we have to decide what happens when the buffer is full: we can either drop the oldest scancodes, or drop the latest one we tried to add. This is not really an issue if the buffer is made large enough, given that some application will be consuming the keyboard events from the buffer shortly after they're added. - -```c -#define MAX_KEYB_BUFFER_SIZE 255 - -uint8_t keyboard_buffer[MAX_KEYB_BUFFER_SIZE]; -uint8_t buf_position = 0; -``` - -If we want to store just the scancode we don't need much more, so we can already implement our new irq handler: - -```c - -void keyboard_driver_irq_handler() { - - - uint8_t scancode = inb(0x60); // Read byte from the Keyboard data port - - keyboard_buffer[buf_position] = scancode; - buf_position = (buf_position + 1) % MAX_KEYB_BUFFER_SIZE; - -} - -``` - -And we're done! This first function will keep track of the scancode generated by a keypress, and since we're using set 1 it also will tell us if the button has been pressed (MAKE) or released (BREAK). - -Now using `uint8_t` as the buffer type can work in this rather simple scenario, but it make our driver hard to expand for future updates. For example what if we want to attach some extra information to each key event? We will actually be doing this in the future, so we'll make our lives easier now by using a struct. - -```c -typedef struct { - uint8_t code; -} key_event; -``` - -So the updated irq function will be: -```c -#define MAX_KEYB_BUFFER_SIZE 255 - -key_event keyboard_buffer[MAX_KEYB_BUFFER_SIZE]; -uint8_t buf_position = 0; - -void keyboard_driver_irq_handler() { - int scancode = inb(0x60); // Read byte from the Keyboard data port - - keyboard_buffer[buf_position].code = scancode; - buf_position = (buf_position + 1) % MAX_KEYB_BUFFER_SIZE; -} -``` - -There are a few limitations with this implementation, but we have a working skeleton of a driver. We can track keypresses in a circular buffer. - -### Handling Multi-Byte Scancodes - -Depending on the scancode set, there are some keys that generate a scancode with more than one byte. This means that we will have one interrupt generated for every byte placed on the data port. For example when using the scancode set 1 there are some keys (i.e. ctrl, shift, alt) that have the prefix byte `0xE0`. Now the problem is that we can't read both bytes in one single interrupt, because even if we do we still get two interupts generated. We're going to solve this problem by keeping track of the current status of what we're reading. To do this we will implement a very simple state machine that has two states: - -* _Normal State_: This is exactly what it sounds like and also the one the driver starts in. If the driver reads a byte that is not the prefix byte (`0xE0`) it will remain in this state. After being in the prefix state and reading a byte, it will also return to this state. -* _Prefix state_: In case the driver it encountered the prefix byte, the driver will enter into this state. While in this state we know the next read is an extended scancode, and can be processed appropriately. - -If you don't know what a state machine is there's a link to the wikipedia page in the useful links section below. It's a straightfoward concept: an algorithm can only be in one of several states, and the algorithm reacts differently in each state. In our example we're going to use a global variable to identity the state: - -```c -#define NORMAL_STATE 0 -#define PREFIX_STATE 1 - -uint8_t current_state; -``` - -There are some scancodes that have up to 4 or more bytes which we're not going to cover here. - -*Editor's note: This is one area where the state-machine implementation can break down. As you potentially need a separate state for each byte in the sequence. An alternative implementation, that's not covered here, is to have an array of `uint8_t`s, and a pointer to the latest byte in the buffer. The idea being: read a byte from the buffer, place it after the last received byte in the array, and then increment the variable of the latest byte. Then you can check if a full scancode has been received, for extended codes beginning with 0xE0 you're expecting 2 bytes, for normal codes only 1 byte. Once you've detected a full scancode in the buffer, process it, and reset the pointer in the buffer for the next byte to zero. Therefore the next byte gets placed at the start of the buffer. Now it's just a matter of making the buffer large enough, which is trivial.* - -Regarding storing the prefix byte, this comes down a design decision. In our case we're not going to store them as they don't contain any information we need later on, when translating these scancodes into the kernel scancodes. Just to re-iterate: the idea of using a separate, unrelated, scancode set inside the kernel is that we're not bound to any implementation. Our keyboard driver can support as many sets as needed, and the running programs just use what the kernel provides, in this case it's own scancode set. It seems like a lot of work up front, but it's a very useful abstraction to have! - -Now by changing the `current_state` variable, we can change how the code will treat the incoming data. We'll also need an init function, so we that can do some set up like setting the default state and zeroing the keyboard event buffer: - -```c -#define NORMAL_STATE 0 -#define PREFIX_STATE 1 - -uint8_t current_state; - -void init_keyboard() { - // Do other initialization stuff like: clean the keyboard buffer, identify the scancode set, enable the IRQ etc. - current_state = NORMAL_STATE; -} - -void keyboard_driver_irq_handler() { - int scancode = inb(0x60); // Read byte from the Keyboard data port - if (scancode == 0xE0) { - current_state = PREFIX_STATE - // We have read a prefix, so let's update the state and finish here - // this is a very simple scenario, there could be more needed depending on the design - return; - } - if (current_state == PREFIX_STATE) { - // Do what you need to store the key_code and eventually translate it to the kernel_code and return to the normal state - current_state = NORMAL_STATE; - } -} -``` - - -### Handling Modifier keys - -For our purposes we're considering the modifier keys to be *ctrl*, *alt*, *shift*, *gui/super*. The caps lock could also be considered a modifier key too. -These keys are interesting because they can drastically alter the meaning of other key presses. Of course an application can choose any key to be a modifier key, but we will only be supporting the common ones. -We're going to store the state of these modifier keys alognside each keypress (inside the struct we created earlier - see below) so that an application can quickly tell how to interpret a key event by only looking at a single event, -rather than having to track the state of the modifiers themselves. This reduces a lot of duplicate code, is a nice api to work with! - -Some examples of how an application might use the modifiers: - -* If the `shift` key is pressed the translation to ascii mechanism needs to know it because it has to return the shifted/capital symbol associated with that key. -* If `ctrl` or `alt` are pressed the driver needs to know it because it can trigger either a key combination or some of the "alt"ernative symbols on some special keyboard keys. -* If the caps lock key is pressed (not kept pressed) we need the translation function to return only the capital version of the key. - -Our driver will need to keep track of the current state of all the modifiers, and then store a snapshot of their state when a key event happens. Time to update our `key_event` structure: - -```c -typedef struct { - uint8_t code; - bool shift_pressed; - bool alt_pressed; - // ... etc -} key_event; - -``` - -Now the above structure will work, but it's not optimal as each bool takes a full byte. We can do better! Let's use a bitfield. - -Each modifier is represented by a bit, with 1 meaning the modifier was also pressed and 0 meaning it wasn't. - -```c -typedef struct { - uint8_t code; - uint8_t status_mask; -} key_event; -``` - -Now it's just a matter of keeping track of which bit represents which modifier key. The easiest way is to use `#define`s for each bit, something like: - -```c -#define CTRL_MASK 1 -#define ALT_MASK 2 -#define SHIFT_MASK 3 -``` - -We're not interested in the difference between the left and right versions of the modifier keys for now, but you could store those as separate bits if you were. -Updating the state of a modifier key can be done by using standard bitwise operations. - -As an example, say we detect the CTRL key is pressed. We would want to update the current modifiers (which we store a copy of when whenever we store a new key event): - -```c -current_modifiers |= 1 << CTRL_MASK; -``` - -And to clear the bit when we detect CTRL is released: - -```c -current_modifiers &= ~(1 << CTRL_MASK); -``` - -So now we need to just identify what key is being pressed/released and update the status_mask accordingly. - -The case of caps lock can be handled in 2 ways. The first is to add a boolean variable to the key_event struct which stores the current state of caps lock. We can also use one of the unused bits in the status_mask field. -An interesting note is that on ps/2 keyboards the LEDs must be controlled manually, implementing this is as simple as a single command to the keyboard, and is left as an exercise for the reader. - -### Translation - -Now that all the core parts of the driver are in place, let's talk about translation. - -There's two main stages of translation we're interested in at the moment: - -* From the keyboard-specific scancode to our kernel scancode (the one applications use). -* From the kernel scancode to a printable ascii character. This isn't really part of the keyboard driver, but we will cover it here since it's a useful function to test if your keyboard driver works. - -Translation from the keyboard scancode to the kernel one can be done a number of ways. For our example driver we're going to use a lookup table in the form of an array. - -Our array is going to be an aray of kernel scancodes, with the index into the array being the keyboard scancode. Let's say get scancode 0x12 from the keyboard, and we know that key is the F1 key (just an example, check the real scancodes before implementing this). - -We could use the following: -```c - -//an example of our kernel-specific scancodes -typedef enum kernel_scancodes { - [ ... ] - F1 = 0xAABBCCDD, //this can be defined to whatever value you want, the exact value is totally arbitrary. - [ ... ] -}; - -//this is our lookup table for converting scancodes -kernel_scancodes scancode_mapping[] = { - [ ... 0x11 previous entries ] - //this is at position 0x12 in the array - F1, - [ ... entries 0x13 and onwards ] -}; - -//now to translate a scancode, we would use: -uint8_t keyboard_scancode = 0x12; -kernel_scancodes translated_scancode = scancode_mapping[keyboard_scancode]; -``` - -There are a few edge cases here, one of them being what if a keyboard scancode dosnt have a kernel scancode to map to? We've used the value zero to mean 'no translation' and any key events with 0 as the scancode should be ignored. -We could also filter them out when an application tries to get any pending key events. - -We also don't check if the keyboard scancode is within the lookup table, which it may not be. This is something to consider. - -So now we have our internal representation of a scancode, and the `code` field in the `key_event` structure outlined above can use it. In the paragraph _Store Key Press History_ we have seen how the the interrupt handler should save the key event in the circular buffer. However that was before we had any translation. Using what we saw above we'll change the following line to now use the lookup table instead of storing the scancode directly: - -```c - keyboard_buffer[buf_position].code = scancode; -``` -becomes - -```c - keyboard_buffer[buf_position].code = scancode_mapping[scancode]; -``` - -At this point you have a fully functioning PS/2 keyboard driver! However we will quickly cover translating a kernel scancode into a printable character, as that's a useful feature to have at this stage. - -There's a few approaches to getting printable characters from our kernel scancodes: - -* Using a lookup table like we did before. We could have 2 tables, one for shifted keys and one for non-shifted keys. - -* Using a big switch statement, with inline if/elses to handle shifting. - -A lookup table would work the same as it did above. If you want the scancode with the value 6 to to translate to the printable character 'f', you would put 'f' at the 6th position in the lowercase array, and 'F' in the 6th position of the shifted array. - -```c -char lower_chars[] = { - 'a', 'b', 'c', 'd', 'e', 'f', [ ... ] -}; - -char shifted_chars[] = { - 'A', 'B', 'C', 'D', 'E', 'F', [ ... ] -}; - -char get_printable_char(key_event key) -{ - if (key.status_mask & CTRL_MASK || key.caps_lock) - return shifted_chars[key.code]; - else - return lower_chars[key.code]; -} -``` - -Instead of having two tables, only the lower_chars one can be used and an offset (if using basic ascii) can be used to calculate the shifted key value. This works for simple scenarios, but will break for any non-us keyboards or symbols. It's also not very expandable in the future. - -To calculate the offset to apply, you can use `size_t offset = 'a' - 'A';`, and then add `offset` to the value from the lookup table if it's a letter, or just add 0x10 if it's a digit. - -Using the switch statement approach looks how you'd expect: - -```c -char get_printable_char(key_event key) -{ - const bool shifted = key.status_mask & CTRL_MASK || key.caps_lock; - switch (key.code) - { - case KEY_A: - return shifted ? 'A' : 'a'; - case KEY_B: - return shifted ? 'B' : 'b'; - [ ... ] - } -} -``` diff --git a/98_Drivers/Timers.md b/98_Drivers/Timers.md deleted file mode 100644 index fc95d3b2..00000000 --- a/98_Drivers/Timers.md +++ /dev/null @@ -1,292 +0,0 @@ -# Timer - -Timers are useful for all sorts of things, from keeping track of real-world time to forcing entry into the kernel to allow for pre-emptive multitasking. There are many timers available, some standard and some not. - -In this chapter we're going to take a look at the main timers used on x86 and what they're useful for. - -## Types and Characteristics - -At a high level, there a few things we might want from a timer: - -- Can it generate interrupts? And does it support a periodic mode? -- Can we poll it to determine how much time has passed? -- Does the main clock count up or down? -- What kind of accuracy, precision and latency does it have? - -At first most of these questions might seem unnecessary, as all we really need is a periodic timer to generate interrupts for the scheduler right? Well that can certainly work, but as you do more things with the timer you may want to accurately determine the length of time between two points of execution. This is hard to do with interrupts, and it's easier to do with polling. A periodic mode is also not always available, and sometimes you are stuck with a one-shot timer. - -For x86, the common timers are: - -- The PIT: it can generate interrupts (both periodic and one-shot) and is pollable. When active it counts down from a reload value to 0. It has a fixed frequency and is very useful for calibrating other timers we don't know the frequency of. However it does come with some latency due to operating over port IO, and it's frequency is low compared to the other timers available. -- The local APIC timer: it is also capable of generating interrupts (periodic and oneshot) and is pollable. It operates in a similar manner to the PIT where it counts down from a reload value towards 0. It's often low latency due to operating over MMIO and comes with the benefit of being per-core. This means each core can have it's own private timer, and more cores means more timers. -- The HPET: capable of polling with a massive 64-bit main counter, and can generate interrupts with a number of comparators. These comparators always support one-shot operation and may optionally support a periodic mode. It's main clock is count-up, and it is often cited as being high-latency. It's frequency can be determined by parsing an ACPI table, and thus it serves as a more accurate alternative to the PIT for calibrating other timers. -- The TSC: the timestamp-counter is tied to the core clock of the cpu, and increments once per cycle. It can be polled and has a count-up timer. It can also be used with the local APIC to generate interrupts, but only one-shot mode is available. It is often the most precise and accurate timer out of the above options. - -We're going to focus on setting up the local APIC timer, and calibrating it with either the PIT or HPET. We'll also have a look at a how you could also use the TSC with the local APIC to generate interrupts. - -### Calibrating Timers - -There are some timers that we aren't told the frequency of, and must determine this ourselves. The local APIC timer and TSC (up until recently) are examples of this. In order to use these, we have to know how fast each 'tick' is in real-world time, and the easiest way to do this is with another time that we do know the frequency of. - -This is where timers like the PIT can still be useful: even though it's very simple and not very flexible, it can used to calibrate more advanced timers like the local APIC timer. Commonly the HPET is also used for calibration purposes if it's available, since we can know it's frequency without calibration. - -Actually calibrating a timer is straightforward. We'll refer to the timer we know the frequency of as the reference timer and the one we're calibrating as the target timer. This isn't common terminology, it's just useful for the following description. - -- Ensure both timers are stopped. -- If the target timer is counts down, set it the maximum allowed value. If it counts up, set it to zero. -- Choose how long you want to calibrate for. This should be long enough to allow a good number of ticks to pass on the reference timer, because more ticks passing will mean a more accurate calibration. This time shouldn't be too long however, because if one of the timer counters rolls over then we'll trouble determining the results. A good starting place is 5-10ms. -- Start both timers, and poll the reference timer until the calibration time has passed. -- Stop both timers, and we look at how many ticks has passed for the target timer. If it's a count-down timer, we can determine this by subtracting the current value from the maximum value for the counter. -- Now we know that a certain amount of time (the calibration time) is equal to a certain number of ticks for our target timer. - -Sometimes running your kernel in a virtual machine, or on less-stable hardware can give varying results, so it can be useful to calibrate a timer multiple times and compare the results. If some results are odd, don't use them. It can also be helpful to continuously calibrate timers while you're using them, which will help correct small errors over time. - -## Programmable Interval Timer (PIT) - -The PIT is actually from the original IBM PC, and has remained as a standard device all these years. Of course these days we don't have a real PIT in our computers, rather the device is emulated by newer hardware that pretends to be the PIT until configured otherwise. Often this hardware is the HPET (see below). - -On the original PC the PIT also had other uses, like providing the clock for the RAM and the oscillator for the speaker. Each of these functions is provided by a 'channel', with channel 0 being the timer (channels 1 and 2 are the other functions). On modern PITs it's likely that only channel 0 exists, so the other channels are best left untouched. - -Despite it being so old the PIT is still useful because it provides several useful modes and a known frequency. This means we can use it to calibrate the other timers in our system, which we don't always know the frequency of. - -The PIT itself provides several modes of operation, although we only really care about a few of them: - -- Mode 0: provides a one-shot timer. -- Mode 2: provides a periodic timer. - -To access we PIT we use a handful of IO ports: - -| I/O Port | Description | -|----------|----------------------| -| 0x40 | Channel 0 data Port | -| 0x41 | Channel 1 data Port | -| 0x42 | Channel 2 data Port | -| 0x43 | Mode/Command register| - -### Theory Of Operation - -As mentioned the PIT runs at a fixed frequency of 1.19318MHz. This is an awkward number but it makes sense in the context of the original PC. The PIT contains a pair of registers per channel: the count and reload count. When the PIT is started the count register is set to value of the reload count, and then every time the main clock ticks (at 1.19318MHz) the count is decremented by 1. When the count register reaches 0 the PIT sends an interrupt. Depending on the mode the PIT may then set the count register to the reload register again (in mode 2 - periodic operation), or simple stay idle (mode 0 - one shot operation). - -The PIT's counters are only 16-bits, this means that the PIT can't count up to 1 second. If you wish to have timers with a long duration like that, you will need some software assistance by chaining time-outs together. - -### Example - -As an example let's say we want the PIT to trigger an interrupt every 1ms (1ms = 1/1000 of a second). To figure out what to set the reload register to (how many cycles of the PIT's clock) we divide the clock rate by the duration we want: - -$$\frac{1,193,180 (clock frequency)}{1000 (duration wanted)} = 1193.18 (Hz for duration)$$ - - -One problem is that we can't use floating point numbers for these counters so we truncate the result to 1193. This does introduce some error, and you can correct for this over a long time if you want. However for our purposes it's small enough to ignore, for now. - -To actually program the PIT with this value is pretty straightfoward, we first send a configuration byte to the command port (`0x43`) and then the reload value to the channel port (`0x40`). - -The configuration byte is actually a bitfield with the following layout: - -| Bits | Description | -|--------|----------------------------------------------------------------------------------------------------------------------| -| 0 | Selects BCD/binary coded decimal (1) or binary (0) encoding. If you're unsure, leave this as zero. | -| 1 - 3 | Selects the mode to use for this channel. | -| 4 - 5 | Select the access mode for the channel: generally you want 0b11 which means we send the low byte, then the high byte of the 16-bit register. | -| 6 - 7 | Select the channel we want to use, we always want channel 0. | - -For our example we're going to use binary encoding, mode 2 and channel 0 with the low byte/high byte access mode. This results in the following config byte: `0b00110100`. - -Now it's a matter of sending the config byte and reload value to the PIT over the IO ports, like so: - -```c -void set_pit_periodic(uint16_t count) { - outb(0x43, 0b00110100); - outb(0x40, count & 0xFF); //low-byte - outb(0x40, count >> 8); //high-byte -} -``` - -Now we should be getting an interrupt from the PIT every millisecond! By default the PIT appears on irq0, which may be remapped to irq2 on modern (UEFI-based) systems. Also be aware that the PIT is system-wide device, and if you're using the APIC you will need to program the IO APIC to route the interrupt to one of the LAPICs. - -## High Precision Event Timer (HPET) - -The HPET was meant to be the successor to the PIT as a system-wide timer, with more options however it's design has been plagued with latency issues and occasional glitches. With all that said it's still a much more accurate and precise timer than the PIT, and provides more features. It's also worth noting the HPET is not available on every system, and can sometimes be disabled via firmware. - -### Discovery - -To determine if the HPET is available you'll need access to the ACPI tables. Handling these is covered in a separate chapter, but we're after one particular SDT with the signature of 'HPET'. If you're not familiar with ACPI tables yet, feel free to come back to the HPET later. - -This SDT has the standard header, followed by the following fields: - -```c -struct HpetSdt { - ACPISDTHeader header; - uint32_t event_timer_block_id; - uint32_t reserved; - uint64_t address; - uint8_t id; - uint16_t min_ticks; - uint8_t page_protection; -}__attribute__((packed)); -``` - -*Authors note: the reserved field before the address field is actually some type information describing the address space where the HPET registers are located. In the ACPI table this reserved field is the first part of a 'generic address structure', however we can safely ignore this info because the HPET spec requires the registers to be memory mapped (thus in memory space).* - -We're mainly interested in the `address` field which gives us the physical address of the HPET registers. The other fields are explained in the HPET specification but are not needed for our purposes right now. - -As with any MMIO you will need to map this physical address into the virtual address space so we can access the registers with paging enabled. - -### Theory Of Operation - -The HPET consists of a single main counter (that counts up) with some global configuration, and a number of comparators that can trigger interrupts when certain conditions are met in relation to the main counter. The HPET will always have at least 3 comparators, but may have up to 32. - -The HPET is similar to the PIT in that we are told the frequency of it's clock. Unlike the PIT, the HPET spec does not give us the frequency directly, we have to read it from the HPET registers. - -Each register is accessed by adding an offset to the base address we obtained before. The main registers we're interested in are: - -- General capabilities: offset `0x0`. -- General configuration: offset `0x10`. -- Main counter value: `0xF0`. - -We can read the main counter at any time, which is measured in in timer ticks. We can convert these ticks into realtime by multiplying them with the timer period in the general capabilities register. Bits 63:32 of the general capabilities register contain the number of femtoseconds for each tick. A nanosecond is 1000 femtoseconds, and 1 second is 1'000'000'000 femtoseconds. - -We can also write to the main counter, usually you would write a 0 here when initializing the HPET in order to be able to determine uptime, but this is not really necessary. - -The general capabilities register contains some other useful information, briefly summarized below. If you're after more detail, all of this is available in the public specification. - -- *Bits 63:32*: This number of femtoseconds for each tick of the main clock. -- *Bits 31:16*: This field contains the PCI vendor ID of the HPET manufacturer, not needed for operation. -- *Bit 15*: Legacy routing support, if set indicates this HPET can emulate the PIT and RTC timers present in older PCs. -- *Bit 13*: If 1 indicates the main counter is 64-bits wide, otherwise it's 32-bits. -- *Bits 12:8*: Encodes the number of timers supported. This is the id of the last timer; a value of 2 means there are three timers (0, 1, 2). -- *Bits 7:0*: Hardware revision id. - -In order for the main counter to actually begin counting, we need to enable it. This is done by setting bit 0 of the general configuration register. Once this bit is set, the main counter will increment by one every time it's internal clock ticks. The period of this clock is what's specified in the general capabilities register (bits 63:32). - -The general configuration register also contains one other interesting setting: bit 1. If this bit is set the HPET is in legacy replacement mode, where it pretends to be the PIT and RTC timer. This is the default setting, and if you intend to use the HPET as described above this bit should be cleared. - -### Comparators - -The main counter is only suitable for polling the time, but it cannot generate interrupts. For that we have to use one of the comparators. The HPET will always have at least three comparators, but may have up to 32. In reality most vendors use the stock intel chip which comes with 3 comparators, but there are some other vendors of compatible hardware out there which may support more. - -By default the first two comparators are set up to mimic the PIT and RTC clocks, but they can be configured like the others. - -It's worth noting that all comparators support one-shot mode, but periodic mode is optional. Testing if a comparator supports periodic mode can be done by checking if bit 4 is set in the capabilities register for that comparator. - -Speaking of which: each comparator has it's own set of registers to control it. These registers are accessed as an offset from the HPET base. There are two registers we're interested in: the comparator config and capability registger (accessed at offset `0x100 + N * 0x20`), and the comparator value register (at offset `0x108 + N * 0x20`). In those equations `N` is the comparator number you want. As an example to access the config and capability register for comparator 2, we would determine it's location as: `0x100 + 2 * 0x20 = 0x140`. Meaning we would access the register at offset `0x140` from the HPET mmio base address. - -The config and capabilities register for a comparator also contains some other useful fields to be aware of: - -- *Bits 63:32*: This is a bitfield indicating which interrupts this comparator can trigger. If a bit is set, the comparator can trigger that interrupt. This maps directly to GSIs, which are the inputs to the IO APIC. If there is only a single IO APIC in the system, then these interrupt numbers map directly to the IO APIC input pins. For example if bits 2/3/4 are set, then we could trigger the IO APIC pins 2/3/4 from this comparator. -- *Bits 13:9*: Write the integer value of the interrupt you want this comparator to trigger here. It's recommended to read this register back after writing to verify the comparator accepted the interrupt number you wrote. -- *Bits 4:3*: Bit 4 is set if the comparator supports periodic mode. Bit 3 is used to select periodic mode if it's supported. If either bit is cleared, the comparator operates as a one-shot. -- *Bit 2*: Enables the comparator to generate interrupts. Even if this is cleared the comparator will still operate, and set the interrupt pending bit, but no interrupt will be sent to the IO APIC. This bit acts in reverse to how a mask bit would: if this bit is set, interrupts are generated. - -### Example - -Let's look at two examples of using the HPET timer: polling the main counter and setting up a one-shot timer. If you want a periodic timer you'll have to do a bit more work, and check that a comparator supports periodic mode. - -We're going to assume you have the HPET registers mapped into virtual memory, and that address is stored in a variable `void* hpet_regs`. - -Polling the main counter is very straightforward: - -```c -uint64_t poll_hpet() { - volatile uint64_t* caps_reg = hpet_regs; - uint32_t period = *caps_reg >> 32; - - volatile uint64_t* counter_reg = hpet_regs + 0xF0; - return *counter_reg * period; -} -``` - -This function returns the main counter of the hpet as a number of femtoseconds since it was last reset. You may want to convert this to a more managemable unit like nano or even microseconds. - -Next let's look at setting up an interrupt timer. This requires the use of a comparator, and a bit of logic. You'll also need the IO APIC set up, and we're going to use some dummy functions to show what you'd need to do. We're going to use comparator 0, but this could be any comparator. - -```c -#define COMPARATOR_0_REGS 0x100 - -void arm_hpet_interrupt_timer(size_t femtos) { - volatile uint64_t* config_reg = hpet_regs + COMPARATOR_0_REGS; - - //first determine allowed IO APIC routing - uint32_t allowed_routes = *config_reg >> 32; - size_t used_route = 0; - while ((allowed_routes & 1) == 0) { - used_route++; - allowed_routes >>= 1; - } - - //set route and enable interrupts - *config_reg &= ~(0xFul << 9); - *config_reg |= used_route << 9; - *config_reg |= 1ul << 2; - //you should configure the io apic routing here. - //this interrupt will appear on the pin 'used_route'. - - volatile uint64_t* counter_reg = hpet_regs + 0xF0; - uint64_t target = *counter_reg + (femtos / hpet_period); - volatile uint64_t* compare_reg = hpet_regs + COMPARATOR_0_REGS + 8; - *compare_reg = target; -} -``` - -## Local APIC Timer - -The next timer on our list is the local APIC timer. This timer is a bit special as a processor can only access it's local timer, and each core gets a dedicated timer. Very cool! Historically these timers have been quite good, as they're built as part of the CPU, meaning they get the same treatment as the rest of that silicon. - -However not all local APIC timers are created equal! There are a few feature flags to check for before using them: - -- ARAT/Always Running APIC Timer: cpuid leaf 6, eax bit 2. If the cpu hasn't set this bit the APIC timer may stop in lower power states. This is okay for a hobby OS, but if you do begin managing system power states later on, it's good to be aware of this. - -The timer is managed by registers within the local APIC MMIO area. The base address for this can be obtained from the lapic MSR (MSR `0x1B`). See the APIC chapter for more info on this. We're interested in three registers for the timer: the divisor (offset `0x3E0`), initial count (offset `0x380`) and timer entry in the LVT (offset `0x320`). There is also a current count register, but we don't need ot access that right now. - -Unfortunately we're not told the frequency of this timer (except for some very new cpus which include this in cpuid), so we'll need to calibrate this timer against one we already know the speed of. Other than this, using the local APIC is very simple: simply set the mode you want in the LVT entry, set the divisor and initial count and it should work. - -### Example - -Calibrating a timer is explained above, so we're going to assume you have a function called `lapic_ms_to_ticks` that converts a number of milliseconds into the number of local APIC timer ticks. You may not need this function yourself, but it serves for the example. We're also going to assume that you've set the divisor register to what you want. If you're not sure what this does, its divides the incoming clock pulses, reducing the rate the timer ticks. This is useful if you want longer clock durations. Starting with a value of 2 or 4 is recommended. - -Other than setting the initial count, we also have to set up the timer LVT entry. There's a few fields here, but we're mostly interested in the following: - -- *Bits 7:0*: this is interrupt vector the timer will trigger when it expires. It will only trigger that vector on the core the LAPIC is attached to. -- *Bit 16*: Acts as a mask bit, if set the timer won't generate an interrupt when expiring. -- *Bits 18:17*: The mode field. Set this to *0b00* for one-shot operation, and *0b01* for periodic. - -The intel and AMD manuals contain the full description if you want to explore the other functionality offered. - -```c -void arm_lapic_interrupt_timer(size_t millis, uint8_t vector) { - volatile uint32_t* lvt_reg = lapic_regs + 0x320; - //note this clears bits 16 (mask) and 18:17 (mode) - *lvt_reg = vector; - - uint32_t ticks = lapic_ms_to_ticks(millis); - volatile uint32_t* init_reg = lapic_regs + 0x380; - *init_reg = ticks; -} -``` - -## Timestamp Counter (TSC) - -The TSC is a bit more modern than the LAPIC timer, but still pre-dates most long mode processors, so this is another timer that should always be present. Having said that, it can be checked for using cpuid leaf 1, edx bit 4. - -The TSC is probably the simplest timer we've covered so far: it's simply a 64-bit counter that increments every time the base clock of the processor pulses. To read this counter we can use the `rdtsc` instruction which places the low 33-bits in eax and high 32-bits in edx. Similar to how the MSR instructions work. - -There are some issues with this version of the TSC however: modern processors will change their base speed depending on power/performance requirements, which means that the rate the TSC ticks at will change dynamically! This makes it pretty useless as a timer, and a newer version was quickly implemented, called the invariant TSC. - -The I-TSC ticks at the base speed the processor is supposed to run at, not what it's actually running at, meaning the tick-rate is constant. Most processors support the I-TSC nowadays, and most emulators also do, even if they don't advertise it through cpuid (qemu has invariant TSC, but doesn't set the bit). To test if the TSC is invariant can be done via cpuid once again: leaf 7, edx bit 8. - -How about generating interrupts with the TSC? This is also an option feature (that's almost always supported) called TSC deadline. We can test for it's existence via cpuid leaf 1, ecx, bit 24. To use TSC deadline we write the absolute time (in TSC ticks) of when we want the interrupt to a special MSR, called IA_32_TSC_DEADLINE (MSR `0x6E0`). - -When the TSC passes the tick value in this MSR, it tells the local APIC, and if TSC deadline mode is selected in the timer LVT an interrupt is generated. Selecting TSC deadline mode can be done by using mode `0b10` instead of `0b00`/`0b01` in the timer LVT register. - -## Useful Abstractions - -As we've seen there are lots of timers with varying capabilities. Some of these have analogies on other platforms, while some don't. If you intend to support all of these timers, or go cross-platform it can be worth implementing an abstract timer API, and then hiding the implementation of these timers behind it. You'll want to start with an API that at least provides the following: - -- polled_sleep(): this functions spins until the requested time has passed. -- poll_timer(): gets an absolute value of a timer, useful for timing short sections of code. Also useful for keeping track of time when an interrupt timer is not armed. -- arm_interrupt_timer(): sets a timer to trigger an interrupt at a point in the future, immediately returns control to the calling function. Arguably the most of these functions, and what you'll use to impement scheduling or other clock-based functions. - -## Useful links - -* [Ehtereality osdev Notes - Apic/Timing/Context Switching](https//ethv.net/workshops/osdev/notes/notes-4.html) -* [OSdev Wiki - Pit page](https://wiki.osdev.org/Programmable_Interval_Timer) -* [Brokern Thron Osdev Series](http://www.brokenthorn.com/Resources/OSDev16.html) diff --git a/98_Drivers/test.pdf b/98_Drivers/test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c06e39563e5cdf67493d49872197c9bfa2b55e7c GIT binary patch literal 168665 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 827d162d..1a736f4f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Osdev Notes -## Test + [![Discord Chat](https://img.shields.io/discord/578193015433330698.svg?style=flat)](https://discordapp.com/channels/578193015433330698/578193713340219392) Buy Me A Coffee donate button @@ -27,27 +27,30 @@ We hope you enjoy, and find something interesting here! * [A Higher Higher Kernel](02_Architecture/02_HigherHalf.md) * [Global Descriptor Table](02_Architecture/03_GDT.md) * [Interrupts](02_Architecture/04_InterruptHandling.md) -* [Chapter 3: Memory Management](03_Memory_Management/01_README.md) - * [Physical Memory](03_Memory_Management/02_Physical_Memory.md) - * [Paging](03_Memory_Management/03_Paging.md) - * [Virtual Memory Manager](03_Memory_Management/04_Virtual_Memory_Manager.md) - * [Heap Allocation](03_Memory_Management/05_Heap_Allocation.md) - * [Memory Protection](03_Memory_Management/06_Memory_Protection.md) -* [Chapter 4: Scheduling](04_Scheduling/01_README.md) - * [The Scheduler](04_Scheduling/02_Scheduler.md) - * [Processes and Threads](04_Scheduling/03_Processes_And_Threads.md) - * [Locks](04_Scheduling/04_Locks.md) -* [Chapter 5: Getting to Userspace](05_Userspace/01_README.md) - * [Switching Modes](05_Userspace/02_Switching_Modes.md) - * [Updated Interrupt Handling](05_Userspace/03_Handling_Interrupts.md) - * [System Calls](05_Userspace/04_System_Calls.md) - * [Example Syscall ABI](05_Userspace/05_Example_ABI.md) -* [Chapter 6: Inter-Process Communication](06_IPC/01_README.md) - * [Shared Memory](06_IPC/02_Shared_Memory.md) - * [Message Passing](06_IPC/03_Message_Passing.md) -* [Chapter 7: File System](07_VirtualFileSystem/01_README.md) - * [The Virtual File System](07_VirtualFileSystem/02_VirtualFileSystem.md) -* [Chapter 9: Going Beyond](09_Going_Beyond/01_README.md) +* [Chapter 3: Video Output](/03_Video_Output/01_Readme.md) + * [The Framebuffer](/03_Video_Output/Framebuffer.md) + * [Drawing Text on Framebuffer](03_Video_Output/DrawingTextOnFB.md) +* [Chapter 3: Memory Management](04_Memory_Management/01_README.md) + * [Physical Memory](04_Memory_Management/02_Physical_Memory.md) + * [Paging](04_Memory_Management/03_Paging.md) + * [Virtual Memory Manager](04_Memory_Management/04_Virtual_Memory_Manager.md) + * [Heap Allocation](04_Memory_Management/05_Heap_Allocation.md) + * [Memory Protection](04_Memory_Management/06_Memory_Protection.md) +* [Chapter 4: Scheduling](05_Scheduling/01_README.md) + * [The Scheduler](05_Scheduling/02_Scheduler.md) + * [Processes and Threads](05_Scheduling/03_Processes_And_Threads.md) + * [Locks](05_Scheduling/04_Locks.md) +* [Chapter 5: Getting to Userspace](06_Userspace/01_README.md) + * [Switching Modes](06_Userspace/02_Switching_Modes.md) + * [Updated Interrupt Handling](06_Userspace/03_Handling_Interrupts.md) + * [System Calls](06_Userspace/04_System_Calls.md) + * [Example Syscall ABI](06_Userspace/05_Example_ABI.md) +* [Chapter 6: Inter-Process Communication](07_IPC/01_README.md) + * [Shared Memory](07_IPC/02_Shared_Memory.md) + * [Message Passing](07_IPC/03_Message_Passing.md) +* [Chapter 7: File System](08_VirtualFileSystem/01_README.md) + * [The Virtual File System](08_VirtualFileSystem/02_VirtualFileSystem.md) +* [Chapter 9: Going Beyond](10_Going_Beyond/01_README.md) * [Extras: Hardware and Drivers](98_Drivers/01_README.md) * [Local APIC and IO APIC](98_Drivers/APIC.md) * [Linear Framebuffer](98_Drivers/Framebuffer.md) From bc3372246ca20fbce116dc7c1520891e9b43e2f8 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 28 Mar 2023 11:34:38 +0100 Subject: [PATCH 04/32] add conclusion part decorator --- .pandoc/decorators/part_conclusion.tex | 1 + 1 file changed, 1 insertion(+) create mode 100644 .pandoc/decorators/part_conclusion.tex diff --git a/.pandoc/decorators/part_conclusion.tex b/.pandoc/decorators/part_conclusion.tex new file mode 100644 index 00000000..e49ecc4b --- /dev/null +++ b/.pandoc/decorators/part_conclusion.tex @@ -0,0 +1 @@ +\part{Conclusion} From 92b1749eac596c8a23542a3b9dcba985810ac067 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 28 Mar 2023 11:53:01 +0100 Subject: [PATCH 05/32] remove pdf file --- 98_Drivers/test.pdf | Bin 168665 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 98_Drivers/test.pdf diff --git a/98_Drivers/test.pdf b/98_Drivers/test.pdf deleted file mode 100644 index c06e39563e5cdf67493d49872197c9bfa2b55e7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168665 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 From 6cd1a68e4f88756518ec27fb05efd4cadd3dc778 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Thu, 30 Mar 2023 13:06:14 +0100 Subject: [PATCH 06/32] Add missing files --- 02_Architecture/ACPITables.md | 162 +++++++++ 02_Architecture/APIC.md | 314 ++++++++++++++++++ 02_Architecture/PS2_Keyboard/01_README.md | 47 +++ .../PS2_Keyboard/02_Interrupt_Handling.md | 111 +++++++ .../PS2_Keyboard/03_Driver_Implementation.md | 297 +++++++++++++++++ 02_Architecture/Timers.md | 292 ++++++++++++++++ 6 files changed, 1223 insertions(+) create mode 100644 02_Architecture/ACPITables.md create mode 100644 02_Architecture/APIC.md create mode 100644 02_Architecture/PS2_Keyboard/01_README.md create mode 100644 02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md create mode 100644 02_Architecture/PS2_Keyboard/03_Driver_Implementation.md create mode 100644 02_Architecture/Timers.md diff --git a/02_Architecture/ACPITables.md b/02_Architecture/ACPITables.md new file mode 100644 index 00000000..5cafcbc7 --- /dev/null +++ b/02_Architecture/ACPITables.md @@ -0,0 +1,162 @@ +# Acpi Tables + +ACPI (Advanced Configuration and Power Interface) is a Power Management and configuration standard for the PC, it allows operating systems to control many different hardware features, like amount of power on each device, thermal zones, fan control, IRQs, battery levels etc. + +We need to access the ACPI Tables in order to read the IO-Apic information, used to receive hardware interrupts (it will be explained later) + +## RSDP and RSDT/XSDT + +Many of the information are organized and accessible through different data structures, but since the ACPI specs are quite big, and cover so many different components, we focus only on what we just need to get the informations we need about the APIC. + +Before proceeding let's keep in mind that all address described below are physical, so if we will enable paging, keep in mind that we need to ensure they are properly mapped in the virtual memory spacea. + +### RSDP + +The RSDP (Root System Description Pointer) used in the ACPI programming interface is the pointer to the RSDT (Root System Descriptor Table) the full structure is depending if the version of ACPI used is 1 or 2, the newer version is just extending the previous one. + +The newer version is backward compatible with the older. + +#### Accessing the RSDP + +Accessing the RSDP register depends on the boot system used, if we are using grub, we get a copy of the RSDT/XSDT in one of the multiboot2 header tags. The specs contains two possible tags for the RSDP value, which one is used depend on the version: + +* For the version 1 the MULTIBOOT_TAG_TYPE_ACPI_OLD is used (type 14) +* For the version 2 the MULTIBOOT_TAG_TYPE_ACPI_NEW is used (type 15) + +Both headers are identical, with the only difference being in the type value, they are compoosed of just two fields: + +* The type field that can be 14 or 15 depending on the version +* The size of the RSDP + +And is followed by the RSDP itself. + +#### RSDP Structure + +As already mentioned there are two different version of RSDP, basic data structure for RSDP v1 is: + +```c +struct RSDPDescriptor { + char Signature[8]; + uint8_t Checksum; + char OEMID[6]; + uint8_t Revision; + uint32_t RsdtAddress; +} __attribute__ ((packed)); +``` + +Where the fields are: + +* *Signature*: Is an 8 byte string, that must contain: "RSDT PTR " **P.S. The string is not null terminated** +* *Checksum*: The value to add to all the other bytes (of the Version 1.0 table) to calculate the Checksum of the table. If this value added to all the others and casted to byte isn't equal to 0, the table must be ignored. +* *OEMID*: Is a string that identifies the OEM +* *Revision*: Is the revision number +* *RSDTAddress*: The address of the RSDT Table + +The structure for the v2 header is an extension of the previous one, so the fields above are still valid, but in addition it has also the following extra-fields: + +```c +struct RSDP2Descriptor +{ + //v1 fields + uint32_t Length; + uint64_t XSDTAddress; + uint8_t ExtendedChecksum; + uint8_t Reserved[3]; +}; +``` + +* *Length*: is the length of this data and its data, meaning the xsdt + all the other SDTs. +* *XSDTAddress*: Address of the XSDT table. If this is non-zero, the RSDT address **must** be ignored and the XSDT is to be used instead. +* *ExtendedChecksum*: Same as the previous checksum, just includes the new fields. + +#### RSDP Validation + +Before proceeding let's explain little bit better the validation. For both version what we need to check is that the sum of all bytes composing the descriptor structure have last byte equals to 0. How is possible to achieve that, and keep the same function for both? That is pretty easy, we just need cast the `RSDP*Descriptor` to a char pointer, and pass the size of the correct struct. Once we have done that is just mutter of cycling a byte array. Here the example code: + +```c +bool validate_RSDP(char *byte_array, size_t size) { + uint32_t sum = 0; + for(int i = 0; i < size; i++) { + sum += byte_array[i]; + } + return (sum & 0xFF) == 0; +} +``` + +Having last byte means that `result mod 0x100` is 0. Now there are two ways to test it: + +* Using the `mod` instruction, and check the result, if is 0 the structure is valid, otherwise it should be ignored +* Just checking the last byte of the result it can be achieved in several ways: for example is possible cast the result to `uint_8` if the content after casting is 0 the struct is valid, or use bitwise AND with `0xFF` value (`0xFF` is equivalent to the 0b11111111 byte) `sum & 0xFF`, if it is 0 the struct is valid otherwise it has to be ignored. + +The function above works perfectly with both versions of descriptors. +In the XSDT since it has more fields, the previous checksum field wont offset them properly (because it doesn't know about them), so this is why an extended checksum field is added. + +### RSDT Data structure and fields + +RSDT (Root System Description Table) is a data structure used in the ACPI programming interface. This table contains pointers to many different table descriptor (SDTs). Explaining all the tables is beyond of the scope of these notes, and for our purpose we are going to need only one of those table (the APIC table that we will enocunter later). + +Since every SDT table contains different type of information, they are all different from each other, we can define an RSDT table by the composition of two parts: + +* the first part is the header, common between all the SDTs with the following structure: + +```c +struct ACPISDTHeader { + char Signature[4]; + uint32_t Length; + uint8_t Revision; + uint8_t Checksum; + char OEMID[6]; + char OEMTableID[8]; + uint32_t OEMRevision; + uint32_t CreatorID; + uint32_t CreatorRevision; +}; +``` +* The second part is the table itself, every SDT has it's own table + +#### RSDT vs XSDT + +These 2 tables have the same purpose and are mutually exclusive. If the latter exists, the former is to be ignored, otherwise use the former. + +The RSDT is an SDT header followed by an array of `uint32_t`s, representing the address of another SDT header. + +The XSDT is the same, except the array is of `uint64_t`s. + +```c +struct RSDP +{ + ACPISDTHeader sdtHeader; //signature "RSDP" + uint32_t sdtAddresses[]; +}; + +struct XSDT +{ + ACPISDTHeader sdtHeader; //signature "XSDT" + uint64_t sdtAddresses[]; +}; +``` + +This means that if we want to get the n-th SDT table we just need to acces the corresponding item in the *SDT array: + +```c +//to get the sdt header at n index +ACPISDTHeader* header = (ACPISDTHeader*)(use_xsdt ? xsdt->sdtAddresses[n] : (uint64_t)rsdt->sdtAddresses[n]); +``` + +### Some useful infos + +* Be aware that the Signature in the RSD* structure is not null terminated. This means that if you try to print it, you will most likely end up in printing garbage in the best case scenario. +* The RSDT Data is an array of uint32_t addresses while the XSDT data is an array of uint64_t addresses. The number of items in the RSDT and XSDT can be computed in the following way: + +```c +//for the RSDT +size_t number_of_items = (rsdt->sdtHeader.Length - sizeof(ACPISDTheader)) / 4; +//for the XSDT +size_t number_of_items = (xsdt->sdtHeader.Length - sizeof(ACPISDTHeader)) / 8; +``` + +## Useful links + +* Osdev wiki page for RSDP: https://wiki.osdev.org/RSDP +* Osdev wiki page for RSDT: https://wiki.osdev.org/RSDT + diff --git a/02_Architecture/APIC.md b/02_Architecture/APIC.md new file mode 100644 index 00000000..9f95cba7 --- /dev/null +++ b/02_Architecture/APIC.md @@ -0,0 +1,314 @@ +# APIC + +## What is APIC + +APIC stands for *Advanced Programmable Interrupt Controller*, and it's the device used to manage incoming interrupts to a processor core. It replaces of the old PIC8259 (that remains still available), but it offers more functionality especially when dealing with SMP. In fact one of the limitations of the PIC was that it was able to deal with only one cpu at time, and this is also the main reason why the APIC was firstly introduced. + +It's worth noting that Intel later developed a version of the APIC called the SAPIC for the Itanium platform. These are referred to collectively as the *xapic*, so if you see this term used in documentation know that it just means the local APIC. + +## Types of APIC + +There are two types of APIC: + +* _Local APIC_: it is present in every processor core, it is responsible for handling incoming interrupts for *that core*. It can also be used for sending an IPI (inter-processor interrupt) to other cores, as well as generating some interrupts itself. Interrupts generated by the local APIC are controlled by the LVT (local vector table), which is part of the local APIC registers. The most interesting of these is the timer LVT, which we will take a closer look at in the timers chapter. +* _IO/APIC_: An IO APIC acts a 'gateway' for devices in the system to send interrupts to local APICs. Most personal computers will only have a single IO APIC, but more complex systems (like servers or industrial equipment) may contain multiple IO APICs. Each IO APIC has a number of input pins, which a connected device triggers when it wants to send an interrupt. When this pin is triggered, the IO APIC will send an interrupt to one (or many) local APICs, depending on the *redirection entry* for that pin. We can program these redirection entries, and they're presented as an array of memory-mapped registers. We'll look more at this later. In summary, an IO APIC allows us to route device interrupts to processor cores however we want. + +Both types of APIC are accessed by memory mapped registers, with 32-bit wide registers. They both have well-known base addresses, but rather than hardcoding these they should be fetched from the proper places as firmware (or even the bootloader) may move these around before our kernel boots. + +## Local APIC + +When a system boots up, the cpu starts in PIC8259A emulation mode for legacy reasons. This simply means that instead of having the LAPIC/IO-APIC up and running, we have them working to emulate the old interrupt controller, so before we can use them properly we should to disable the PIC8259 emulation. + +### Disabling The PIC8259 + +This part should be pretty straightforward, and we will not go deep into explaining the meaning of all command sent to it. The sequence of commands is: + +```c +void disable_pic() { + outportb(PIC_COMMAND_MASTER, ICW_1); + outportb(PIC_COMMAND_SLAVE, ICW_1); + outportb(PIC_DATA_MASTER, ICW_2_M); + outportb(PIC_DATA_SLAVE, ICW_2_S); + outportb(PIC_DATA_MASTER, ICW_3_M); + outportb(PIC_DATA_SLAVE, ICW_3_S); + outportb(PIC_DATA_MASTER, ICW_4); + outportb(PIC_DATA_SLAVE, ICW_4); + outportb(PIC_DATA_MASTER, 0xFF); + outportb(PIC_DATA_SLAVE, 0xFF); +} +``` + +The old x86 architecture had two PIC processor, and they were called "master" and "slave", and each of them has it's own data port and command port: + +* Master PIC command port: `0x20` and data port: `0x21`. +* Slave PIC command port: `0xA0` and data port `0xA1`. + +The ICW values are initialization commands (ICW stands for Initialization Command Words), every command word is one byte, and their meaning is: + +* ICW_1 (value `0x11`) is a word that indicates a start of inizialization sequence, it is the same for both the master and slave pic. +* ICW_2 (value `0x20` for master, and `0x28` for slave) are just the interrupt vector address value (IDT entries), since the first 31 interrupts are used by the exceptions/reserved, we need to use entries above this value (remember that each pic has 8 different irqs that can handle. +* ICW_3 (value `0x2` for master, `0x4` for slave) Is is used to indicate if the pin has a slave or not (since the slave pic will be connected to one of the interrupt pins of the master we need to indicate which one is), or in case of a slave device the value will be it's id. On x86 architectures the master irq pin connected to the slave is the second, this is why the value of ICW_M is 2 +* ICW_4 contains some configuration bits for the mode of operation, in our case we just tell that we are going to use the 8086 mode. +* Finally `0xFF` is used to mask all interrupts for the pic. + +### Discovering the Local APIC + +The first step needed to configure the LAPIC is getting access to it. The APIC registers are memory mapped, and to get their location we need to read the MSR (*model specific register*) that contains its base address, using the __rdmsr__ instruction. This instruction reads the content of the MSR specified in `ecx`, the result is placed in `eax` and `edx` (with `eax` containing the lower 32-bits, and `edx` container the upper 32-bits). + +In our case the MSR that we need to read is called IA32_APIC_BASE and its value is `0x1B`. + +This register contains the following information: + +* Bits 0:7: reserved. +* Bit 8: if set, it means that the processor is the Bootstrap Processor (BSP). +* Bits 9:10: reserved. +* Bit 11: APIC global enable. This bit can be cleared to disable the local APIC for this processor. Realistically there is no reason to do this on modern processors. +* Bits 12:31: Contains the base address of the local APIC for this processor core. +* Bits 32:63: reserved. + +Note that the registers are given as a *physical address*, so to access these you will need to map them somewhere in the virtual address space. This is true for the addresses of any IO APICs you obtain as well. When the system boots, the base address is usually `0xFEE0000` and often this is the value we read from `rdmsr`. + +A complete list of local APIC registers is available in the Intel/AMD software development manuals, but the important ones for now are: + +- Spurious Interrupt Vector: offset `0xF0`. +- EOI (end of interrupt): offset `0xB0`. +- Timer LVT: offset `0x320`. +- Local APIC ID: offset `0x20`. + +### Enabling the Local APIC, and The Spurious Vector + +The spurious vector register is also contains some miscellanious config for the local APIC, including the enable/disable flag. This register has the following format: + +| Bits | Value | +|-------|------------------------------| +| 0-7 | Spurious vector | +| 8 | APIC Software enable/disable | +| 9 | Focus Processor checking | +| 10-31 | Reserved | + +The functions of the fields in the registers are as follows: + +* Bits 0-7: They determine the vector number (IDT entry) for the spurious interrupt generated by the APIC. +* Bit 8: This bit acts a software toggle for enabling the local APIC, if set the local APIC is enabled. +* Bit 9: This is an optional feature not available on processors, but if set it indicates that some interrupts can be routed according to a list of priorities. This is an advanced topic and this bit can be safely left clear and ignored. + +The Spurious Vector register is writable only in the first 9 bits, the rest is read only. In order to enable the lapic we need to set bit 8, and set-up a spurious vector entry for the idt. In modern processors the spurious vector can be any vector, however old CPUs have the upper 4 bits of the spurious vector forced to 1, meaning that the vector must be between `0xF0` and `0xFF`. For compatibility it's best to place your spurious vector in that change. Of course we need to set-up the corresponding idt entry with a function to handle it, but for now printing an error message is enough. + +### Reading APIC Id and Version + +The ID register contains the *physical id* of the local APIC in the system. This is unique and assigned by the firmware when the system is first started. Often this ID is used to distinguish each processor from the others due to them being unique. This register is allowed to be read/write in some processors, but it's recommended to treat it as read-only. + +The version register contains some useful (if not really needed) information. Exploring this register is left as an exercise to the reader. + +### Local Vector Table + +The local vector table allows the software to specify how the local interrupts are delivered. +There are 6 items in the LVT starting from offset `0x320` to `0x370`: + +* *Timer*: used for controlling the local APIC timer. Offset: `0x320`. +* *Thermal Monitor*: used for configuring interrupts when certain thermal conditions are met. Offset: `0x330`. +* *Performance Counter*: allows an interrupt to be generated when a performance counter overflows. Offset: `0x340`. +* *LINT0*: Specifies the interrupt delivery when an interrupt is signaled on LINT0 pin. Offset: `0x350`. +* *LINT1*: Specifies the interrupt delivery when an interrupt is signaled on LINT1 pin. Offset: `0x360`. +* *Error*: configures how the local APIC should report an internal error, Offset `0x370`. + +The `LINT0` and `LINT1` pins are mostly used for emulating the legacy PIC, but they may also be used as NMI sources. These are best left untouched until you have parsed the MADT, which will tell you how you should program the LVT for these pins. + +Most LVT entries use the following format, with the timer LVT being the notable exception. It's format is explained in the timers chapter. The thermal sensor and performance entries ignore bits 15:13. + +| Bit | Description | +|----------|----------------------------------------------------------------------------------------------| +| 0:7 | Interrupt Vector. This is the IDT entry we want to trigger when for this interrupt. | +| 8:10 | Delivery mode (see below) | +| 11 | Destination Mode, can be either physical or logical. | +| 12 | Delivery Status **(Read Only)**, whether the interrupt has been served or not.| +| 13 | Pin polarity: 0 is active-high, 1 is active-low. | +| 14 | Remote IRR **(Read Only)** used by the APIC for managing level-triggered interrupts. | +| 15 | Trigger mode: 0 is edge-triggered, 1 is level-triggered. | +| 16 | Interrupt mask, if it is 1 the interrupt is disabled, if 0 is enabled. | + +The delivery mode field determines how the the APIC should present the interrupt to the processor. The fixed mode (0b000) is fine in almost all cases, the other modes are for specific functions or advanced usage. + +### X2 APIC + +The X2APIC is an extension of the XAPIC (the local APIC in it's regular mode). The main difference is the registers are now accessed via MSRs and some the ID register is expanded to use a 32-bit value (previously 8-bits). While we're going to look at how to use this mode, it's perfectly fine to not support it. + +Checking whether the current processor supports the X2APIC or not can be done via `cpuid`. It will be under leaf 1, bit 21 in `ecx`. If this bit is set, your processor supoorts the X2APIC. + +Enabling the X2APIC is done by setting bit 10 in the IA32_APIC_BASE MSR. It's important to note that once this bit is set, you cannot clear it to transition back to the regular APIC operation without resetting the system. + +Once enabled, the local APIC registers are no longer memory mapped (trying to access them there is now an error) and can instead be accessed as a range of MSRs starting at `0x800`. Since each MSR is 64-bits wide, the offset used to access an APIC register is shifted right by 4 bits. + +As an example, the spurious interrupt register is offset `0xF0`. To access the MSR version of this register we would shift it right by 4 (`0xF0 >> 4` = 0xF) and then add the base offset (`0x800`) to get the MSR we want. That means the spurious interrupt register is MSR `0x80F`. + +Since MSRs are 64-bits, the upper 32 bits are zero on reads and ignored on writes. As always there is an exception to this, which is the ICR register (used for sending IPIs to other cores) which is now a single 64-bit register. + +### Handling Interrupts + +Once an interrupt for the local APIC is served, it won't send any further interrupts until the end of interrupt signal is sent. To do this write a 0 to the EOI register, and the local APIC will resume sending interrupts to the processor. This is a separate mechanism to the interrupt flag (IF), which also disables interrupts being served to the processor. It is possible to send EOI to the local APIC while IF is cleared (disabling interrupts) and no futher interrupts will be served until IF is set again. + +There are few exceptions where sending an EOI is not needed, this is mainly spurious interrupts and NMIs. + +The EOI can be sent at any time when handling an interrupt, but it's important to do it before returning with `iret`. If you enable interrupts and only receive a single interrupt, forgetting to send EOI may be the reason. + +### Sending An IPI + +If you want to support SMP (multiple cores) in your kernel, you will need a way to inform other cores that an event has occured. This is typically done by sending an IPI. Note that IPIs don't carry any information about what event occureed, they simply indicate that *something* has happened. To send data about what the event is a struct is usually placed in memory somewhere, sometimes called a *mailbox*. + +To send an IPI we need to know the local APIC ID of the core we wish to interrupt. We will also need a vector in the IDT set up for handling IPIs. With these two things we can use the ICR (interrupt command register). + +The ICR is 64-bits wide and therefore we access it as two registers (a higher and lower half). The IPI is sent when the lower register is written to, so we should set up the destination in the higher half first, before writing the vector in the lower half. + +This register contains a few fields but most can be safely ignored and left to zero. We're interested in bits 63:56 which is the ID of the target local APIC (in X2APIC mode it's bits 63:32) and bits 7:0 which contain the interrupt vector that will be served on the target core. + +An example function might look like the following: + +```c +void lapic_send_ipi(uint32_t dest_id, uint8_t vector) { + lapic_write_reg(ICR_HIGH, dest_id << 24); + lapic_write_reg(ICR_LOW, vector); +} +``` + +At this point the target core would receive an interrupt with the vector we specified (assuming that core is setup correctly). + + +There is also a shorthand field in the ICR which overrides the destination id. It's available in bits 19:18 and has the following definition: + +- 0b00: no shorthand, use the destination id. +- 0b01: send this IPI to ourselves, no one else. +- 0b10: send this IPI to all lapics, including ourselves. +- 0b11: send this IPI to all lapics, but not ourselves. + +## IOAPIC + +The IOAPIC primary function is to receive external interrupt events from the systems, and is associated with I/O devices, and relay them to the local apic as interrupt messages, with the exception of the lapic timer, all external devices are going to use the IRQs provided by it (like it was done in the passt by the PIC8259). + +### Configure the IO-APIC + +To configure the IO-APIC we need to: + +1. Get the IO-APIC base address from the MADT +2. Read the IO-APIC Interrupt Source Override table +3. Initialize the IO Redirection table entries for the interrupt we want to enable + +### Getting IO-APIC address + +Read IO-APIC information from MADT table (the MADT table is available within the RSDT data (please refer here: https://github.com/dreamos82/Osdev-Notes/blob/master/RSDP_and_RSDT.md), you need to search for the MADT Table item type 1). The content of the MADT Table for the IO_APIC type is: + +| Offset | Length | Description | +|--------|--------|------------------------------| +| 2 | 1 | I/O Apic ID's | +| 3 | 1 | Reserved (should be 0) | +| 4 | 4 | I/O Apic Address | +| 8 | 4 | Global System Interrupt Base | + +The IO APIC ID field is mostly fluff, as you'll be accessing the io apic by it's mmio address, not it's ID. + +The Global System Interrupt Base is the first interrupt number that the I/O Apic handles. In the case of most systems, with only a single IO APIC, this will be 0. + +To check the number of inputs an IO APIC supports: + +```c +uint32_t ioapicver = read_io_apic_register(IOAPICVER); +size_t number_of_inputs = ((ioapicver >> 16) & 0xFF) + 1; +``` + +The number of inputs is encoded as bits 23:16 of the IOAPICVER register, minus one. + + +### IO-APIC Registers + +The IO-APIC has 2 memory mapped registers for accessing the other IO-APIC registers: + +| Memory Address | Mnemonic Name | Register Name | Description | +|----------------|---------------|--------------------|----------------------------------------------| +| FEC0 0000h | IOREGSEL | I/O Register Select| Is used to select the I/O Register to access | +| FEC0 0010h | IOWIN | I/O Window (data) | Used to access data selected by IOREGSEL | + +And then there are 4 I/O Registers that can be accessed using the two above: + +| Name | Offset | Description | Attribute | +|:------------:|----------|--------------------------------------------------------|-----------| +| IOAPICID | 00h | Identification register for the IOAPIC | R/W | +| IOAPICVER | 01h | IO APIC Version | RO | +| IOAPICARB | 02h | It contains the BUS arbitration priority for the IOAPIC| RO | +| IOREDTBL | 03h-3fh | The redirection tables (see the IOREDTBL paragraph) | RW | + + +### Reading data from IO-APIC + +There are basically two addresses that we need to use in order to write/read data from apic registers and they are: + +* IO_APIC_BASE address, that is the base address of the IOAPIC, called *register select* (or IOREGSEL) and used to select the offset of the register we want to read +* IO_APIC_BASE + 0x10, called *i/o window register* (or IOWIN), is the memory location mapped to the register we intend to read/write specified by the contents of the *Register Select* + +The format of the IOREGSEL is: + +| Bit | Description | +|---------|----------------------------------------------------------------------------------------------------------------------| +| 31:8 | Reserved | +| 7:0 | APIC Register Address, they specifies the IOAPIC Registers to be read or written via the IOWIN Register | + +So basically if we want to read/write a register of the IOAPIC we need to: + +1. write the register index in the IOREGSEL register +2. read/write the content of the register selected in IOWIN register + +The actual read or write operation is performed when IOWIN is accessed. +Accessing IOREGSEL has no side effects. + +### Interrupt source overrides +They contain differences between the IA-PC standard and the dual 8250 interrupt definitions. The isa interrupts should be identity mapped into the first IO-APIC sources, but most of the time there will be at least one exception. This table contains those exceptions. + +An example is the PIT Timer is connected to ISA IRQ 0, but when apic is enabled it is connected to the IO-APIC interrupt input pin 2, so in this case we need an interrupt source override where the Source entry (bus source) is 0 and the global system interrupt is 2 +The values stored in the IO Apic Interrupt source overrides in the MADT are: + +| Offset | Length | Description | +|--------|--------|------------------------------| +| 2 | 1 | bus source (it should be 0) | +| 3 | 1 | irq source | +| 4 | 4 | Global System Interrupt | +| 8 | 2 | Flags | + +* Bus source usually is constant and is 0 (is the ISA irq source), starting from ACPI v2 it is also a reserved field. +* Irq source is the source IRQ pin +* Global system interrupt is the target IRQ on the APIC + +Flags are defined as follows: + +* Polarity (*Lenght*: **2 bits**, *Offset*: *0* of the APIC/IO input signals, possible values are: + * 00 Use the default settings is active-low for level-triggered interrupts) + * 01 Active High + * 10 Reserved + * 11 Active Low +* Trigger Mode (*Length*: **2 bits**, *Offset*: *2*) Trigger mode of the APIC I/O Input signals: + * 00 Use the default settiungs (in the ISA is edge-triggered) + * 01 Edge-triggered + * 10 Reserved + * 11 Level-Triggered +* Reserved (*Length*: **12 bits**, *Offset*: **4**) this must be 0 + + +### IO Redirection Table (IOREDTBL) + +They can be accessed vie memory mapped registers. Each entry is composed of 2 registers (starting from offset 10h). So for example the first entry will be composed by registers 10h and 11h. + +The content of each entry is: + +* The lower double word is basically an LVT entry, for their definition check the LVT entry definition +* The upper double word contains: + - Bits 17 to 55: are Reserved + - Bits 56 to 63: are the Destitnation Field, In physical addressing mode (see the destination bit of the entry) it is the local apic id to forward the interrupts to, for more information read the IO-APIC datasheet. + +The number of items is stored in the IO-APIC MADT entry, but usually on modern architectures is 24. + +#### Delivery modes + + Do we need it? + +## Useful Resources + +* Intel Software developer's manual Vol 3A APIC Chapter +* IOAPIC Datasheet https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf +* http://www.brokenthorn.com/Resources/OSDevPic.html diff --git a/02_Architecture/PS2_Keyboard/01_README.md b/02_Architecture/PS2_Keyboard/01_README.md new file mode 100644 index 00000000..23e6b44b --- /dev/null +++ b/02_Architecture/PS2_Keyboard/01_README.md @@ -0,0 +1,47 @@ +# Adding keyboard support + +Writing an OS is great fun, but instead of only printing stuff to the screen, it would be better if we could interact with the user, right? + +In this section we will see how to interact with keyboard, and get the user input. + +The topics covered by this section are: + +* [Handling the keyboard interrupt](02_Interrupt_Handling.md) +* [Writing a driver](03_Driver_Implementation.md) + +## Keyboard Overview + +Before proceeding further let's have a quick high level overview of a keyboard. + +We'll be dealing with the PS/2 keyboard in this section, which communicates with us via the PS/2 controller in our system. Other keyboard running over more complex protocols (like USB) can be used to emulate a PS/2 keyboard, but this requires support from the device and motherboard. The good news for laptop developers is that most laptop keyboards (and trackpads) are actually still using PS/2 internally. + +Keyboards can accept several commands and generate interrupts, placing a byte on the communication port. + +Whenever a key is pressed or released the keyboard sends some data to us via the communication port, this data is called a *scancode*, and is composed of one or more bytes. + +There are three different sets of scancodes available (1, 2 and 3). Sets 1 and 2 are the most widely supported, set 3 was a later addition and is rare to see in the wild. Set 1 was the first, and a lot of software at the time was hardcoded to support it. This prevented an interesting problem when set 2 was introduced later on, and then standardized as being the default set for a keyboard. The solution was to keep set 2 as the default, but the ps/2 controller will translate set 2 scancodes into set 1 scancodes. To ensure compatability with older software, and confuse future os developers, this feature is enabled by default. + +The scancode that is generated when a key is pressed is called the **make** code, while the scancode generated by a key release is calle the **break** code. + +In order to develop our keyboard driver we'll need to do the following: + +* First identify the scancode set used by our keyboard, this is important because it is going to influence our mapping. +* Enable the Keyboard IRQ, how to do this depends if we are using the PIC or the IOAPIC, but in both cases we need to set up a handler and unmask the relevant entry into a IRQ table. +* Read the scancode byte. +* Once we have the full scancode, store it in a buffer along with any extra info we might need (any currently pressed modifers). + +As you can see translation the scancode to a printable character is not in the list above, we'll touch on how to do this briefly, although it's not really related to the keyboard driver. + +### Useful Links + +* [https://wiki.osdev.org/PS/2_Keyboard](https://wiki.osdev.org/PS/2_Keyboard) +* [https://wiki.osdev.org/IRQ#From_the_keyboard.27s_perspective](https://wiki.osdev.org/IRQ#From_the_keyboard.27s_perspective) +* [https://wiki.osdev.org/%228042%22_PS/2_Controller#Translation](https://wiki.osdev.org/%228042%22_PS/2_Controller#Translation) +* [https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#scancodesets](https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#scancodesets) +* [http://www.brokenthorn.com/Resources/OSDev19.html](http://www.brokenthorn.com/Resources/OSDev19.html) + + + + + + diff --git a/02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md b/02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md new file mode 100644 index 00000000..77acf3ff --- /dev/null +++ b/02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md @@ -0,0 +1,111 @@ +# Handling The Keyboard Interrupt + +Either the PIC or IOAPIC can be used to set up the keyboard irq. For this section we'll use the IOAPIC as it's more modern and the LAPIC + IOAPIC is the evolution of the PIC. However if you are using the PIC, most of the theory still applies, you'll need to adjust the irq routing code accordingly. + +To keep the examples below simple, we'll assume only a single IOAPIC is present in the system. This is true for most desktop systems, and is only something to worry about in server hardware. + +## IRQ and IOAPIC + +* The ps/2 keyboard is irq 1, this corresponds to pin 1 on the IOAPIC meaning we'll be accessing redirect entry 1. +* Redirection entries are accessed as 2x 32-bit registers, where the register number is defined as follows: + +``` +redtbl_offset = 0x10 + (entry_number * 2) +``` + +In this case then we have the offset for our entry at: `0x12` and `0x13` (called IOREDTBL1 in the spec), where `0x12` is the lower 32-bits of the table entry. + +Before unmasking the keyboard interrupt, we need an entry in the IDT, and a function (we can leave it empty for now) for the IDT entry to call. For this section we will call the function `keyboard_irq_handler`: + +```c +void keyboard_irq_handler() { + +} +``` + +Once we have a valid IDT entry, we can clear the mask bit in the IOAPIC redirect entry for the ps/2 keyboard. Be sure that the destination LAPIC id is set to the cpu you want to handle the keyboard interrupts. +This id can be read from the LAPIC registers. + + +## Driver Information + +The ps2 keyboard uses two IO ports for communication: + +| IO Port | Access Type | Purpose | +|---------|-------------|-----------------------------------------------------------------| +| 0x60 | R/W | Data Port | +| 0x64 | R/W | On read: status register. On Write: command register | + +* Since there are three different scancode sets, it's a good idea to check what set the keyboard is currently using. +* Usually the PS/2 controller (the device that the OS is actually talking to on ports `0x60` and `0x64`) converts set 2 scancodes into set 1 (for legacy reasons). +* To check if the translation is enabled, the command `0x20` must be sent on port `0x64`, and then read the byte on `0x60`. If the 6th bit is set than the translation is enabled. +* If we want to disable the translation we need: + - Read current controller configuration byte, by sending command `0x20` to port `0x64` (the reply byte will be sent on port `0x60`). + - Clear the 6th bit on the current controller configuration byte. + - To send the modified config byte back to the controller, send command `0x60` (to port `0x64`), then send the byte to port `0x60`. + - For our driver we will keep the translation enabled, since we'll be using set 1. +* The only scancode set guaranted to be supported by keyboards is the set 2. Keep in mind that most of the time the kernel communicate with the a controller compatible with the intel 8042 PS2 controller. In this case the scancodes can be translated into set 1. + + +### Sending Commands To The Keyboard + +To send commands to the PS/2 keyboard, we need to send the bytes directly to the data port (instead of the PS/2 controller command port). + +## Identifying The Scancode Set + +As mentioned in the introduction, we'll need to know to implement our keyboard support is what scancode set is being used by our system, and do one of the following things: + +* If we want to implement the support to all the three sets we will need to tell the driver what is the one being used by the keyboard. +* Try to set the keyboard to use a scancode we support (not all keyboard support all the sets, but it worth a try). +* If we're supporting set 1, we can try to enable translation on the PS2 controlle. +* Do nothing if it is the same set supported by our os. + +The keyboard command to get/set the scancode set used by the controller is `0x60` followed by another byte: + +| Value | Description | +|-------|-----------------------| +| 0 | Get current set | +| 1 | Set scancode set 1 | +| 2 | Set scancode set 2 | +| 3 | Set scancode set 3 | + +Now the keyboard will reply with 2 bytes: if we are setting the scancode, set the reply will be: `0xFA 0xFE`. If we are reading the current used set the response will be: `0xFA` followed by one of the below values: + +| Value | Description | +|-------|-------------------| +| 0x43 | Scancode set 1 | +| 0x41 | Scancode set 2 | +| 0x3f | Scancode set 3 | + +### About Scancode + +The scancode can be one of the following types: + +* A MAKE code, generated when a key is pressed. +* A BREAK code, generated when a key is released. + +The value of those code depends on the set in use. + +## Handling Keyboard Interrupts + +When a key is pressed/released the keyboard pushes the bytes that make up the scancode into the ps2 controller buffer, then triggers an interrupt. We'll need to read these bytes, and assemble them into a scancode. +If it's a simple scancode, only 1 byte in length then we can get onto the next step. + +```C +void keyboard_irq_handler() { + int scancode = inb(0x60); + //do_something_with_the_scancode(scancode); + + //Let's print the scancode we received for now + printf("Scancode read: %s\n", scancode); +} + +``` + +For set 1, the most significant bit of the scancode indicates whether it's a MAKE (MSB = 0) or BREAK (MSB = 1). +For set 2, a scancode is always a MAKE code, unless prefixed with the byte `0xF0`. + +Keep in mind that when we have multibyte scancodes (i.e. left ctrl, pause, and others), an interrupt is raised for every byte placed on the data buffer. + +*To be Continued...* + diff --git a/02_Architecture/PS2_Keyboard/03_Driver_Implementation.md b/02_Architecture/PS2_Keyboard/03_Driver_Implementation.md new file mode 100644 index 00000000..b888d6f1 --- /dev/null +++ b/02_Architecture/PS2_Keyboard/03_Driver_Implementation.md @@ -0,0 +1,297 @@ +# Keyboard Driver Implementation + +Now that we can get scancodes from the keyboard (see [here](InterruptHandling.md)), we'll look at building a simple ps/2 keyboard driver. + +First of all, the driver is generally not responsible for translating the key presses and releases into printable characters, the driver's purpose is to deal with the specifics of the device (the ps2 keyboard) and provide a generic interface for getting key presses/releases. However it does usually involve translating from the keyboard-specific scancode into an os-specific one. The idea is that if more scancode sets or keyboards (like USB) are supported later on, these can be added without having to modify any code that uses the keyboard. Simply write a new driver that provides the same interface and it will work! + +Our keyboard driver does care about keeping track of any keyboard events (presses/releases), and making them available to any code that needs them. +Quite often these events will be consumed (that is, read by some other code and then removed from the driver's buffer). + +As already mentioned there are 3 scan code sets. We'll focus on just one (set 1, since by default the ps2 controller translates the other sets to set 1 when the system is powered). We'll implement the translate function in a generic fashion to make adding other scancode sets easier in the future. + +Now let's see what are the problems we need to solve when developing a keyboard driver: + +* We'll need to store the history of key press and their statuses somewhere. +* There are some special keys that also need to be handled, and some combinations that we should handle (was shift/alt/ctrl/super pressed at the same time as this key?). +* Handle the press/release status if needed (we don't care much when we release a normal key, but we do care when we release a key like shift or similar). +* Try to not lose sequence of key pressed/released. +* Handle the caps, num, and scroll lock keys (with the leds). +* We can optionally translate the scancode into a human readable character when needed. + +From now on we will assume that the scancode translation is enabled, so no matter what set is being used it will be translate to set 1. + +## High Level Overview + +In the previous section we have seen how an interrupt was generated and how to read data from the keyboard. Now we need to write a proper driver, one which addresses the issues listed above (well not all of them since some are an higher level than they will be implemented "using" the driver, not by it). + +We will try to build the driver in small steps adding one piece at time, so it will be easier to understand it. + +### Storing A History Of Pressed Keys + +The first thing we'll want to keep track of in the keyboard driver: what keys were pressed and in what order. For our example driver we're going to use a circular buffer because it has a fixed memory usage (does not require re-allocating memory) and is similar in speed to an array. The only downside is that we have to decide what happens when the buffer is full: we can either drop the oldest scancodes, or drop the latest one we tried to add. This is not really an issue if the buffer is made large enough, given that some application will be consuming the keyboard events from the buffer shortly after they're added. + +```c +#define MAX_KEYB_BUFFER_SIZE 255 + +uint8_t keyboard_buffer[MAX_KEYB_BUFFER_SIZE]; +uint8_t buf_position = 0; +``` + +If we want to store just the scancode we don't need much more, so we can already implement our new irq handler: + +```c + +void keyboard_driver_irq_handler() { + + + uint8_t scancode = inb(0x60); // Read byte from the Keyboard data port + + keyboard_buffer[buf_position] = scancode; + buf_position = (buf_position + 1) % MAX_KEYB_BUFFER_SIZE; + +} + +``` + +And we're done! This first function will keep track of the scancode generated by a keypress, and since we're using set 1 it also will tell us if the button has been pressed (MAKE) or released (BREAK). + +Now using `uint8_t` as the buffer type can work in this rather simple scenario, but it make our driver hard to expand for future updates. For example what if we want to attach some extra information to each key event? We will actually be doing this in the future, so we'll make our lives easier now by using a struct. + +```c +typedef struct { + uint8_t code; +} key_event; +``` + +So the updated irq function will be: +```c +#define MAX_KEYB_BUFFER_SIZE 255 + +key_event keyboard_buffer[MAX_KEYB_BUFFER_SIZE]; +uint8_t buf_position = 0; + +void keyboard_driver_irq_handler() { + int scancode = inb(0x60); // Read byte from the Keyboard data port + + keyboard_buffer[buf_position].code = scancode; + buf_position = (buf_position + 1) % MAX_KEYB_BUFFER_SIZE; +} +``` + +There are a few limitations with this implementation, but we have a working skeleton of a driver. We can track keypresses in a circular buffer. + +### Handling Multi-Byte Scancodes + +Depending on the scancode set, there are some keys that generate a scancode with more than one byte. This means that we will have one interrupt generated for every byte placed on the data port. For example when using the scancode set 1 there are some keys (i.e. ctrl, shift, alt) that have the prefix byte `0xE0`. Now the problem is that we can't read both bytes in one single interrupt, because even if we do we still get two interupts generated. We're going to solve this problem by keeping track of the current status of what we're reading. To do this we will implement a very simple state machine that has two states: + +* _Normal State_: This is exactly what it sounds like and also the one the driver starts in. If the driver reads a byte that is not the prefix byte (`0xE0`) it will remain in this state. After being in the prefix state and reading a byte, it will also return to this state. +* _Prefix state_: In case the driver it encountered the prefix byte, the driver will enter into this state. While in this state we know the next read is an extended scancode, and can be processed appropriately. + +If you don't know what a state machine is there's a link to the wikipedia page in the useful links section below. It's a straightfoward concept: an algorithm can only be in one of several states, and the algorithm reacts differently in each state. In our example we're going to use a global variable to identity the state: + +```c +#define NORMAL_STATE 0 +#define PREFIX_STATE 1 + +uint8_t current_state; +``` + +There are some scancodes that have up to 4 or more bytes which we're not going to cover here. + +*Editor's note: This is one area where the state-machine implementation can break down. As you potentially need a separate state for each byte in the sequence. An alternative implementation, that's not covered here, is to have an array of `uint8_t`s, and a pointer to the latest byte in the buffer. The idea being: read a byte from the buffer, place it after the last received byte in the array, and then increment the variable of the latest byte. Then you can check if a full scancode has been received, for extended codes beginning with 0xE0 you're expecting 2 bytes, for normal codes only 1 byte. Once you've detected a full scancode in the buffer, process it, and reset the pointer in the buffer for the next byte to zero. Therefore the next byte gets placed at the start of the buffer. Now it's just a matter of making the buffer large enough, which is trivial.* + +Regarding storing the prefix byte, this comes down a design decision. In our case we're not going to store them as they don't contain any information we need later on, when translating these scancodes into the kernel scancodes. Just to re-iterate: the idea of using a separate, unrelated, scancode set inside the kernel is that we're not bound to any implementation. Our keyboard driver can support as many sets as needed, and the running programs just use what the kernel provides, in this case it's own scancode set. It seems like a lot of work up front, but it's a very useful abstraction to have! + +Now by changing the `current_state` variable, we can change how the code will treat the incoming data. We'll also need an init function, so we that can do some set up like setting the default state and zeroing the keyboard event buffer: + +```c +#define NORMAL_STATE 0 +#define PREFIX_STATE 1 + +uint8_t current_state; + +void init_keyboard() { + // Do other initialization stuff like: clean the keyboard buffer, identify the scancode set, enable the IRQ etc. + current_state = NORMAL_STATE; +} + +void keyboard_driver_irq_handler() { + int scancode = inb(0x60); // Read byte from the Keyboard data port + if (scancode == 0xE0) { + current_state = PREFIX_STATE + // We have read a prefix, so let's update the state and finish here + // this is a very simple scenario, there could be more needed depending on the design + return; + } + if (current_state == PREFIX_STATE) { + // Do what you need to store the key_code and eventually translate it to the kernel_code and return to the normal state + current_state = NORMAL_STATE; + } +} +``` + + +### Handling Modifier keys + +For our purposes we're considering the modifier keys to be *ctrl*, *alt*, *shift*, *gui/super*. The caps lock could also be considered a modifier key too. +These keys are interesting because they can drastically alter the meaning of other key presses. Of course an application can choose any key to be a modifier key, but we will only be supporting the common ones. +We're going to store the state of these modifier keys alognside each keypress (inside the struct we created earlier - see below) so that an application can quickly tell how to interpret a key event by only looking at a single event, +rather than having to track the state of the modifiers themselves. This reduces a lot of duplicate code, is a nice api to work with! + +Some examples of how an application might use the modifiers: + +* If the `shift` key is pressed the translation to ascii mechanism needs to know it because it has to return the shifted/capital symbol associated with that key. +* If `ctrl` or `alt` are pressed the driver needs to know it because it can trigger either a key combination or some of the "alt"ernative symbols on some special keyboard keys. +* If the caps lock key is pressed (not kept pressed) we need the translation function to return only the capital version of the key. + +Our driver will need to keep track of the current state of all the modifiers, and then store a snapshot of their state when a key event happens. Time to update our `key_event` structure: + +```c +typedef struct { + uint8_t code; + bool shift_pressed; + bool alt_pressed; + // ... etc +} key_event; + +``` + +Now the above structure will work, but it's not optimal as each bool takes a full byte. We can do better! Let's use a bitfield. + +Each modifier is represented by a bit, with 1 meaning the modifier was also pressed and 0 meaning it wasn't. + +```c +typedef struct { + uint8_t code; + uint8_t status_mask; +} key_event; +``` + +Now it's just a matter of keeping track of which bit represents which modifier key. The easiest way is to use `#define`s for each bit, something like: + +```c +#define CTRL_MASK 1 +#define ALT_MASK 2 +#define SHIFT_MASK 3 +``` + +We're not interested in the difference between the left and right versions of the modifier keys for now, but you could store those as separate bits if you were. +Updating the state of a modifier key can be done by using standard bitwise operations. + +As an example, say we detect the CTRL key is pressed. We would want to update the current modifiers (which we store a copy of when whenever we store a new key event): + +```c +current_modifiers |= 1 << CTRL_MASK; +``` + +And to clear the bit when we detect CTRL is released: + +```c +current_modifiers &= ~(1 << CTRL_MASK); +``` + +So now we need to just identify what key is being pressed/released and update the status_mask accordingly. + +The case of caps lock can be handled in 2 ways. The first is to add a boolean variable to the key_event struct which stores the current state of caps lock. We can also use one of the unused bits in the status_mask field. +An interesting note is that on ps/2 keyboards the LEDs must be controlled manually, implementing this is as simple as a single command to the keyboard, and is left as an exercise for the reader. + +### Translation + +Now that all the core parts of the driver are in place, let's talk about translation. + +There's two main stages of translation we're interested in at the moment: + +* From the keyboard-specific scancode to our kernel scancode (the one applications use). +* From the kernel scancode to a printable ascii character. This isn't really part of the keyboard driver, but we will cover it here since it's a useful function to test if your keyboard driver works. + +Translation from the keyboard scancode to the kernel one can be done a number of ways. For our example driver we're going to use a lookup table in the form of an array. + +Our array is going to be an aray of kernel scancodes, with the index into the array being the keyboard scancode. Let's say get scancode 0x12 from the keyboard, and we know that key is the F1 key (just an example, check the real scancodes before implementing this). + +We could use the following: +```c + +//an example of our kernel-specific scancodes +typedef enum kernel_scancodes { + [ ... ] + F1 = 0xAABBCCDD, //this can be defined to whatever value you want, the exact value is totally arbitrary. + [ ... ] +}; + +//this is our lookup table for converting scancodes +kernel_scancodes scancode_mapping[] = { + [ ... 0x11 previous entries ] + //this is at position 0x12 in the array + F1, + [ ... entries 0x13 and onwards ] +}; + +//now to translate a scancode, we would use: +uint8_t keyboard_scancode = 0x12; +kernel_scancodes translated_scancode = scancode_mapping[keyboard_scancode]; +``` + +There are a few edge cases here, one of them being what if a keyboard scancode dosnt have a kernel scancode to map to? We've used the value zero to mean 'no translation' and any key events with 0 as the scancode should be ignored. +We could also filter them out when an application tries to get any pending key events. + +We also don't check if the keyboard scancode is within the lookup table, which it may not be. This is something to consider. + +So now we have our internal representation of a scancode, and the `code` field in the `key_event` structure outlined above can use it. In the paragraph _Store Key Press History_ we have seen how the the interrupt handler should save the key event in the circular buffer. However that was before we had any translation. Using what we saw above we'll change the following line to now use the lookup table instead of storing the scancode directly: + +```c + keyboard_buffer[buf_position].code = scancode; +``` +becomes + +```c + keyboard_buffer[buf_position].code = scancode_mapping[scancode]; +``` + +At this point you have a fully functioning PS/2 keyboard driver! However we will quickly cover translating a kernel scancode into a printable character, as that's a useful feature to have at this stage. + +There's a few approaches to getting printable characters from our kernel scancodes: + +* Using a lookup table like we did before. We could have 2 tables, one for shifted keys and one for non-shifted keys. + +* Using a big switch statement, with inline if/elses to handle shifting. + +A lookup table would work the same as it did above. If you want the scancode with the value 6 to to translate to the printable character 'f', you would put 'f' at the 6th position in the lowercase array, and 'F' in the 6th position of the shifted array. + +```c +char lower_chars[] = { + 'a', 'b', 'c', 'd', 'e', 'f', [ ... ] +}; + +char shifted_chars[] = { + 'A', 'B', 'C', 'D', 'E', 'F', [ ... ] +}; + +char get_printable_char(key_event key) +{ + if (key.status_mask & CTRL_MASK || key.caps_lock) + return shifted_chars[key.code]; + else + return lower_chars[key.code]; +} +``` + +Instead of having two tables, only the lower_chars one can be used and an offset (if using basic ascii) can be used to calculate the shifted key value. This works for simple scenarios, but will break for any non-us keyboards or symbols. It's also not very expandable in the future. + +To calculate the offset to apply, you can use `size_t offset = 'a' - 'A';`, and then add `offset` to the value from the lookup table if it's a letter, or just add 0x10 if it's a digit. + +Using the switch statement approach looks how you'd expect: + +```c +char get_printable_char(key_event key) +{ + const bool shifted = key.status_mask & CTRL_MASK || key.caps_lock; + switch (key.code) + { + case KEY_A: + return shifted ? 'A' : 'a'; + case KEY_B: + return shifted ? 'B' : 'b'; + [ ... ] + } +} +``` diff --git a/02_Architecture/Timers.md b/02_Architecture/Timers.md new file mode 100644 index 00000000..fc95d3b2 --- /dev/null +++ b/02_Architecture/Timers.md @@ -0,0 +1,292 @@ +# Timer + +Timers are useful for all sorts of things, from keeping track of real-world time to forcing entry into the kernel to allow for pre-emptive multitasking. There are many timers available, some standard and some not. + +In this chapter we're going to take a look at the main timers used on x86 and what they're useful for. + +## Types and Characteristics + +At a high level, there a few things we might want from a timer: + +- Can it generate interrupts? And does it support a periodic mode? +- Can we poll it to determine how much time has passed? +- Does the main clock count up or down? +- What kind of accuracy, precision and latency does it have? + +At first most of these questions might seem unnecessary, as all we really need is a periodic timer to generate interrupts for the scheduler right? Well that can certainly work, but as you do more things with the timer you may want to accurately determine the length of time between two points of execution. This is hard to do with interrupts, and it's easier to do with polling. A periodic mode is also not always available, and sometimes you are stuck with a one-shot timer. + +For x86, the common timers are: + +- The PIT: it can generate interrupts (both periodic and one-shot) and is pollable. When active it counts down from a reload value to 0. It has a fixed frequency and is very useful for calibrating other timers we don't know the frequency of. However it does come with some latency due to operating over port IO, and it's frequency is low compared to the other timers available. +- The local APIC timer: it is also capable of generating interrupts (periodic and oneshot) and is pollable. It operates in a similar manner to the PIT where it counts down from a reload value towards 0. It's often low latency due to operating over MMIO and comes with the benefit of being per-core. This means each core can have it's own private timer, and more cores means more timers. +- The HPET: capable of polling with a massive 64-bit main counter, and can generate interrupts with a number of comparators. These comparators always support one-shot operation and may optionally support a periodic mode. It's main clock is count-up, and it is often cited as being high-latency. It's frequency can be determined by parsing an ACPI table, and thus it serves as a more accurate alternative to the PIT for calibrating other timers. +- The TSC: the timestamp-counter is tied to the core clock of the cpu, and increments once per cycle. It can be polled and has a count-up timer. It can also be used with the local APIC to generate interrupts, but only one-shot mode is available. It is often the most precise and accurate timer out of the above options. + +We're going to focus on setting up the local APIC timer, and calibrating it with either the PIT or HPET. We'll also have a look at a how you could also use the TSC with the local APIC to generate interrupts. + +### Calibrating Timers + +There are some timers that we aren't told the frequency of, and must determine this ourselves. The local APIC timer and TSC (up until recently) are examples of this. In order to use these, we have to know how fast each 'tick' is in real-world time, and the easiest way to do this is with another time that we do know the frequency of. + +This is where timers like the PIT can still be useful: even though it's very simple and not very flexible, it can used to calibrate more advanced timers like the local APIC timer. Commonly the HPET is also used for calibration purposes if it's available, since we can know it's frequency without calibration. + +Actually calibrating a timer is straightforward. We'll refer to the timer we know the frequency of as the reference timer and the one we're calibrating as the target timer. This isn't common terminology, it's just useful for the following description. + +- Ensure both timers are stopped. +- If the target timer is counts down, set it the maximum allowed value. If it counts up, set it to zero. +- Choose how long you want to calibrate for. This should be long enough to allow a good number of ticks to pass on the reference timer, because more ticks passing will mean a more accurate calibration. This time shouldn't be too long however, because if one of the timer counters rolls over then we'll trouble determining the results. A good starting place is 5-10ms. +- Start both timers, and poll the reference timer until the calibration time has passed. +- Stop both timers, and we look at how many ticks has passed for the target timer. If it's a count-down timer, we can determine this by subtracting the current value from the maximum value for the counter. +- Now we know that a certain amount of time (the calibration time) is equal to a certain number of ticks for our target timer. + +Sometimes running your kernel in a virtual machine, or on less-stable hardware can give varying results, so it can be useful to calibrate a timer multiple times and compare the results. If some results are odd, don't use them. It can also be helpful to continuously calibrate timers while you're using them, which will help correct small errors over time. + +## Programmable Interval Timer (PIT) + +The PIT is actually from the original IBM PC, and has remained as a standard device all these years. Of course these days we don't have a real PIT in our computers, rather the device is emulated by newer hardware that pretends to be the PIT until configured otherwise. Often this hardware is the HPET (see below). + +On the original PC the PIT also had other uses, like providing the clock for the RAM and the oscillator for the speaker. Each of these functions is provided by a 'channel', with channel 0 being the timer (channels 1 and 2 are the other functions). On modern PITs it's likely that only channel 0 exists, so the other channels are best left untouched. + +Despite it being so old the PIT is still useful because it provides several useful modes and a known frequency. This means we can use it to calibrate the other timers in our system, which we don't always know the frequency of. + +The PIT itself provides several modes of operation, although we only really care about a few of them: + +- Mode 0: provides a one-shot timer. +- Mode 2: provides a periodic timer. + +To access we PIT we use a handful of IO ports: + +| I/O Port | Description | +|----------|----------------------| +| 0x40 | Channel 0 data Port | +| 0x41 | Channel 1 data Port | +| 0x42 | Channel 2 data Port | +| 0x43 | Mode/Command register| + +### Theory Of Operation + +As mentioned the PIT runs at a fixed frequency of 1.19318MHz. This is an awkward number but it makes sense in the context of the original PC. The PIT contains a pair of registers per channel: the count and reload count. When the PIT is started the count register is set to value of the reload count, and then every time the main clock ticks (at 1.19318MHz) the count is decremented by 1. When the count register reaches 0 the PIT sends an interrupt. Depending on the mode the PIT may then set the count register to the reload register again (in mode 2 - periodic operation), or simple stay idle (mode 0 - one shot operation). + +The PIT's counters are only 16-bits, this means that the PIT can't count up to 1 second. If you wish to have timers with a long duration like that, you will need some software assistance by chaining time-outs together. + +### Example + +As an example let's say we want the PIT to trigger an interrupt every 1ms (1ms = 1/1000 of a second). To figure out what to set the reload register to (how many cycles of the PIT's clock) we divide the clock rate by the duration we want: + +$$\frac{1,193,180 (clock frequency)}{1000 (duration wanted)} = 1193.18 (Hz for duration)$$ + + +One problem is that we can't use floating point numbers for these counters so we truncate the result to 1193. This does introduce some error, and you can correct for this over a long time if you want. However for our purposes it's small enough to ignore, for now. + +To actually program the PIT with this value is pretty straightfoward, we first send a configuration byte to the command port (`0x43`) and then the reload value to the channel port (`0x40`). + +The configuration byte is actually a bitfield with the following layout: + +| Bits | Description | +|--------|----------------------------------------------------------------------------------------------------------------------| +| 0 | Selects BCD/binary coded decimal (1) or binary (0) encoding. If you're unsure, leave this as zero. | +| 1 - 3 | Selects the mode to use for this channel. | +| 4 - 5 | Select the access mode for the channel: generally you want 0b11 which means we send the low byte, then the high byte of the 16-bit register. | +| 6 - 7 | Select the channel we want to use, we always want channel 0. | + +For our example we're going to use binary encoding, mode 2 and channel 0 with the low byte/high byte access mode. This results in the following config byte: `0b00110100`. + +Now it's a matter of sending the config byte and reload value to the PIT over the IO ports, like so: + +```c +void set_pit_periodic(uint16_t count) { + outb(0x43, 0b00110100); + outb(0x40, count & 0xFF); //low-byte + outb(0x40, count >> 8); //high-byte +} +``` + +Now we should be getting an interrupt from the PIT every millisecond! By default the PIT appears on irq0, which may be remapped to irq2 on modern (UEFI-based) systems. Also be aware that the PIT is system-wide device, and if you're using the APIC you will need to program the IO APIC to route the interrupt to one of the LAPICs. + +## High Precision Event Timer (HPET) + +The HPET was meant to be the successor to the PIT as a system-wide timer, with more options however it's design has been plagued with latency issues and occasional glitches. With all that said it's still a much more accurate and precise timer than the PIT, and provides more features. It's also worth noting the HPET is not available on every system, and can sometimes be disabled via firmware. + +### Discovery + +To determine if the HPET is available you'll need access to the ACPI tables. Handling these is covered in a separate chapter, but we're after one particular SDT with the signature of 'HPET'. If you're not familiar with ACPI tables yet, feel free to come back to the HPET later. + +This SDT has the standard header, followed by the following fields: + +```c +struct HpetSdt { + ACPISDTHeader header; + uint32_t event_timer_block_id; + uint32_t reserved; + uint64_t address; + uint8_t id; + uint16_t min_ticks; + uint8_t page_protection; +}__attribute__((packed)); +``` + +*Authors note: the reserved field before the address field is actually some type information describing the address space where the HPET registers are located. In the ACPI table this reserved field is the first part of a 'generic address structure', however we can safely ignore this info because the HPET spec requires the registers to be memory mapped (thus in memory space).* + +We're mainly interested in the `address` field which gives us the physical address of the HPET registers. The other fields are explained in the HPET specification but are not needed for our purposes right now. + +As with any MMIO you will need to map this physical address into the virtual address space so we can access the registers with paging enabled. + +### Theory Of Operation + +The HPET consists of a single main counter (that counts up) with some global configuration, and a number of comparators that can trigger interrupts when certain conditions are met in relation to the main counter. The HPET will always have at least 3 comparators, but may have up to 32. + +The HPET is similar to the PIT in that we are told the frequency of it's clock. Unlike the PIT, the HPET spec does not give us the frequency directly, we have to read it from the HPET registers. + +Each register is accessed by adding an offset to the base address we obtained before. The main registers we're interested in are: + +- General capabilities: offset `0x0`. +- General configuration: offset `0x10`. +- Main counter value: `0xF0`. + +We can read the main counter at any time, which is measured in in timer ticks. We can convert these ticks into realtime by multiplying them with the timer period in the general capabilities register. Bits 63:32 of the general capabilities register contain the number of femtoseconds for each tick. A nanosecond is 1000 femtoseconds, and 1 second is 1'000'000'000 femtoseconds. + +We can also write to the main counter, usually you would write a 0 here when initializing the HPET in order to be able to determine uptime, but this is not really necessary. + +The general capabilities register contains some other useful information, briefly summarized below. If you're after more detail, all of this is available in the public specification. + +- *Bits 63:32*: This number of femtoseconds for each tick of the main clock. +- *Bits 31:16*: This field contains the PCI vendor ID of the HPET manufacturer, not needed for operation. +- *Bit 15*: Legacy routing support, if set indicates this HPET can emulate the PIT and RTC timers present in older PCs. +- *Bit 13*: If 1 indicates the main counter is 64-bits wide, otherwise it's 32-bits. +- *Bits 12:8*: Encodes the number of timers supported. This is the id of the last timer; a value of 2 means there are three timers (0, 1, 2). +- *Bits 7:0*: Hardware revision id. + +In order for the main counter to actually begin counting, we need to enable it. This is done by setting bit 0 of the general configuration register. Once this bit is set, the main counter will increment by one every time it's internal clock ticks. The period of this clock is what's specified in the general capabilities register (bits 63:32). + +The general configuration register also contains one other interesting setting: bit 1. If this bit is set the HPET is in legacy replacement mode, where it pretends to be the PIT and RTC timer. This is the default setting, and if you intend to use the HPET as described above this bit should be cleared. + +### Comparators + +The main counter is only suitable for polling the time, but it cannot generate interrupts. For that we have to use one of the comparators. The HPET will always have at least three comparators, but may have up to 32. In reality most vendors use the stock intel chip which comes with 3 comparators, but there are some other vendors of compatible hardware out there which may support more. + +By default the first two comparators are set up to mimic the PIT and RTC clocks, but they can be configured like the others. + +It's worth noting that all comparators support one-shot mode, but periodic mode is optional. Testing if a comparator supports periodic mode can be done by checking if bit 4 is set in the capabilities register for that comparator. + +Speaking of which: each comparator has it's own set of registers to control it. These registers are accessed as an offset from the HPET base. There are two registers we're interested in: the comparator config and capability registger (accessed at offset `0x100 + N * 0x20`), and the comparator value register (at offset `0x108 + N * 0x20`). In those equations `N` is the comparator number you want. As an example to access the config and capability register for comparator 2, we would determine it's location as: `0x100 + 2 * 0x20 = 0x140`. Meaning we would access the register at offset `0x140` from the HPET mmio base address. + +The config and capabilities register for a comparator also contains some other useful fields to be aware of: + +- *Bits 63:32*: This is a bitfield indicating which interrupts this comparator can trigger. If a bit is set, the comparator can trigger that interrupt. This maps directly to GSIs, which are the inputs to the IO APIC. If there is only a single IO APIC in the system, then these interrupt numbers map directly to the IO APIC input pins. For example if bits 2/3/4 are set, then we could trigger the IO APIC pins 2/3/4 from this comparator. +- *Bits 13:9*: Write the integer value of the interrupt you want this comparator to trigger here. It's recommended to read this register back after writing to verify the comparator accepted the interrupt number you wrote. +- *Bits 4:3*: Bit 4 is set if the comparator supports periodic mode. Bit 3 is used to select periodic mode if it's supported. If either bit is cleared, the comparator operates as a one-shot. +- *Bit 2*: Enables the comparator to generate interrupts. Even if this is cleared the comparator will still operate, and set the interrupt pending bit, but no interrupt will be sent to the IO APIC. This bit acts in reverse to how a mask bit would: if this bit is set, interrupts are generated. + +### Example + +Let's look at two examples of using the HPET timer: polling the main counter and setting up a one-shot timer. If you want a periodic timer you'll have to do a bit more work, and check that a comparator supports periodic mode. + +We're going to assume you have the HPET registers mapped into virtual memory, and that address is stored in a variable `void* hpet_regs`. + +Polling the main counter is very straightforward: + +```c +uint64_t poll_hpet() { + volatile uint64_t* caps_reg = hpet_regs; + uint32_t period = *caps_reg >> 32; + + volatile uint64_t* counter_reg = hpet_regs + 0xF0; + return *counter_reg * period; +} +``` + +This function returns the main counter of the hpet as a number of femtoseconds since it was last reset. You may want to convert this to a more managemable unit like nano or even microseconds. + +Next let's look at setting up an interrupt timer. This requires the use of a comparator, and a bit of logic. You'll also need the IO APIC set up, and we're going to use some dummy functions to show what you'd need to do. We're going to use comparator 0, but this could be any comparator. + +```c +#define COMPARATOR_0_REGS 0x100 + +void arm_hpet_interrupt_timer(size_t femtos) { + volatile uint64_t* config_reg = hpet_regs + COMPARATOR_0_REGS; + + //first determine allowed IO APIC routing + uint32_t allowed_routes = *config_reg >> 32; + size_t used_route = 0; + while ((allowed_routes & 1) == 0) { + used_route++; + allowed_routes >>= 1; + } + + //set route and enable interrupts + *config_reg &= ~(0xFul << 9); + *config_reg |= used_route << 9; + *config_reg |= 1ul << 2; + //you should configure the io apic routing here. + //this interrupt will appear on the pin 'used_route'. + + volatile uint64_t* counter_reg = hpet_regs + 0xF0; + uint64_t target = *counter_reg + (femtos / hpet_period); + volatile uint64_t* compare_reg = hpet_regs + COMPARATOR_0_REGS + 8; + *compare_reg = target; +} +``` + +## Local APIC Timer + +The next timer on our list is the local APIC timer. This timer is a bit special as a processor can only access it's local timer, and each core gets a dedicated timer. Very cool! Historically these timers have been quite good, as they're built as part of the CPU, meaning they get the same treatment as the rest of that silicon. + +However not all local APIC timers are created equal! There are a few feature flags to check for before using them: + +- ARAT/Always Running APIC Timer: cpuid leaf 6, eax bit 2. If the cpu hasn't set this bit the APIC timer may stop in lower power states. This is okay for a hobby OS, but if you do begin managing system power states later on, it's good to be aware of this. + +The timer is managed by registers within the local APIC MMIO area. The base address for this can be obtained from the lapic MSR (MSR `0x1B`). See the APIC chapter for more info on this. We're interested in three registers for the timer: the divisor (offset `0x3E0`), initial count (offset `0x380`) and timer entry in the LVT (offset `0x320`). There is also a current count register, but we don't need ot access that right now. + +Unfortunately we're not told the frequency of this timer (except for some very new cpus which include this in cpuid), so we'll need to calibrate this timer against one we already know the speed of. Other than this, using the local APIC is very simple: simply set the mode you want in the LVT entry, set the divisor and initial count and it should work. + +### Example + +Calibrating a timer is explained above, so we're going to assume you have a function called `lapic_ms_to_ticks` that converts a number of milliseconds into the number of local APIC timer ticks. You may not need this function yourself, but it serves for the example. We're also going to assume that you've set the divisor register to what you want. If you're not sure what this does, its divides the incoming clock pulses, reducing the rate the timer ticks. This is useful if you want longer clock durations. Starting with a value of 2 or 4 is recommended. + +Other than setting the initial count, we also have to set up the timer LVT entry. There's a few fields here, but we're mostly interested in the following: + +- *Bits 7:0*: this is interrupt vector the timer will trigger when it expires. It will only trigger that vector on the core the LAPIC is attached to. +- *Bit 16*: Acts as a mask bit, if set the timer won't generate an interrupt when expiring. +- *Bits 18:17*: The mode field. Set this to *0b00* for one-shot operation, and *0b01* for periodic. + +The intel and AMD manuals contain the full description if you want to explore the other functionality offered. + +```c +void arm_lapic_interrupt_timer(size_t millis, uint8_t vector) { + volatile uint32_t* lvt_reg = lapic_regs + 0x320; + //note this clears bits 16 (mask) and 18:17 (mode) + *lvt_reg = vector; + + uint32_t ticks = lapic_ms_to_ticks(millis); + volatile uint32_t* init_reg = lapic_regs + 0x380; + *init_reg = ticks; +} +``` + +## Timestamp Counter (TSC) + +The TSC is a bit more modern than the LAPIC timer, but still pre-dates most long mode processors, so this is another timer that should always be present. Having said that, it can be checked for using cpuid leaf 1, edx bit 4. + +The TSC is probably the simplest timer we've covered so far: it's simply a 64-bit counter that increments every time the base clock of the processor pulses. To read this counter we can use the `rdtsc` instruction which places the low 33-bits in eax and high 32-bits in edx. Similar to how the MSR instructions work. + +There are some issues with this version of the TSC however: modern processors will change their base speed depending on power/performance requirements, which means that the rate the TSC ticks at will change dynamically! This makes it pretty useless as a timer, and a newer version was quickly implemented, called the invariant TSC. + +The I-TSC ticks at the base speed the processor is supposed to run at, not what it's actually running at, meaning the tick-rate is constant. Most processors support the I-TSC nowadays, and most emulators also do, even if they don't advertise it through cpuid (qemu has invariant TSC, but doesn't set the bit). To test if the TSC is invariant can be done via cpuid once again: leaf 7, edx bit 8. + +How about generating interrupts with the TSC? This is also an option feature (that's almost always supported) called TSC deadline. We can test for it's existence via cpuid leaf 1, ecx, bit 24. To use TSC deadline we write the absolute time (in TSC ticks) of when we want the interrupt to a special MSR, called IA_32_TSC_DEADLINE (MSR `0x6E0`). + +When the TSC passes the tick value in this MSR, it tells the local APIC, and if TSC deadline mode is selected in the timer LVT an interrupt is generated. Selecting TSC deadline mode can be done by using mode `0b10` instead of `0b00`/`0b01` in the timer LVT register. + +## Useful Abstractions + +As we've seen there are lots of timers with varying capabilities. Some of these have analogies on other platforms, while some don't. If you intend to support all of these timers, or go cross-platform it can be worth implementing an abstract timer API, and then hiding the implementation of these timers behind it. You'll want to start with an API that at least provides the following: + +- polled_sleep(): this functions spins until the requested time has passed. +- poll_timer(): gets an absolute value of a timer, useful for timing short sections of code. Also useful for keeping track of time when an interrupt timer is not armed. +- arm_interrupt_timer(): sets a timer to trigger an interrupt at a point in the future, immediately returns control to the calling function. Arguably the most of these functions, and what you'll use to impement scheduling or other clock-based functions. + +## Useful links + +* [Ehtereality osdev Notes - Apic/Timing/Context Switching](https//ethv.net/workshops/osdev/notes/notes-4.html) +* [OSdev Wiki - Pit page](https://wiki.osdev.org/Programmable_Interval_Timer) +* [Brokern Thron Osdev Series](http://www.brokenthorn.com/Resources/OSDev16.html) From 141932ffd52bdc805aa7681a5e7f98d7a5102435 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Thu, 30 Mar 2023 15:58:55 +0100 Subject: [PATCH 07/32] Updating README and renaming some chapters --- .../{ACPITables.md => 05_ACPITables.md} | 0 02_Architecture/{APIC.md => 06_APIC.md} | 0 02_Architecture/{Timers.md => 07_Timers.md} | 0 README.md | 33 +++++++++---------- 4 files changed, 16 insertions(+), 17 deletions(-) rename 02_Architecture/{ACPITables.md => 05_ACPITables.md} (100%) rename 02_Architecture/{APIC.md => 06_APIC.md} (100%) rename 02_Architecture/{Timers.md => 07_Timers.md} (100%) diff --git a/02_Architecture/ACPITables.md b/02_Architecture/05_ACPITables.md similarity index 100% rename from 02_Architecture/ACPITables.md rename to 02_Architecture/05_ACPITables.md diff --git a/02_Architecture/APIC.md b/02_Architecture/06_APIC.md similarity index 100% rename from 02_Architecture/APIC.md rename to 02_Architecture/06_APIC.md diff --git a/02_Architecture/Timers.md b/02_Architecture/07_Timers.md similarity index 100% rename from 02_Architecture/Timers.md rename to 02_Architecture/07_Timers.md diff --git a/README.md b/README.md index 1a736f4f..3b9b5b5e 100644 --- a/README.md +++ b/README.md @@ -14,50 +14,49 @@ We hope you enjoy, and find something interesting here! ## Current Chapters: -* [Chapter 0: Introduction](00_Introduction/01_README.md) +* [Part 0: Introduction](00_Introduction/01_README.md) * [Assumed Knowledge](00_Introduction/02_AssumedKnowledge.md) * [About The Authors](00_Introduction/03_AboutTheAuthors.md) -* [Chapter 1: Building & Boot Protocols](01_Build_Process/01_README.md) +* [Part 1: Building & Boot Protocols](01_Build_Process/01_README.md) * [Building a Kernel](01_Build_Process/02_Overview.md) * [Bootloaders and Boot Protocols](01_Build_Process/03_Boot_Protocols.md) * [Makefiles](01_Build_Process/04_Gnu_Makefiles.md) * [Linker Scripts](01_Build_Process/05_Linker_Scripts.md) * [Generating a Bootable Iso](01_Build_Process/06_Generating_Iso.md) -* [Chapter 2: Architecture](02_Architecture/01_README.md) +* [Part 2: Architecture and Basic Drivers](02_Architecture/01_README.md) * [A Higher Higher Kernel](02_Architecture/02_HigherHalf.md) * [Global Descriptor Table](02_Architecture/03_GDT.md) * [Interrupts](02_Architecture/04_InterruptHandling.md) -* [Chapter 3: Video Output](/03_Video_Output/01_Readme.md) + * [ACPI Tables](02_Architecture/05_ACPITables.md) + * [APIC](02_Architecture/06_APIC.md) + * [Timers](02_Architecture/07_Timers.md) + * [Adding Keyboard support](02_Architecture/PS2_Keyboard/01_README.md) + * [Handling the keyboard interrupt](02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md) + * [Keyboard Driver Implementation](02_Interrupt_Handling/PS2_Keyboard/03_Driver_Implementation.md) +* [Part 3: Video Output](/03_Video_Output/01_Readme.md) * [The Framebuffer](/03_Video_Output/Framebuffer.md) * [Drawing Text on Framebuffer](03_Video_Output/DrawingTextOnFB.md) -* [Chapter 3: Memory Management](04_Memory_Management/01_README.md) +* [Part 3: Memory Management](04_Memory_Management/01_README.md) * [Physical Memory](04_Memory_Management/02_Physical_Memory.md) * [Paging](04_Memory_Management/03_Paging.md) * [Virtual Memory Manager](04_Memory_Management/04_Virtual_Memory_Manager.md) * [Heap Allocation](04_Memory_Management/05_Heap_Allocation.md) * [Memory Protection](04_Memory_Management/06_Memory_Protection.md) -* [Chapter 4: Scheduling](05_Scheduling/01_README.md) +* [Part 4: Scheduling](05_Scheduling/01_README.md) * [The Scheduler](05_Scheduling/02_Scheduler.md) * [Processes and Threads](05_Scheduling/03_Processes_And_Threads.md) * [Locks](05_Scheduling/04_Locks.md) -* [Chapter 5: Getting to Userspace](06_Userspace/01_README.md) +* [Part 5: Getting to Userspace](06_Userspace/01_README.md) * [Switching Modes](06_Userspace/02_Switching_Modes.md) * [Updated Interrupt Handling](06_Userspace/03_Handling_Interrupts.md) * [System Calls](06_Userspace/04_System_Calls.md) * [Example Syscall ABI](06_Userspace/05_Example_ABI.md) -* [Chapter 6: Inter-Process Communication](07_IPC/01_README.md) +* [Part 6: Inter-Process Communication](07_IPC/01_README.md) * [Shared Memory](07_IPC/02_Shared_Memory.md) * [Message Passing](07_IPC/03_Message_Passing.md) -* [Chapter 7: File System](08_VirtualFileSystem/01_README.md) +* [Part 7: File System](08_VirtualFileSystem/01_README.md) * [The Virtual File System](08_VirtualFileSystem/02_VirtualFileSystem.md) -* [Chapter 9: Going Beyond](10_Going_Beyond/01_README.md) -* [Extras: Hardware and Drivers](98_Drivers/01_README.md) - * [Local APIC and IO APIC](98_Drivers/APIC.md) - * [Linear Framebuffer](98_Drivers/Framebuffer.md) - * [Drawing Text](98_Drivers/DrawingTextOnFB.md) - * [ACPI Tables](98_Drivers/ACPITables.md) - * [Timers](98_Drivers/Timer.md) - * [PS/2 Keyboard](98_Drivers/PS2Keyboard.md) +* [Part 9: Going Beyond](10_Going_Beyond/01_README.md) * [Extras: Appendices](99_Appendices/0_README.md) * [General Troubleshooting](99_Appendices/A_Troubleshooting.md) * [Tips and Tricks](99_Appendices/B_Tips_And_Tricks.md) From 8891875810e1b0cc2b343e6ca0bcc78503563514 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Fri, 31 Mar 2023 11:43:06 +0100 Subject: [PATCH 08/32] Move Serial logging section --- 02_Architecture/01_README.md | 4 +- 02_Architecture/02_Getting_Some_Output.md | 113 ++++++++++++++++++ .../{Framebuffer.md => 01_Framebuffer.md} | 0 ...awingTextOnFB.md => 02_DrawingTextOnFB.md} | 0 99_Appendices/E_Debugging.md | 77 ------------ README.md | 6 +- 6 files changed, 118 insertions(+), 82 deletions(-) create mode 100644 02_Architecture/02_Getting_Some_Output.md rename 03_Video_Output/{Framebuffer.md => 01_Framebuffer.md} (100%) rename 03_Video_Output/{DrawingTextOnFB.md => 02_DrawingTextOnFB.md} (100%) diff --git a/02_Architecture/01_README.md b/02_Architecture/01_README.md index 50caefe7..6f2e1060 100644 --- a/02_Architecture/01_README.md +++ b/02_Architecture/01_README.md @@ -1,4 +1,4 @@ -# Architecture +# Architecture and Drivers Before going beyond a basic "hello world" and implementing the first real parts of our kernel, there are some key concepts about how the CPU operates that we have to understand. What is an interrupt, and how do we handle it? What does it mean to mask them? What is the GDT and what is it's purpose? @@ -51,7 +51,7 @@ When an unexpected event happens, the cpu will immediately stop the current code The interrupted code is usually never aware that an interrupt even occured, and should continue on as normal. -# Drivers +## Drivers Not device drivers for graphic cards, network interfaces, and other hardware, but on early stages of development we will need some basic drivers to implement some of the future features, for example we will need to have at least one supported Timer to implement the scheduler, we will most likely want to add a basic support for a keyboard in order to implement a cli, these topics will be covered in this section, along with other architecture specific drivers required by the CPU. diff --git a/02_Architecture/02_Getting_Some_Output.md b/02_Architecture/02_Getting_Some_Output.md new file mode 100644 index 00000000..a0d3a30e --- /dev/null +++ b/02_Architecture/02_Getting_Some_Output.md @@ -0,0 +1,113 @@ +# Serial Logging (aka Hello World) + +During the developmen of our kernel we will need to debug a lot, and checking a lot of values, but so far our kernel is not capable of doing anything, and having proper video output with scrolling, fonts etc, can take some time to implement (and probably we need to check again some values), so we need a quick way of getting some output from our kernel, not necessarily on the screen. + +This is where the serial logging came to an aid, we will use the serial port to output our text and numbers. + +Many emulators has an option to redirect serial output to a file, if you are using QEmu (for more information about it refer to the Appendices section) you need to start it passing the parameter *-s filename*: + +```bash +qemu -S filename.log -cdrom yourosiso +``` + +This will save the serial output on the file called `filename.log`, if we want the serial output directly on the screen, we can use `stdio` instead. + +## Printing to Serial + +We will use the `inb` and `outb` instruction to communicate with the serial port. But the first thing our kernel should do is do is being able to write to serial ports. To do that we need: + +* for simiplicity and readability two C functions that will make use of the inb/outb asm instructions (luckily they are asm functions so making their c version is very easy) +* initialization of serial communication +* and at least an instruction to send characters and strings to the serial. + +The first step is pretty strightforward, using inline assembly we will create two "one-line" functions for inb and outb: + +```C +extern inline unsigned char inportb (int portnum) +{ + unsigned char data=0; + __asm__ __volatile__ ("inb %%dx, %%al" : "=a" (data) : "d" (portnum)); + return data; +} + +extern inline void outportb (int portnum, unsigned char data) +{ + __asm__ __volatile__ ("outb %%al, %%dx" :: "a" (data),"d" (portnum)); +} + +``` + +### Initialization + +The second part again is pretty simple, we just need to send few configuration command for initializing the serial communication, the code below is copied from https://wiki.osdev.org/Serial_Ports#Initialization: + +```C +#define PORT 0x3f8 // COM1 + +static int init_serial() { + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if(inb(PORT + 0) != 0xAE) { + return 1; + } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + outb(PORT + 4, 0x0F); + return 0; +} +``` + +Notice that usually the com1 port is mapped to address: *0x3f8*. The function above is setting just default values for serial communication. + +### Sending a string + +Last thing to do is to create functions to print string/numbers on the serial. The idea is pretty simple, the current functions we created are handling single bytes/char, what we want is to send strings, so a good idea is to start with a function like: + +```c +void log_to_serial (char *string) { + // Left as exercise +} +``` + +The input parameter for this function is a string, so what it will do is looping through the variable `string` and printing each character until the symbol `\0` (End Of String) is found. + +This is the first function that we want to implement. + +### Printing Digits + +Once we are able to print strings is time to print digits. The basic idea is simple, we takeread every single digit that compose the number, and print the corresponding character, luckily enough the digits symbols are consecutive in the ascii map, so for example: + +```c +'0' + 1 // will contain the symbol '1' +'0' + 5 // will contain the symbol '5' +``` + +How to get the single digits will depend on what base we are using (the most common are base 8, 10 and 16), let's assume we want for now just print decimals (base 10). For doing this we will use a property of division by 10, that the remainder of any integer number divided by 10 is always the same as the least significant digit, this means that for example $1235/10=123.5$ and $1235 \mod 10=5$, remember that in C (and other programming languages) a division between integers will ignore any decimal digit, so this means that $1235=123$. And what if now we divide 123 by 10? yes we get 3 as remainder, below the full list of divisions for the number 1235: + +* $1235/10 = 123$ and $1235 \mod 10 = 5$ +* $123/10 = 12$ and $123 \mod 10 = 3$ +* $12/10 = 1$ and $12 \mod10 = 2$ +* $1/10 = 0$ and $1 \mod 10 = 1$ + +And as you can see we got all the digits in reverse order, so now the only thing we need to do is reverse the them. The implementation of this function should be now pretty straightforward, and it will be left as exercise. + +Printing other format like Hex or Octal is little bit different, but the base idea of getting the single number and converting it into a character is similar. The only tricky thing with the hex number is that now we have symbols for numbers between 10 and 15 that are characters, and they are before the digits simbol in the ascii map, but once that is know is going to be just an if statement in our function. + +### Troubleshooting + +If the output to serial is not working, there is no output in the log, try to remove the line that set the serial as loopback: + +```C +outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip +``` + diff --git a/03_Video_Output/Framebuffer.md b/03_Video_Output/01_Framebuffer.md similarity index 100% rename from 03_Video_Output/Framebuffer.md rename to 03_Video_Output/01_Framebuffer.md diff --git a/03_Video_Output/DrawingTextOnFB.md b/03_Video_Output/02_DrawingTextOnFB.md similarity index 100% rename from 03_Video_Output/DrawingTextOnFB.md rename to 03_Video_Output/02_DrawingTextOnFB.md diff --git a/99_Appendices/E_Debugging.md b/99_Appendices/E_Debugging.md index 8ddd02cf..a8971424 100644 --- a/99_Appendices/E_Debugging.md +++ b/99_Appendices/E_Debugging.md @@ -1,82 +1,5 @@ # Debugging -## Serial Logging - -I think that in early stages of development, this can be a useful option especially when switching from VGA to framebuffer -to print useful debug information. - -Many emulaors has an option to redirect serial output to a file, you need to start it passing the parameter *-s filename*: - -```bash -qemu -S filename.log -cdrom yourosiso -``` - -Next thing to do is make our os able to write to serial ports. To do that you need: - -* inb/outb functions (luckily they are asm functions so making their c version is very easy) -* initialization of serial communication -* writing strings to serial. - -For first step, you just need to create the following one-line functions for inb and outb: - -```C -extern inline unsigned char inportb (int portnum) -{ - unsigned char data=0; - __asm__ __volatile__ ("inb %%dx, %%al" : "=a" (data) : "d" (portnum)); - return data; -} - -extern inline void outportb (int portnum, unsigned char data) -{ - __asm__ __volatile__ ("outb %%al, %%dx" :: "a" (data),"d" (portnum)); -} - -``` - -The second again is pretty simple, the code below is copied from https://wiki.osdev.org/Serial_Ports#Initialization: - -```C -#define PORT 0x3f8 // COM1 - -static int init_serial() { - outb(PORT + 1, 0x00); // Disable all interrupts - outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) - outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud - outb(PORT + 1, 0x00); // (hi byte) - outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit - outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold - outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip - outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) - - // Check if serial is faulty (i.e: not same byte as sent) - if(inb(PORT + 0) != 0xAE) { - return 1; - } - - // If serial is not faulty set it in normal operation mode - // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - outb(PORT + 4, 0x0F); - return 0; -} -``` - -The com1 port is mapped to address: *0x3f8* - -Last thing to do is to create functions to print string/numbers on the serial. -This is pretty similar to what has been done for I/O video functions, but in this case you send the text as it is -using outb instead of writing it on a memory location. - -But probably a good idea is to reuse some of the code of the video functions to convert numbers into strings. - -### Troubleshooting - -If the output to serial is not working, there is no output in the log, try to remove the line that set the serial as loopback: - -```C -outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip -``` ## Dumping register on exception diff --git a/README.md b/README.md index 3b9b5b5e..26b4bba9 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ We hope you enjoy, and find something interesting here! * [Adding Keyboard support](02_Architecture/PS2_Keyboard/01_README.md) * [Handling the keyboard interrupt](02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md) * [Keyboard Driver Implementation](02_Interrupt_Handling/PS2_Keyboard/03_Driver_Implementation.md) -* [Part 3: Video Output](/03_Video_Output/01_Readme.md) - * [The Framebuffer](/03_Video_Output/Framebuffer.md) - * [Drawing Text on Framebuffer](03_Video_Output/DrawingTextOnFB.md) +* [Part 3: Video Output](/03_Video_Output/01_README.md) + * [The Framebuffer](/03_Video_Output/01_Framebuffer.md) + * [Drawing Text on Framebuffer](03_Video_Output/02_DrawingTextOnFB.md) * [Part 3: Memory Management](04_Memory_Management/01_README.md) * [Physical Memory](04_Memory_Management/02_Physical_Memory.md) * [Paging](04_Memory_Management/03_Paging.md) From 9a6ec3658abfd87e980e18d997d8809ea15b9724 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Sat, 1 Apr 2023 13:02:20 +0100 Subject: [PATCH 09/32] Add mention to debugcon --- 02_Architecture/02_Getting_Some_Output.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/02_Architecture/02_Getting_Some_Output.md b/02_Architecture/02_Getting_Some_Output.md index a0d3a30e..8665a291 100644 --- a/02_Architecture/02_Getting_Some_Output.md +++ b/02_Architecture/02_Getting_Some_Output.md @@ -37,9 +37,11 @@ extern inline void outportb (int portnum, unsigned char data) ``` +Where `portnum` is the number of port where we are sending our data (usually is 0x3f8 or 0xe9), and the data is the `char` we want to send in output. + ### Initialization -The second part again is pretty simple, we just need to send few configuration command for initializing the serial communication, the code below is copied from https://wiki.osdev.org/Serial_Ports#Initialization: +The second part is pretty simple, we just need to send few configuration command for initializing the serial communication, the code below is copied from https://wiki.osdev.org/Serial_Ports#Initialization: ```C #define PORT 0x3f8 // COM1 @@ -67,7 +69,7 @@ static int init_serial() { } ``` -Notice that usually the com1 port is mapped to address: *0x3f8*. The function above is setting just default values for serial communication. +Notice that usually the com1 port is mapped to address: *0x3f8*. The function above is setting just default values for serial communication. An alternative that does not require any initialization is to use the port `0xe9`, this is also know as the _debugcon_ or the _port e9 hack_ and it still use the `inportb` and `outportb` functions as they are, but is often faster because is a special port that sends data directly to the emulator console output. ### Sending a string From e1574ab88d4699be7198faa8a7ae9c6c63b22d86 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Sat, 1 Apr 2023 13:03:08 +0100 Subject: [PATCH 10/32] Fix typo --- 02_Architecture/02_Getting_Some_Output.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_Architecture/02_Getting_Some_Output.md b/02_Architecture/02_Getting_Some_Output.md index 8665a291..c5421cab 100644 --- a/02_Architecture/02_Getting_Some_Output.md +++ b/02_Architecture/02_Getting_Some_Output.md @@ -1,6 +1,6 @@ # Serial Logging (aka Hello World) -During the developmen of our kernel we will need to debug a lot, and checking a lot of values, but so far our kernel is not capable of doing anything, and having proper video output with scrolling, fonts etc, can take some time to implement (and probably we need to check again some values), so we need a quick way of getting some output from our kernel, not necessarily on the screen. +During the development of our kernel we will need to debug a lot, and checking a lot of values, but so far our kernel is not capable of doing anything, and having proper video output with scrolling, fonts etc, can take some time to implement (and probably we need to check again some values), so we need a quick way of getting some output from our kernel, not necessarily on the screen. This is where the serial logging came to an aid, we will use the serial port to output our text and numbers. From 9274a78fbf93957b0e39c5882bfe9f906850b7b4 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Sat, 1 Apr 2023 15:00:02 +0100 Subject: [PATCH 11/32] minor fixes to memory section --- 04_Memory_Management/02_Physical_Memory.md | 24 +++++++++---------- 04_Memory_Management/03_Paging.md | 2 +- .../04_Virtual_Memory_Manager.md | 10 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/04_Memory_Management/02_Physical_Memory.md b/04_Memory_Management/02_Physical_Memory.md index bc7da6dd..b13128f1 100644 --- a/04_Memory_Management/02_Physical_Memory.md +++ b/04_Memory_Management/02_Physical_Memory.md @@ -17,7 +17,7 @@ In this document we will explain the bitmap method, because is probably the simp Now let's start with a simple example, imagine that we have a very tiny amount of ram like 256kb of ram, and we want to use 4kb pages, and assume that we have the kernel that takes the first 3 pages. As said above using the bitmap method assign 1 bit to every page, this means that every bytes can keep track of $8*4k=32kb$ of memory, if the page is taken the bit is set to 1, if is free the bit is clear (=0) -This means that a single *unsigned char* variable can hold the status of 32kb of ram, to keep track of 256kb of ram we then need 8bytes (They can stay in a single uint64_t variable, but for this example let's stick with the char type), this means that with an array of 8 elements of *unsigned char* we can represent the whole amount of memory, so we are going to have something like this: +This means that a single *unsigned char* variable can hold the status of 32kb of ram, to keep track of 256kb of ram we then need 8bytes (They can stay in a single `uint64_t` variable, but for this example let's stick with the char type), this means that with an array of 8 elements of *unsigned char* we can represent the whole amount of memory, so we are going to have something like this: | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | @@ -37,15 +37,15 @@ So marking a memory location as free or used is just matter of setting clearing But how do we mark a page as taken or free? We need to translate row/column in an address, or the address in row/column. Let's assume that we asked fro a free page and we found the first available bit at row 0 and column 3, how we translate it to address, well for that we need few extra info: -* The page size (we should know what is the size of the page you are using XD), Let's call it PAGE_SIZE -* How many bits are in a row (it's up to us to decide it, in this example we are using an unsigned char, but most probably in real life it is going to be a `uint32_t` for 32bit OS or `uint64_t` for 64bit os) let's call it BITS_PER_ROW +* The page size (we should know what is the size of the page you are using XD), Let's call it `PAGE_SIZE` +* How many bits are in a row (it's up to us to decide it, in this example we are using an unsigned char, but most probably in real life it is going to be a `uint32_t` for 32bit OS or `uint64_t` for 64bit os) let's call it `BITS_PER_ROW` To get the address we just need to do: -* bit_number = (row * BITS_PER_ROW) + column -* address = bit_number * PAGE_SIZE +* `bit_number = (row * BITS_PER_ROW) + column` +* `address = bit_number * PAGE_SIZE` -Let's pause for a second, and have a look at bit_number, what it represent? Maybe it is not straightforward what it is, but consider that the memory is just a linear space of consecutive addresses (just like a long tape of bits grouped in bytes), so when we declare an array we just reserve *NxSizeof(chosendatatype)* contiguous address of this space, so the reality is that our array is just something like: +Let's pause for a second, and have a look at `bit_number`, what it represent? Maybe it is not straightforward what it is, but consider that the memory is just a linear space of consecutive addresses (just like a long tape of bits grouped in bytes), so when we declare an array we just reserve *NxSizeof(chosendatatype)* contiguous addresses of this space, so the reality is that our array is just something like: | bit_number | 0 | 1 | 2 | ... | *8* | ... | 31 | *32* | ... | 63 | |------------|---|---|---|-----|-----|-----|----|------|-----|----| @@ -55,13 +55,13 @@ It just represent the offset in bit from `&bitmap` (the starting address of the In our example with *row=0 column=3* (and page size of 4k) we get: -* bit_number = (0 * 8) + 3 = 3 -* address = bit_number * 4k = 3 * 4096 = 3 * 0x1000 = 0x3000 +* `bit_number = (0 * 8) + 3 = 3` +* `address = bit_number * 4k = 3 * 4096 = 3 * 0x1000 = 0x3000` Another example: *row = 1 column = 4* we will get: -* bit_number = (1 * 8) + 4 = 12$ -* address = bit_number * 4k = 0xC000 +* `bit_number = (1 * 8) + 4 = 12` +* `address = bit_number * 4k = 0xC000` But what about the opposite way? Given an address compute the bitmap location? Still pretty easy: @@ -76,8 +76,8 @@ In this way we know the "page" index into an hypoteteical array of Pages. But we So now knowing how the bitmap works, let's see how to update/test it. We need basically three very simple functions: -* A function to test if a given frame location (in this case bit_number will be used) is clear or set +* A function to test if a given frame location (in this case `bit_number` will be used) is clear or set * A function to mark a location as set * A function to mark a location as clear -For all the above functions we are going to use bitwise operators, and all of them will take one argument that is the bit_number location (as seen in the previous paragraph), the implementation is left as exercise. +For all the above functions we are going to use bitwise operators, and all of them will take one argument that is the `bit_number` location (as seen in the previous paragraph), the implementation is left as exercise. diff --git a/04_Memory_Management/03_Paging.md b/04_Memory_Management/03_Paging.md index b06b451d..affbb1f7 100644 --- a/04_Memory_Management/03_Paging.md +++ b/04_Memory_Management/03_Paging.md @@ -34,7 +34,7 @@ A virtual address is what a running program sees. Thats any program: a driver, u A virtual address is usually a composition of entry numbers for each level of tables. The picture below shows how address translation works: -![address_translation drawio](/Images/addrtranslation.png) +![Address Translation](/Images/addrtranslation.png) Using logical address and paging, we can introduce a new address space that can be much bigger of the available physical memory. diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index 345a66f8..4cd74884 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -10,7 +10,7 @@ As mentioned before, a simple kernel only requires a simple VMM which may end up What exactly does the virtual memory manager *manage*? The PMM manages the physical memory installed in a computer, so it would make sense that the VMM manages the virtual memory. What do we mean by virtual memory? -Once we have some kind of address translation enabled, all memory we can access is now virtual memory. This address translation is usually performed by the MMU (memory management unit) which we can program in someway. On x86_64 the MMU parses the page tables we provide to determine what should happen during this translation. +Once we have some kind of address translation enabled, all memory we can access is now virtual memory. This address translation is usually performed by the MMU (memory management unit) which we can program in someway. On `x86_64` the MMU parses the page tables we provide to determine what should happen during this translation. Even if you create an identity map of physical memory (meaning virtual address = physical address) you're still accessing physical memory *through* virtual memory. This is subtle, but important difference. @@ -31,9 +31,9 @@ A lot of these features are not needed in the beginning, but hopefully the uses ## Concepts As you might expect, there are many VMM designs out there. We're going to look at a simple one that should provide all the functionality needed for now. -First we'll need to introduce a new concept: a *virtual memory object*, sometimes called a *virtual memory range*. This is just a struct that represents part of the virtual address space, so it will need a base address and length, both of these are measured in bytes and will be page-aligned. This requirement to be page-aligned comes from the mechanism used to manage virtual memory: paging. On x86 the smallest page we can manage is 4K, meaning that all of our VM objects must be aligned to this. +First we'll need to introduce a new concept: a *virtual memory object*, sometimes called a *virtual memory range*. This is just a struct that represents part of the virtual address space, so it will need a base address and length, both of these are measured in bytes and will be page-aligned. This requirement to be page-aligned comes from the mechanism used to manage virtual memory: paging. On `x86` the smallest page we can manage is `4K`, meaning that all of our VM objects must be aligned to this. -These flags we store seem like the flags used in the page tables, so you could just store them there, but storing them as part of the object makes looking them up faster, since you don't need to manually traverse the paging structure. It also allows us to store flags that the are not relevant to paging. +In addition we might want to store some flags in the *vm object*, they are like the flags used in the page tables, we could technically just store them there, but having them as part of the object makes looking them up faster, since we don't need to manually traverse the paging structure. It also allows us to store flags that the are not relevant to paging. Here's what our example virtual memory object looks like: @@ -53,9 +53,9 @@ typedef struct { The `flags` field is actually a bitfield, and we've defined some macros to use with it. -These don't correspond to the bits in the page table, but having them separate like this means they are platform-agnostic. We can port our kernel to any cpu architecture that supports some kind of MMU and most of the code won't need to change, we'll just need a short function that converts our vm flags into page table flags. This is especially convinient for oddities like x86 and it's nx-bit, where all memory is executable by default, and you must specify if you *don't* want it to be executable. +These don't correspond to the bits in the page table, but having them separate like this means they are platform-agnostic. We can port our kernel to any cpu architecture that supports some kind of MMU and most of the code won't need to change, we'll just need a short function that converts our vm flags into page table flags. This is especially convenient for oddities like `x86` and it's nx-bit, where all memory is executable by default, and you must specify if you *don't* want it to be executable. -Having it like this allows that to be abstracted away from the rest of our kernel. For x86_64 our translation function would look like the following: +Having it like this allows that to be abstracted away from the rest of our kernel. For `x86_64` our translation function would look like the following: ```c uint64_t convert_x86_64_vm_flags(size_t flags) { From dcb949f567f3e2548f87109f48949f0de127584e Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Mon, 3 Apr 2023 16:23:42 +0100 Subject: [PATCH 12/32] Expand VMM section --- 04_Memory_Management/03_Paging.md | 6 ++++-- 04_Memory_Management/04_Virtual_Memory_Manager.md | 13 ++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/04_Memory_Management/03_Paging.md b/04_Memory_Management/03_Paging.md index affbb1f7..943a8a6b 100644 --- a/04_Memory_Management/03_Paging.md +++ b/04_Memory_Management/03_Paging.md @@ -260,6 +260,8 @@ The virtual memory manager is a layer between the physical memory manager and th The workflow should be the similar to the following: -Allcoation function return an address --> This address is mapped to it's own page table (eventually allocating intermediate page dirs) -> Physical memory is requested. +Allocation function return an address --> This address is mapped to it's own page table (eventually allocating intermediate page dirs) -> Physical memory is requested. -Is not necessary to allocate physical memory immediately, but it can be handled also during the page fault. +Is not necessary to allocate physical memory immediately, but it can be handled also during the page fault, this depends on the design. + +Details about implementing a basic VMM will be given in the following chapter. diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index 4cd74884..68a5d2a4 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -70,9 +70,9 @@ uint64_t convert_x86_64_vm_flags(size_t flags) { }; ``` -The `PT_xyz` macros are just setting the bits in the page table entry, for specifics see the paging chapter. Notice how we set the NX-bit if `VM_FLAG_EXEC` is not set because of a quirk on x86. +The `PT_xyz` macros are just setting the bits in the page table entry, for specifics see the *paging chapter*. Notice how we set the NX-bit if `VM_FLAG_EXEC` is not set because of a quirk on x86. -We're going to store these vm objects as a linked list, which is the purpose of the `next` field. +We're going to store these *vm objects* as a linked list, which is the purpose of the `next` field. ### How Many VMMs Is Enough? @@ -84,12 +84,19 @@ There are many ways of handling this, one example is to have a special kernel VM ### Managing An Address Space -This is where design and reality collide, because our high level VMM needs to program the MMU. The exact details of this vary by platform, but for x86(_64) we have paging! See the previous chapter on how x86 paging works. Each virtual memory manager will need to store the appropriate data to manage the address space it controls: for paging we just need the address of the root table. +This is where design and reality collide, because our high level VMM needs to program the MMU. The exact details of this vary by platform, but for `x86(_64)` we have paging! See the previous chapter on how x86 paging works. Each virtual memory manager will need to store the appropriate data to manage the address space it controls: for paging we just need the address of the root table. ```c void* vmm_pt_root; ``` +This variable can be placed anywhere, this depend on our design decisions, there is not correct answer, but a good idea is to reserve some space in the VM space to be used by the VMM to store it's data. Usually a good idea is to place this space somewhere in the higher half area probably anwhere below the kernel. + +Once we got the address, this needs to be mappet to an existing physical address, so we will need to do two things: + +* Allocate a physical page for the `vmm_pt_root` pointer (at this point a function to do that should be present) +* Map the phyiscal address into the virtual address `vmm_pt_root`. + ## Allocating Objects Now we know what a VM object is, let's look at how we're going to create them. From f5007705d453220fd7a6d99442def76bc99d0308 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 4 Apr 2023 19:40:03 +0100 Subject: [PATCH 13/32] Expand vmm section --- 02_Architecture/02_Getting_Some_Output.md | 2 +- 04_Memory_Management/03_Paging.md | 14 -------------- 04_Memory_Management/04_Virtual_Memory_Manager.md | 4 ++++ 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/02_Architecture/02_Getting_Some_Output.md b/02_Architecture/02_Getting_Some_Output.md index c5421cab..022849b2 100644 --- a/02_Architecture/02_Getting_Some_Output.md +++ b/02_Architecture/02_Getting_Some_Output.md @@ -1,4 +1,4 @@ -# Serial Logging (aka Hello World) +# Hello World During the development of our kernel we will need to debug a lot, and checking a lot of values, but so far our kernel is not capable of doing anything, and having proper video output with scrolling, fonts etc, can take some time to implement (and probably we need to check again some values), so we need a quick way of getting some output from our kernel, not necessarily on the screen. diff --git a/04_Memory_Management/03_Paging.md b/04_Memory_Management/03_Paging.md index 943a8a6b..45045e44 100644 --- a/04_Memory_Management/03_Paging.md +++ b/04_Memory_Management/03_Paging.md @@ -251,17 +251,3 @@ A few examples of recursive addresses: - If we want to access the content of the PML4 page itself, using the recursion we need to build a special address using the entries: PML4: 510, PDPR: 510, PD: 510, PT: 510, now keep in mind that the 510th entry of PML4 is PML4 itself, so this means that when the processor loads that entry, it loads PML4 itself instead of PDPR, but now the value for the PDPR entry is still 510, that is still PML4 then, the table loaded is PML4 again, repat this process for PD and PT wit page number equals to 510, and we obtain access to the PML4 page itself. - Now using a similar approach we can get acces to other tables, for example the following values: PML4: 510, PDPR:510, PD: 1, PT: 256, will give access at the Page Directory PD at entry number 256 in PDPR that is contained in the first PML4 entry . -## Virtual Memory Manager - -The virtual memory manager is a layer between the physical memory manager and the allocation function (slab/heap/whatever), it basically has to do only two things: - -* Given a virtual address in input it has to be mapped in the page table -* And also given a virtual address in input it has to be unmapped it from the physical location. - -The workflow should be the similar to the following: - -Allocation function return an address --> This address is mapped to it's own page table (eventually allocating intermediate page dirs) -> Physical memory is requested. - -Is not necessary to allocate physical memory immediately, but it can be handled also during the page fault, this depends on the design. - -Details about implementing a basic VMM will be given in the following chapter. diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index 68a5d2a4..ddc3ea3a 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -97,6 +97,8 @@ Once we got the address, this needs to be mappet to an existing physical address * Allocate a physical page for the `vmm_pt_root` pointer (at this point a function to do that should be present) * Map the phyiscal address into the virtual address `vmm_pt_root`. +It is important to keep in mind that the all the addresses must be page aligned. + ## Allocating Objects Now we know what a VM object is, let's look at how we're going to create them. @@ -113,6 +115,8 @@ The `length` field is how many bytes we want. Internally we will round this **up The final argument is unused for the moment, but will be used to pass data for more exotic allocations. We'll look at an example of this later on. +The function will return a virtual address, it doesn't have necessarily to be already mapped and present, it just need to be an available address. Again the question is: where is that address? The answer is again that it depends on the design decisions. So we again need to decide where we want the virtual memory range to be returned is, and use it's base as starting address. It can be the same space used for the vmm data strutctures, or another area, that is up to us. + For the example code we're going to assume you have a function to modify page tables that looks like the following: ```c From 29f9c34f8e1edb6fd6d91922ed52a4fb6c8b65a8 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 4 Apr 2023 23:58:01 +0100 Subject: [PATCH 14/32] Minor update in VMM chapter --- 04_Memory_Management/04_Virtual_Memory_Manager.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index ddc3ea3a..2464c339 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -115,7 +115,7 @@ The `length` field is how many bytes we want. Internally we will round this **up The final argument is unused for the moment, but will be used to pass data for more exotic allocations. We'll look at an example of this later on. -The function will return a virtual address, it doesn't have necessarily to be already mapped and present, it just need to be an available address. Again the question is: where is that address? The answer is again that it depends on the design decisions. So we again need to decide where we want the virtual memory range to be returned is, and use it's base as starting address. It can be the same space used for the vmm data strutctures, or another area, that is up to us. +The function will return a virtual address, it doesn't have necessarily to be already mapped and present, it just need to be an available address. Again the question is: where is that address? The answer is again that it depends on the design decisions. So we need to decide where we want the virtual memory range to be returned is, and use it as starting address. It can be the same space used for the vmm data strutctures, or another area, that is up to us. For the example code we're going to assume you have a function to modify page tables that looks like the following: @@ -135,7 +135,7 @@ Now onto our alloc function. The first thing it will need to do is align the len length = (length + (PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; ``` -The next step is to find a space between two VM objects big enough to hold `length` bytes. We'll also want to handle the edge cases of allocating before the first object, after the last object, or if there are no VM objects in the list at all. +The next step is to find a space between two VM objects big enough to hold `length` bytes. We'll also want to handle the edge cases of allocating before the first object, after the last object, or if there are no VM objects in the list at all (not covered in the example below, they are left as exercise). ```c vm_object* current = vm_objs; From 947fdbb22b8bef67606593143cdcc5b4edac9650 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Fri, 7 Apr 2023 18:55:05 +0100 Subject: [PATCH 15/32] Minor changes on vmm chapteR --- 04_Memory_Management/04_Virtual_Memory_Manager.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index 2464c339..66d94fa1 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -90,9 +90,9 @@ This is where design and reality collide, because our high level VMM needs to pr void* vmm_pt_root; ``` -This variable can be placed anywhere, this depend on our design decisions, there is not correct answer, but a good idea is to reserve some space in the VM space to be used by the VMM to store it's data. Usually a good idea is to place this space somewhere in the higher half area probably anwhere below the kernel. +This variable can be placed anywhere, this depend on our design decisions, there is not correct answer, but a good idea is to reserve some space in the VM space to be used by the VMM to store it's data. Usually a good idea is to place this space somewhere in the higher half area probably anywhere below the kernel. -Once we got the address, this needs to be mappet to an existing physical address, so we will need to do two things: +Once we got the address, this needs to be mapped to an existing physical address, so we will need to do two things: * Allocate a physical page for the `vmm_pt_root` pointer (at this point a function to do that should be present) * Map the phyiscal address into the virtual address `vmm_pt_root`. @@ -115,7 +115,7 @@ The `length` field is how many bytes we want. Internally we will round this **up The final argument is unused for the moment, but will be used to pass data for more exotic allocations. We'll look at an example of this later on. -The function will return a virtual address, it doesn't have necessarily to be already mapped and present, it just need to be an available address. Again the question is: where is that address? The answer is again that it depends on the design decisions. So we need to decide where we want the virtual memory range to be returned is, and use it as starting address. It can be the same space used for the vmm data strutctures, or another area, that is up to us. +The function will return a virtual address, it doesn't have necessarily to be already mapped and present, it just need to be an available address. Again the question is: where is that address? The answer again is that it depends on the design decisions. So we need to decide where we want the virtual memory range to be returned is, and use it as starting address. It can be the same space used for the vmm data strutctures, or another area, that is up to us, of course this decision will have an impact on the design of the algorithm. For the example code we're going to assume you have a function to modify page tables that looks like the following: From 28feffe2ce43b4db9fc40f6345b3c38d5aa61090 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Fri, 7 Apr 2023 19:15:46 +0100 Subject: [PATCH 16/32] Rearrange files in Architecture folder --- ...{02_Getting_Some_Output.md => 02_Hello_World.md} | 0 .../{02_HigherHalf.md => 03_HigherHalf.md} | 0 02_Architecture/{03_GDT.md => 04_GDT.md} | 0 ...InterruptHandling.md => 05_InterruptHandling.md} | 0 .../{05_ACPITables.md => 06_ACPITables.md} | 0 02_Architecture/{06_APIC.md => 07_APIC.md} | 0 02_Architecture/{07_Timers.md => 08_Timers.md} | 0 README.md | 13 +++++++------ 8 files changed, 7 insertions(+), 6 deletions(-) rename 02_Architecture/{02_Getting_Some_Output.md => 02_Hello_World.md} (100%) rename 02_Architecture/{02_HigherHalf.md => 03_HigherHalf.md} (100%) rename 02_Architecture/{03_GDT.md => 04_GDT.md} (100%) rename 02_Architecture/{04_InterruptHandling.md => 05_InterruptHandling.md} (100%) rename 02_Architecture/{05_ACPITables.md => 06_ACPITables.md} (100%) rename 02_Architecture/{06_APIC.md => 07_APIC.md} (100%) rename 02_Architecture/{07_Timers.md => 08_Timers.md} (100%) diff --git a/02_Architecture/02_Getting_Some_Output.md b/02_Architecture/02_Hello_World.md similarity index 100% rename from 02_Architecture/02_Getting_Some_Output.md rename to 02_Architecture/02_Hello_World.md diff --git a/02_Architecture/02_HigherHalf.md b/02_Architecture/03_HigherHalf.md similarity index 100% rename from 02_Architecture/02_HigherHalf.md rename to 02_Architecture/03_HigherHalf.md diff --git a/02_Architecture/03_GDT.md b/02_Architecture/04_GDT.md similarity index 100% rename from 02_Architecture/03_GDT.md rename to 02_Architecture/04_GDT.md diff --git a/02_Architecture/04_InterruptHandling.md b/02_Architecture/05_InterruptHandling.md similarity index 100% rename from 02_Architecture/04_InterruptHandling.md rename to 02_Architecture/05_InterruptHandling.md diff --git a/02_Architecture/05_ACPITables.md b/02_Architecture/06_ACPITables.md similarity index 100% rename from 02_Architecture/05_ACPITables.md rename to 02_Architecture/06_ACPITables.md diff --git a/02_Architecture/06_APIC.md b/02_Architecture/07_APIC.md similarity index 100% rename from 02_Architecture/06_APIC.md rename to 02_Architecture/07_APIC.md diff --git a/02_Architecture/07_Timers.md b/02_Architecture/08_Timers.md similarity index 100% rename from 02_Architecture/07_Timers.md rename to 02_Architecture/08_Timers.md diff --git a/README.md b/README.md index 26b4bba9..d0558f44 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,13 @@ We hope you enjoy, and find something interesting here! * [Linker Scripts](01_Build_Process/05_Linker_Scripts.md) * [Generating a Bootable Iso](01_Build_Process/06_Generating_Iso.md) * [Part 2: Architecture and Basic Drivers](02_Architecture/01_README.md) - * [A Higher Higher Kernel](02_Architecture/02_HigherHalf.md) - * [Global Descriptor Table](02_Architecture/03_GDT.md) - * [Interrupts](02_Architecture/04_InterruptHandling.md) - * [ACPI Tables](02_Architecture/05_ACPITables.md) - * [APIC](02_Architecture/06_APIC.md) - * [Timers](02_Architecture/07_Timers.md) + * [Hello World](02_Architecture/02_HelloWorld.md) + * [A Higher Higher Kernel](02_Architecture/03_HigherHalf.md) + * [Global Descriptor Table](02_Architecture/04_GDT.md) + * [Interrupts](02_Architecture/05_InterruptHandling.md) + * [ACPI Tables](02_Architecture/06_ACPITables.md) + * [APIC](02_Architecture/07_APIC.md) + * [Timers](02_Architecture/08_Timers.md) * [Adding Keyboard support](02_Architecture/PS2_Keyboard/01_README.md) * [Handling the keyboard interrupt](02_Architecture/PS2_Keyboard/02_Interrupt_Handling.md) * [Keyboard Driver Implementation](02_Interrupt_Handling/PS2_Keyboard/03_Driver_Implementation.md) From f1585c59f8d73477625cc303d965b62f6e60e1a1 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Mon, 10 Apr 2023 13:36:05 +0100 Subject: [PATCH 17/32] Replace array with lists --- 08_VirtualFileSystem/02_VirtualFileSystem.md | 77 ++++++++++++-------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/08_VirtualFileSystem/02_VirtualFileSystem.md b/08_VirtualFileSystem/02_VirtualFileSystem.md index 37646dbf..069fba82 100644 --- a/08_VirtualFileSystem/02_VirtualFileSystem.md +++ b/08_VirtualFileSystem/02_VirtualFileSystem.md @@ -5,14 +5,14 @@ Nowadays there are many OSes available for many different hardware architectures, and probably there are even more file systems. One of the problems for the OS is to provide a generic enough interface to support as many file systems as possible, and making it easy to implement new ones, in the future. This is where the VFS layer comes to aid, in this chapter we are going to see in detail how it works, and make a basic implementation of it. To keep our design simple, the features of our VFS driver will be: -* Fixed number of mountpoints using an array. +* Mountpoints will be handled using a simple linked list (with no particular sorting or extra features) * Support only the following functions: `open, read, write, close, opendir, readdir, closedir, stat`. * No extra features like permissions, uid and gid (although we are going to add those fields, they will not be used). * The path length will be limited. ## How Does VFS Works -The basic concept of a VFS layer is pretty simple, we can see it like a common way to access files/directories across different file systems, it is a layer that sits between the higher level interface to the FS and the low level implementation of the FS driver. +The basic concept of a VFS layer is pretty simple, we can see it like a common way to access files/directories across different file systems, it is a layer that sits between the higher level interface to the FS and the low level implementation of the FS driver, as shown in the picture ![Where the VFS sits in an OS](/Images/vfs_layer.png) @@ -58,7 +58,15 @@ To be able to access the different filesystems currently lodaed (*mounted*) by t * A data structure to store all the information related to the loaded File System * A list/tree/array of all the file system currently loaded by the os -As we anticipated earlier this chapter we are going to use an array to keep track of the mounted file systems, even if it has several limitations and probably a tree is the best choice. We want to focus on the implementation details of the VFS without having to also write and explain the tree-handling functions. +As we anticipated earlier in this chapter we are going to use a linked list to keep track of the mounted file systems, even if it has several limitations and probably a tree is the best choice. We want to focus on the implementation details of the VFS without having to also write and explain the tree-handling functions. + +So we assume that functions to handle list of mountpoints are present (their implementation is left as exercise), from now on we assume the following functions are present: + +```c +mountpoint_t *create_mountpoint(...) +mountpoint_t *add_mountpoint(mountpoint_t* mountpoint); +void remove_mountpoint(mountpoint_t* mountpoint); +``` We just said that we need a data structure to keep track of the information of a mounted file system, but what we need to keep track? Let's see what we need to store: @@ -83,16 +91,15 @@ struct { typedef struct mountpoint_t mountpoint_t; ``` -The next thing is to declare an array with this new data structure, that is going to contain all the mounted filesystem, and will be the first place where we will look whenever we want to access a folder or a file: +The next thing is to have a variable to store those mountpoints, since we are using a linked list it is going to be just a pointer to it's root, this will be the first place where we will look whenever we want to access a folder or a file: ```c #define MAX_MOUNTPOINTS 12 -mountpoint_t mountpoints[MAX_MOUNTPOINTS]; +mountpoint_t *mountpoints_root; ``` This is all that we need to keep track of the mountpoints. - ### Mounting and umounting Now that we have a representation of a mountpoint, is time to see how to mount a file system. By mounting we mean making a device/image/network storage able to be accessed by the operating system on a target folder (the `mountpoint`) loading the driver and the target device. @@ -120,16 +127,17 @@ The first one for mounting, let's call it for example `vfs_mount`, to work it wi int vfs_mount(char *device, char *target, char *fs_type); ``` -Once called it will simply add a new item in the mountpoint on the first available position, and will populate the data mountpoint data structure with the information provided, for example using the array approach, if a free spot is found at index `i` to add a new file sytem we will have something like: +Once called it will simply create and add a new item to the mountpoints list, and will populate the data structure with the information provided, for example inside the function to create a mountpoint (in our example `create_mountpoint`) we are going to have something like the following code: ```c -mountpoints[i].device = device; -mountpoints[i].type = type; -mountpoints[i].mountpoint = target; -mountpoints[i[.operations = NULL +mountpoint_t *new_mountpoint = malloc(sizeof(mountpoint_t)); // We assume a kind of malloc is present +new_mountpoint.device = device; +new_mountpoint.type = type; +new_mountpoint.mountpoint = target; +new_mountpoint.operations = NULL ``` -the last line will be populated soon, for now let's leave it to null. +the last line will be populated soon, for now let's leave it to `NULL`. The second instruction is for umounting, in this case since we are just unloading the file device from the system, we don't need to know what type is it, so technically we need either the target device or the target folder, the function can actually accept both parameters, but use only one of them, let's call it `vfs_umount`: @@ -137,9 +145,8 @@ The second instruction is for umounting, in this case since we are just unloadin int vfs_umount(char *device, char *target); ``` -In this case we need to find the item in the list that contains the required file system, and if found remove it from the list/tree. In our case since we are using an array we need to clear all the fields in the array at the position containing our fs. +In this case we just need to find the item in the list that contains the required file system, and if found remove it from the list/tree by calling the `remove_mountpoint` function, making sure to free all resources if possible, or return an error. -One thing that we should keep in mind is that using an array, once we umount a file system we are just marking that position as available again, so this means that it can be in the middle of the array, and there can be mounted file system after, so we need to keep in mind this while searching for the next free mouuntpoint. #### A Short Diversion: The Initialization @@ -162,14 +169,12 @@ Now that we know how to handle the mountpoints, we need to understand how given We will cover the single root approach, but eventually changing to a multi-root approach should be pretty easy. One last thing to keep in mind is that the path separator is another design decision, mostly every operating system use either "/" or "\" (the latter is mostly on windows os and derivatives), but in theory everything can be used as a path separator, we will stick with the unix-friendly "/", just keep in mind if going for the "windows" way, the separator is the same as the escape character, so it can interfere with the escape sequences. -For example let's assume that we have the following list of mountpoints: +For example let's assume that we have the following list of mountpoints : -```c -mountpoints[0].mountpoint = "/" -mountpoints[1].mountpoint = "/home/mount" -mountpoints[2].mountpoint = "/usr" -mountpoints[3].mountpoint = "/home" -``` +* "/" +* "/home/mount" +* "/usr" +* "/home" And we want to access the following paths: @@ -192,10 +197,10 @@ What if for example path doesn't start with a "/"? this means that it's a relati Implementing the function is left as exercise, below we just declare the header (that we will use in the next sections): ```c -int get_mounpoint_id(char *path); +mountpoint_t get_mountpoint(char *path); ``` -If the above function fail it should return a negative number (i.e. -1) to let the caller know that something didn't work (it should always return at least 0 in a single root implementation). +If the above function fail it should return NULL to let the caller know that something didn't work (even if it should always return at least the root "/" item in a single root implementation). #### Absolute vs Relative Path @@ -278,10 +283,10 @@ struct { } file_descriptor_t ``` -We need to declare a variable that contains the opened file descriptors, as usual we are using a naive approach, and just use an array, this means that we will have a limited number of files that can be opened: +We need to declare a variable that contains the opened file descriptors, as usual we are using a naive approach, and just use an array for simplicity, this means that we will have a limited number of files that can be opened: ```c -struct file_descriptors_t vfS_opened_files[MAX_OPENED_FILES] +struct file_descriptors_t vfs_opened_files[MAX_OPENED_FILES] ``` Where the `mountpoint_id` fields is the id of the mounted file system that is contining the requested file. The `fs_file_id` is the fs specific id of the fs opened by thefile descriptor, `buf_read_pos` and `buf_write_pos` are the current positions of the buffer pointer for the read and write operations and `file_size` is the the size of the opened file. @@ -308,11 +313,11 @@ The basic idea is that once mountpoint_id has been found, the vfs will use the m ```c int open(const char *path, int flags){ - mountpoint_id = get_mountpoint_id(pathname); + mountpoint_t *mountpoint = get_mountpoint(pathname); - if (mountpoint_id > -1) { - char *rel_path = get_rel_path(mountpoints[mountpoint_id], path); - int fs_specific_id = mountpoints[mountpoint_id].operations.open(rel_path, flags); + if (mountpoint != NULL`) { + char *rel_path = get_rel_path(mountpoint, path); + int fs_specific_id = mountpoint.operations.open(rel_path, flags); if (fs_specific_id != ERROR) { /* IMPLEMENTATION LEFT AS EXERCISE */ // Get a new vfs descriptor id vfs_id @@ -340,8 +345,9 @@ In our case where we have no FIFO or data-pipes, we can outline our close functi int close(int fildes) { if (vfs_opened_files[fildes].fs_file_id != -1) { mountpoint_id = vfs_opened_files[fildes].mountpoint_id; + mountpoint_t *mountpoint = get_mountpoint_by_id(mountpoint_id); fs_file_id = vfs_opened_files[fildes].fs_file_id; - fs_close_result = mountpoints[mountpoint_id].close(fs_file_id); + fs_close_result = mountpoint.close(fs_file_id); if(fs_close_result == 0) { vfs_opened_files[fildes].fs_file_id = -1; return 0; @@ -351,6 +357,14 @@ int close(int fildes) { } ``` +The above code expects a function to find a mountpoint given it's id `get_mountpoint_by_id`, the implementation is left as exercise, since it's pretty trivial and consists only of iterating inside a list where the header is: + +```c +mountpoint_t *get_mountpoint_by_id(size_t mountpoint_id); +``` + +This function will be used in the following paragraphs too. + #### Reading From A File So now we have managed to access a file stored somewhere on a file system using our VFS, and now we need to read its contents. The function used in the file read example at the beginning of this chapter is the C read include in unistd, with the following signature: @@ -387,8 +401,9 @@ ssize_t read(int fildes, void *buf, size_t nbytes) { if (vfs_opened_files[fildes].fs_fildes_id != -1) { int mountpoint_id = vfs_opened_files[fildes].mountpoint_id; + mountpoint_t *mountpoint = get_mountpoint_by_id(mountpoint_id) int fs_file_id = vfs_opened_files[fildes].fs_file_id; - int bytes_read = mountpoints[mountpoint_id].read(fs_file_id, buf, nbytes) + int bytes_read = mountpoints.read(fs_file_id, buf, nbytes) if (opened_files[fildes].buf_read_pos + nbytes < opened_files[fildes].file_size) { opened_files[fildes].buf_read_pos += nbytes; } else { From d0584857c9c36769f2297485cbc14360cce8ec47 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 2 Feb 2023 04:18:24 +1100 Subject: [PATCH 18/32] some theory --- 08_Loading_Elf/01_README.md | 15 +++++++++++++ 08_Loading_Elf/02_Elf_Theory.md | 27 ++++++++++++++++++++++++ 08_Loading_Elf/03_Loading_And_Running.md | 6 ++++++ 3 files changed, 48 insertions(+) create mode 100644 08_Loading_Elf/01_README.md create mode 100644 08_Loading_Elf/02_Elf_Theory.md create mode 100644 08_Loading_Elf/03_Loading_And_Running.md diff --git a/08_Loading_Elf/01_README.md b/08_Loading_Elf/01_README.md new file mode 100644 index 00000000..a14728d7 --- /dev/null +++ b/08_Loading_Elf/01_README.md @@ -0,0 +1,15 @@ +# Loading An ELF + +This chapter won't be too heavy on new concepts, besides the ELF specification itself, but will focus on bringing everything together. We're going to load a program in a new process, and run it in userspace. This is typically how most programs run, and then from there we can execute a few example system calls. + +It should be noted that the original ELF specification is for 32-bit programs, but a *64-bit extensions* was created later on called ELF64. We'll be focusing on ELF64. + +## Restrictions + +To simplify our program loader we're going to put a few restrictions in place for now. Later on you can expand the loader yourself as you come across features you might want to support. + +For a program to be compatible with our loader: + +- It cannot contain any relocations. We don't care if it's statically linked or uses PIC (position independent code) however. +- All libraries must be statically linked, we won't support dynamic linking for now. This feature can be implemented over a weekend, but greatly increases the complexity of your loader. +- The program must be freestanding, since we haven't ported (or written) a libc we can't use any standard functions. Porting a libc is worthwhile, but it's outside the scope of this chapter. diff --git a/08_Loading_Elf/02_Elf_Theory.md b/08_Loading_Elf/02_Elf_Theory.md new file mode 100644 index 00000000..f7d3fbc9 --- /dev/null +++ b/08_Loading_Elf/02_Elf_Theory.md @@ -0,0 +1,27 @@ +# Executable Linker Format + +The executable and linker format (ELF) is a multi-purpose format: it can be used to store compiled (but not linked) object files, as well as fully linked programs/dynamic libraries. + +The format has four main sections: + +- The ELF header. This contains the magic number used to identify it as an ELF, as well as information about the architecture the ELF was compiled for, the target operating system and other useful info. +- The data blob. The bulk of the file is made up of this blob. This is a big binary blob containing code, all kinds of data, some string tables and sometimes debugging information. All program data lives here. +- Section headers. Each header has a name and some metadata associated with it, and describes a region of the data blob. Section names usually begin with a dot (`.`), like `.strtab` which refers to the string table. Section headers are for other software to parse the ELF and understand it's structure and contents. +- Program headers. These are for the program loader (what we're going to write). Each program header has a type that tells the loader how to interpret it, as well as specifying a range within the data blob. These ranges in the data blob can overlap (or often cover the same area as some section header ranges) ranges described by section headers. + +Within the ELF specification section headers and program headers are often abbreviated to SHDRs and PHDRs. In a real file the data blob is actually located after the section and program headers. + +## Section Headers + +We won't be dealing with a lot of section headers, as the program loader is mainly interested in program headers. However there are some core SHDRs you should be aware of. + +- special shdrs +- how to parse a shdr, + +## Program Headers + +## Loading Theory + +- validate header +- find all PT_LOAD headers, copy those in +- you're good! diff --git a/08_Loading_Elf/03_Loading_And_Running.md b/08_Loading_Elf/03_Loading_And_Running.md new file mode 100644 index 00000000..d754970a --- /dev/null +++ b/08_Loading_Elf/03_Loading_And_Running.md @@ -0,0 +1,6 @@ +- create new address space, +- load all PHDRs into address space, +- create new thread with e_entrypoint as starting function, +- executate + +- dont forgot to exit()! From 9d2b1db780f62bf2e2e368807e7ea2a059caa692 Mon Sep 17 00:00:00 2001 From: Dean Date: Sat, 4 Feb 2023 00:26:52 +1100 Subject: [PATCH 19/32] more work --- 08_Loading_Elf/01_README.md | 19 +++++- 08_Loading_Elf/02_Elf_Theory.md | 102 ++++++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 7 deletions(-) diff --git a/08_Loading_Elf/01_README.md b/08_Loading_Elf/01_README.md index a14728d7..b9aa30c4 100644 --- a/08_Loading_Elf/01_README.md +++ b/08_Loading_Elf/01_README.md @@ -2,7 +2,24 @@ This chapter won't be too heavy on new concepts, besides the ELF specification itself, but will focus on bringing everything together. We're going to load a program in a new process, and run it in userspace. This is typically how most programs run, and then from there we can execute a few example system calls. -It should be noted that the original ELF specification is for 32-bit programs, but a *64-bit extensions* was created later on called ELF64. We'll be focusing on ELF64. +It should be noted that the original ELF specification is for 32-bit programs, but a *64-bit extension* was created later on called ELF64. We'll be focusing on ELF64. + +It's worth having a copy of the ELF specification as a reference for this chapter as we won't define every structure required. The specification doesn't use fixed width types in it's definiton, instead using `words` and `half words`, which are based on the word size of the cpu. For the exact definition of these terms you will need the platform-specific part of the ELF spec, which gives concrete types for these. + +For x86_64 these types are defined as follows: + +```c +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint8_t Elf64_UnsignedChar; +``` + +All structs in the base ELF spec are defined using these types, and so we will use them too. Note that their exact definitions *will* change depending on your target platform. ## Restrictions diff --git a/08_Loading_Elf/02_Elf_Theory.md b/08_Loading_Elf/02_Elf_Theory.md index f7d3fbc9..39871ad0 100644 --- a/08_Loading_Elf/02_Elf_Theory.md +++ b/08_Loading_Elf/02_Elf_Theory.md @@ -13,15 +13,105 @@ Within the ELF specification section headers and program headers are often abbre ## Section Headers -We won't be dealing with a lot of section headers, as the program loader is mainly interested in program headers. However there are some core SHDRs you should be aware of. +We won't be dealing with a lot of section headers, as the program loader is mainly interested in program headers. Having said that, there are some special section headers you should be aware of: -- special shdrs -- how to parse a shdr, +- `.strtab`: This header contains a number of null-terminated strings, with the first string simply being a null-terminator. When a string is referenced in an ELF, it's stored as an offset +- `.symtab`: This section contains information on symbols (variables and functions) within the ELF. This is where to look for extracting debug information. + +TODO: how to parse SHDRs (shdrstridx or whatever it's called) ## Program Headers +While section headers contain a more granular description of our ELF binary, program headers contain just enough information to load the program. Program headers are design to be simple, and by extension allow the program loader to be simple. + +The layout of a `PHDR` is as follows: + +```c +typedef struct { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; +``` + +This is the layout of a program header in memory. Locating a phdr is similar to locating an shdr. The first header is located `elf_header->phoff` bytes from the start of the ELF file. It's that easy! + +Like section headers, each program header is tighly packed against the next one. This means you can treat the program headers as an array. As an example you could loop through the phdrs as follows: + +```c +void loop_phdrs(Elf64_Hdr* ehdr) { + Elf64_Phdr* phdrs = *(Elf64_Phdr*)((uintptr_t)ehdr + ehdr->e_phoff); + + for (size_t i = 0; i < ehdr->e_phnum; i++) + { + Elf64_Phdr* program_header = phdrs[i]; + //do something with program_header here. + } +} +``` + +Unlike section headers, program headers don't have names. Instead we use the type field (`p_type`) to determine what to do with the contents of the phdr. + ## Loading Theory -- validate header -- find all PT_LOAD headers, copy those in -- you're good! +For now we're only interested in one type of phdr: `PT_LOAD`. This constant is defined in the elf64 spec as `1`. + +This type means that we are expected to load the contents of this program header at a specified address before running the program. Often there will be a few headers with this type, with different permissions (to map to different parts of our program: `.rodata`, `.data`, `.text` for example). + +To load our simple, statically-linked, program the process is as follows: + +- Load the ELF file in memory somewhere. +- Validate the ELF header by checking the machine type matches what we expect (is this an x86_64 program?). +- Find all program headers with the `PT_LOAD` type. +- Load each program header: we'll cover this shortly. +- Jump to the start address defined in the ELF header. + +Do note that these are just the steps for loading the ELF, there are actually other things we'll need like a stack for the program to use. Of course this is likely covered when we create a new thread for the program to run. + +### Loading A Program Header + +Loading a program header is essentially a memcpy. The program header describes where we copy data from (via `p_offset` and `p_filesz`), and where we copy it to (via `p_vaddr` and `p_memsz`). + +Like the program headers are located `e_phoff` bytes into the ELF, it's the same with `p_offset`. We can copy from `p_offset` bytes from the base of the ELF file. From that address we'll copy `p_filesz` bytes to the address contained in `p_vaddr` (virtual address). There's an important detail that's easy to miss with the copy: we are expected to make `p_memsz` bytes available at `p_vaddr`, even if `p_memsz` is bigger than `p_filesz`. The spec says that this extra space (`p_memsz` - `p_filesz`) should be zeroed. + +This is actually how the `.bss` section is allocated, and any pre-zeroed parts of an ELF executable are created this way. + +Before looking at some example code your VMM will need a new function that tries to allocate memory at a *specific* virtual address, instead of whatever is the best fit. For our example we're going to assume you have the following implemented, but adjust to your own design: + +```c +void* vmm_alloc_at(uintptr_t addr, size_t length, size_t flags); +``` + +Alternatively you could make use of the extra argument in `vmm_alloc`, and add a new flag like `VM_FLAG_AT_ADDR` that indicates the VMM should use the extra arg as the virtual address. + +The reason we need to use a specific address is that the code and data contained in the ELF are compiled and linked assuming that they're at that address. There might be code that jumps to a fixed address or data that is expected to be at a certain address. If we don't copy the program header where it expects to be, the program may break. + +*Authors Note: Relocations are another way of dealing with the problem of not being to use the requested virtual address, but these are more advanced. They're not hard to implement, certainly easier than dynamic linking, but still beyond the scope of this section.* + +Now that we have that, lets look at the example code (without error handling, as always): + +```c +void load_phdr(Elf64_EHdr* ehdr, Elf64_Phdr* phdr) { + if (phdr->p_type != PT_LOAD) + return; + + void* dest = vmm_alloc_at(phdr->p_vaddr, phdr->p_memsz, VM_FLAG_WRITE); + memcpy(dest, (void*)ehdr + phdr->p_offset, phdr->p_filesz); + + const zero_count = phdr->p_memsz - phdr->p_filesz; + memset(dest + phdr->p_filesz, 0, zero_count); +} +``` + +### Program Header Flags + +At this point we've got the program header's content loaded in the correct place. We'll run into an issue if we try to use the loaded program header in this state: we've mapped all program headers as read/write/no-execute. This means if we try to execute any of the headers as code (and at least one of them is guarenteed to be code), we'll fault. + +Fortunately the solution is quite straight forward, the read/write/execute permissions required for a phdr are encoded in the `p_flags` field. This field is actually a bitfield, with bit 0 representing execute, bit 1 representing write and bit 2 representing read. You can ignore the read permission as most platform's dont allow for write-only memory anyway, but you'll want to be sensitive to the write and execute permissions. + +You'll want to adjust these permission *after copying the program header content*, because you'll need the memory to be writable for that. Then you can modify the flags of the mapped memory to what the program header requests. From 71e5519e3354eb1a9165da34e36d987a8a99e955 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 7 Feb 2023 22:07:10 +1100 Subject: [PATCH 20/32] more work --- 08_Loading_Elf/02_Elf_Theory.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/08_Loading_Elf/02_Elf_Theory.md b/08_Loading_Elf/02_Elf_Theory.md index 39871ad0..8e9e2f1c 100644 --- a/08_Loading_Elf/02_Elf_Theory.md +++ b/08_Loading_Elf/02_Elf_Theory.md @@ -4,10 +4,10 @@ The executable and linker format (ELF) is a multi-purpose format: it can be used The format has four main sections: -- The ELF header. This contains the magic number used to identify it as an ELF, as well as information about the architecture the ELF was compiled for, the target operating system and other useful info. -- The data blob. The bulk of the file is made up of this blob. This is a big binary blob containing code, all kinds of data, some string tables and sometimes debugging information. All program data lives here. -- Section headers. Each header has a name and some metadata associated with it, and describes a region of the data blob. Section names usually begin with a dot (`.`), like `.strtab` which refers to the string table. Section headers are for other software to parse the ELF and understand it's structure and contents. -- Program headers. These are for the program loader (what we're going to write). Each program header has a type that tells the loader how to interpret it, as well as specifying a range within the data blob. These ranges in the data blob can overlap (or often cover the same area as some section header ranges) ranges described by section headers. +- *The ELF header*: This contains the magic number used to identify it as an ELF, as well as information about the architecture the ELF was compiled for, the target operating system and other useful info. +- *The data blob*: The bulk of the file is made up of this blob. This is a big binary blob containing code, all kinds of data, some string tables and sometimes debugging information. All program data lives here. +- *Section headers*: Each header has a name and some metadata associated with it, and describes a region of the data blob. Section names usually begin with a dot (`.`), like `.strtab` which refers to the string table. Section headers are for other software to parse the ELF and understand it's structure and contents. +- *Program headers*: These are for the program loader (what we're going to write). Each program header has a type that tells the loader how to interpret it, as well as specifying a range within the data blob. These ranges in the data blob can overlap (or often cover the same area as some section header ranges) ranges described by section headers. Within the ELF specification section headers and program headers are often abbreviated to SHDRs and PHDRs. In a real file the data blob is actually located after the section and program headers. @@ -65,11 +65,11 @@ This type means that we are expected to load the contents of this program header To load our simple, statically-linked, program the process is as follows: -- Load the ELF file in memory somewhere. -- Validate the ELF header by checking the machine type matches what we expect (is this an x86_64 program?). -- Find all program headers with the `PT_LOAD` type. -- Load each program header: we'll cover this shortly. -- Jump to the start address defined in the ELF header. +1) Load the ELF file in memory somewhere. +2) Validate the ELF header by checking the machine type matches what we expect (is this an x86_64 program?). +3) Find all program headers with the `PT_LOAD` type. +4) Load each program header: we'll cover this shortly. +5) Jump to the start address defined in the ELF header. Do note that these are just the steps for loading the ELF, there are actually other things we'll need like a stack for the program to use. Of course this is likely covered when we create a new thread for the program to run. @@ -91,7 +91,7 @@ Alternatively you could make use of the extra argument in `vmm_alloc`, and add a The reason we need to use a specific address is that the code and data contained in the ELF are compiled and linked assuming that they're at that address. There might be code that jumps to a fixed address or data that is expected to be at a certain address. If we don't copy the program header where it expects to be, the program may break. -*Authors Note: Relocations are another way of dealing with the problem of not being to use the requested virtual address, but these are more advanced. They're not hard to implement, certainly easier than dynamic linking, but still beyond the scope of this section.* +*Authors Note: Relocations are another way of dealing with the problem of not being able to use the requested virtual address, but these are more advanced. They're not hard to implement, certainly easier than dynamic linking, but still beyond the scope of this section.* Now that we have that, lets look at the example code (without error handling, as always): @@ -112,6 +112,10 @@ void load_phdr(Elf64_EHdr* ehdr, Elf64_Phdr* phdr) { At this point we've got the program header's content loaded in the correct place. We'll run into an issue if we try to use the loaded program header in this state: we've mapped all program headers as read/write/no-execute. This means if we try to execute any of the headers as code (and at least one of them is guarenteed to be code), we'll fault. -Fortunately the solution is quite straight forward, the read/write/execute permissions required for a phdr are encoded in the `p_flags` field. This field is actually a bitfield, with bit 0 representing execute, bit 1 representing write and bit 2 representing read. You can ignore the read permission as most platform's dont allow for write-only memory anyway, but you'll want to be sensitive to the write and execute permissions. +Fortunately the solution is quite straightforward, the read/write/execute permissions required for a phdr are encoded in the `p_flags` field. This field is actually a bitfield, with the following definition: + +- `bit 0`: Represents whether a phdr should be executable. Remember that the executable flag is backwards on x86: all memory can be executed by default, unless you set the NX bit. Ideally this should be hidden behind your VMM interface though. +- `bit 1`: Indicates a region should be writable, the region is read-only if this bit is clear. +- `bit 2`: Indicates a region should be readable. This bit should always be set, as exec-only or write-only memory is not very useful, and some hardware platforms will consider these states as an error. You'll want to adjust these permission *after copying the program header content*, because you'll need the memory to be writable for that. Then you can modify the flags of the mapped memory to what the program header requests. From e15656278e4ea3ccb6a6d4bd22af90ee78812a8f Mon Sep 17 00:00:00 2001 From: Dean Date: Sun, 12 Feb 2023 10:23:43 +1100 Subject: [PATCH 21/32] incremented commit --- 08_Loading_Elf/01_README.md | 11 +++------- 08_Loading_Elf/03_Loading_And_Running.md | 26 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/08_Loading_Elf/01_README.md b/08_Loading_Elf/01_README.md index b9aa30c4..698cd010 100644 --- a/08_Loading_Elf/01_README.md +++ b/08_Loading_Elf/01_README.md @@ -21,12 +21,7 @@ typedef uint8_t Elf64_UnsignedChar; All structs in the base ELF spec are defined using these types, and so we will use them too. Note that their exact definitions *will* change depending on your target platform. -## Restrictions +In this chapter we're going to look at the following topics: -To simplify our program loader we're going to put a few restrictions in place for now. Later on you can expand the loader yourself as you come across features you might want to support. - -For a program to be compatible with our loader: - -- It cannot contain any relocations. We don't care if it's statically linked or uses PIC (position independent code) however. -- All libraries must be statically linked, we won't support dynamic linking for now. This feature can be implemented over a weekend, but greatly increases the complexity of your loader. -- The program must be freestanding, since we haven't ported (or written) a libc we can't use any standard functions. Porting a libc is worthwhile, but it's outside the scope of this chapter. +- [General ELF Theory](02_Elf_Theory.md) +- [Loading A Program](03_Loading_And_Running.md) diff --git a/08_Loading_Elf/03_Loading_And_Running.md b/08_Loading_Elf/03_Loading_And_Running.md index d754970a..3bb06cfd 100644 --- a/08_Loading_Elf/03_Loading_And_Running.md +++ b/08_Loading_Elf/03_Loading_And_Running.md @@ -1,6 +1,24 @@ -- create new address space, -- load all PHDRs into address space, -- create new thread with e_entrypoint as starting function, -- executate +# Loading and Running an ELF + +Before we start, we're going to apply a few restrictions to our program loader. These are things you can easily add later, but they only serve to complicate the process. + +For a program to be compatible with our loader: + +- It cannot contain any relocations. We don't care about static linking or position independent code (PIC) however, as that doesn't affect the loader. +- All libraries must be statically linked, we won't support dynamic linking for now. This feature isn't too hard to implement, but we will leave this as an exercise to the reader. +- The program must be freestanding! As of right now we don't have a libc that targets our kernel. It can be worth porting (or writing) a libc later on. + +# Overview + +In the previous chapter we looked at the details of loading program headers, but we glossed over a lot of the high level details of loading a program. Assuming we want to start running a new program (we're ignoring `fork()` and `exec()` for the moment), we'll need to perform the following: + +- Create a new address space for the program. The specifics may depend on your design, but this usually results in a new VMM being instanced for the new program. Of course the kernel must live in the higher half of this new address space. +- Inside this address space we're going to load the program headers, like we did perviously. Remember that the phdrs expect to be loaded at certain virtual addresses. +- Now we'll need to create a new thread that uses this address space, this thread will serve as our main thread. In our design this involves first creating a new process, attaching the address space and then creating the thread. You will also need create a stack for this thread to run on. +- We'll want this thread to execute the entry function of the + +## Caveats + +- running user thread requires ring switch - dont forgot to exit()! From f2d9786f3b6f43e726ea303c2e14c65e4ae060af Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 30 Mar 2023 16:53:44 +1100 Subject: [PATCH 22/32] Incremental commit, finished loading + running part --- 08_Loading_Elf/01_README.md | 4 ++++ 08_Loading_Elf/02_Elf_Theory.md | 26 +++++++++++++----------- 08_Loading_Elf/03_Loading_And_Running.md | 14 ++++++++----- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/08_Loading_Elf/01_README.md b/08_Loading_Elf/01_README.md index 698cd010..ecb3d86c 100644 --- a/08_Loading_Elf/01_README.md +++ b/08_Loading_Elf/01_README.md @@ -1,5 +1,9 @@ # Loading An ELF +The *executable and linker file* (ELF) is an open standard for programs, libraries and shards of code and data that are waiting to linked. It's the most common format used by linux and BSD operating systems, and sees some use elsewhere. It's also the most common format for programs in hobby as it's quite simple to implement and it's public specification is feature-complete. + +That's not to say ELF is the *only* format for these kinds of files (there are others like PE/portable execute, a.out or even mach-o), but the ELF format is the best for our purposes. A majority of operating systems have come to a similar to conclusion. You could also use your own format, but be aware this requires a compiler capable of outputting your custom format (meaning you either write your own compiler, or modify an existing one - a lot of work!). + This chapter won't be too heavy on new concepts, besides the ELF specification itself, but will focus on bringing everything together. We're going to load a program in a new process, and run it in userspace. This is typically how most programs run, and then from there we can execute a few example system calls. It should be noted that the original ELF specification is for 32-bit programs, but a *64-bit extension* was created later on called ELF64. We'll be focusing on ELF64. diff --git a/08_Loading_Elf/02_Elf_Theory.md b/08_Loading_Elf/02_Elf_Theory.md index 8e9e2f1c..8c5b9293 100644 --- a/08_Loading_Elf/02_Elf_Theory.md +++ b/08_Loading_Elf/02_Elf_Theory.md @@ -9,7 +9,7 @@ The format has four main sections: - *Section headers*: Each header has a name and some metadata associated with it, and describes a region of the data blob. Section names usually begin with a dot (`.`), like `.strtab` which refers to the string table. Section headers are for other software to parse the ELF and understand it's structure and contents. - *Program headers*: These are for the program loader (what we're going to write). Each program header has a type that tells the loader how to interpret it, as well as specifying a range within the data blob. These ranges in the data blob can overlap (or often cover the same area as some section header ranges) ranges described by section headers. -Within the ELF specification section headers and program headers are often abbreviated to SHDRs and PHDRs. In a real file the data blob is actually located after the section and program headers. +Within the ELF specification section headers and program headers are often abbreviated to *SHDRs* and *PHDRs*. In a real file the data blob is actually located after the section and program headers. ## Section Headers @@ -22,7 +22,7 @@ TODO: how to parse SHDRs (shdrstridx or whatever it's called) ## Program Headers -While section headers contain a more granular description of our ELF binary, program headers contain just enough information to load the program. Program headers are design to be simple, and by extension allow the program loader to be simple. +While section headers contain a more granular description of our ELF binary, program headers contain just enough information to load the program. Program headers are designed to be simple, and by extension allow the program loader to be simple. The layout of a `PHDR` is as follows: @@ -39,7 +39,9 @@ typedef struct { } Elf64_Phdr; ``` -This is the layout of a program header in memory. Locating a phdr is similar to locating an shdr. The first header is located `elf_header->phoff` bytes from the start of the ELF file. It's that easy! +The meaning of all these fields is explained below when we look at how actually loading a program header. The most important field here is `p_type`: this tells the program loader what it should do with this particular header. A full list of types is available in the ELF spec, but for now we only need one type: `PT_LOAD`. + +Finding the program headers within an ELF binary is also quite straightforward. The offset of the first phdr is given by the `phoff` (program header offset) field of the ELF header. Like section headers, each program header is tighly packed against the next one. This means you can treat the program headers as an array. As an example you could loop through the phdrs as follows: @@ -55,8 +57,6 @@ void loop_phdrs(Elf64_Hdr* ehdr) { } ``` -Unlike section headers, program headers don't have names. Instead we use the type field (`p_type`) to determine what to do with the contents of the phdr. - ## Loading Theory For now we're only interested in one type of phdr: `PT_LOAD`. This constant is defined in the elf64 spec as `1`. @@ -87,7 +87,7 @@ Before looking at some example code your VMM will need a new function that tries void* vmm_alloc_at(uintptr_t addr, size_t length, size_t flags); ``` -Alternatively you could make use of the extra argument in `vmm_alloc`, and add a new flag like `VM_FLAG_AT_ADDR` that indicates the VMM should use the extra arg as the virtual address. +Alternatively you could make use of the extra argument in `vmm_alloc`, and add a new flag like `VM_FLAG_AT_ADDR` that indicates the VMM should use the extra arg as the virtual address. Bare in mind that if you're loading a program into another address space you will need a way to copy the phdr contents into that address space. The specifics of this don't matter too much, as long as you have a way to do it. The reason we need to use a specific address is that the code and data contained in the ELF are compiled and linked assuming that they're at that address. There might be code that jumps to a fixed address or data that is expected to be at a certain address. If we don't copy the program header where it expects to be, the program may break. @@ -110,12 +110,14 @@ void load_phdr(Elf64_EHdr* ehdr, Elf64_Phdr* phdr) { ### Program Header Flags -At this point we've got the program header's content loaded in the correct place. We'll run into an issue if we try to use the loaded program header in this state: we've mapped all program headers as read/write/no-execute. This means if we try to execute any of the headers as code (and at least one of them is guarenteed to be code), we'll fault. +At this point we've got the program header's content loaded in the correct place. We'll run into an issue if we try to use the loaded program header in this state: we've mapped all program headers in virtual memory as read/write/no-execute. This means if we try to execute any of the headers as code (and at least one of them is guarenteed to be code), we'll fault. Some of these headers should be read-only, and some (in the case of code) should be readable and executable. + +While you could map everything as read + write + execute, that's not recommended for security reasons. It can also lead to bugs in your programs, and potentially cause crashes. -Fortunately the solution is quite straightforward, the read/write/execute permissions required for a phdr are encoded in the `p_flags` field. This field is actually a bitfield, with the following definition: +Each program header stores what permissions it requires in the `p_flags` field. This field is actually a bitfield, with the following definition: -- `bit 0`: Represents whether a phdr should be executable. Remember that the executable flag is backwards on x86: all memory can be executed by default, unless you set the NX bit. Ideally this should be hidden behind your VMM interface though. -- `bit 1`: Indicates a region should be writable, the region is read-only if this bit is clear. -- `bit 2`: Indicates a region should be readable. This bit should always be set, as exec-only or write-only memory is not very useful, and some hardware platforms will consider these states as an error. +- `Bit 0`: Represents whether a phdr should be executable. Remember that the executable flag is backwards on x86: all memory can be executed by default, unless you set the NX bit. Ideally this should be hidden behind your VMM interface though. +- `Bit 1`: Indicates a region should be writable, the region is read-only if this bit is clear. +- `Bit 2`: Indicates a region should be readable. This bit should always be set, as exec-only or write-only memory is not very useful, and some hardware platforms will consider these states as an error. -You'll want to adjust these permission *after copying the program header content*, because you'll need the memory to be writable for that. Then you can modify the flags of the mapped memory to what the program header requests. +You'll want to adjust the permissions of the mapped memory *after copying the program header content*. This is because you will need the memory to be mapped as writable so the CPU lets us copy the phdr content into it, and then you can adjust the permissions to what the program header requested. diff --git a/08_Loading_Elf/03_Loading_And_Running.md b/08_Loading_Elf/03_Loading_And_Running.md index 3bb06cfd..89d5ee2f 100644 --- a/08_Loading_Elf/03_Loading_And_Running.md +++ b/08_Loading_Elf/03_Loading_And_Running.md @@ -13,12 +13,16 @@ For a program to be compatible with our loader: In the previous chapter we looked at the details of loading program headers, but we glossed over a lot of the high level details of loading a program. Assuming we want to start running a new program (we're ignoring `fork()` and `exec()` for the moment), we'll need to perform the following: - Create a new address space for the program. The specifics may depend on your design, but this usually results in a new VMM being instanced for the new program. Of course the kernel must live in the higher half of this new address space. -- Inside this address space we're going to load the program headers, like we did perviously. Remember that the phdrs expect to be loaded at certain virtual addresses. -- Now we'll need to create a new thread that uses this address space, this thread will serve as our main thread. In our design this involves first creating a new process, attaching the address space and then creating the thread. You will also need create a stack for this thread to run on. -- We'll want this thread to execute the entry function of the +- Inside this address space we're going to load the program headers, like we did perviously. Remember that the phdrs expect to be loaded at certain virtual addresses with certain permissions. +- Now we'll need to create a new thread that uses this address space, this thread will serve as our main thread. In our design this involves first creating a new process, attaching the address space and then creating the thread. You will also need create a stack for this thread to run on (if this is not already part of your thread-creation process). +- We'll want this thread to execute the entry function of the ELF file, this is available in the ELF header as the field `e_entry`. + +If you've done all of this then the program is ready to run! You should be able to queue the main thread in your scheduler and let it run. ## Caveats -- running user thread requires ring switch +As you can already see from the restrictions we made above there is plenty of room for improvement. There are also some other things to keep in mind: -- dont forgot to exit()! +- If you're loading a program into *userspace* (rather than in the kernel) you will need to map all the memory you want to allow the program to use as user-accessible. This means not just the program headers but also the stack. +- Again if you're loading a user program your scheduler will need to handle switching between different privilege levels on the cpu. On x86_64 these are called rings (ring 0 = kernel, ring 3 = user), other platforms may use different names. See the userspace chapter for more detail. +- As was mentioned in the scheduling chapter, don't forget to call a function when exiting the main thread of the program! In a typical userspace program the standard library does this for us, but our programs are freedstanding so you'll need to do this manually. If coming from userspace this will require a syscall. From 9f7e138b99ea7af3a20fe293da9bd747a3b8ecb7 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 11 Apr 2023 13:01:25 +1000 Subject: [PATCH 23/32] (hopefully) finishing touches --- 08_Loading_Elf/02_Elf_Theory.md | 13 +++++++++---- 08_Loading_Elf/03_Loading_And_Running.md | 19 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/08_Loading_Elf/02_Elf_Theory.md b/08_Loading_Elf/02_Elf_Theory.md index 8c5b9293..d4dccb5b 100644 --- a/08_Loading_Elf/02_Elf_Theory.md +++ b/08_Loading_Elf/02_Elf_Theory.md @@ -13,12 +13,17 @@ Within the ELF specification section headers and program headers are often abbre ## Section Headers -We won't be dealing with a lot of section headers, as the program loader is mainly interested in program headers. Having said that, there are some special section headers you should be aware of: +Section headers describe the ELF in more detail and often contain useful (but not required for running) data. We won't be dealing with section headers at all in our program loader, since everything we need is nicely contained in the program headers. -- `.strtab`: This header contains a number of null-terminated strings, with the first string simply being a null-terminator. When a string is referenced in an ELF, it's stored as an offset -- `.symtab`: This section contains information on symbols (variables and functions) within the ELF. This is where to look for extracting debug information. +Having said that, if you're curious about what's inside the rest of the ELF file, tools like `objdump` or `readelf` can parse and display section headers for you. They're also documented thoroughly in the ELF specification. -TODO: how to parse SHDRs (shdrstridx or whatever it's called) +There are a few special section headers worth knowing about, even if we dont use them right now: + +- `.text`, `.rodata`, `.data`, and `.bss`: These usually map directly to the program headers of the same name. Since section headers contain more information than program headers, there is often some extra information stored here about these sections. This is not needed by a program loader so it's not present in the PHDRs. +- `.strtab`: Short for *string table*, this section header is a series of null-terminated strings. The first entry in this table is also a null-terminator. When other sections need to store a string they actually store a byte offset into this section. +- `.symtab`: Short for *symbol table*, this section contains all the exported (and internal) symbols for the program. This section may also include some debugging symbols if compiling with `-g` or they may be stored under a `.debug_*` section. If you ever need to get symbols for a program, they'll be here. + +Often there will be other section headers in your program, often serving specific purposes. For example `.eh_frame` is used for storing language-based exception and unwinding information, and you may also have `.ctors` if there any global constructors. ## Program Headers diff --git a/08_Loading_Elf/03_Loading_And_Running.md b/08_Loading_Elf/03_Loading_And_Running.md index 89d5ee2f..3e829cd7 100644 --- a/08_Loading_Elf/03_Loading_And_Running.md +++ b/08_Loading_Elf/03_Loading_And_Running.md @@ -8,21 +8,24 @@ For a program to be compatible with our loader: - All libraries must be statically linked, we won't support dynamic linking for now. This feature isn't too hard to implement, but we will leave this as an exercise to the reader. - The program must be freestanding! As of right now we don't have a libc that targets our kernel. It can be worth porting (or writing) a libc later on. -# Overview +# Steps Required -In the previous chapter we looked at the details of loading program headers, but we glossed over a lot of the high level details of loading a program. Assuming we want to start running a new program (we're ignoring `fork()` and `exec()` for the moment), we'll need to perform the following: +In the previous chapter we looked at the details of loading program headers, but we glossed over a lot of the high level details of loading a program. Assuming we want to start running a new program (we're ignoring `fork()` and `exec()` for the moment), we'll need to do a few things. Most of this was covered in previous chapters, and now it's a matter of putting it all together. -- Create a new address space for the program. The specifics may depend on your design, but this usually results in a new VMM being instanced for the new program. Of course the kernel must live in the higher half of this new address space. -- Inside this address space we're going to load the program headers, like we did perviously. Remember that the phdrs expect to be loaded at certain virtual addresses with certain permissions. -- Now we'll need to create a new thread that uses this address space, this thread will serve as our main thread. In our design this involves first creating a new process, attaching the address space and then creating the thread. You will also need create a stack for this thread to run on (if this is not already part of your thread-creation process). -- We'll want this thread to execute the entry function of the ELF file, this is available in the ELF header as the field `e_entry`. +- First you'll need a copy of the ELF file you want to load. The recommended way is to load a file via the VFS, but it could be a bootloader module or even embedded into your kernel. +- Once you have the ELF, verify it's header is correct. You'll want to check the architecture (machine type) matches the current machine, and that the bit-ness is correct (dont try to run a 32-bit program if you dont support it!). +- Find all the loadable program headers for the ELF, we'll need those in a moment. +- Create a new address space for the program to live in. This usually involves creating a new VMM instance, but the specifics will vary depending on your design. Don't forget to keep the kernel mappings in the higher half! +- Copy the loadable program headers into this new address space. Take care when writing this code, as the program headers may not be page-aligned. Don't forget to zero the extra bytes between `memsz` and `filesz`. +- Once loaded, set the appropriate permission on the memory each program header lives in: the write, execute (or no-execute) and user flags. +- Now we'll need to create a thread to act as the main thread for this program, set the thread's entry function to the `e_entry` field in the ELF header. This field is the start function of the program. You'll also need to create a stack in the memory space of this program for the thread to use, if this wasnt already done as part of your thread creation. -If you've done all of this then the program is ready to run! You should be able to queue the main thread in your scheduler and let it run. +If you've done all of this then the program is ready to run! You should be able to emqueue the main thread in your scheduler and let it run. ## Caveats As you can already see from the restrictions we made above there is plenty of room for improvement. There are also some other things to keep in mind: -- If you're loading a program into *userspace* (rather than in the kernel) you will need to map all the memory you want to allow the program to use as user-accessible. This means not just the program headers but also the stack. +- If you're loading a program into *userspace* (rather than in the kernel) you will need to map all the memory you want to allow the program to use as user-accessible. This means not just the program headers but also the stack. You'll want to mark all this memory as user-accessible *after* copying the program data in there though. - Again if you're loading a user program your scheduler will need to handle switching between different privilege levels on the cpu. On x86_64 these are called rings (ring 0 = kernel, ring 3 = user), other platforms may use different names. See the userspace chapter for more detail. - As was mentioned in the scheduling chapter, don't forget to call a function when exiting the main thread of the program! In a typical userspace program the standard library does this for us, but our programs are freedstanding so you'll need to do this manually. If coming from userspace this will require a syscall. From 28ee4ee32bf9d90a4f5617b577d7c0993c385a45 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 11 Apr 2023 13:08:33 +1000 Subject: [PATCH 24/32] Added list/array info to assumed knowledge --- 00_Introduction/02_AssumedKnowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Introduction/02_AssumedKnowledge.md b/00_Introduction/02_AssumedKnowledge.md index 405efdfe..97713fc9 100644 --- a/00_Introduction/02_AssumedKnowledge.md +++ b/00_Introduction/02_AssumedKnowledge.md @@ -8,6 +8,6 @@ As such, below is a list of the recommended prior experience before continuing w - Intermediate understanding of the C programming language. Mastery is not required, but you should be very familiar with the ins and outs of the language, especially pointers and pointer arithmetic. - You should be comfortable compiling and debugging code in userspace. GDB is recommended as several emulators provide a GDB server you can use to step through your kernel. -- Knowledge and experience using common data structures like intrusive linked lists. +- Knowledge and experience using common data structures like intrusive linked lists. While we may use array notation at several points to help visualize what's going on, you wont want to place arbitrary limits on your kernel by using fixed size arrays. If you feel confident in your knowledge of the above, please read on! If not, don't be discouraged. There are plenty of resources available for learning, and you can always come back later. From 6eae2affa136b1dfb3a48b4a56b4027401f4440f Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 11 Apr 2023 13:12:40 +1000 Subject: [PATCH 25/32] previously requested changes --- 08_Loading_Elf/02_Elf_Theory.md | 2 +- 08_Loading_Elf/03_Loading_And_Running.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/08_Loading_Elf/02_Elf_Theory.md b/08_Loading_Elf/02_Elf_Theory.md index d4dccb5b..5c48f3d3 100644 --- a/08_Loading_Elf/02_Elf_Theory.md +++ b/08_Loading_Elf/02_Elf_Theory.md @@ -117,7 +117,7 @@ void load_phdr(Elf64_EHdr* ehdr, Elf64_Phdr* phdr) { At this point we've got the program header's content loaded in the correct place. We'll run into an issue if we try to use the loaded program header in this state: we've mapped all program headers in virtual memory as read/write/no-execute. This means if we try to execute any of the headers as code (and at least one of them is guarenteed to be code), we'll fault. Some of these headers should be read-only, and some (in the case of code) should be readable and executable. -While you could map everything as read + write + execute, that's not recommended for security reasons. It can also lead to bugs in your programs, and potentially cause crashes. +While you could map everything as *read* + *write* + *execute*, that's not recommended for security reasons. It can also lead to bugs in your programs, and potentially cause crashes. Each program header stores what permissions it requires in the `p_flags` field. This field is actually a bitfield, with the following definition: diff --git a/08_Loading_Elf/03_Loading_And_Running.md b/08_Loading_Elf/03_Loading_And_Running.md index 3e829cd7..d94af760 100644 --- a/08_Loading_Elf/03_Loading_And_Running.md +++ b/08_Loading_Elf/03_Loading_And_Running.md @@ -18,7 +18,7 @@ In the previous chapter we looked at the details of loading program headers, but - Create a new address space for the program to live in. This usually involves creating a new VMM instance, but the specifics will vary depending on your design. Don't forget to keep the kernel mappings in the higher half! - Copy the loadable program headers into this new address space. Take care when writing this code, as the program headers may not be page-aligned. Don't forget to zero the extra bytes between `memsz` and `filesz`. - Once loaded, set the appropriate permission on the memory each program header lives in: the write, execute (or no-execute) and user flags. -- Now we'll need to create a thread to act as the main thread for this program, set the thread's entry function to the `e_entry` field in the ELF header. This field is the start function of the program. You'll also need to create a stack in the memory space of this program for the thread to use, if this wasnt already done as part of your thread creation. +- Now we'll need to create a new thread to act as the main thread for this program, and set it's entry point to the `e_entry` field in the ELF header. This field is the start function of the program. You'll also need to create a stack in the memory space of this program for the thread to use, if this wasnt already done as part of your thread creation. If you've done all of this then the program is ready to run! You should be able to emqueue the main thread in your scheduler and let it run. @@ -28,4 +28,4 @@ As you can already see from the restrictions we made above there is plenty of ro - If you're loading a program into *userspace* (rather than in the kernel) you will need to map all the memory you want to allow the program to use as user-accessible. This means not just the program headers but also the stack. You'll want to mark all this memory as user-accessible *after* copying the program data in there though. - Again if you're loading a user program your scheduler will need to handle switching between different privilege levels on the cpu. On x86_64 these are called rings (ring 0 = kernel, ring 3 = user), other platforms may use different names. See the userspace chapter for more detail. -- As was mentioned in the scheduling chapter, don't forget to call a function when exiting the main thread of the program! In a typical userspace program the standard library does this for us, but our programs are freedstanding so you'll need to do this manually. If coming from userspace this will require a syscall. +- As was mentioned in the scheduling chapter, don't forget to call a function when exiting the main thread of the program! In a typical userspace program the standard library does this for us, but our programs are freestanding so you'll need to do this manually. If coming from userspace this will require a syscall. From 585c129c634259187cd0fb7ce26fcffcfc57a361 Mon Sep 17 00:00:00 2001 From: Ivan G <59960116+dreamos82@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:13:13 +0100 Subject: [PATCH 26/32] Update 02_VirtualFileSystem.md minor changes to the VFS chapter. --- 08_VirtualFileSystem/02_VirtualFileSystem.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/08_VirtualFileSystem/02_VirtualFileSystem.md b/08_VirtualFileSystem/02_VirtualFileSystem.md index 069fba82..41e64922 100644 --- a/08_VirtualFileSystem/02_VirtualFileSystem.md +++ b/08_VirtualFileSystem/02_VirtualFileSystem.md @@ -182,13 +182,13 @@ And we want to access the following paths: * /home/mount/folder1/file * /opt -As we can see the first two paths have a common part, but belongs to different file system so we need to implement a function that given a path return the index of the file system it belongs to. +As we can see the first two paths have a common part, but belongs to different file system so we need to implement a function that given a path return a reference of the file system it belongs to. -How to do it is pretty simple, we scan the array, and search for the "longest" mountpoint that is contained in the path, so in the first example, we can see that there are two items in the array that are contained in the path: "/" (0), and "/home" (3), and the longest one is number 3, so this is what our function is going to return. +How to do it is pretty simple, we scan the list, and search for the "longest" mountpoint that is contained in the path, so in the first example, we can see that there are two items in the array that are contained in the path: _"/" (0)_, and _"/home" (3)_, and the longest one is number 3, so this is the file system our function is going to return (wheter it is going to be an id or the reference to the mountpoint item). -The second path instead has three mountpoints contained into it: "/" (0), "/home/mount" (1), "/home", in this case we are going to return 1. +The second path instead has three mountpoints contained into it: _/" (0)_, _"/home/mount" (1)_, _"/home" (3)_, in this case we are going to return 1. -The last one, has only one mountpoint that is contained into the path, and it is "/" (0). +The last one, has only one mountpoint that is contained into the path, and it is _"/" (0)_. In a single root scenario, there is always at least a mountpoint that is contained into the given path, and this is the root folder "/". @@ -373,7 +373,7 @@ So now we have managed to access a file stored somewhere on a file system using ssize_t read(int fildes, void *buf, size_t nbyte); ``` -Where the paramaters are the opened file descriptor (fildes) the buffer we want to read into (buf), and the number of bytes (nbyte`) we want to read. +Where the paramaters are the opened file descriptor (`fildes) the buffer we want to read into (`buf`), and the number of bytes (`nbytes`) we want to read. The read function will return the number of bytes read, and in case of failure -1. Like all other vfs functions, what the read will do is search for the file descriptor with id `fildes`, and if it exists call the fs driver function to read data from an opened file and fill the `buf` buffer. From e4827dbdee8833f7de06f73cde5dd87dd22d87c5 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 11 Apr 2023 15:30:40 +0100 Subject: [PATCH 27/32] Minor fixes to hello world chapter --- 02_Architecture/02_Hello_World.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/02_Architecture/02_Hello_World.md b/02_Architecture/02_Hello_World.md index 022849b2..5ce79788 100644 --- a/02_Architecture/02_Hello_World.md +++ b/02_Architecture/02_Hello_World.md @@ -1,10 +1,10 @@ # Hello World -During the development of our kernel we will need to debug a lot, and checking a lot of values, but so far our kernel is not capable of doing anything, and having proper video output with scrolling, fonts etc, can take some time to implement (and probably we need to check again some values), so we need a quick way of getting some output from our kernel, not necessarily on the screen. +During the development of our kernel we will need to debug a lot, and checking a lot of values, but so far our kernel is not capable of doing anything, and having proper video output with scrolling, fonts etc, can take some time, so we need a quick way of getting some text out from our kernel, not necessarily on the screen. This is where the serial logging came to an aid, we will use the serial port to output our text and numbers. -Many emulators has an option to redirect serial output to a file, if you are using QEmu (for more information about it refer to the Appendices section) you need to start it passing the parameter *-s filename*: +Many emulators has an option to redirect serial data to a file, if you are using QEmu (for more information about it refer to the Appendices section) you need to start it passing the parameter *-s filename*: ```bash qemu -S filename.log -cdrom yourosiso @@ -87,14 +87,18 @@ This is the first function that we want to implement. ### Printing Digits -Once we are able to print strings is time to print digits. The basic idea is simple, we takeread every single digit that compose the number, and print the corresponding character, luckily enough the digits symbols are consecutive in the ascii map, so for example: +Once we are able to print strings is time to print digits. The basic idea is simple, we read every single digit that compose the number, and print the corresponding character, luckily enough the digits symbols are consecutive in the ascii map, so for example: ```c '0' + 1 // will contain the symbol '1' '0' + 5 // will contain the symbol '5' ``` -How to get the single digits will depend on what base we are using (the most common are base 8, 10 and 16), let's assume we want for now just print decimals (base 10). For doing this we will use a property of division by 10, that the remainder of any integer number divided by 10 is always the same as the least significant digit, this means that for example $1235/10=123.5$ and $1235 \mod 10=5$, remember that in C (and other programming languages) a division between integers will ignore any decimal digit, so this means that $1235=123$. And what if now we divide 123 by 10? yes we get 3 as remainder, below the full list of divisions for the number 1235: +How to get the single digits will depend on what base we are using (the most common are base 8, 10 and 16), let's assume we want for now just print decimals (base 10). + +To get decimal strings we will use a property of division by 10: _The remainder of any integer number divided by 10 is always the same as the least significant digit. _ + +As an example consider the number 1235: $1235/10=123.5$ and $1235 \mod 10=5$, remember that in C (and other programming languages) a division between integers will ignore any decimal digit, so this means that $1235=123$. And what if now we divide 123 by 10? yes we get 3 as remainder, below the full list of divisions for the number 1235: * $1235/10 = 123$ and $1235 \mod 10 = 5$ * $123/10 = 12$ and $123 \mod 10 = 3$ From cd556e4213cebf664f24a07f765b6251dbffa0ac Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 11 Apr 2023 15:48:48 +0100 Subject: [PATCH 28/32] Fix part numbering for elfs and add decorator --- .pandoc/decorators/part_elfs.tex | 1 + {08_Loading_Elf => 09_Loading_Elf}/01_README.md | 0 {08_Loading_Elf => 09_Loading_Elf}/02_Elf_Theory.md | 0 {08_Loading_Elf => 09_Loading_Elf}/03_Loading_And_Running.md | 0 4 files changed, 1 insertion(+) create mode 100644 .pandoc/decorators/part_elfs.tex rename {08_Loading_Elf => 09_Loading_Elf}/01_README.md (100%) rename {08_Loading_Elf => 09_Loading_Elf}/02_Elf_Theory.md (100%) rename {08_Loading_Elf => 09_Loading_Elf}/03_Loading_And_Running.md (100%) diff --git a/.pandoc/decorators/part_elfs.tex b/.pandoc/decorators/part_elfs.tex new file mode 100644 index 00000000..aef64d91 --- /dev/null +++ b/.pandoc/decorators/part_elfs.tex @@ -0,0 +1 @@ +\part{Loading ELFs} diff --git a/08_Loading_Elf/01_README.md b/09_Loading_Elf/01_README.md similarity index 100% rename from 08_Loading_Elf/01_README.md rename to 09_Loading_Elf/01_README.md diff --git a/08_Loading_Elf/02_Elf_Theory.md b/09_Loading_Elf/02_Elf_Theory.md similarity index 100% rename from 08_Loading_Elf/02_Elf_Theory.md rename to 09_Loading_Elf/02_Elf_Theory.md diff --git a/08_Loading_Elf/03_Loading_And_Running.md b/09_Loading_Elf/03_Loading_And_Running.md similarity index 100% rename from 08_Loading_Elf/03_Loading_And_Running.md rename to 09_Loading_Elf/03_Loading_And_Running.md From 187dbf3ecf4aeb7a5ebbe83191e3bd12a4895ee7 Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Tue, 11 Apr 2023 16:10:41 +0100 Subject: [PATCH 29/32] Fix typos --- 10_Going_Beyond/01_README.md | 4 ++-- 99_Appendices/C_Language_Info.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/10_Going_Beyond/01_README.md b/10_Going_Beyond/01_README.md index f2ae9f5e..ea9896e6 100644 --- a/10_Going_Beyond/01_README.md +++ b/10_Going_Beyond/01_README.md @@ -207,7 +207,7 @@ The exact process depends on the library you've chosen to port. The best instruc After porting a standard library to your OS, you'll also want to build *another* cross compiler, but this time instead of targetting bare-metal you target your operating system. -Similar to how linux targets are built with the target triplet of something like `x86_64-linux-elf` you would build a toolchain that targets `x86_64-your_us_here-elf`. This is actually very exciting as it means you can use this compiler for any program that can be built just using the standard library! +Similar to how linux targets are built with the target triplet of something like `x86_64-linux-elf` you would build a toolchain that targets `x86_64-your_os_here-elf`. This is actually very exciting as it means you can use this compiler for any program that can be built just using the standard library! ## Networking @@ -259,7 +259,7 @@ Like for the GUI implementing a TCP/IP stack is not a quick task, neither trivia ## Few final words -Now we're nearly at the end of our kernel development notes. We tried to cover all the topics so that you can have a bare but complete-enough kernel. We had an overview on all the core components of an operating system explaining how they should be implemented, and what are the key concepts to be understood. We tried to stay focused on the implementation part of the development, using theory only when it was strictly necessary. We provided lot of code examples to help explain some of the trcikier parts of the kernel. At the same time the purpose was not to provide some ready-to-use code, our intention was to give the readers enough knowledge to get started implementing it themselves. +Now we're nearly at the end of our kernel development notes. We tried to cover all the topics so that you can have a bare but complete-enough kernel. We had an overview on all the core components of an operating system explaining how they should be implemented, and what are the key concepts to be understood. We tried to stay focused on the implementation part of the development, using theory only when it was strictly necessary. We provided lot of code examples to help explain some of the trickier parts of the kernel. At the same time the purpose was not to provide some ready-to-use code, our intention was to give the readers enough knowledge to get started implementing it themselves. The solutions proposed are optimized for the simplicity of the explanation. You will likely find ways to improve the code in your implementation! Finding better (or perhaps more interesting) solutions is all a part of your kernel development journey. diff --git a/99_Appendices/C_Language_Info.md b/99_Appendices/C_Language_Info.md index 853f3a95..8ff4ceeb 100644 --- a/99_Appendices/C_Language_Info.md +++ b/99_Appendices/C_Language_Info.md @@ -36,7 +36,7 @@ Pointers can be compared too, with the operators: ==, <=, >=, <.>, of course the The inline assembly instruction has the following format: ```C -asm("assenmbly_template" +asm("assembly_template" : output_operand : input_operand : list of clobbered registers From 7fef063afef00db43d8993e0f51192948ca62a5d Mon Sep 17 00:00:00 2001 From: Ivan Gualandri Date: Wed, 12 Apr 2023 10:35:19 +0100 Subject: [PATCH 30/32] Minor fixes --- 04_Memory_Management/02_Physical_Memory.md | 6 ++--- 99_Appendices/B_Tips_And_Tricks.md | 29 +++++++++++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/04_Memory_Management/02_Physical_Memory.md b/04_Memory_Management/02_Physical_Memory.md index b13128f1..cbd2bd3c 100644 --- a/04_Memory_Management/02_Physical_Memory.md +++ b/04_Memory_Management/02_Physical_Memory.md @@ -1,4 +1,4 @@ -Physical memory manager +Physical Memory Manager ======================= The physical memory manager will keep track of used physical memory in chunks of pages. The page size will depends on the configuration of VMM. @@ -11,7 +11,7 @@ What the physical memory manager has to take care of as its bare minimum is: 2. Check if given an address it is already used or not 3. Allocate/free a page -In this document we will explain the bitmap method, because is probably the simplest to understand for a beginner. +In this document we will explain the bitmap method, because is probably the simplest to understand for a beginner. To keep the explanation simple, we will assume that the kernel will support only one page size. ## The Bitmap @@ -37,7 +37,7 @@ So marking a memory location as free or used is just matter of setting clearing But how do we mark a page as taken or free? We need to translate row/column in an address, or the address in row/column. Let's assume that we asked fro a free page and we found the first available bit at row 0 and column 3, how we translate it to address, well for that we need few extra info: -* The page size (we should know what is the size of the page you are using XD), Let's call it `PAGE_SIZE` +* The page size (we should know what is the size of the page you are using), Let's call it `PAGE_SIZE` * How many bits are in a row (it's up to us to decide it, in this example we are using an unsigned char, but most probably in real life it is going to be a `uint32_t` for 32bit OS or `uint64_t` for 64bit os) let's call it `BITS_PER_ROW` To get the address we just need to do: diff --git a/99_Appendices/B_Tips_And_Tricks.md b/99_Appendices/B_Tips_And_Tricks.md index 32b2bb48..4fb2b88d 100644 --- a/99_Appendices/B_Tips_And_Tricks.md +++ b/99_Appendices/B_Tips_And_Tricks.md @@ -1,12 +1,22 @@ # Tips and Tricks -## don't forget about unions +## Don't forget about unions + Unions may not see as much use as structs (or classes), but they can be useful. -For example if you have a packed struct of 8 uint8_ts that are from a single hardware register. -Rather than reading a uint64_t, and then breaking it up into the various fields of a struct, use a union! +For example if you have a packed struct of 8 `uint8_t`s that are from a single hardware register. +Rather than reading a `uint64_t`, and then breaking it up into the various fields of a struct, use a union. + +The following example will show what are the benefits: + +Imagine we have a function that reads a register and return it's value as `uint64_t`: + ```c uint64_t read_register(); +``` + +If we want to use a struct and populate it with the value returned by the function, we will have something similar to the following code: +```c struct BadIdea { uint8_t a; @@ -28,6 +38,8 @@ bi.c = (reg >> 16) & 0xFF; //yes the AND is not necessary, but it makes the poin etc... ``` +Now let's see what happens instead if we are using a union approach: + ```c union GoodIdea { @@ -55,6 +67,11 @@ gi.squished = read_register(); //assuming a is bits 7:0, b is bits 16:8, etc ... ``` +As you can see we moved the struct declaration inside the union. This means that now that the struct and the union share the same memory location, using an anonymous structure it ensures that the fields are treated as a _single item_ + +In this way we can either access the `uint64_t` value of the register _squished_, or the single fields _a, b, ..., h_. + + ## Bitfields? More like minefields. ```c @@ -70,11 +87,11 @@ struct BitfieldExample ``` Bitfields can be very useful, as they allow access to oddly sized bits of data. However there's big issue that can lead to unexpected bugs: -Consider the example above. This struct would form 16bits of data in memory, and while `_3bits` and `_5bits` would share 1 byte, same with `_6bits` and `_2bits`, the compiler makes no guaren'tees about which field occupies the least or most significant bits. -Byte order of fields is always guaren'teed by the spec to be in the order they were declared in the source file. +Consider the example above. This struct would form 16bits of data in memory, and while `_3bits` and `_5bits` would share 1 byte, same with `_6bits` and `_2bits`, the compiler makes no guarentees about which field occupies the least or most significant bits. +Byte order of fields is always guarenteed by the spec to be in the order they were declared in the source file. Bitwise order is not. It is worth noting that relying on this is *usually* okay, most compilers will do the right thing, but optimizations can get a little weird sometimes. Especially -O2 and above. ### The solution? -There's no easy replacement for bitfields. Personally I'd suggest doing the maths yourself, and just store data in a uint8_t or whatever size is appropriate. Until the day some compiler extensions come along to resolve this. +There's no easy replacement for bitfields. Our suggestion is doing the maths by ourselves, and just store data in a `uint8_t` or whatever size is appropriate. Until the day some compiler extensions come along to resolve this. From 0412f7ccef43d784363b8d58af5a5dfb9956999c Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 13 Apr 2023 21:13:54 +1000 Subject: [PATCH 31/32] spelling fixes, removed empty 'drivers' chapter --- 01_Build_Process/01_README.md | 6 +++--- 04_Memory_Management/04_Virtual_Memory_Manager.md | 2 +- 98_Drivers/01_README.md | 9 --------- README.md | 15 +++++++++------ 4 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 98_Drivers/01_README.md diff --git a/01_Build_Process/01_README.md b/01_Build_Process/01_README.md index 1219d73f..8b12299d 100644 --- a/01_Build_Process/01_README.md +++ b/01_Build_Process/01_README.md @@ -3,11 +3,11 @@ An OS like any other project needs to be built, and packaged in a special way in order to be "booted". This part will cover all the steps needed to have an initial set of building script for our os, and also explore some of the bootloader that can be used to load our kernel. -- [General Overview](02_Overview.md) This chapter will a high level overview of the building process, introducing some of the basic concepts and tools that will be used in the following chapters and showing two possible compiler options +- [General Overview](02_Overview.md) This chapter will serve as a high level overview of the building process, introducing some of the basic concepts and tools that will be used in the following chapters and showing two possible compiler options - [Boot Protocols & Bootloaders](03_Boot_Protocols.md) Here we will explore two possible solutions for booting our kernel: Multiboot2 and Stivale, explaining how they must be used and configured in order to boot our kernel - [Makefiles](04_Gnu_Makefiles.md) The building script, we are going to use: Makefile. -- [Linker Scripts](05_Linker_Scripts.md) Probably one of the most _obscure_ parts of the building process, especially for beginners, this chapter explains what are the linker scripts, why they are important, an how to write one. -- [Generating A Bootable Iso](06_Generating_Iso.md) After building our kernel we want to run it too (yeah like the cake...) but for doing that we need a bootable support, only the kernel file is not enough, this chapter will show how to create a bootable iso and start to test it on emulators/real hardware. +- [Linker Scripts](05_Linker_Scripts.md) Probably one of the most _obscure_ parts of the building process, especially for beginners, this chapter explains what are the linker scripts, why they are important, and how to write one. +- [Generating A Bootable Iso](06_Generating_Iso.md) After building our kernel we want to run it too (yeah like the cake...). In order to do that we need a bootable iso, as only the kernel file is not enough. This chapter will show how to create a bootable iso and start to test it on emulators/real hardware. ## Useful Links diff --git a/04_Memory_Management/04_Virtual_Memory_Manager.md b/04_Memory_Management/04_Virtual_Memory_Manager.md index 66d94fa1..eb0c33f2 100644 --- a/04_Memory_Management/04_Virtual_Memory_Manager.md +++ b/04_Memory_Management/04_Virtual_Memory_Manager.md @@ -132,7 +132,7 @@ vm_object* vm_objs = NULL; Now onto our alloc function. The first thing it will need to do is align the length up to the nearest page. This should look familiar. ```c -length = (length + (PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; +length = ((length + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; ``` The next step is to find a space between two VM objects big enough to hold `length` bytes. We'll also want to handle the edge cases of allocating before the first object, after the last object, or if there are no VM objects in the list at all (not covered in the example below, they are left as exercise). diff --git a/98_Drivers/01_README.md b/98_Drivers/01_README.md deleted file mode 100644 index 7bf51d02..00000000 --- a/98_Drivers/01_README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Drivers -This chapter is a collection of articles about writing the specifics of writing drivers for common pieces of hardware. Overall driver architecture, and how they fit into your operating system's design is not covered here. - -- [Local APIC and IO APIC](APIC.md) -- [Linear Framebuffer](Framebuffer.md) -- [Drawing Text](DrawingTextOnFB.md) -- [ACPI Tables](ACPITables.md) -- [Timers](Timers.md) -- [PS/2 Keyboard](PS2Keyboard.md) diff --git a/README.md b/README.md index d0558f44..7607edc8 100644 --- a/README.md +++ b/README.md @@ -37,27 +37,30 @@ We hope you enjoy, and find something interesting here! * [Part 3: Video Output](/03_Video_Output/01_README.md) * [The Framebuffer](/03_Video_Output/01_Framebuffer.md) * [Drawing Text on Framebuffer](03_Video_Output/02_DrawingTextOnFB.md) -* [Part 3: Memory Management](04_Memory_Management/01_README.md) +* [Part 4: Memory Management](04_Memory_Management/01_README.md) * [Physical Memory](04_Memory_Management/02_Physical_Memory.md) * [Paging](04_Memory_Management/03_Paging.md) * [Virtual Memory Manager](04_Memory_Management/04_Virtual_Memory_Manager.md) * [Heap Allocation](04_Memory_Management/05_Heap_Allocation.md) * [Memory Protection](04_Memory_Management/06_Memory_Protection.md) -* [Part 4: Scheduling](05_Scheduling/01_README.md) +* [Part 5: Scheduling](05_Scheduling/01_README.md) * [The Scheduler](05_Scheduling/02_Scheduler.md) * [Processes and Threads](05_Scheduling/03_Processes_And_Threads.md) * [Locks](05_Scheduling/04_Locks.md) -* [Part 5: Getting to Userspace](06_Userspace/01_README.md) +* [Part 6: Getting to Userspace](06_Userspace/01_README.md) * [Switching Modes](06_Userspace/02_Switching_Modes.md) * [Updated Interrupt Handling](06_Userspace/03_Handling_Interrupts.md) * [System Calls](06_Userspace/04_System_Calls.md) * [Example Syscall ABI](06_Userspace/05_Example_ABI.md) -* [Part 6: Inter-Process Communication](07_IPC/01_README.md) +* [Part 7: Inter-Process Communication](07_IPC/01_README.md) * [Shared Memory](07_IPC/02_Shared_Memory.md) * [Message Passing](07_IPC/03_Message_Passing.md) -* [Part 7: File System](08_VirtualFileSystem/01_README.md) +* [Part 8: File System](08_VirtualFileSystem/01_README.md) * [The Virtual File System](08_VirtualFileSystem/02_VirtualFileSystem.md) -* [Part 9: Going Beyond](10_Going_Beyond/01_README.md) +* [Part 9: Loading & Executing ELFs](09_Loading_Elf/01_README.md) + * [Theory](09_Loading_Elf/02_Elf_Theory.md) + * [Loading and Running](09_Loading_Elf/03_Loading_And_Running.md) +* [Part 10: Going Beyond](10_Going_Beyond/01_README.md) * [Extras: Appendices](99_Appendices/0_README.md) * [General Troubleshooting](99_Appendices/A_Troubleshooting.md) * [Tips and Tricks](99_Appendices/B_Tips_And_Tricks.md) From 6db227504680b10718cd730f2bc4c23c027eb5cd Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 13 Apr 2023 23:19:01 +1000 Subject: [PATCH 32/32] spelling, added warning for unions. --- 00_Introduction/02_AssumedKnowledge.md | 2 +- 99_Appendices/B_Tips_And_Tricks.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/00_Introduction/02_AssumedKnowledge.md b/00_Introduction/02_AssumedKnowledge.md index 97713fc9..1f109c96 100644 --- a/00_Introduction/02_AssumedKnowledge.md +++ b/00_Introduction/02_AssumedKnowledge.md @@ -8,6 +8,6 @@ As such, below is a list of the recommended prior experience before continuing w - Intermediate understanding of the C programming language. Mastery is not required, but you should be very familiar with the ins and outs of the language, especially pointers and pointer arithmetic. - You should be comfortable compiling and debugging code in userspace. GDB is recommended as several emulators provide a GDB server you can use to step through your kernel. -- Knowledge and experience using common data structures like intrusive linked lists. While we may use array notation at several points to help visualize what's going on, you wont want to place arbitrary limits on your kernel by using fixed size arrays. +- Knowledge and experience using common data structures like intrusive linked lists. While we may use array notation at several points to help visualize what's going on, you won't want to place arbitrary limits on your kernel by using fixed size arrays. If you feel confident in your knowledge of the above, please read on! If not, don't be discouraged. There are plenty of resources available for learning, and you can always come back later. diff --git a/99_Appendices/B_Tips_And_Tricks.md b/99_Appendices/B_Tips_And_Tricks.md index 4fb2b88d..7cc7763e 100644 --- a/99_Appendices/B_Tips_And_Tricks.md +++ b/99_Appendices/B_Tips_And_Tricks.md @@ -1,14 +1,14 @@ # Tips and Tricks -## Don't forget about unions +## Don't Forget About Unions Unions may not see as much use as structs (or classes), but they can be useful. For example if you have a packed struct of 8 `uint8_t`s that are from a single hardware register. Rather than reading a `uint64_t`, and then breaking it up into the various fields of a struct, use a union. -The following example will show what are the benefits: +Let's look at some examples and see how they can be useful. While this technique is useful, it has to be used carefully. If accessing MMIO using a `volatile` instance of a union, be sure you read about access requirements for the underlying hardware. For example a device may expose a 64-bit register, consisting of 8 8-bit fields. However the device may *require* that perform 64-bit reads and writes to the register, in which you will have to read the whole register, and create the union from that value. If the device doesn't have such a requirement, you could instead use a `volatile` union and access it normally. -Imagine we have a function that reads a register and return it's value as `uint64_t`: +Imagine we have a function that reads a register and returns it's value as `uint64_t`: ```c uint64_t read_register(); @@ -34,7 +34,7 @@ uint64_t reg = read_register(); BadIdea bi; bi.a = reg & 0xFF; bi.b = (reg >> 8) & 0xFF; -bi.c = (reg >> 16) & 0xFF; //yes the AND is not necessary, but it makes the point. +bi.c = (reg >> 16) & 0xFF; //T AND is not necessary, but it makes the point. etc... ``` @@ -94,4 +94,4 @@ Bitwise order is not. It is worth noting that relying on this is *usually* okay, most compilers will do the right thing, but optimizations can get a little weird sometimes. Especially -O2 and above. ### The solution? -There's no easy replacement for bitfields. Our suggestion is doing the maths by ourselves, and just store data in a `uint8_t` or whatever size is appropriate. Until the day some compiler extensions come along to resolve this. +There's no easy replacement for bitfields. Our suggestion is doing the maths yourself, and store data in a `uint8_t` or whatever size is appropriate. Until the day some compiler extensions come along to resolve this.