core: add a proper interrupt handler for the serial console
authorH. Peter Anvin <hpa@zytor.com>
Sun, 24 May 2009 00:37:18 +0000 (17:37 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sun, 24 May 2009 00:37:18 +0000 (17:37 -0700)
If we enable interrupts for the serial console, add a proper interrupt
handler.  Since we don't know what vector we'll end up using, or if we
are shared with other devices, simply hook *all* the interrupts and
poll the serial port then.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
core/bcopy32.inc
core/cleanup.inc
core/conio.inc
core/head.inc
core/io.inc [new file with mode: 0644]
core/layout.inc
core/parseconfig.inc

index c715557..3df69f8 100644 (file)
@@ -189,14 +189,6 @@ simple_pm_call:
 ;
 ; We typically toggle A20 twice for every 64K transferred.
 ;
-%define IO_DELAY_PORT  80h             ; Invalid port (we hope!)
-
-slow_out:      out dx, al              ; Fall through
-
-%macro io_delay 0
-               out IO_DELAY_PORT,al
-               out IO_DELAY_PORT,al
-%endmacro
 
                section .data
                alignz 2
index 1b00e0b..063ed73 100644 (file)
@@ -49,6 +49,7 @@ cleanup_hardware:
                int 10h
 .no_vmware:
 %endif
-
                popad
-               ret
+
+               ; If we enabled serial port interrupts, clean them up now
+               jmp sirq_cleanup
index 4488c94..16c39c6 100644 (file)
@@ -261,7 +261,7 @@ write_serial:
 
                xchg dx,bx                      ; DX -> THR
                pop ax
-               call slow_out                   ; Send data
+               slow_out dx,al                  ; Send data
 .noserial:     popad
                popfd
 .end:          ret
@@ -294,10 +294,14 @@ pollchar:
                mov dx,[SerialPort]
                and dx,dx
                jz .done                ; No serial port -> no input
-               add dx,byte 5           ; DX -> LSR
+               mov ax,[SerialTail]     ; Already-queued input?
+               cli
+               cmp ax,[SerialHead]
+               jne .done_sti           ; If so, return ZF = 0
+               add dx,5                ; DX -> LSR
                in al,dx
                test al,1               ; ZF = 0 if data pending
-               jz .done
+               jz .done_sti
                inc dx                  ; DX -> MSR
                mov ah,[FlowIgnore]     ; Required status bits
                in al,dx
@@ -305,12 +309,15 @@ pollchar:
                cmp al,ah
                setne al
                dec al                  ; Set ZF = 0 if equal
+.done_sti:     sti
 .done:         popad
                ret
 
 ;
 ; getchar: Read a character from keyboard or serial port
 ;
+getchar.sti_again:
+               sti
 getchar:
 .again:
                call do_idle
@@ -320,20 +327,38 @@ getchar:
                mov bx,[SerialPort]
                and bx,bx
                jz .again
+               mov ax,[SerialTail]
+               cli
+               cmp ax,[SerialHead]
+               jne .serial_queued
                lea dx,[bx+5]           ; DX -> LSR
                in al,dx
                test al,1
-               jz .again
+               jz .sti_again
                inc dx                  ; DX -> MSR
                mov ah,[FlowIgnore]
                in al,dx
                and al,ah
                cmp al,ah
-               jne .again
+               jne .sti_again
 .serial:       xor ah,ah               ; Avoid confusion
                mov dx,bx               ; Data port
                in al,dx                ; Read data
-               ret
+               sti
+               jmp .done
+.serial_queued:
+               sti                     ; We already know we'll consume data
+               xchg bx,ax
+               push ds
+               mov ax,aux_seg + (aux.serial >> 4)
+               mov ds,ax
+               mov al,[bx]
+               pop ds
+               inc bx
+               and bx,serial_buf_size-1
+               mov [SerialTail],bx
+               jmp .done
+
 .kbd:          mov ah,10h              ; Get keyboard input
                int 16h
                cmp al,0E0h
@@ -345,8 +370,8 @@ getchar:
                mov bx,KbdMap           ; Convert character sets
                xlatb
 .func_key:
-               call reset_idle         ; Character received
-               ret
+.done:
+               jmp reset_idle          ; Character received
 
 %ifdef DEBUG_TRACERS
 ;
@@ -387,13 +412,20 @@ ScreenSize      equ $
 VidCols         resb 1                 ; Columns on screen-1
 VidRows         resb 1                 ; Rows on screen-1
 
-; Serial console stuff...
-BaudDivisor    resw 1                  ; Baud rate divisor
+; Serial console stuff; don't put this in .config becasue we don't want
+; loading a new config file to undo this setting.
+               section .data
+               alignz 4
+SerialPort     dw 0                    ; Serial port base (or 0 for no serial port)
+BaudDivisor    dw 115200/9600          ; Baud rate divisor
 FlowControl    equ $
-FlowOutput     resb 1                  ; Outputs to assert for serial flow
-FlowInput      resb 1                  ; Input bits for serial flow
-FlowIgnore     resb 1                  ; Ignore input unless these bits set
-FlowDummy      resb 1                  ; Unused
+FlowOutput     db 0                    ; Outputs to assert for serial flow
+FlowInput      db 0                    ; Input bits for serial flow
+FlowIgnore     db 0                    ; Ignore input unless these bits set
+FlowDummy      db 0                    ; Unused
 
+               section .bss
 TextAttribute   resb 1                 ; Text attribute for message file
 DisplayMask    resb 1                  ; Display modes mask
+
+%include "serirq.inc"
index 37f1b36..7117b4e 100644 (file)
@@ -27,5 +27,6 @@
 %include "bios.inc"
 %include "tracers.inc"
 %include "stack.inc"
+%include "io.inc"
 
 %endif ; _HEAD_INC
diff --git a/core/io.inc b/core/io.inc
new file mode 100644 (file)
index 0000000..7161346
--- /dev/null
@@ -0,0 +1,35 @@
+;; -----------------------------------------------------------------------
+;;
+;;   Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;;   This program is free software; you can redistribute it and/or modify
+;;   it under the terms of the GNU General Public License as published by
+;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;;   Boston MA 02111-1307, USA; either version 2 of the License, or
+;;   (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; io.inc
+;;
+;; I/O related macros
+;;
+
+%ifndef _IO_INC
+%define _IO_INC
+
+%define IO_DELAY_PORT  80h             ; Invalid port (we hope!)
+
+%macro io_delay 0.nolist
+               out IO_DELAY_PORT,al
+               out IO_DELAY_PORT,al
+%endmacro
+
+%macro slow_out 2.nolist
+               out %1,%2
+               io_delay
+%endmacro
+
+%endif ; _IO_INC
index 8d56745..8c2e248 100644 (file)
@@ -93,11 +93,15 @@ RBFG_brainfuck:     resb 2048               ; Bigger than an Ethernet packet...
 xfer_buf_seg   equ 1000h
 aux_seg                equ 2000h
 
+serial_buf_size        equ 4096                ; Should be a power of 2
+
 ;
 ; Contents of aux_seg
 ;
                struc aux
 .fontbuf       resb 8192
+.serial                resb serial_buf_size
+
                alignb 4096             ; Align the next segment to 4K
                endstruc
 
index 61e7b33..efa41d1 100644 (file)
@@ -224,46 +224,48 @@ pc_serial:        call getint
                ;
                ; Begin code to actually set up the serial port
                ;
+               call sirq_cleanup               ; Cleanup existing IRQ handler
+
                lea dx,[di+3]                   ; DX -> LCR
                mov al,83h                      ; Enable DLAB
-               call slow_out
+               slow_out dx,al
 
                pop ax                          ; Divisor
                mov dx,di                       ; DX -> LS
-               call slow_out
+               slow_out dx,al
 
                inc dx                          ; DX -> MS
                mov al,ah
-               call slow_out
+               slow_out dx,al
 
                mov al,03h                      ; Disable DLAB
                inc dx                          ; DX -> LCR
                inc dx
-               call slow_out
-
-               in al,dx                        ; Read back LCR (detect missing hw)
-               cmp al,03h                      ; If nothing here we'll read 00 or FF
-               jne .err                        ; Assume serial port busted
-               dec dx
-               dec dx                          ; DX -> IER
-               test byte [FlowOutput],8
-               setnz al                        ; Bit 0 -> input available IRQ
-               call slow_out
-
-               inc dx                          ; DX -> FCR/IIR
+               slow_out dx,al
+
+               in al,dx                ; Read back LCR (detect missing hw)
+               cmp al,03h              ; If nothing here we'll read 00 or FF
+               jne .err                ; Assume serial port busted
+               dec dx                          ; DX -> IIR/FCR
                mov al,01h
-               call slow_out                   ; Enable FIFOs if present
+               slow_out dx,al                  ; Enable FIFOs if present
                in al,dx
                cmp al,0C0h                     ; FIFOs enabled and usable?
                jae .fifo_ok
                xor ax,ax                       ; Disable FIFO if unusable
-               call slow_out
+               slow_out dx,al
 .fifo_ok:
 
                inc dx
                inc dx                          ; DX -> MCR
                mov al,[FlowOutput]             ; Assert bits
-               call slow_out
+               slow_out dx,al
+
+               ; Enable interrupts if requested
+               test al,8
+               jz .noirq
+               call sirq_install
+.noirq:
 
                ; Show some life
                cmp byte [SerialNotice],0
@@ -461,7 +463,6 @@ AllowImplicit   dw 1                    ; Allow implicit kernels
 AllowOptions   dw 1                    ; User-specified options allowed
 IncludeLevel   dw 1                    ; Nesting level
 DefaultLevel   dw 0                    ; The current level of default
-SerialPort     dw 0                    ; Serial port base (or 0 for no serial port)
 VKernel                db 0                    ; Have we seen any "label" statements?
 
 %if IS_PXELINUX