| ; |
| ; Process a PXE interrupt |
| ; |
| section .text16 |
| |
| PXEIRQ_MAX equ 100 ; Max spurious interrupts in a timer tick |
| |
| global pxe_isr |
| pxe_isr: |
| cld |
| pusha |
| push ds |
| push es |
| push fs |
| push gs |
| |
| xor ax,ax |
| mov ds,ax |
| mov es,ax |
| |
| mov bx,PXENV_UNDI_ISR |
| mov di,pxenv_undi_isr_buf |
| |
| mov cx,pxenv_undi_isr_buf.size/2 |
| push di |
| rep stosw |
| pop di |
| |
| mov byte [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_IN_START |
| |
| call pxenv |
| mov ax,[__jiffies] |
| jc .notus |
| |
| cmp word [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_OUT_OURS |
| jne .notus |
| |
| ; Its ours - set the flag for the return to PM. |
| ; We need to EOI this ourselves, so that the |
| ; leftover BC doesn't get control. |
| mov byte [pxe_irq_pending],1 |
| inc dword [pxe_irq_count] |
| |
| cmp byte [pxe_irq_vector], 8 |
| mov al,0x20 ; Non-specific EOI |
| jb .pri_pic |
| |
| out 0xA0, al ; Secondary PIC |
| .pri_pic: |
| out 0x20,al ; Primary PIC |
| |
| mov [pxeirq_last],ax |
| mov word [pxeirq_deadman],PXEIRQ_MAX |
| |
| .exit: |
| pop gs |
| pop fs |
| pop es |
| pop ds |
| popa |
| iret |
| |
| .notus: |
| cmp ax,[pxeirq_last] |
| jne .reset_timeout |
| dec word [pxeirq_deadman] |
| jz .timeout |
| |
| .chain: |
| pop gs |
| pop fs |
| pop es |
| pop ds |
| popa |
| jmp 0:0 |
| global pxe_irq_chain |
| pxe_irq_chain equ $-4 |
| |
| .reset_timeout: |
| mov [pxeirq_last],ax |
| mov word [pxeirq_deadman],PXEIRQ_MAX |
| jmp .chain |
| |
| ; Too many spurious interrupts, shut off the interrupts |
| ; and go to polling mode |
| .timeout: |
| mov al,[pxe_irq_vector] |
| mov dx,21h |
| movzx cx,al |
| shl cx,7-3 |
| add dx,cx |
| and al,7 |
| xchg ax,cx |
| mov ch,1 |
| shl ch,cl |
| in al,dx |
| or al,ch |
| out dx,al |
| or byte [pxe_need_poll],1 |
| jmp .exit |
| |
| |
| ; Emulate a PXE interrupt from the polling thread |
| global pxe_poll |
| pxe_poll: |
| pushf |
| cli |
| cld |
| pusha |
| push ds |
| push es |
| push fs |
| push gs |
| |
| mov bx,PXENV_UNDI_ISR |
| mov di,pxenv_undi_isr_buf |
| |
| mov cx,pxenv_undi_isr_buf.size/2 |
| push di |
| rep stosw |
| pop di |
| |
| mov byte [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_IN_START |
| |
| call pxenv |
| jc .notus |
| |
| cmp word [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_OUT_OURS |
| jne .notus |
| |
| ; Its ours - set the flag for the return to PM. |
| ; We need to EOI this ourselves, so that the |
| ; leftover BC doesn't get control. |
| mov byte [pxe_irq_pending],1 |
| |
| .notus: |
| pop gs |
| pop fs |
| pop es |
| pop ds |
| popa |
| popf |
| ret |
| |
| section .bss16 |
| alignb 4 |
| pxenv_undi_isr_buf: |
| .status: resw 1 |
| .funcflag: resw 1 |
| .bufferlength: resw 1 |
| .framelen: resw 1 |
| .framehdrlen: resw 1 |
| .frame: resw 2 |
| .prottype: resb 1 |
| .pkttype: resb 1 |
| .size equ $-pxenv_undi_isr_buf |
| |
| alignb 4 |
| pxeirq_last resw 1 |
| pxeirq_deadman resw 1 |
| |
| global pxe_irq_count |
| pxe_irq_count resd 1 ; PXE IRQ counter |
| global pxe_irq_vector |
| pxe_irq_vector resb 1 ; PXE IRQ vector |
| global pxe_irq_pending |
| pxe_irq_pending resb 1 ; IRQ pending flag |
| global pxe_need_poll |
| pxe_need_poll resb 1 ; Bit 0 = need polling |
| ; Bit 1 = polling active |
| |
| section .text16 |