kolibrios/kernel/trunk/core/apic.inc
Ivan Baravy 8e5b79b154 kernel: Don't read acpi_dev_* vars that if uninitialized.
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
2020-10-26 04:29:48 +00:00

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