;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision: 8284 $ align 4 proc mem_test ; if we have BIOS with fn E820, skip the test cmp [BOOT_LO.memmap_block_cnt], 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_LO.memmap_block_cnt] xor eax, eax mov [BOOT_LO.memmap_blocks+e820entry.addr.lo], eax mov [BOOT_LO.memmap_blocks+e820entry.addr.hi], eax mov [BOOT_LO.memmap_blocks+e820entry.size.lo], edi mov [BOOT_LO.memmap_blocks+e820entry.size.hi], eax inc eax mov [BOOT_LO.memmap_blocks+e820entry.type], eax .ret: ret endp align 4 proc init_mem ; calculate maximum allocatable address and number of allocatable pages mov edi, BOOT_LO.memmap_blocks mov ecx, [edi-4] ; memmap_block_cnt 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+e820entry.addr.lo] cmp byte [edi+e820entry.type], 1 jne .unusable test eax, 0xFFF jz @f neg eax and eax, 0xFFF add [edi+e820entry.addr.lo], eax adc [edi+e820entry.addr.hi], 0 sub [edi+e820entry.size.lo], eax sbb [edi+e820entry.size.hi], 0 jc .unusable @@: and [edi+e820entry.size.lo], not 0xFFF jz .unusable ; ignore memory after 4 GiB cmp [edi+e820entry.addr.hi], 0 jnz .unusable mov eax, [edi+e820entry.addr.lo] cmp [edi+e820entry.size.hi], 0 jnz .overflow add eax, [edi+e820entry.size.lo] jnc @f .overflow: mov eax, 0xFFFFF000 @@: cmp edx, eax jae @f mov edx, eax @@: sub eax, [edi+e820entry.addr.lo] mov [edi+e820entry.size.lo], eax add esi, eax jmp .usable .unusable: ; and dword [edi+e820entry.size.lo], 0 .usable: add edi, sizeof.e820entry 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_proc-OS_BASE mov ecx, 8192/4 cld rep stosd mov edx, (sys_proc-OS_BASE+PROC.pdt_0)+ 0x800; (OS_BASE shr 20) bt [cpu_caps-OS_BASE], CAPS_PSE jnc .no_PSE mov ebx, cr4 or ebx, CR4_PSE mov eax, PDE_LARGE+PG_SWR 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_SWR 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_SWR mov edi, edx .map_kernel_tabs: stosd add eax, 0x1000 dec ecx jnz .map_kernel_tabs mov dword [sys_proc-OS_BASE+PROC.pdt_0+(page_tabs shr 20)], sys_proc+PROC.pdt_0+PG_SWR-OS_BASE mov edi, (sys_proc+PROC.pdt_0-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_LO.memmap_blocks mov edx, [ebx-4] .scanmap: cmp byte [ebx+e820entry.type], 1 jne .next mov ecx, [ebx+e820entry.size.lo] shr ecx, 12; ecx = number of pages jz .next mov edi, [ebx+e820entry.addr.lo] 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, sizeof.e820entry 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 ; descriptors for PCI BIOS are created here 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 structure should be filled here .BIOS32_not_found: .end: ret align 4 proc test_cpu locals cpu_type dd ? endl xor eax, eax mov [cpu_type], eax mov [cpu_caps-OS_BASE], eax mov [cpu_caps+4-OS_BASE], eax mov [cpu_phys_addr_width-OS_BASE], 32 pushfd pop eax mov ecx, eax xor eax, EFLAGS_AC 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, EFLAGS_ID push eax popfd pushfd pop eax xor eax, ecx je .end_cpuid 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 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 bt edx, CAPS_PAE jnc @f mov [cpu_phys_addr_width-OS_BASE], 36 @@: mov eax, 0x80000000 cpuid cmp eax, 0x80000008 jb @f mov eax, 0x80000008 cpuid mov [cpu_phys_addr_width-OS_BASE], al @@: mov eax, [cpu_sign-OS_BASE] shr eax, 8 and eax, 0x0f ret .end_cpuid: mov eax, [cpu_type] ret endp ACPI_HI_RSDP_WINDOW_START = 0x000E0000 ACPI_HI_RSDP_WINDOW_END = 0x00100000 ACPI_RSDP_CHECKSUM_LENGTH = 20 proc acpi_locate_tables uses ebx esi edi mov ebx, [ebx+ACPI_RSDP.RsdtAddress] mov [acpi_rsdt_base-OS_BASE], ebx mov eax, [ebx+ACPI_RSDT.Length] mov [acpi_rsdt_size-OS_BASE], eax mov esi, [acpi_rsdt_base-OS_BASE] mov ecx, [esi+ACPI_RSDT.Length] lea edi, [esi+ecx] add esi, sizeof.ACPI_TABLE movi ecx, 1 .next_table: cmp esi, edi jae .done lodsd cmp [eax+ACPI_TABLE.Signature], 'SSDT' ; skip DSDT if present jz .ssdt ; read it from FADT cmp [eax+ACPI_TABLE.Signature], 'FACP' ; this is FADT jz .fadt cmp [eax+ACPI_TABLE.Signature], 'APIC' ; this is MADT jz .madt cmp [eax+ACPI_TABLE.Signature], 'HPET' jz .hpet jmp .next_table .ssdt: mov [acpi_ssdt_base+ecx*4-OS_BASE], eax mov eax, [eax+ACPI_TABLE.Length] mov [acpi_ssdt_size+ecx*4-OS_BASE], eax inc ecx jmp .next_table .fadt: mov [acpi_fadt_base-OS_BASE], eax cmp [eax+ACPI_FADT.DSDT], 0 jz @f mov edx, [eax+ACPI_FADT.DSDT] mov [acpi_ssdt_base-OS_BASE], edx mov edx, [edx+ACPI_TABLE.Length] mov [acpi_ssdt_size-OS_BASE], edx @@: mov eax, [eax+ACPI_TABLE.Length] mov [acpi_fadt_size-OS_BASE], eax jmp .next_table .madt: mov [acpi_madt_base-OS_BASE], eax mov eax, [eax+ACPI_TABLE.Length] mov [acpi_madt_size-OS_BASE], eax jmp .next_table .hpet: mov [acpi_hpet_base-OS_BASE], eax mov eax, [eax+ACPI_TABLE.Length] mov [acpi_hpet_size-OS_BASE], eax jmp .next_table .done: mov [acpi_ssdt_cnt-OS_BASE], ecx ret endp acpi_locate: push ebx push edi if defined UEFI ; UEFI loader knows where RSDP is mov ebx, [BOOT_LO.acpi_rsdp] test ebx, ebx jz .done call .check else movzx ebx, word [0x40E] shl ebx, 4 lea ecx, [ebx+1024] call .check test ebx, ebx jz @F jmp .done @@: mov ebx, ACPI_HI_RSDP_WINDOW_START mov edi, ACPI_HI_RSDP_WINDOW_END call .check end if .done: mov [acpi_rsdp_base-OS_BASE], ebx test ebx, ebx jz @f call acpi_locate_tables @@: pop edi pop ebx ret .check: cmp [ebx], dword 'RSD ' jne .next cmp [ebx+4], dword 'PTR ' 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 ret .next: add ebx, 16 cmp ebx, edi jb .check xor ebx, ebx ret