Skip to content

Commit ed52bc1

Browse files
Minor layout fixes (#48)
* Minor layout fixes * Replace memory manager image * Fixing indentation and line overflows * Update yaml headers with margin and image fixes --------- Co-authored-by: Dean <dean243@hotmail.com>
1 parent 445ae1a commit ed52bc1

16 files changed

Lines changed: 109 additions & 84 deletions

File tree

.pandoc/pandoc.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,34 @@ author:
55
- Dean T.
66
header-includes:
77
- \usepackage{fvextra}
8+
- \usepackage{geometry}
89
- \usepackage[page,toc,titletoc,title]{appendix}
10+
- \usepackage{fancyhdr}
11+
- \pagestyle{fancy}
12+
- \fancyhead[LE]{\leftmark}
13+
- \fancyhead[RE]{\thepage}
14+
- \fancyhead[LO]{\thepage}
15+
- \fancyhead[RO]{\rightmark}
16+
- \usepackage{float}
17+
- |
18+
```{=latex}
19+
\let\origfigure\figure
20+
\let\endorigfigure\endfigure
21+
\renewenvironment{figure}[1][2] {
22+
\expandafter\origfigure\expandafter[H]
23+
} {
24+
\endorigfigure
25+
}
26+
```
927
- \DefineVerbatimEnvironment{Highlighting}{Verbatim}{breaklines,commandchars=\\\{\}}
28+
geometry:
29+
- tmargin=2.5cm
30+
- bmargin=2.5cm
31+
- lmargin=2.5cm
32+
- rmargin=2.5cm
33+
- headsep =0.89cm
34+
- footskip =0.89cm
35+
- columnsep=1.5cm
36+
- headheight=1.5cm
1037
book: true
1138
---

02_Architecture/02_Hello_World.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ static int init_serial() {
5555
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
5656
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
5757
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
58-
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
58+
outb(PORT + 0, 0xAE); // Send a test byte
5959
60-
// Check if serial is faulty (i.e: not same byte as sent)
60+
// Check that we received the same test byte we sent
6161
if(inb(PORT + 0) != 0xAE) {
6262
return 1;
6363
}
6464
65-
// If serial is not faulty set it in normal operation mode
66-
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
65+
// If serial is not faulty set it in normal operation mode:
66+
// not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled
6767
outb(PORT + 4, 0x0F);
6868
return 0;
6969
}

02_Architecture/04_GDT.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -260,18 +260,18 @@ If not familiar with inline assembly, check the appendix on using inline assembl
260260
void flush_gdt()
261261
{
262262
asm volatile("\
263-
mov $0x10, %ax \n\
264-
mov %ax, %ds \n\
265-
mov %ax, %es \n\
266-
mov %ax, %fs \n\
267-
mov %ax, %gs \n\
268-
mov %ax, %ss \n\
269-
\n\
270-
pop %rdi \n\
271-
push $0x8 \n\
272-
push %rdi \n\
273-
lretq \n\
274-
");
263+
mov $0x10, %ax \n\
264+
mov %ax, %ds \n\
265+
mov %ax, %es \n\
266+
mov %ax, %fs \n\
267+
mov %ax, %gs \n\
268+
mov %ax, %ss \n\
269+
\n\
270+
pop %rdi \n\
271+
push $0x8 \n\
272+
push %rdi \n\
273+
lretq \n\
274+
");
275275
}
276276
```
277277

02_Architecture/06_ACPITables.md

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ As already mentioned there are two different version of RSDP, basic data structu
3636

3737
```c
3838
struct RSDPDescriptor {
39-
char Signature[8];
40-
uint8_t Checksum;
41-
char OEMID[6];
42-
uint8_t Revision;
43-
uint32_t RsdtAddress;
39+
char Signature[8];
40+
uint8_t Checksum;
41+
char OEMID[6];
42+
uint8_t Revision;
43+
uint32_t RsdtAddress;
4444
} __attribute__ ((packed));
4545
```
4646

@@ -55,13 +55,12 @@ Where the fields are:
5555
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:
5656

5757
```c
58-
struct RSDP2Descriptor
59-
{
60-
//v1 fields
61-
uint32_t Length;
62-
uint64_t XSDTAddress;
63-
uint8_t ExtendedChecksum;
64-
uint8_t Reserved[3];
58+
struct RSDP2Descriptor {
59+
//v1 fields
60+
uint32_t Length;
61+
uint64_t XSDTAddress;
62+
uint8_t ExtendedChecksum;
63+
uint8_t Reserved[3];
6564
};
6665
```
6766

@@ -75,11 +74,11 @@ Before proceeding let's explain little bit better the validation. For both versi
7574

7675
```c
7776
bool validate_RSDP(char *byte_array, size_t size) {
78-
uint32_t sum = 0;
79-
for(int i = 0; i < size; i++) {
80-
sum += byte_array[i];
81-
}
82-
return (sum & 0xFF) == 0;
77+
uint32_t sum = 0;
78+
for(int i = 0; i < size; i++) {
79+
sum += byte_array[i];
80+
}
81+
return (sum & 0xFF) == 0;
8382
}
8483
```
8584
@@ -101,15 +100,15 @@ Since every SDT table contains different type of information, they are all diffe
101100
102101
```c
103102
struct ACPISDTHeader {
104-
char Signature[4];
105-
uint32_t Length;
106-
uint8_t Revision;
107-
uint8_t Checksum;
108-
char OEMID[6];
109-
char OEMTableID[8];
110-
uint32_t OEMRevision;
111-
uint32_t CreatorID;
112-
uint32_t CreatorRevision;
103+
char Signature[4];
104+
uint32_t Length;
105+
uint8_t Revision;
106+
uint8_t Checksum;
107+
char OEMID[6];
108+
char OEMTableID[8];
109+
uint32_t OEMRevision;
110+
uint32_t CreatorID;
111+
uint32_t CreatorRevision;
113112
};
114113
```
115114
* The second part is the table itself, every SDT has it's own table
@@ -123,16 +122,14 @@ The RSDT is an SDT header followed by an array of `uint32_t`s, representing the
123122
The XSDT is the same, except the array is of `uint64_t`s.
124123

125124
```c
126-
struct RSDP
127-
{
128-
ACPISDTHeader sdtHeader; //signature "RSDP"
129-
uint32_t sdtAddresses[];
125+
struct RSDP {
126+
ACPISDTHeader sdtHeader; //signature "RSDP"
127+
uint32_t sdtAddresses[];
130128
};
131129

132-
struct XSDT
133-
{
134-
ACPISDTHeader sdtHeader; //signature "XSDT"
135-
uint64_t sdtAddresses[];
130+
struct XSDT {
131+
ACPISDTHeader sdtHeader; //signature "XSDT"
132+
uint64_t sdtAddresses[];
136133
};
137134
```
138135

02_Architecture/11_Keyboard_Driver_Implementation.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ If we want to store just the scancode we don't need much more, so we can already
4343
```c
4444

4545
void keyboard_driver_irq_handler() {
46-
47-
4846
uint8_t scancode = inb(0x60); // Read byte from the Keyboard data port
4947

5048
keyboard_buffer[buf_position] = scancode;
@@ -113,20 +111,21 @@ Now by changing the `current_state` variable, we can change how the code will tr
113111
uint8_t current_state;
114112

115113
void init_keyboard() {
116-
// Do other initialization stuff like: clean the keyboard buffer, identify the scancode set, enable the IRQ etc.
114+
// You'll want to do other setup here in your own driver:
115+
// ensure the input buffer of the keyboard is empty, check which scancode
116+
// set is in use, enable irqs.
117117
current_state = NORMAL_STATE;
118118
}
119119

120120
void keyboard_driver_irq_handler() {
121121
int scancode = inb(0x60); // Read byte from the Keyboard data port
122122
if (scancode == 0xE0) {
123123
current_state = PREFIX_STATE
124-
// We have read a prefix, so let's update the state and finish here
125-
// this is a very simple scenario, there could be more needed depending on the design
124+
// We have read a prefix, so update the state and exit.
126125
return;
127126
}
128127
if (current_state == PREFIX_STATE) {
129-
// Do what you need to store the key_code and eventually translate it to the kernel_code and return to the normal state
128+
// Store the next part of the scancode, then return to normal state.
130129
current_state = NORMAL_STATE;
131130
}
132131
}
@@ -214,10 +213,11 @@ We could use the following:
214213

215214
```c
216215

217-
//an example of our kernel-specific scancodes
216+
//an example of our kernel-specific scancodes:
217+
//note that these are totally arbitrary and can be whatever you want.
218218
typedef enum kernel_scancodes {
219219
[ ... ]
220-
F1 = 0xAABBCCDD, //this can be defined to whatever value you want, the exact value is totally arbitrary.
220+
F1 = 0xAABBCCDD,
221221
[ ... ]
222222
};
223223

03_Video_Output/02_DrawingTextOnFB.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ All the fields are 4 bytes in size, so creating a structure that can hold it is
122122
Let's assume from now on that we have a data structure called PSF_font with all the fields specified above. The first thing that we need of course, is to access to this variable:
123123

124124
```C
125-
// We have linked _binary_font_psf_start from another .o file so we must specify that we are dealing
126-
// with an external variable
125+
// We have linked _binary_font_psf_start from another .o file so we must
126+
// specify that we are dealing with an external variable.
127127
extern char _binary_font_psf_start;
128128
PSF_font *default_font = (PSF_font *)&_binary_font_psf_start
129129
```
@@ -157,15 +157,18 @@ Below an example of how a glyph is stored:
157157
The glyphs start right after the psf header, the address of the first character will be then:
158158

159159
```C
160-
uint8_t* first_glyph = (uint8_t*) &_binary_font_psf_start + default_font->headersize
160+
uint8_t* first_glyph = (uint8_t*) &_binary_font_psf_start +
161+
default_font->headersize
161162
```
162163

163164
Since we know that every glyph has the same size, and this is available in the PSF_Header, if we want to access the *i-th* character, we just need to do the following:
164165

165166
```C
166-
uint8_t* selected_glyph_v1 = (uint8_t*) &_binary_font_psf_start + sizeof(PSFv1_Header_Struct) + (i * default_font->bytesperglyph); //psf_v1
167+
uint8_t* selected_glyph_v1 = (uint8_t*) &_binary_font_psf_start +
168+
sizeof(PSFv1_Header_Struct) + (i * default_font->bytesperglyph);
167169

168-
uint8_t* selected_glyph_v2 = (uint8_t*) &_binary_font_psf_start + default_font->headersize + (i * default_font->bytesperglyph); //psf_v2
170+
uint8_t* selected_glyph_v2 = (uint8_t*) &_binary_font_psf_start +
171+
default_font->headersize + (i * default_font->bytesperglyph);
169172
```
170173

171174
Where in the v1 case, `PSFv1_Header_Struct` is just the name of the struct containing the PSFv1 definition.

04_Memory_Management/01_Overview.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ We will cover the following topics:
1717

1818
*Authors note: don't worry, we will try to keep it as simple as possible, using basic algorithms and explaining all the gray areas as we go. The logic may sometimes be hard to follow, you will most likely have to go through several reads of this part multiple times.*
1919

20-
Each of the layers has a dedicated section below, however we'll start with a high level look at how they fit together. Before proceeding let's briefly define the concepts above:
20+
Each of the layers has a dedicated chapter, however we'll start with a high level look at how they fit together. Before proceeding let's briefly define the concepts above:
2121

2222
| Memory Management Layer | Description |
23-
|---|---|
23+
|---|------|
2424
| Physical Memory Manager | Responsible for keeping track of which parts of the available hardware memory (usually ram) are free/in-use. It usually allocates in fixed size blocks, the native page size. This is 4096 bytes on x86.|
2525
| Paging | It introduces the concepts of *virtual memory* and *virtual addresses*, providing the OS with a bigger address space, protection to the data and code in its pages, and isolation between programs. |
26-
| Virtual memory manager | For a lot of projects, the VMM and paging will be the same thing. However the VMM should be seen as the virtual memory *manager*, and paging is just one tool that it uses to accomplish its job: ensuring that a program has memory where it needs it, when it needs it. Often this is just mapping physical ram to the requested virtual address (via paging or segmentation), but it can evolve into stealing pages from other processes. |
26+
| Virtual memory manager | For a lot of projects, the VMM and paging will be the same thing. However the VMM should be seen as the virtual memory *manager*, and paging is just one tool that it uses to accomplish its job: ensuring that a program has memory where it needs it, when it needs it. Often this is just mapping physical ram to the requested virtual address (via paging or segmentation) |
2727
| Heap Allocator | The VMM can handle page-sized allocations just fine, but that is not always useful. A heap allocator allows for allocations of any size, big or small. |
2828

2929
## PMM - Physical Memory Manager

04_Memory_Management/05_Heap_Allocation.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ What we have so far is already an allocation algorithm, that's easy to implement
9090
Its implementation is very simple:
9191
9292
```c
93-
uint8_t *cur_heap_position = 0; //This is just pseudocode in real world this will be a memory location
93+
uint8_t *cur_heap_position = 0; //Just an example, in the real world you would use
94+
//a virtual address allocated from the VMM.
9495
void *first_alloc(size_t size) {
9596
uint8_t *addr_to_return = cur_heap_position;
9697
cur_heap_position= cur_heap_position + size;
@@ -401,7 +402,7 @@ if (prev_node != NULL && prev_node->status == FREE) {
401402
```
402403
What we're describing here is the left node being "swallowed" by the right one, and growing in size. The memory that the left node owns and is responsible for is now part of the right oneTo make it easier to understand, consider the portion of a hypothetical heap in the picture below:
403404

404-
![heap_example_start](/Images/heapexample.png)
405+
![Heap initial status](/Images/heapexample.png)
405406

406407

407408
Basically the heap starts from address 0, the first node is marked as free and the next two nodes are both used. Now imagine that `free()` is called on the second address (for this exammple we consider size of the heap node structure to be just of 2 bytes):
@@ -413,7 +414,7 @@ free(0x27); //Remember the overhead
413414
414415
This means that the allocator (before marking this location as free and returning) will check if it is possible to merge first to the left (YES) and then to the right (NO since the next node is still in use) and then will proceed with a merge only on the left side. The final result will be:
415416
416-
![heap_example_after_merge](/Images/heap_example_after_merge.png)
417+
![The heap status after the merge](/Images/heap_example_after_merge.png)
417418
418419
The fields in bold are the fields that are changed. The exact implementation of this code is left to the reader.
419420

05_Scheduling/03_Processes_And_Threads.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Creating a process is pretty trivial. We need a place to store the new `process_
6565
size_t next_free_pid = 0;
6666

6767
process_t* create_process(char* name, void(*function)(void*), void* arg) {
68-
process_t* process = alloc(sizeof(process_t)); // We should have an allocation function available
68+
process_t* process = alloc(sizeof(process_t));
6969

7070
strncpy(process->name, name, NAME_MAX_LEN);
7171
process->pid = next_free_pid++;

06_Userspace/05_Example_ABI.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ We're going to implement a wrapper function for system calls in C, purely for co
4141

4242
```c
4343
__attribute__((naked))
44-
void do_syscall(uint64_t num, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3)
45-
{
44+
void do_syscall(uint64_t num, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) {
4645
asm ("int $0x50" ::: "rdi", "rsi", "rdx", "rcx", "r8", "memory");
4746
}
4847
```
@@ -54,8 +53,7 @@ This function also uses the `naked` attribute. If unfamiliar with attributes, th
5453
Now, let's combine our wrapper function with our example system call from above. We're going to write a `memcpy` function that could be called by another code, but uses the system call internally:
5554
5655
```c
57-
void memcpy(void* src, void* dest, size_t count)
58-
{
56+
void memcpy(void* src, void* dest, size_t count) {
5957
return do_syscall(3, (uint64_t)src, (uint64_t)dest, (uint64_t)count, 0, 0);
6058
}
6159
```

0 commit comments

Comments
 (0)