forked from KolibriOS/kolibrios
Ivan Baravy
8e5b79b154
Currently only uefi4kos loader initializes these variables. May be one day BIOS loaders will load DEVICES.DAT file and initialize these vars too, may be one day we will detect APIC IRQs via ACPI. But not today. git-svn-id: svn://kolibrios.org@8117 a494cfbc-eb01-0410-851d-a64ba20cac60
567 lines
13 KiB
PHP
567 lines
13 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
$Revision$
|
|
|
|
MAX_IOAPICS = 2
|
|
|
|
uglobal
|
|
IRQ_COUNT rd MAX_IOAPICS
|
|
irq_mode rd 1 ; PIC/(IO)APIC
|
|
IOAPIC_base rd MAX_IOAPICS
|
|
ioapic_gsi_base rd MAX_IOAPICS ; zero-based, i.e. not vector
|
|
ioapic_cnt dd ? ; from MADT aka APIC table
|
|
ioapic_cur dd ?
|
|
LAPIC_BASE rd 1
|
|
endg
|
|
|
|
APIC_ID = 0x20
|
|
APIC_TPR = 0x80
|
|
APIC_EOI = 0xb0
|
|
APIC_LDR = 0xd0
|
|
APIC_DFR = 0xe0
|
|
APIC_SVR = 0xf0
|
|
APIC_ISR = 0x100
|
|
APIC_ESR = 0x280
|
|
APIC_ICRL = 0x300
|
|
APIC_ICRH = 0x310
|
|
APIC_LVT_LINT0 = 0x350
|
|
APIC_LVT_LINT1 = 0x360
|
|
APIC_LVT_err = 0x370
|
|
|
|
; APIC timer
|
|
APIC_LVT_timer = 0x320
|
|
APIC_timer_div = 0x3e0
|
|
APIC_timer_init = 0x380
|
|
APIC_timer_cur = 0x390
|
|
; IOAPIC
|
|
IOAPIC_ID = 0x0
|
|
IOAPIC_VER = 0x1
|
|
IOAPIC_ARB = 0x2
|
|
IOAPIC_REDTBL = 0x10
|
|
|
|
align 4
|
|
APIC_init:
|
|
push ebx
|
|
mov [irq_mode], IRQ_PIC
|
|
|
|
cmp [acpi_ioapic_base], 0
|
|
jz .no_apic
|
|
|
|
cmp [acpi_lapic_base], 0
|
|
jz .no_apic
|
|
|
|
; non-UEFI loaders don't load DEVICES.DAT and don't initialize [acpi_dev_size]
|
|
if defined UEFI
|
|
cmp [acpi_dev_size], 0
|
|
jz @f
|
|
stdcall map_io_mem, [acpi_dev_data], [acpi_dev_size], PG_SWR
|
|
mov [acpi_dev_data], eax
|
|
jmp .loaded
|
|
@@:
|
|
end if
|
|
|
|
stdcall load_file, dev_data_path
|
|
test eax, eax
|
|
jz .no_apic
|
|
|
|
mov [acpi_dev_data], eax
|
|
mov [acpi_dev_size], ebx
|
|
.loaded:
|
|
|
|
; IOAPIC init
|
|
xor ebx, ebx
|
|
@@:
|
|
stdcall map_io_mem, [acpi_ioapic_base+ebx*4], 0x20, PG_GLOBAL+PG_NOCACHE+PG_SWR
|
|
mov [IOAPIC_base+ebx*4], eax
|
|
inc ebx
|
|
cmp ebx, [ioapic_cnt]
|
|
jnz @b
|
|
|
|
call IRQ_mask_all
|
|
mov [ioapic_cur], 0
|
|
.next_ioapic:
|
|
mov edx, [ioapic_cur]
|
|
mov eax, IOAPIC_VER
|
|
call IOAPIC_read
|
|
shr eax, 16
|
|
inc al
|
|
movzx eax, al
|
|
mov ecx, [ioapic_gsi_base+edx*4]
|
|
cmp ecx, IRQ_RESERVED
|
|
jae .lapic_init
|
|
add ecx, eax
|
|
sub ecx, IRQ_RESERVED
|
|
jbe @f
|
|
sub eax, ecx
|
|
@@:
|
|
mov [IRQ_COUNT+edx*4], eax
|
|
|
|
; Reroute IOAPIC & mask all interrupts
|
|
xor ecx, ecx
|
|
mov eax, IOAPIC_REDTBL
|
|
.next_irq:
|
|
mov ebx, eax
|
|
call IOAPIC_read
|
|
mov ah, 0x08; Delivery Mode: Fixed, Destination Mode: Logical
|
|
mov al, cl
|
|
add al, 0x20; vector
|
|
add eax, [ioapic_gsi_base+edx*4]
|
|
or eax, 0x1a000; Mask Interrupt, level-triggered active-low
|
|
cmp [ioapic_cur], 0
|
|
jnz @f
|
|
cmp ecx, 16
|
|
jae @f
|
|
and eax, NOT 0xa000 ; edge-triggered active-high for IRQ0-15
|
|
@@:
|
|
xchg eax, ebx
|
|
call IOAPIC_write
|
|
inc eax
|
|
mov ebx, eax
|
|
call IOAPIC_read
|
|
or eax, 0xff000000; Destination Field
|
|
xchg eax, ebx
|
|
call IOAPIC_write
|
|
inc eax
|
|
inc ecx
|
|
cmp ecx, [IRQ_COUNT+edx*4]
|
|
jb .next_irq
|
|
|
|
inc [ioapic_cur]
|
|
inc edx
|
|
cmp edx, [ioapic_cnt]
|
|
jnz .next_ioapic
|
|
|
|
.lapic_init:
|
|
call LAPIC_init
|
|
|
|
mov [irq_mode], IRQ_APIC
|
|
|
|
mov al, 0x70
|
|
out 0x22, al
|
|
mov al, 1
|
|
out 0x23, al
|
|
|
|
call pci_irq_fixup
|
|
.no_apic:
|
|
pop ebx
|
|
ret
|
|
|
|
;===========================================================
|
|
align 4
|
|
LAPIC_init:
|
|
|
|
cmp [LAPIC_BASE], 0
|
|
jne .done
|
|
|
|
stdcall map_io_mem, [acpi_lapic_base], 0x1000, PG_GLOBAL+PG_NOCACHE+PG_SWR
|
|
mov [LAPIC_BASE], eax
|
|
mov esi, eax
|
|
|
|
; Program Destination Format Register for Flat mode.
|
|
mov eax, [esi + APIC_DFR]
|
|
or eax, 0xf0000000
|
|
mov [esi + APIC_DFR], eax
|
|
|
|
; Program Logical Destination Register.
|
|
mov eax, [esi + APIC_LDR]
|
|
;and eax, 0xff000000
|
|
and eax, 0x00ffffff
|
|
or eax, 0x01000000;!!!!!!!!!!!!
|
|
mov [esi + APIC_LDR], eax
|
|
|
|
; Task Priority Register initialization.
|
|
mov eax, [esi + APIC_TPR]
|
|
and eax, 0xffffff00
|
|
mov [esi + APIC_TPR], eax
|
|
|
|
; Flush the queue
|
|
mov edx, 0
|
|
.nxt2:
|
|
mov ecx, 32
|
|
mov eax, [esi + APIC_ISR + edx]
|
|
.nxt:
|
|
shr eax, 1
|
|
jnc @f
|
|
mov dword [esi + APIC_EOI], 0; EOI
|
|
@@:
|
|
loop .nxt
|
|
|
|
add edx, 0x10
|
|
cmp edx, 0x170
|
|
jbe .nxt2
|
|
|
|
; Spurious-Interrupt Vector Register initialization.
|
|
mov eax, [esi + APIC_SVR]
|
|
or eax, 0x1ff
|
|
and eax, 0xfffffdff
|
|
mov [esi + APIC_SVR], eax
|
|
|
|
; Initialize LVT LINT0 register. (INTR)
|
|
mov eax, 0x00700
|
|
; mov eax, 0x10700
|
|
mov [esi + APIC_LVT_LINT0], eax
|
|
|
|
; Initialize LVT LINT1 register. (NMI)
|
|
mov eax, 0x00400
|
|
mov [esi + APIC_LVT_LINT1], eax
|
|
|
|
; Initialize LVT Error register.
|
|
mov eax, [esi + APIC_LVT_err]
|
|
or eax, 0x10000; bit 16
|
|
mov [esi + APIC_LVT_err], eax
|
|
|
|
; LAPIC timer
|
|
; pre init
|
|
mov dword[esi + APIC_timer_div], 1011b; 1
|
|
mov dword[esi + APIC_timer_init], 0xffffffff; max val
|
|
push esi
|
|
mov esi, 640 ; wait 0.64 sec
|
|
call delay_ms
|
|
pop esi
|
|
mov eax, [esi + APIC_timer_cur]; read current tick couner
|
|
xor eax, 0xffffffff ; eax = 0xffffffff - eax
|
|
shr eax, 6 ; eax /= 64; APIC ticks per 0.01 sec
|
|
|
|
; Start (every 0.01 sec)
|
|
mov dword[esi + APIC_LVT_timer], 0x30020; periodic int 0x20
|
|
mov dword[esi + APIC_timer_init], eax
|
|
|
|
.done:
|
|
ret
|
|
|
|
;===========================================================
|
|
; IOAPIC implementation
|
|
align 4
|
|
IOAPIC_read:
|
|
; in : EAX - IOAPIC register
|
|
; out: EAX - readed value
|
|
push esi
|
|
mov esi, [ioapic_cur]
|
|
mov esi, [IOAPIC_base+esi*4]
|
|
mov [esi], eax
|
|
mov eax, [esi + 0x10]
|
|
pop esi
|
|
ret
|
|
|
|
align 4
|
|
IOAPIC_write:
|
|
; in : EAX - IOAPIC register
|
|
; EBX - value
|
|
; out: none
|
|
push esi
|
|
mov esi, [ioapic_cur]
|
|
mov esi, [IOAPIC_base+esi*4]
|
|
mov [esi], eax
|
|
mov [esi + 0x10], ebx
|
|
pop esi
|
|
ret
|
|
;===========================================================
|
|
; Remap all IRQ to 0x20+ Vectors
|
|
; IRQ0 to vector 0x20, IRQ1 to vector 0x21....
|
|
align 4
|
|
PIC_init:
|
|
mov [IRQ_COUNT], 16
|
|
cli
|
|
mov al, 0x11 ; icw4, edge triggered
|
|
out 0x20, al
|
|
out 0xA0, al
|
|
|
|
mov al, 0x20 ; generate 0x20 +
|
|
out 0x21, al
|
|
mov al, 0x28 ; generate 0x28 +
|
|
out 0xA1, al
|
|
|
|
mov al, 0x04 ; slave at irq2
|
|
out 0x21, al
|
|
mov al, 0x02 ; at irq9
|
|
out 0xA1, al
|
|
|
|
mov al, 0x01 ; 8086 mode
|
|
out 0x21, al
|
|
out 0xA1, al
|
|
|
|
call IRQ_mask_all
|
|
ret
|
|
|
|
; -----------------------------------------
|
|
; TIMER SET TO 1/100 S
|
|
align 4
|
|
PIT_init:
|
|
mov al, 0x34 ; set to 100Hz
|
|
out 0x43, al
|
|
mov al, 0x9b ; lsb 1193180 / 1193
|
|
out 0x40, al
|
|
mov al, 0x2e ; msb
|
|
out 0x40, al
|
|
ret
|
|
|
|
; -----------------------------------------
|
|
align 4
|
|
unmask_timer:
|
|
cmp [irq_mode], IRQ_APIC
|
|
je @f
|
|
|
|
stdcall enable_irq, 0
|
|
ret
|
|
@@:
|
|
; use PIT
|
|
; in some systems PIT no connected to IOAPIC
|
|
; mov eax, 0x14
|
|
; call IOAPIC_read
|
|
; mov ah, 0x09 ; Delivery Mode: Lowest Priority, Destination Mode: Logical
|
|
; mov al, 0x20
|
|
; or eax, 0x10000 ; Mask Interrupt
|
|
; mov ebx, eax
|
|
; mov eax, 0x14
|
|
; call IOAPIC_write
|
|
; stdcall enable_irq, 2
|
|
; ret
|
|
|
|
; use LAPIC timer
|
|
mov esi, [LAPIC_BASE]
|
|
mov eax, [esi + APIC_LVT_timer]
|
|
and eax, 0xfffeffff
|
|
mov [esi + APIC_LVT_timer], eax
|
|
ret
|
|
|
|
; -----------------------------------------
|
|
; Disable all IRQ
|
|
align 4
|
|
IRQ_mask_all:
|
|
cmp [irq_mode], IRQ_APIC
|
|
je .APIC
|
|
|
|
mov al, 0xFF
|
|
out 0x21, al
|
|
out 0xA1, al
|
|
mov ecx, 0x1000
|
|
ret
|
|
.APIC:
|
|
cmp [IOAPIC_base], 0
|
|
jz .done
|
|
mov [ioapic_cur], 0
|
|
.next_ioapic:
|
|
mov edx, [ioapic_cur]
|
|
mov ecx, [IRQ_COUNT+edx*4]
|
|
mov eax, 0x10
|
|
@@:
|
|
mov ebx, eax
|
|
call IOAPIC_read
|
|
or eax, 0x10000; bit 16
|
|
xchg eax, ebx
|
|
call IOAPIC_write
|
|
inc eax
|
|
inc eax
|
|
loop @b
|
|
|
|
inc [ioapic_cur]
|
|
inc edx
|
|
cmp edx, [ioapic_cnt]
|
|
jnz .next_ioapic
|
|
.done:
|
|
ret
|
|
|
|
; -----------------------------------------
|
|
; End Of Interrupt
|
|
; cl - IRQ number
|
|
align 4
|
|
irq_eoi: ; __fastcall
|
|
cmp [irq_mode], IRQ_APIC
|
|
je .APIC
|
|
|
|
cmp cl, 8
|
|
mov al, 0x20
|
|
jb @f
|
|
out 0xa0, al
|
|
@@:
|
|
out 0x20, al
|
|
ret
|
|
|
|
.APIC:
|
|
mov eax, [LAPIC_BASE]
|
|
mov dword [eax + APIC_EOI], 0; EOI
|
|
ret
|
|
|
|
; -----------------------------------------
|
|
; from dll.inc
|
|
align 4
|
|
proc enable_irq stdcall, irq_line:dword
|
|
mov ebx, [irq_line]
|
|
cmp [irq_mode], IRQ_APIC
|
|
je .APIC
|
|
|
|
mov edx, 0x21
|
|
cmp ebx, 8
|
|
jb @F
|
|
|
|
mov edx, 0xA1
|
|
sub ebx, 8
|
|
@@:
|
|
in al, dx
|
|
btr eax, ebx
|
|
out dx, al
|
|
ret
|
|
.APIC:
|
|
push [ioapic_cur]
|
|
xor eax, eax
|
|
.next_ioapic:
|
|
mov ecx, [ioapic_gsi_base+eax*4]
|
|
add ecx, [IRQ_COUNT+eax*4]
|
|
cmp ebx, ecx
|
|
jb .found
|
|
inc eax
|
|
cmp eax, [ioapic_cnt]
|
|
jnz .next_ioapic
|
|
jmp .done
|
|
.found:
|
|
mov [ioapic_cur], eax
|
|
sub ebx, [ioapic_gsi_base+eax*4]
|
|
shl ebx, 1
|
|
add ebx, 0x10
|
|
mov eax, ebx
|
|
call IOAPIC_read
|
|
and eax, 0xfffeffff; bit 16
|
|
xchg eax, ebx
|
|
call IOAPIC_write
|
|
.done:
|
|
pop [ioapic_cur]
|
|
ret
|
|
endp
|
|
|
|
proc disable_irq stdcall, irq_line:dword
|
|
mov ebx, [irq_line]
|
|
cmp [irq_mode], IRQ_APIC
|
|
je .APIC
|
|
|
|
mov edx, 0x21
|
|
cmp ebx, 8
|
|
jb @F
|
|
|
|
mov edx, 0xA1
|
|
sub ebx, 8
|
|
@@:
|
|
in al, dx
|
|
bts eax, ebx
|
|
out dx, al
|
|
ret
|
|
.APIC:
|
|
push [ioapic_cur]
|
|
xor eax, eax
|
|
.next_ioapic:
|
|
mov ecx, [ioapic_gsi_base+eax*4]
|
|
add ecx, [IRQ_COUNT+eax*4]
|
|
cmp ebx, ecx
|
|
jae .found
|
|
inc eax
|
|
cmp eax, [ioapic_cnt]
|
|
jnz .next_ioapic
|
|
jmp .done
|
|
.found:
|
|
mov [ioapic_cur], eax
|
|
sub ebx, [ioapic_gsi_base+eax*4]
|
|
shl ebx, 1
|
|
add ebx, 0x10
|
|
mov eax, ebx
|
|
call IOAPIC_read
|
|
or eax, 0x10000; bit 16
|
|
xchg eax, ebx
|
|
call IOAPIC_write
|
|
.done:
|
|
pop [ioapic_cur]
|
|
ret
|
|
endp
|
|
|
|
align 4
|
|
pci_irq_fixup:
|
|
|
|
push ebp
|
|
|
|
mov esi, [acpi_dev_data]
|
|
mov ebx, [acpi_dev_size]
|
|
|
|
lea edi, [esi+ebx]
|
|
|
|
.iterate:
|
|
|
|
cmp esi, edi
|
|
jae .done
|
|
|
|
mov eax, [esi]
|
|
|
|
cmp eax, -1
|
|
je .done
|
|
|
|
movzx ebx, al
|
|
movzx ebp, ah
|
|
|
|
stdcall pci_read32, ebp, ebx, 0
|
|
|
|
cmp eax, [esi+4]
|
|
jne .skip
|
|
|
|
mov eax, [esi+8]
|
|
stdcall pci_write8, ebp, ebx, 0x3C, eax
|
|
.skip:
|
|
add esi, 16
|
|
jmp .iterate
|
|
|
|
.done:
|
|
.fail:
|
|
pop ebp
|
|
ret
|
|
|
|
align 4
|
|
get_clock_ns:
|
|
|
|
mov eax, [hpet_base]
|
|
test eax, eax
|
|
jz .old_tics
|
|
|
|
push ebx
|
|
push esi
|
|
pushfd
|
|
cli
|
|
|
|
mov ebx, eax
|
|
@@:
|
|
mov edx, [ebx+0xF4]
|
|
mov eax, [ebx+0xF0]
|
|
mov ecx, [ebx+0xF4]
|
|
cmp ecx, edx
|
|
jne @B
|
|
popfd
|
|
|
|
;96-bit arithmetic
|
|
;ebx - low dword
|
|
;esi - medium dword
|
|
;edx - high dword
|
|
|
|
mul [hpet_period]
|
|
mov ebx, eax
|
|
mov esi, edx
|
|
|
|
mov eax, ecx
|
|
mul [hpet_period]
|
|
add esi, eax
|
|
adc edx, 0
|
|
mov eax, ebx
|
|
mov ebx, esi
|
|
shrd eax, ebx, 10
|
|
shrd esi, edx, 10
|
|
mov edx, esi
|
|
|
|
pop esi
|
|
pop ebx
|
|
ret
|
|
|
|
.old_tics:
|
|
mov eax, [timer_ticks]
|
|
mov edx, 10000000
|
|
mul edx
|
|
ret
|