sortof works
[com32] / src / loader.asm
index 68504f8..4cdb702 100644 (file)
@@ -4,6 +4,8 @@
        extern _ldr_main_start
        extern _main_start
        extern _main_size
+       extern boot_mem_map
+       extern boot_mem_map_size
 
 %include 'macros.inc'
 
@@ -34,6 +36,7 @@ _start:
 .notvm86:
        call setup_serial
        call enable_a20
+       call detect_memory
 
        ; calculate GDT linear address
        xor eax, eax
@@ -79,6 +82,14 @@ _start:
        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
@@ -202,8 +213,187 @@ kbc_wait_write:
        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