2025-07-04 03:10:55 +02:00
|
|
|
// vim: et:sw=12:ts=12:sts=12
|
|
|
|
|
|
|
|
|
|
.global _start
|
|
|
|
|
.text
|
2025-07-04 04:02:05 +02:00
|
|
|
.code16
|
2025-07-04 03:10:55 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// _start: entry point
|
2025-07-04 15:29:41 +02:00
|
|
|
_start: cli
|
|
|
|
|
cld
|
|
|
|
|
|
2025-07-04 15:51:51 +02:00
|
|
|
// we keep our text and data close to each other
|
|
|
|
|
xor %ax, %ax
|
2025-07-04 04:02:05 +02:00
|
|
|
mov %ax, %ds
|
|
|
|
|
|
2025-07-04 16:17:38 +02:00
|
|
|
call init_com1
|
|
|
|
|
|
2025-07-04 15:51:51 +02:00
|
|
|
mov $msg_start, %si
|
2025-07-04 15:29:41 +02:00
|
|
|
call print
|
|
|
|
|
|
2025-07-04 15:51:51 +02:00
|
|
|
mov $msg_a20, %si
|
|
|
|
|
call print
|
2025-07-04 15:29:41 +02:00
|
|
|
call enable_a20
|
|
|
|
|
|
2025-07-04 15:51:51 +02:00
|
|
|
mov $msg_unreal, %si
|
2025-07-04 04:02:05 +02:00
|
|
|
call print
|
2025-07-04 15:51:51 +02:00
|
|
|
call unreal
|
2025-07-04 15:29:41 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
mov $msg_getmap, %si
|
2025-07-04 16:33:05 +02:00
|
|
|
call print
|
2025-07-05 15:30:38 +02:00
|
|
|
call getmap
|
|
|
|
|
|
2025-07-05 19:30:14 +02:00
|
|
|
mov $msg_mkheap, %si
|
|
|
|
|
call print
|
|
|
|
|
call makeheap
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
mov $msg_paging, %si
|
|
|
|
|
call print
|
|
|
|
|
call paging
|
2025-07-04 16:33:05 +02:00
|
|
|
|
2025-07-04 15:51:51 +02:00
|
|
|
mov $msg_fin, %si
|
|
|
|
|
call print
|
2025-07-05 15:30:38 +02:00
|
|
|
|
|
|
|
|
jmp hang
|
2025-07-04 04:02:05 +02:00
|
|
|
|
2025-07-04 16:17:38 +02:00
|
|
|
.set COM1, 0x3F8
|
|
|
|
|
.macro com1_write offset=0, byte
|
|
|
|
|
mov $COM1+\offset, %dx
|
|
|
|
|
mov $\byte, %al
|
|
|
|
|
outb %al, %dx
|
|
|
|
|
.endm
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// init_com1: Set up COM1 port for debug output
|
2025-07-04 16:17:38 +02:00
|
|
|
init_com1: com1_write 1, 0x00 // clear interrupts
|
|
|
|
|
com1_write 3, 0x80 // set DLAB to 1
|
|
|
|
|
com1_write 0, 0x0C // 9600 baud rate
|
|
|
|
|
com1_write 1, 0x00
|
|
|
|
|
com1_write 3, 0x07 // 8 bit data + 1 parity bit
|
|
|
|
|
ret
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// enable_a20: Allow use of 'high' memory
|
2025-07-04 15:29:41 +02:00
|
|
|
enable_a20: // TODO more thorough implementation
|
|
|
|
|
inb $0x92, %al
|
|
|
|
|
or $2, %al
|
|
|
|
|
outb %al, $0x92
|
|
|
|
|
ret
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// unreal: Enter unreal mode
|
2025-07-04 15:51:51 +02:00
|
|
|
unreal: push %ds
|
|
|
|
|
lgdt gdt_ptr
|
|
|
|
|
|
|
|
|
|
mov %cr0, %eax
|
|
|
|
|
or $0x01, %al
|
2025-07-04 15:29:41 +02:00
|
|
|
mov %eax, %cr0
|
2025-07-05 15:30:38 +02:00
|
|
|
ljmp $0x8, $_prot
|
2025-07-04 15:51:51 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
_prot: mov $0x10, %cx
|
2025-07-04 15:51:51 +02:00
|
|
|
mov %cx, %ds
|
2025-07-04 15:29:41 +02:00
|
|
|
|
2025-07-04 15:51:51 +02:00
|
|
|
and $0xFE, %al
|
|
|
|
|
mov %eax, %cr0
|
2025-07-05 15:30:38 +02:00
|
|
|
ljmp $0x0, $_unreal
|
2025-07-04 15:51:51 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
_unreal: pop %ds
|
2025-07-04 15:51:51 +02:00
|
|
|
ret
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// getmap: Retrieve memory map using e820 BIOS function
|
|
|
|
|
getmap: mov %ds, %ax
|
2025-07-04 16:33:05 +02:00
|
|
|
mov %ax, %es
|
2025-07-05 15:30:38 +02:00
|
|
|
mov $memmap, %di
|
2025-07-04 16:33:05 +02:00
|
|
|
xor %ebx, %ebx
|
2025-07-05 15:30:38 +02:00
|
|
|
mov $0x534D4150, %edx // e820 magic number
|
|
|
|
|
_nextmap: movl $0, 20(%di)
|
2025-07-04 16:33:05 +02:00
|
|
|
mov $24, %ecx
|
|
|
|
|
mov $0xE820, %eax
|
|
|
|
|
int $0x15
|
2025-07-05 15:30:38 +02:00
|
|
|
jc _endmap
|
|
|
|
|
test %ebx, %ebx
|
|
|
|
|
jz _endmap
|
|
|
|
|
add $24, %di
|
|
|
|
|
jmp _nextmap
|
|
|
|
|
_endmap: add $24, %di
|
|
|
|
|
mov %di, memmap_end
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
// paging: Set up initial page tables for long mode
|
|
|
|
|
paging:
|
|
|
|
|
mov $4*4096, %ecx
|
|
|
|
|
call alloc
|
|
|
|
|
mov %eax, pd_ptr
|
|
|
|
|
mov $4096, %ecx
|
|
|
|
|
call alloc
|
|
|
|
|
mov %eax, pdp_ptr
|
|
|
|
|
mov $4096, %ecx
|
|
|
|
|
call alloc
|
|
|
|
|
mov %eax, pml4_ptr
|
|
|
|
|
|
|
|
|
|
mov pd_ptr, %edi
|
|
|
|
|
xor %ecx, %ecx
|
|
|
|
|
_pgnext: mov %ecx, %eax
|
|
|
|
|
shl $21, %eax
|
|
|
|
|
or $0b110000111, %eax
|
|
|
|
|
movl %eax, 0(%edi)
|
|
|
|
|
//movl %eax, 0(%edi,%ecx,8)
|
|
|
|
|
//movl $0, 4(%edi,%ecx,8)
|
|
|
|
|
inc %ecx
|
|
|
|
|
cmp $4*512, %ecx
|
|
|
|
|
jne _pgnext
|
|
|
|
|
|
|
|
|
|
//mov pml4_ptr, %edi
|
|
|
|
|
//movl 0(%edi)
|
|
|
|
|
//movl $0, 4(%edi)
|
2025-07-04 16:33:05 +02:00
|
|
|
|
|
|
|
|
ret
|
|
|
|
|
|
2025-07-05 19:30:14 +02:00
|
|
|
// makeheap: find a memory range suitable for heap usage
|
|
|
|
|
makeheap: mov $memmap-24, %si
|
|
|
|
|
_mhnext: add $24, %si
|
|
|
|
|
cmp memmap_end, %si
|
|
|
|
|
jae _mhdone
|
|
|
|
|
|
|
|
|
|
cmpl $1, 16(%si)
|
|
|
|
|
jne _mhnext
|
|
|
|
|
|
|
|
|
|
cmpl $0, 4(%si)
|
|
|
|
|
ja _mhnext
|
|
|
|
|
|
|
|
|
|
mov 0(%si), %ebx
|
|
|
|
|
mov 8(%si), %ecx
|
|
|
|
|
|
|
|
|
|
// find end of range, clip to 4Gb
|
|
|
|
|
add %ebx, %ecx
|
|
|
|
|
jnc 1f
|
|
|
|
|
mov $0xFFFFFFFF, %ecx
|
|
|
|
|
|
|
|
|
|
// handle wraparound if length > 4Gb
|
|
|
|
|
1: cmpl $0, 12(%si)
|
|
|
|
|
je 1f
|
|
|
|
|
mov $0xFFFFFFFF, %ecx
|
|
|
|
|
|
|
|
|
|
// adjust base to above 1Mb, above the bootloader
|
|
|
|
|
1: cmp $0x10000, %ebx
|
|
|
|
|
jae 1f
|
|
|
|
|
mov $0x10000, %ebx
|
|
|
|
|
|
|
|
|
|
// align to 4Kb boundaries
|
|
|
|
|
1: add $0xFFF, %ebx
|
|
|
|
|
and $0xFFFFF000, %ebx
|
|
|
|
|
and $0xFFFFF000, %ecx
|
|
|
|
|
|
|
|
|
|
sub %ebx, %ecx
|
|
|
|
|
cmp heap_size, %ecx
|
|
|
|
|
jbe _mhnext
|
|
|
|
|
|
|
|
|
|
mov %ebx, heap_start
|
|
|
|
|
mov %ecx, heap_size
|
|
|
|
|
jmp _mhnext
|
|
|
|
|
|
|
|
|
|
_mhdone: ret
|
|
|
|
|
|
2025-07-05 19:34:54 +02:00
|
|
|
// alloc: take ECX bytes from heap, return ptr in EAX
|
|
|
|
|
// The allocation does not get marked in the memmap.
|
2025-07-05 15:30:38 +02:00
|
|
|
// No realignment is performed, so only alloc aligned sizes.
|
2025-07-05 19:34:54 +02:00
|
|
|
alloc: cmp heap_size, %ecx
|
|
|
|
|
ja _aerr
|
|
|
|
|
mov heap_start, %eax
|
|
|
|
|
add %ecx, heap_start
|
|
|
|
|
sub %ecx, heap_size
|
2025-07-05 15:30:38 +02:00
|
|
|
ret
|
|
|
|
|
_aerr: mov $msg_aerr, %si
|
|
|
|
|
call print
|
|
|
|
|
jmp hang
|
|
|
|
|
|
|
|
|
|
// print: print NUL-terminated string pointed to by SI
|
2025-07-04 15:29:41 +02:00
|
|
|
print: xor %bx, %bx
|
2025-07-04 04:02:05 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
_nextchr: mov $COM1+5, %dx
|
2025-07-04 16:17:38 +02:00
|
|
|
inb %dx, %al
|
|
|
|
|
test $0x20, %al
|
2025-07-05 15:30:38 +02:00
|
|
|
jz _nextchr
|
2025-07-04 16:17:38 +02:00
|
|
|
|
|
|
|
|
lodsb
|
2025-07-04 04:02:05 +02:00
|
|
|
or %al, %al
|
2025-07-05 15:30:38 +02:00
|
|
|
jz _endprint
|
2025-07-04 16:17:38 +02:00
|
|
|
|
|
|
|
|
mov $COM1, %dx
|
|
|
|
|
outb %al, %dx
|
|
|
|
|
|
2025-07-04 03:10:55 +02:00
|
|
|
mov $0x0E, %ah
|
|
|
|
|
int $0x10
|
2025-07-05 15:30:38 +02:00
|
|
|
jmp _nextchr
|
2025-07-04 04:02:05 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
_endprint: ret
|
2025-07-04 15:29:41 +02:00
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// gdt: Protected mode / Unreal mode 16-bit GDT
|
2025-07-04 15:29:41 +02:00
|
|
|
gdt: // entry 0: null descriptor
|
|
|
|
|
.word 0
|
|
|
|
|
.word 0
|
|
|
|
|
.byte 0
|
|
|
|
|
.byte 0
|
|
|
|
|
.byte 0
|
|
|
|
|
.byte 0
|
|
|
|
|
// entry 1: code segment
|
|
|
|
|
.word 0xFFFF
|
|
|
|
|
.word 0
|
|
|
|
|
.byte 0
|
|
|
|
|
.byte 0b10011010
|
|
|
|
|
.byte 0x8F
|
|
|
|
|
.byte 0
|
|
|
|
|
// entry 2: data segment
|
|
|
|
|
.word 0xFFFF
|
|
|
|
|
.word 0
|
|
|
|
|
.byte 0
|
|
|
|
|
.byte 0b10010010
|
|
|
|
|
.byte 0x8F
|
|
|
|
|
.byte 0
|
|
|
|
|
.set gdt_size, .-gdt
|
|
|
|
|
gdt_ptr: .word gdt_size-1
|
|
|
|
|
.long gdt
|
2025-07-04 04:02:05 +02:00
|
|
|
|
2025-07-05 19:34:54 +02:00
|
|
|
// hang: sleep indefinitely
|
|
|
|
|
hang: hlt
|
|
|
|
|
jmp hang
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// Messages to print
|
2025-07-04 15:51:51 +02:00
|
|
|
msg_start: .asciz "Netboot via fernlader v1 ...\r\n"
|
|
|
|
|
msg_a20: .asciz " * Enabling A20\r\n"
|
|
|
|
|
msg_unreal: .asciz " * Unreal Mode\r\n"
|
2025-07-05 15:30:38 +02:00
|
|
|
msg_getmap: .asciz " * Memory Map\r\n"
|
2025-07-05 19:30:14 +02:00
|
|
|
msg_mkheap: .asciz " * Making Space\r\n"
|
2025-07-05 15:30:38 +02:00
|
|
|
msg_paging: .asciz " * Paging\r\n"
|
2025-07-04 15:51:51 +02:00
|
|
|
msg_fin: .asciz "Finished.\r\n"
|
2025-07-05 19:34:54 +02:00
|
|
|
msg_aerr: .asciz "panic: Out of heap space.\r\n"
|
2025-07-05 15:30:38 +02:00
|
|
|
|
2025-07-05 19:30:14 +02:00
|
|
|
heap_start: .long 0
|
|
|
|
|
heap_size: .long 0
|
|
|
|
|
|
2025-07-05 15:30:38 +02:00
|
|
|
// Long mode initial page tables
|
|
|
|
|
pd_ptr: .long 0
|
|
|
|
|
pdp_ptr: .long 0
|
|
|
|
|
pml4_ptr: .long 0
|
|
|
|
|
|
|
|
|
|
// Memory map area
|
|
|
|
|
memmap_end: .word 0
|
|
|
|
|
.align 8
|
|
|
|
|
memmap: // begins at end of binary
|