;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision$


MEM_WB     equ 6               ;write-back memory
MEM_WC     equ 1               ;write combined memory
MEM_UC     equ 0               ;uncached memory

align 4
proc mem_test
; if we have BIOS with fn E820, skip the test
           cmp dword [BOOT_VAR-OS_BASE + 0x9100], 0
           jnz .ret

           mov eax, cr0
           and eax, not (CR0_CD+CR0_NW)
           or eax, CR0_CD         ;disable caching
           mov cr0, eax
           wbinvd                 ;invalidate cache

           xor edi, edi
           mov ebx, 'TEST'
@@:
           add edi, 0x100000
           xchg ebx, dword [edi]
           cmp dword [edi], 'TEST'
           xchg ebx, dword [edi]
           je @b

           and eax, not (CR0_CD+CR0_NW)  ;enable caching
           mov cr0, eax
           inc dword [BOOT_VAR-OS_BASE + 0x9100]
           xor eax, eax
           mov [BOOT_VAR-OS_BASE + 0x9104], eax
           mov [BOOT_VAR-OS_BASE + 0x9108], eax
           mov [BOOT_VAR-OS_BASE + 0x910C], edi
           mov [BOOT_VAR-OS_BASE + 0x9110], eax
.ret:
           ret
endp

align 4
proc init_mem
; calculate maximum allocatable address and number of allocatable pages
           mov edi, BOOT_VAR-OS_BASE + 0x9104
           mov ecx, [edi-4]
           xor esi, esi ; esi will hold total amount of memory
           xor edx, edx ; edx will hold maximum allocatable address
.calcmax:
; round all to pages
           mov eax, [edi]
           test eax, 0xFFF
           jz @f
           neg eax
           and eax, 0xFFF
           add [edi], eax
           adc dword [edi+4], 0
           sub [edi+8], eax
           sbb dword [edi+12], 0
           jc .unusable
@@:
           and dword [edi+8], not 0xFFF
           jz .unusable
; ignore memory after 4 Gb
           cmp dword [edi+4], 0
           jnz .unusable
           mov eax, [edi]
           cmp dword [edi+12], 0
           jnz .overflow
           add eax, [edi+8]
           jnc @f
.overflow:
           mov eax, 0xFFFFF000
@@:
           cmp edx, eax
           jae @f
           mov edx, eax
@@:
           sub eax, [edi]
           mov [edi+8], eax
           add esi, eax
           jmp .usable
.unusable:
           and dword [edi+8], 0
.usable:
           add edi, 20
           loop .calcmax
.calculated:
           mov [MEM_AMOUNT-OS_BASE], esi
           mov [pg_data.mem_amount-OS_BASE], esi
           shr esi, 12
           mov [pg_data.pages_count-OS_BASE], esi

           shr edx, 12
           add edx, 31
           and edx, not 31
           shr edx, 3
           mov [pg_data.pagemap_size-OS_BASE], edx

           add edx, (sys_pgmap-OS_BASE)+4095
           and edx, not 4095
           mov [tmp_page_tabs], edx

           mov edx, esi
           and edx, -1024
           cmp edx, (OS_BASE/4096)
           jbe @F
           mov edx, (OS_BASE/4096)
           jmp .set
@@:
           cmp edx, (HEAP_BASE-OS_BASE+HEAP_MIN_SIZE)/4096
           jae .set
           mov edx, (HEAP_BASE-OS_BASE+HEAP_MIN_SIZE)/4096
.set:
           mov [pg_data.kernel_pages-OS_BASE], edx
           shr edx, 10
           mov [pg_data.kernel_tables-OS_BASE], edx

           xor eax, eax
           mov edi, sys_pgdir-OS_BASE
           mov ecx, 4096/4
           cld
           rep stosd

           mov edx, (sys_pgdir-OS_BASE)+ 0x800; (OS_BASE shr 20)
           bt [cpu_caps-OS_BASE], CAPS_PSE
           jnc .no_PSE

           mov ebx, cr4
           or ebx, CR4_PSE
           mov eax, PG_LARGE+PG_SW
           mov cr4, ebx
           dec [pg_data.kernel_tables-OS_BASE]

           mov [edx], eax
           add edx, 4

           mov edi, [tmp_page_tabs]
           jmp .map_kernel_heap		; new kernel fits to the first 4Mb - nothing to do with ".map_low"
.no_PSE:
           mov eax, PG_SW
           mov ecx, [tmp_page_tabs]
           shr ecx, 12
.map_low:
           mov edi, [tmp_page_tabs]
@@:                                   ;
           stosd
           add eax, 0x1000
           dec ecx
           jnz @B

.map_kernel_heap:
           mov ecx, [pg_data.kernel_tables-OS_BASE]
           shl ecx, 10
           xor eax, eax
           rep stosd

           mov ecx, [pg_data.kernel_tables-OS_BASE]
           mov eax, [tmp_page_tabs]
           or  eax, PG_SW
           mov edi, edx

.map_kernel_tabs:
           stosd
           add eax, 0x1000
           dec ecx
           jnz .map_kernel_tabs

           mov dword [sys_pgdir-OS_BASE+(page_tabs shr 20)], sys_pgdir+PG_SW-OS_BASE

           mov edi, (sys_pgdir-OS_BASE)
           lea esi, [edi+(OS_BASE shr 20)]
           movsd
           movsd
           ret
endp

align 4
proc init_page_map
; mark all memory as unavailable
           mov edi, sys_pgmap-OS_BASE
           mov ecx, [pg_data.pagemap_size-OS_BASE]
           shr ecx, 2
           xor eax, eax
           cld
           rep stosd

; scan through memory map and mark free areas as available
           mov ebx, BOOT_VAR-OS_BASE + 0x9104
           mov edx, [ebx-4]
.scanmap:
           mov ecx, [ebx+8]
           shr ecx, 12 ; ecx = number of pages
           jz .next
           mov edi, [ebx]
           shr edi, 12 ; edi = first page
           mov eax, edi
           shr edi, 5
           shl edi, 2
           add edi, sys_pgmap-OS_BASE
           and eax, 31
           jz .startok
           add ecx, eax
           sub ecx, 32
           jbe .onedword
           push ecx
           mov ecx, eax
           or eax, -1
           shl eax, cl
           or [edi], eax
           add edi, 4
           pop ecx
.startok:
           push ecx
           shr ecx, 5
           or eax, -1
           rep stosd
           pop ecx
           and ecx, 31
           neg eax
           shl eax, cl
           dec eax
           or [edi], eax
           jmp .next
.onedword:
           add ecx, 32
           sub ecx, eax
@@:
           bts [edi], eax
           inc eax
           loop @b
.next:
           add ebx, 20
           dec edx
           jnz .scanmap

; mark kernel memory as allocated (unavailable)
           mov ecx, [tmp_page_tabs]
           mov edx, [pg_data.pages_count-OS_BASE]
           shr ecx, 12
           add ecx, [pg_data.kernel_tables-OS_BASE]
           sub edx, ecx
           mov [pg_data.pages_free-OS_BASE], edx

           mov edi, sys_pgmap-OS_BASE
           mov ebx, ecx
           shr ecx, 5
           xor eax, eax
           rep stosd

           not eax
           mov ecx, ebx
           and ecx, 31
           shl eax, cl
           and [edi], eax
           add edi, OS_BASE
           mov [page_start-OS_BASE], edi;

           mov ebx, sys_pgmap
           add ebx, [pg_data.pagemap_size-OS_BASE]
           mov [page_end-OS_BASE], ebx

           ret
endp

align 4

init_BIOS32:
           mov edi, 0xE0000
.pcibios_nxt:
           cmp dword[edi], '_32_' ; "magic" word
           je .BIOS32_found
.pcibios_nxt2:
           add edi, 0x10
           cmp edi, 0xFFFF0
           je .BIOS32_not_found
           jmp .pcibios_nxt
.BIOS32_found:			; magic word found, check control summ

           movzx ecx, byte[edi + 9]
           shl ecx, 4
           mov esi, edi
           xor eax, eax
           cld   ; paranoia
@@:	lodsb
           add ah, al
           loop @b
           jnz .pcibios_nxt2 ; control summ must be zero
    ; BIOS32 service found !
           mov ebp, [edi + 4]
           mov [bios32_entry], ebp
    ; check PCI BIOS present
           mov eax, '$PCI'
           xor ebx, ebx
           push cs  ; special for 'ret far' from  BIOS
           call ebp
           test al, al
           jnz .PCI_BIOS32_not_found

 ; ����� ��������� ����������� ��� PCI BIOS

           add ebx, OS_BASE
           dec ecx
           mov [(pci_code_32-OS_BASE)], cx    ;limit 0-15
           mov [(pci_data_32-OS_BASE)], cx    ;limit 0-15

           mov [(pci_code_32-OS_BASE)+2], bx  ;base  0-15
           mov [(pci_data_32-OS_BASE)+2], bx  ;base  0-15

           shr ebx, 16
           mov [(pci_code_32-OS_BASE)+4], bl  ;base  16-23
           mov [(pci_data_32-OS_BASE)+4], bl  ;base  16-23

           shr ecx, 16
           and cl, 0x0F
           mov ch, bh
           add cx, D32
           mov [(pci_code_32-OS_BASE)+6], cx  ;lim   16-19 &
           mov [(pci_data_32-OS_BASE)+6], cx  ;base  24-31

           mov [(pci_bios_entry-OS_BASE)], edx
         ; jmp .end
.PCI_BIOS32_not_found:
	; ����� ������ ���������� pci_emu_dat
.BIOS32_not_found:
.end:
           ret

align 4
proc test_cpu
           locals
              cpu_type   dd ?
              cpu_id     dd ?
              cpu_Intel  dd ?
              cpu_AMD    dd ?
           endl

           xor eax, eax
           mov [cpu_type], eax
           mov [cpu_caps-OS_BASE], eax
           mov [cpu_caps+4-OS_BASE], eax

           pushfd
           pop eax
           mov ecx, eax
           xor eax, 0x40000
           push eax
           popfd
           pushfd
           pop eax
           xor eax, ecx
           mov [cpu_type], CPU_386
           jz .end_cpuid
           push ecx
           popfd

           mov [cpu_type], CPU_486
           mov eax, ecx
           xor eax, 0x200000
           push eax
           popfd
           pushfd
           pop eax
           xor eax, ecx
           je .end_cpuid
           mov [cpu_id], 1

           xor eax, eax
           cpuid

           mov [cpu_vendor-OS_BASE], ebx
           mov [cpu_vendor+4-OS_BASE], edx
           mov [cpu_vendor+8-OS_BASE], ecx
           cmp ebx, dword [intel_str-OS_BASE]
           jne .check_AMD
           cmp edx, dword [intel_str+4-OS_BASE]
           jne .check_AMD
           cmp ecx, dword [intel_str+8-OS_BASE]
           jne .check_AMD
           mov [cpu_Intel], 1
           cmp eax, 1
           jl .end_cpuid
           mov eax, 1
           cpuid
           mov [cpu_sign-OS_BASE], eax
           mov [cpu_info-OS_BASE],  ebx
           mov [cpu_caps-OS_BASE],  edx
           mov [cpu_caps+4-OS_BASE],ecx

           shr eax, 8
           and eax, 0x0f
           ret
.end_cpuid:
           mov eax, [cpu_type]
           ret

.check_AMD:
           cmp ebx, dword [AMD_str-OS_BASE]
           jne .unknown
           cmp edx, dword [AMD_str+4-OS_BASE]
           jne .unknown
           cmp ecx, dword [AMD_str+8-OS_BASE]
           jne .unknown
           mov [cpu_AMD], 1
           cmp eax, 1
           jl .unknown
           mov eax, 1
           cpuid
           mov [cpu_sign-OS_BASE], eax
           mov [cpu_info-OS_BASE],  ebx
           mov [cpu_caps-OS_BASE],  edx
           mov [cpu_caps+4-OS_BASE],ecx
           shr eax, 8
           and eax, 0x0f
           ret
.unknown:
           mov eax, 1
           cpuid
           mov [cpu_sign-OS_BASE], eax
           mov [cpu_info-OS_BASE],  ebx
           mov [cpu_caps-OS_BASE],  edx
           mov [cpu_caps+4-OS_BASE],ecx
           shr eax, 8
           and eax, 0x0f
           ret
endp

uglobal
align 4
acpi_rsdp         rd 1
acpi_rsdt         rd 1
acpi_madt         rd 1

acpi_dev_data     rd 1
acpi_dev_size     rd 1

acpi_rsdt_base    rd 1
acpi_madt_base    rd 1
acpi_lapic_base   rd 1
acpi_ioapic_base  rd 1
endg

ACPI_HI_RSDP_WINDOW_START  equ 0x000E0000
ACPI_HI_RSDP_WINDOW_END    equ 0x00100000
ACPI_RSDP_CHECKSUM_LENGTH  equ 20
ACPI_MADT_SIGN             equ 0x43495041


acpi_locate:
        push ebx
        mov ebx, ACPI_HI_RSDP_WINDOW_START
.check:
        cmp [ebx], dword 0x20445352
        jne .next
        cmp [ebx+4], dword 0x20525450
        jne .next

        mov edx, ebx
        mov ecx, ACPI_RSDP_CHECKSUM_LENGTH
        xor eax, eax
.sum:
        add al, [edx]
        inc edx
        loop .sum

        test al, al
        jnz .next

        mov eax, ebx
        pop ebx
        ret
.next:
        add ebx, 16
        cmp ebx, ACPI_HI_RSDP_WINDOW_END
        jb .check

        pop ebx
        xor eax, eax
        ret

align 4
rsdt_find:           ;ecx= rsdt edx= SIG
        push ebx
        push esi

        lea ebx, [ecx+36]
        mov esi, [ecx+4]
        add esi, ecx
.next:
        mov eax, [ebx]
        cmp [eax], edx
        je .done

        add ebx, 4
        cmp ebx, esi
        jb .next

        xor eax, eax
        pop esi
        pop ebx
        ret

.done:
        mov eax, [ebx]
        pop esi
        pop ebx
        ret


align 4

check_acpi:

        call acpi_locate
        test eax, eax
        jz .done

        mov ecx, [eax+16]
        mov edx, ACPI_MADT_SIGN
        mov [acpi_rsdt_base-OS_BASE], ecx
        call rsdt_find
        test eax, eax
        jz .done

        mov [acpi_madt_base-OS_BASE], eax
        mov ecx, [eax+36]
        mov [acpi_lapic_base-OS_BASE], ecx

        lea edx, [eax+44]
        mov ecx, [eax+4]
        add ecx, eax
.check:
        mov eax, [edx]
        cmp al, 1
        je .ioapic

.next:
        movzx eax, ah
        add edx, eax
        cmp edx, ecx
        jb .check
.done:
        ret
.ioapic:
        mov eax, [edx+4]
        mov [acpi_ioapic_base-OS_BASE], eax
        ret