In this article, we will learn how a microprocessor works in its earliest boot phase (16-bit real mode). We will also understand why a microprocessor with 16-bit registers is not capable of addressing more than 64KB of RAM and how to increase this limit to 1MB thanks to memory segmentation.
Before we begin, it is recommended that you read these previous articles:
When processors start up, they behave like an 8086 in 16-bit real mode. It will be the operating system that prepares the equipment to enter protected mode and thus access all resources, protection mechanisms, etc., abandoning compatibility with processors prior to the 386.
In 16-bit real mode, the registers are 16 bits, and to access a memory address, we must store that address in a register. Since the registers are 16 bits, the maximum value of memory that we can access is 2^16=64k positions.
To solve this problem, CPU designers added special registers called segment registers.
- cs: CodeSegment
- ds: DataSegment
- ss: StackSegment
- es: ExtraSegment
The segment acts as an index, and the RAM is divided into segments of 64k. By combining the segment position with the offset, we obtain the desired memory address.
Let’s take an example:
mov dx,[0]
In this case, we copy what is in memory address 0 to the dx register, but from which segment? In this case, it is ds since it is the default segment when using absolute addressing, this is explained further in this same article.
If we need to access another segment, we must indicate it with a prefix:
mov dx,[es:0]
This addressing mode is called Absolute, there are several ways to indicate the offset, such as based on the value of a register, depending on the register we use to indicate the offset, the default segment will be one or the other:
Name | Offset | Default segment |
---|---|---|
Absolute | Immediate value | ds |
Indirect with base | bx+x | ds |
bp+x | ss | |
Indirect with index | di+x | ds |
si+x | ds | |
Base and index | bx+DI+x | ds |
bx+SI+x | ds | |
bp+DI+x | ss | |
bp+SI+x | ss |
In the following example, we are going to move what is in the es segment with offset the address that is in bp+100:
mov al,[es:bp+100h]
In this example, we have used the bp+x addressing mode, so the default segment is ss, we had to indicate the prefix to change it.
NOTE: In general, it is not a good idea to use segment prefixes, as the instructions that use them are encoded in more bytes and therefore are slower.
The absolute memory address is calculated by multiplying the segment value by 16 and adding the offset:
mov ds, [0x4d]
mov ax, [0x20]
ax would have the value:
(16 * 0x4d) + 0x20
If we calculate the highest possible address using this system, it gives us 1MB of addressable memory:
(16 * 0xffff) + 0xffff = 1MB
NOTE: When working with segment registers, it is important to remember that we cannot move literals directly to them, we have to go through some intermediate general-purpose registers.
In this previous article, we had already used segmentation although it had not been detailed, the segment where the BIOS had copied our code was 0x7c00.
Let’s see an example where we use absolute addressing (Table: Default Segment DS) to different memory addresses to print their contents on the screen.
mov ah, 0x0e; tty mode
mov al, [the_secret]; we are calculating the address without beeing aware of our code segment
int 0x10
mov bx, 0x7c0; we copy segment value to a general purpose register
mov ds, bx; in that way we can copy segment value from general purpose register to segment register
mov al, [the_secret]
int 0x10
mov al, [es:the_secret]; we use prefix segment annotation, es has an unknown value so memory address can be any value
int 0x10
mov bx, 0x7c0; we do the same as second try but we use es instead of ds as segment register and use prefix annotation
mov es, bx
mov al, [es:the_secret]
int 0x10
jmp $
the_secret:
db "X"
times 510 - ($-$$) db 0
dw 0xaa55
We generate the image:
We load it into Qemu:
SeaBIOS (version rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org)
iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F91410+07EF1410 C980
Booting from Hard Disk...
รงXรงX
As expected, only the second and fourth attempts to print the character have worked.