extern _ldr_main_start
extern _main_start
extern _main_size
+ extern boot_mem_map
+ extern boot_mem_map_size
%include 'macros.inc'
.notvm86:
call setup_serial
call enable_a20
+ call detect_memory
; calculate GDT linear address
xor eax, eax
shr ecx, 2
rep movsd
+ ; copy memory map
+ mov eax, [mem_map_size]
+ mov [es:boot_mem_map_size], eax
+ mov esi, mem_map
+ mov edi, boot_mem_map
+ mov ecx, 32 ; 128 bytes
+ rep movsd
+
mov ax, 10h
mov ds, ax
mov ss, ax
jnz kbc_wait_write
ret
-UART_BASE equ 2f8h ; COM1: 3f8, COM2: 2f8
-UART_DIVISOR equ 115200 / 9600 ; 9600 baud
+
+; ---------------------- memory detection -----------------------
+
+detect_memory:
+ mov si, memdet_e820_msg
+ call printstr
+ call detect_mem_e820
+ jnc .done
+ mov si, str_fail
+ call printstr
+
+ mov si, memdet_e801_msg
+ call printstr
+ call detect_mem_e801
+ jnc .done
+ mov si, str_fail
+ call printstr
+
+ mov esi, memdet_88_msg
+ call printstr
+ call detect_mem_88
+ jnc .done
+ mov esi, str_fail
+ call printstr
+
+ mov si, memdet_fail_msg
+ call printstr
+ jmp exit
+.done:
+ mov si, str_ok
+ call printstr
+ ret
+
+str_ok db 'OK',10,0
+str_fail db 'failed',10,0
+memdet_fail_msg db 'Failed to detect available memory!',10,0
+memdet_e820_msg db "Detecting RAM (BIOS 15h/0xe820)... ",0
+memdet_e801_msg db "Detecting RAM (BIOS 15h/0xe801)... ",0
+memdet_88_msg db "Detecting RAM (BIOS 15h/0x88, max 64mb)... ",0
+
+ ; detect extended memory using BIOS call 15h/e820
+detect_mem_e820:
+ mov dword [mem_map_size], 0
+
+ mov edi, .buffer
+ xor ebx, ebx
+ mov edx, 534d4150h
+
+.looptop:
+ mov eax, 0xe820
+ mov ecx, 24
+ int 15h
+ jc .fail
+ cmp eax, 534d4150h
+ jnz .fail
+
+ ; skip areas starting above 4GB as we won't be able to use them
+ cmp dword [di + 4], 0
+ jnz .skip
+
+ ; only care for type 1 (usable ram), otherwise ignore
+ cmp dword [di + 16], 1
+ jnz .skip
+
+ mov eax, [.buffer]
+ mov esi, mem_map
+ mov ebp, [mem_map_size]
+ mov [ebp * 8 + esi], eax
+
+ ; skip areas with 0 size (also clamp size to 4gb)
+ ; test high 32bits
+ cmp dword [edi + 12], 0
+ jz .highzero
+ ; high part is non-zero, make low part ffffffff
+ xor eax, eax
+ not eax
+ jmp .skiph0
+
+.highzero:
+ ; if both high and low parts are zero, ignore
+ mov eax, [di + 8]
+ test eax, eax
+ jz .skip
+
+.skiph0:mov [ebp * 8 + esi + 4], eax
+ inc dword [mem_map_size]
+
+.skip:
+ ; terminate the loop if ebx was reset to 0
+ test ebx, ebx
+ jz .done
+ jmp .looptop
+.done:
+ clc
+ ret
+
+.fail: ; if size > 0, then it's not a failure, just the end
+ cmp dword [mem_map_size], 0
+ jnz .done
+ stc
+ ret
+
+.buffer times 32 db 0
+
+ ; detect extended memory using BIOS call 15h/e801
+detect_mem_e801:
+ mov si, mem_map
+ mov ebp, [mem_map_size]
+ mov dword [ebp], 0
+
+ xor cx, cx
+ xor dx, dx
+ mov ax, 0xe801
+ int 15h
+ jc .fail
+
+ test cx, cx
+ jnz .foo1
+ test ax, ax
+ jz .fail
+ mov cx, ax
+ mov dx, bx
+
+.foo1: mov dword [si], 100000h
+ movzx eax, cx
+ ; first size is in KB, convert to bytes
+ shl eax, 10
+ jnc .foo2
+ ; overflow means it's >4GB, clamp to 4GB
+ mov eax, 0xffffffff
+.foo2: mov [si + 4], eax
+ inc dword [mem_map_size]
+ test dx, dx
+ jz .done
+ mov dword [si + 8], 1000000h
+ movzx eax, dx
+ ; second size is in 64kb blocks, convert to bytes
+ shl eax, 16
+ jnc .foo3
+ ; overflow means it's >4GB, clamp to 4GB
+ mov eax, 0xffffffff
+.foo3: mov [si + 12], eax
+ inc dword [mem_map_size]
+.done:
+ clc
+ ret
+.fail:
+ stc
+ ret
+
+detect_mem_88:
+ ; reportedly some BIOS implementations fail to clear CF on success
+ clc
+ mov ah, 88h
+ int 15h
+ jc .fail
+
+ test ax, ax
+ jz .fail
+
+ ; ax has size in KB, convert to bytes in eax
+ and eax, 0xffff
+ shl eax, 10
+
+ mov esi, mem_map
+ mov dword [si], 100000h
+ mov [si + 4], eax
+
+ mov dword [mem_map_size], 1
+ clc
+ ret
+.fail: stc
+ ret
+
+ align 4
+mem_map_size dd 0
+mem_map times 128 db 0
+
+
+; ----------------------- serial console ------------------------
+
setup_serial:
; set clock divisor
mov dx, UART_BASE + 3 ; LCTL