7.2 KiB
7.2 KiB
Bootloader Documentation
1. Calling Conventions
__cdecl16near Calling Convention
- Purpose: For calling near (within the same segment) functions in 16-bit code.
- Stack Management: Caller cleans up the stack after the function call.
- Parameter Passing: Parameters are pushed onto the stack from right to left.
- Return Address: A near return address (16-bit) is pushed onto the stack.
- Return Value: Placed in the AX register.
Example:
; Caller
push param2
push param1
call near_func
add sp, 4 ; Clean up the stack (2 parameters * 2 bytes each)
; Callee (near_func)
near_func:
push bp
mov bp, sp
; Function body
mov sp, bp
pop bp
ret
__cdecl16far Calling Convention
- Purpose: For calling far (across different segments) functions in 16-bit code.
- Stack Management: Caller cleans up the stack after the function call.
- Parameter Passing: Parameters are pushed onto the stack from right to left.
- Return Address: A far return address (32-bit, consisting of a segment and an offset) is pushed onto the stack.
- Return Value: Placed in the AX register.
Example:
; Caller
push param2
push param1
call far_func
add sp, 4 ; Clean up the stack (2 parameters * 2 bytes each)
; Callee (far_func)
far_func:
push bp
mov bp, sp
; Function body
mov sp, bp
pop bp
retf ; Far return
Key Differences
- Return Address:
__cdecl16nearuses a 16-bit return address;__cdecl16faruses a 32-bit return address (segment:offset). - Function Scope:
__cdecl16nearis for functions within the same segment;__cdecl16faris for functions that may be in different segments. - Return Instruction:
__cdecl16nearusesret;__cdecl16farusesretf(far return).
Register Usage
Caller-Saved (Volatile) Registers
- AX: Accumulator, often used for return values.
- CX: Counter register.
- DX: Data register, used for I/O operations.
- SI/DI: String operation indexes.
Callee-Saved (Non-Volatile) Registers
- BP: Base pointer, used for stack frame management.
- SP: Stack pointer.
- BX: Base register.
Example:
; Caller
push param2
push param1
call near_func
add sp, 4 ; Clean up the stack (2 parameters * 2 bytes each)
; Callee (near_func)
near_func:
push bp
mov bp, sp
; Save callee-saved registers if used
push bx
push si
push di
; Function body
; Use AX, CX, DX freely
; Restore callee-saved registers
pop di
pop si
pop bx
mov sp, bp
pop bp
ret
2. E820 Memory Map Usage
Address Range Descriptor Structure
| Offset | Name | Description |
|---|---|---|
| 0 | BaseAddrLow | Low 32 bits of base address |
| 4 | BaseAddrHigh | High 32 bits of base address |
| 8 | LengthLow | Low 32 bits of length in bytes |
| 12 | LengthHigh | High 32 bits of length in bytes |
| 16 | Type | Address type of this range |
E820 Function Call
Input
- EAX: Function code
E820h. - EBX: Continuation value for physical memory retrieval (0 for the first call).
- ES:DI: Buffer pointer to an Address Range Descriptor structure.
- ECX: Buffer size (minimum size 20 bytes).
- EDX: Signature ('SMAP').
Output
- CF: Carry flag (indicates success/failure).
- EAX: Signature ('SMAP').
- ECX: Buffer size (number of bytes returned).
- EBX: Continuation value for subsequent E820 calls.
Address Type Values
| Value | Pneumonic | Description |
|---|---|---|
| 1 | AddressRangeMemory | Available RAM usable by the operating system. |
| 2 | AddressRangeReserved | Reserved by the system, unusable by the operating system. |
3. Example Calculations
Partition Offset
- Partition 1 offset = LBA 0x800 = 0x100000
bsSectorSize = 512
First FAT Sector
first_fat_sector = bsResSector = 32 => (32*512) = 0x4000first_fat_sector = 0x100000 + 0x4000 = 0x104000
Total FAT Sectors
total_fat_sectors = fat_sectors * number_of_FATs = 2001 * 2 = 4002total_fat_size = total_fat_sectors * bsSectorSize = 0x1F4400
First Data Sector
first_data_sector = FatStartSector + FatAreaSize = 0x104000 + 0x1F4400 = 0x2F8400
FAT Table Look Up
if the cluster we got from the table entry was cluster 354
fat_sector = 354 / 128 = 2
fat_entry = 354 mod 128 = 98
so we load the 3rd (indexed from 0) fat table sector and read the 98th entry
Example:
fat_table_offset = (first_fat_sector + 2) * 512
fat_table = *(fat_table_offset)
disk_read(fat_table[98])
4. Global Descriptor Table (GDT)
Segment Attributes
- Pr: Present bit (must be 1 for valid selectors).
- Privl: Privilege level (0 = kernel, 3 = user).
- S: Descriptor type (set for code/data segments, cleared for system segments).
- Ex: Executable bit (set if segment contains code).
- DC: Direction/Conforming bit (for data or code segments).
- RW: Readable/Writable (depends on segment type).
Granularity (Gr)
- Gr: Granularity bit (0 = byte granularity, 1 = 4 KiB blocks).
- Sz: Size bit (0 = 16-bit mode, 1 = 32-bit mode).
GDT Entry Construction
Each GDT entry is 8 bytes:
- First DWORD: Limit (0:15), Base (0:15)
- Second DWORD: Base (16:31), Attributes (8:12)
5. Memory Layout Example
Low Memory (First MiB)
| Start | End | Size | Type | Description |
|---|---|---|---|---|
| 0x00000000 | 0x000003FF | 1 KiB | RAM (partially unusable) | Real Mode IVT (Interrupt Vector Table) |
| 0x00000400 | 0x000004FF | 256 bytes | RAM (partially unusable) | BDA (BIOS data area) |
| 0x00000500 | 0x00007BFF | almost 30 KiB | RAM - free for use | Conventional memory |
| 0x00007C00 | 0x00007DFF | 512 bytes | RAM (partially unusable) | OS BootSector |
| 0x00007E00 | 0x0007FFFF | 480.5 KiB | RAM - free for use | Conventional memory |
| 0x00080000 | 0x0009FFFF | 128 KiB | RAM (partially unusable) | EBDA (Extended BIOS Data Area) |
| 0x000A0000 | 0x000FFFFF | 384 KiB | various (unusable) | Video memory, ROM Area |
Extended Memory (Above 1 MiB)
| Start | End | Size | Description |
|---|---|---|---|
| 0x00100000 | 0x00EFFFFF | 14 MiB | RAM - free for use |
| 0x00F00000 | 0x00FFFFFF | 1 MiB | Possible memory-mapped hardware (ISA) |
| 0x01000000 | ? | ? | More extended memory |
| 0xC0000000 | 0xFFFFFFFF | 1 GiB | Memory mapped PCI devices, BIOS, etc. |
| 0x0000000100000000 | ? | ? | RAM - usable in PAE/64-bit mode |