forked from KolibriOS/kolibrios
Ivan Baravy
034dd79f43
The initial patch by bzt with my minor edits. git-svn-id: svn://kolibrios.org@9958 a494cfbc-eb01-0410-851d-a64ba20cac60
566 lines
13 KiB
PHP
566 lines
13 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2022. 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 but they zero out [acpi_dev_size]
|
|
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
|
|
@@:
|
|
|
|
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:
|
|
|
|
mov eax, [LAPIC_BASE]
|
|
test eax, eax
|
|
jnz @f
|
|
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
|