0,0 → 1,487 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2007-2008. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
IRQ_RESERVE = 24 ; 16 or 24 |
|
iglobal |
IRQ_COUNT dd 16 |
endg |
|
uglobal |
APIC: dd 0 |
LAPIC_BASE: dd 0 |
IOAPIC_base: dd 0 |
endg |
|
APIC_ID equ 0x20 |
APIC_TPR equ 0x80 |
APIC_EOI equ 0xb0 |
APIC_LDR equ 0xd0 |
APIC_DFR equ 0xe0 |
APIC_SVR equ 0xf0 |
APIC_ISR equ 0x100 |
APIC_ESR equ 0x280 |
APIC_ICRL equ 0x300 |
APIC_ICRH equ 0x310 |
APIC_LVT_LINT0 equ 0x350 |
APIC_LVT_LINT1 equ 0x360 |
APIC_LVT_err equ 0x370 |
|
; APIC timer |
APIC_LVT_timer equ 0x320 |
APIC_timer_div equ 0x3e0 |
APIC_timer_init equ 0x380 |
APIC_timer_cur equ 0x390 |
; IOAPIC |
IOAPIC_ID equ 0x0 |
IOAPIC_VER equ 0x1 |
IOAPIC_ARB equ 0x2 |
IOAPIC_REDTBL equ 0x10 |
|
APIC_init: |
mov dword[APIC], 0 |
; jmp .no_apic ; NO APIC |
bt [cpu_caps], CAPS_APIC |
jnc .no_apic |
; Check for MP table |
;..... |
|
call IRQ_mask_all |
|
; IOAPIC init |
; 0xfec00000 - may be relocated, see chip reference... & MP table |
stdcall map_io_mem, 0xfec00000, 0x20, PG_SW |
mov [IOAPIC_base], eax |
|
mov eax, IOAPIC_VER |
call IOAPIC_read |
shr eax, 16 |
inc al |
movzx eax, al |
cmp al, IRQ_RESERVE |
jbe @f |
mov al, IRQ_RESERVE |
@@: mov [IRQ_COUNT], eax |
|
; Reroute IOAPIC & mask all interrupts |
xor ecx, ecx |
mov eax, IOAPIC_REDTBL |
@@: mov ebx, eax |
call IOAPIC_read |
mov ah, 0x09 ; Delivery Mode: Lowest Priority, Destination Mode: Logical |
mov al, cl |
add al, 0x20 ; vector |
or eax, 0x10000 ; Mask Interrupt |
cmp ecx, 16 |
jb .set |
or eax, 0xa000 ;<<< level-triggered active-low for IRQ16+ |
.set: |
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] |
jb @b |
|
call LAPIC_init |
|
mov dword[APIC], 0xffffffff |
; mov dword[irq_type_to_set], IRQ_TYPE_APIC |
.no_apic: |
ret |
|
;=========================================================== |
align 4 |
LAPIC_init: |
; Check MSR support |
;.... |
; Get LAPIC base address |
mov ecx, 0x1b |
rdmsr ; it may be replaced to |
and ax, 0xf000 ; mov eax, 0xfee00000 |
|
stdcall map_io_mem, eax, 0x1000, PG_SW |
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 |
|
ret |
;=========================================================== |
; IOAPIC implementation |
align 4 |
IOAPIC_read: |
; in : EAX - IOAPIC register |
; out: EAX - readed value |
push esi |
mov esi, [IOAPIC_base] |
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_base] |
mov [esi], eax |
mov [esi + 0x10], ebx |
pop esi |
ret |
;=========================================================== |
; Remap all IRQ to 0x20+ Vectors |
; IRQ0 to vector 0x20, IRQ1 to vector 0x21.... |
PIC_init: |
cli |
mov al,0x11 ; icw4, edge triggered |
out 0x20,al |
call pic_delay |
out 0xA0,al |
call pic_delay |
|
mov al,0x20 ; generate 0x20 + |
out 0x21,al |
call pic_delay |
mov al,0x28 ; generate 0x28 + |
out 0xA1,al |
call pic_delay |
|
mov al,0x04 ; slave at irq2 |
out 0x21,al |
call pic_delay |
mov al,0x02 ; at irq9 |
out 0xA1,al |
call pic_delay |
|
mov al,0x01 ; 8086 mode |
out 0x21,al |
call pic_delay |
out 0xA1,al |
call pic_delay |
|
call IRQ_mask_all |
cli |
; mov dword[irq_type_to_set], IRQ_TYPE_PIC |
ret |
|
; ----------------------------------------- |
pic_delay: |
jmp pdl1 |
pdl1: ret |
|
; ----------------------------------------- |
; TIMER SET TO 1/100 S |
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 |
|
; ----------------------------------------- |
unmask_timer: |
test dword[APIC], 0xffffffff |
jnz @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 |
IRQ_mask_all: |
test dword[APIC], 0xffffffff |
jnz .APIC |
mov al, 0xFF |
out 0x21, al |
out 0xA1, al |
mov ecx,0x1000 |
cld |
@@: call pic_delay |
loop @b |
ret |
.APIC: |
mov ecx, [IRQ_COUNT] |
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 |
ret |
; ----------------------------------------- |
; End Of Interrupt |
; al - IRQ number |
align 16 |
IRQ_EOI: |
test dword[APIC], 0xffffffff |
jnz .APIC |
cmp al, 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] |
test dword[APIC], 0xffffffff |
jnz .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: |
shl ebx, 1 |
add ebx, 0x10 |
mov eax, ebx |
call IOAPIC_read |
and eax, 0xfffeffff ; bit 16 |
xchg eax, ebx |
call IOAPIC_write |
ret |
endp |
|
|
|
; IRQ_TYPE_DISABLE equ 0 |
; IRQ_TYPE_PIC equ 1 |
; IRQ_TYPE_APIC equ 2 |
|
; uglobal |
; irq_type_to_set rd 1 |
; irq_types rd IRQ_RESERVE |
; endg |
|
; ----------------------------------------- |
; End Of Interrupt |
; al - IRQ number |
; align 16 |
; IRQ_EOI: |
; movzx eax, al |
; cmp dword[irq_types + eax * 4], IRQ_TYPE_APIC |
; jne @f |
; mov eax, [LAPIC_BASE] |
; mov dword [eax + APIC_EOI], 0 ; EOI |
; ret |
; @@: |
; cmp al, 8 |
; mov al, 0x20 |
; jb @f |
; out 0xa0, al |
; @@: out 0x20, al |
; ret |
|
; align 4 |
; proc enable_irq stdcall, irq_line:dword |
; cmp dword[irq_type_to_set], IRQ_TYPE_APIC |
; jne @f |
; stdcall APIC_enable_irq, [irq_line] |
; ret |
; @@: stdcall PIC_enable_irq, [irq_line] |
; ret |
; endp |
|
; align 4 |
; proc disable_irq stdcall, irq_line:dword |
; push eax |
; mov eax, [irq_line] |
; cmp dword[irq_types + eax * 4], IRQ_TYPE_APIC |
; jne @f |
; stdcall APIC_disable_irq, eax |
; pop eax |
; ret |
; @@: stdcall PIC_disable_irq, eax |
; pop eax |
; ret |
; endp |
|
; align 4 |
; proc PIC_enable_irq stdcall, irq_line:dword |
; pusha |
; mov ebx, [irq_line] |
; mov eax, [irq_types + ebx * 4] |
; cmp eax, IRQ_TYPE_DISABLE |
; je @f |
; cmp eax, IRQ_TYPE_PIC |
; je @f |
; stdcall disable_irq, ebx |
; @@: mov dword[irq_types + ebx * 4], IRQ_TYPE_PIC |
; mov edx, 0x21 |
; cmp ebx, 8 |
; jb @F |
; mov edx, 0xA1 |
; sub ebx,8 |
; @@: in al,dx |
; btr eax, ebx |
; out dx, al |
; popa |
; ret |
; endp |
|
; align 4 |
; proc PIC_disable_irq stdcall, irq_line:dword |
; pusha |
; mov ebx, [irq_line] |
; mov dword[irq_types + ebx * 4], IRQ_TYPE_DISABLE |
; mov edx, 0x21 |
; cmp ebx, 8 |
; jb @F |
; mov edx, 0xA1 |
; sub ebx,8 |
; @@: in al,dx |
; bts eax, ebx |
; out dx, al |
; popa |
; ret |
; endp |
|
; align 4 |
; proc APIC_enable_irq stdcall, irq_line:dword |
; pusha |
; mov ebx, [irq_line] |
; mov eax, [irq_types + ebx * 4] |
; cmp eax, IRQ_TYPE_DISABLE |
; je @f |
; cmp eax, IRQ_TYPE_APIC |
; je @f |
; stdcall disable_irq, ebx |
; @@: mov dword[irq_types + ebx * 4], IRQ_TYPE_APIC |
; shl ebx, 1 |
; add ebx, 0x10 |
; mov eax, ebx |
; call IOAPIC_read |
; and eax, 0xfffeffff ; bit 16 |
; xchg eax, ebx |
; call IOAPIC_write |
; popa |
; ret |
; endp |
|
; align 4 |
; proc APIC_disable_irq stdcall, irq_line:dword |
; pusha |
; mov ebx, [irq_line] |
; mov dword[irq_types + ebx * 4], IRQ_TYPE_DISABLE |
; shl ebx, 1 |
; add ebx, 0x10 |
; mov eax, ebx |
; call IOAPIC_read |
; or eax, 0x10000 |
; xchg eax, ebx |
; call IOAPIC_write |
; popa |
; ret |
; endp |