Writing a Simple Operating System — from Scratch(by Nick Blundell)
School of Computer Science, University of Birmingham, UK
First memory layout
ASM tips
1 | [org 0x7c00] |
Stack
when storing value on stack, CPU decrease the sp
register firstly and then store the value on stack
1 | mov ax,0x8000 |
protect registers in function
1 | function: |
GDT and segment descriptor
A segment descriptor is an 8-byte structure that defines the following properties of a protected-mode segment:
Base address (32 bits), which defines where the segment begins in physical memory
Segment Limit (20 bits), which defines the size of the segment
Various flags, which affect how the CPU interprets the segment, such as the privilege level of code that runs within it or whether it is read- or write-only.
The simplest workable configuration of segment registers is described by Intel as the basic flat model, whereby two overlapping segments are defined that cover the full 4 GB of addressable memory, one for code and the other for data. The fact that in this model these two segments overlap means that there is no attempt to protect one segment from the other, nor is there any attempt to use the paging features for virtual memory.
The null descriptor is a simple mechanism to catch mistakes where we forget to set a particular segment register before accessing an address, which is easily done if we had some segment registers set to 0x0 and forgot to update them to the appropriate segment descriptors after switching to protected mode
let us look at how we might actually represent the GDT in assembly, a task that requires more patience than anything else.
interrupt handling is implemented completely differently in protected mode than in real mode
Far jump
Far jump do not mean jump a long distance physically but indicating that jump across segments
Addressing in 32-bit protected mode
When paging is disabled you will directly get the physical address rather than a linear address
1 | Physical address = Segment Base (Found from the descriptor GDT[]) + Offset |
The 80386 stores information from descriptors in segment registers, thereby avoiding the need to consult a descriptor table every time it accesses memory.
The segment registers are actually larger than 16 bits but only 16 bits are visible!!!
Paging
Understand ld
-Ttext 0x0
has the same functionality with [org 0x0000]
, telling the linker how to offset the labels
Makefile
1 | $< # first dependency |
1 | # generic rule for compiling object files |
gcc inline assembly
%
is used to denote registers, and this requires an ugly%%
, since%
is an escape character of the C compiler, and so%%
means: escape the escape character, so that it will appear literally in the string
1 | unsigned char port_byte_in ( unsigned short port ) { |