Try to HLT the processor during idle
authorH. Peter Anvin <hpa@zytor.com>
Mon, 18 May 2009 20:42:19 +0000 (13:42 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 18 May 2009 20:44:35 +0000 (13:44 -0700)
Try to HLT the processor during idle.  All the events we care about
should have interrupts associated with them, except possibly the
serial console.  Try to deal with the serial console by waiting some
time before going into HLT, and giving the user the option of enabling
the serial console interrupt, on the assumption that the BIOS will
simply IRET.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
14 files changed:
NEWS
core/comboot.inc
core/conio.inc
core/extlinux.asm
core/idle.inc [new file with mode: 0644]
core/isolinux.asm
core/keywords
core/keywords.inc
core/ldlinux.asm
core/parseconfig.inc
core/pxeidle.inc
core/pxelinux.asm
core/ui.inc
doc/syslinux.txt

diff --git a/NEWS b/NEWS
index 5e9be21..c7fddff 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,11 @@ Changes in 3.81:
        * Shuffler: fix bug in real-mode entry.  This affected a
          number of modules, probably in relatively unimportant ways,
          but it completely broke linux.c32.
+       * Improved performance.
+       * Attempt to halt the processor while idle.  This can cause
+         bad reponsiveness when using a serial console especially for
+         automated input; if that ends up being a problem, use the
+         new "NOHALT 1" configuration command.
 
 Changes in 3.80:
        * New shuffler mechanism and API.
index 4db0b3e..bbb0ad7 100644 (file)
@@ -385,24 +385,11 @@ comboot_getchar:
 ;
 ; INT 28h - DOS idle
 ;
-%ifdef HAVE_IDLE
 comboot_int28:
                cli
                cld
-               pushad
-               xor ax,ax
-               push ds
-               push es
-               mov ds,ax
-               mov es,ax
-               DO_IDLE
-               pop es
-               pop ds
-               popad
+               call do_idle
                iret
-%else
-comboot_int28  equ comboot_iret
-%endif
 
 ;
 ; INT 29h - DOS fast write character
@@ -718,22 +705,11 @@ comapi_dnsresolv equ comapi_err
 ;
 ; INT 22h AX=0013h     Idle call
 ;
-;
-; *** FIX THIS ***
-; The idle call seems to have detrimental effects on some machines when
-; called from a COM32 context (WHY?) --  disable it for now.
-; *** IS THIS STILL TRUE? ***
-;
-%ifdef HAVE_IDLE
 comapi_idle:
-               DO_IDLE
+               call do_idle
                clc
                ret
 
-%else
-comapi_idle    equ comapi_err
-%endif
-
 ;
 ; INT 22h AX=0014h     Local boot
 ;
@@ -1061,7 +1037,7 @@ zero_string       db 0                    ; Empty, null-terminated string
 ; in pxe_detect_nic_type
 ;
 feature_flags:
-               db 3                    ; Have local boot, idle is noop
+               db 1                    ; Have local boot, idle is not noop
 feature_flags_len equ ($-feature_flags)
 
 err_notdos     db ': attempted DOS system call INT ',0
index 8f5a292..d1b92f5 100644 (file)
@@ -286,7 +286,7 @@ write_serial_str:
 ;
 pollchar:
                pushad
-               DO_IDLE
+               call do_idle
                mov ah,11h              ; Poll keyboard
                int 16h
                jnz .done               ; Keyboard response
@@ -312,7 +312,7 @@ pollchar:
 ;
 getchar:
 .again:
-               DO_IDLE
+               call do_idle
                mov ah,11h              ; Poll keyboard
                int 16h
                jnz .kbd                ; Keyboard input?
@@ -330,8 +330,10 @@ getchar:
                cmp al,ah
                jne .again
 .serial:       xor ah,ah               ; Avoid confusion
-               xchg dx,bx              ; Data port
+               mov dx,bx               ; Data port
                in al,dx
+               lea dx,[bx+2]           ; DX -> IIR
+               in al,dx                ; Read IIR to discard any IRQ bits
                ret
 .kbd:          mov ah,10h              ; Get keyboard input
                int 16h
@@ -344,7 +346,7 @@ getchar:
                mov bx,KbdMap           ; Convert character sets
                xlatb
 .func_key:
-               RESET_IDLE              ; Character received
+               call reset_idle         ; Character received
                ret
 
 %ifdef DEBUG_TRACERS
@@ -392,6 +394,7 @@ 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
 
 TextAttribute   resb 1                 ; Text attribute for message file
 DisplayMask    resb 1                  ; Display modes mask
index d54bad5..46faac5 100644 (file)
@@ -46,16 +46,6 @@ SYMLINK_SECTORS      equ 2                   ; Max number of sectors in a symlink
 ROOT_DIR_WORD  equ 0x002F
 CUR_DIR_DWORD  equ 0x00002F2E
 
-;
-; This is what we need to do when idle
-;
-%macro RESET_IDLE 0
-       ; Nothing
-%endmacro
-%macro DO_IDLE 0
-       ; Nothing
-%endmacro
-
 ;
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
@@ -891,6 +881,7 @@ build_curdir_str:
 %include "strcpy.inc"           ; strcpy()
 %include "strecpy.inc"          ; strcpy with end pointer check
 %include "cache.inc"           ; Metadata disk cache
+%include "idle.inc"            ; Idle handling
 %include "adv.inc"             ; Auxillary Data Vector
 %include "localboot.inc"       ; Disk-based local boot
 
diff --git a/core/idle.inc b/core/idle.inc
new file mode 100644 (file)
index 0000000..c2ce134
--- /dev/null
@@ -0,0 +1,50 @@
+;; -*- fundamental -*- ---------------------------------------------------
+;;
+;;   Copyright 2008 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., 51 Franklin St, Fifth Floor,
+;;   Boston MA 02110-1301, USA; either version 2 of the License, or
+;;   (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+               section .text
+TICKS_TO_IDLE  equ 4
+
+reset_idle:
+               push ax
+               mov ax,[cs:BIOS_timer]
+               mov [cs:IdleTimer],ax
+               pop ax
+               ret
+
+do_idle:
+               push ax
+               push ds
+               push es
+               mov ax,cs
+               mov ds,ax
+               mov es,ax
+               mov ax,[BIOS_timer]
+               sub ax,[IdleTimer]
+               cmp ax,TICKS_TO_IDLE
+               jb .done
+               call [IdleHook]
+               cmp word [NoHalt],0
+               jne .done
+               hlt
+.done:
+               pop es
+               pop ds
+               pop ax
+.ret:          ret
+
+               section .data
+NoHalt         dw 0
+IdleHook       dw do_idle.ret
+
+               section .bss
+IdleTimer      resw 1
index 62b1a9c..cc97f47 100644 (file)
@@ -39,16 +39,6 @@ SECTOR_SIZE  equ (1 << SECTOR_SHIFT)
 
 ROOT_DIR_WORD  equ 0x002F
 
-;
-; This is what we need to do when idle
-;
-%macro RESET_IDLE 0
-       ; Nothing
-%endmacro
-%macro DO_IDLE 0
-       ; Nothing
-%endmacro
-
 ;
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
@@ -1707,6 +1697,7 @@ getfssec:
 %include "highmem.inc"         ; High memory sizing
 %include "strcpy.inc"          ; strcpy()
 %include "rawcon.inc"          ; Console I/O w/o using the console functions
+%include "idle.inc"            ; Idle handling
 %include "adv.inc"             ; Auxillary Data Vector
 %include "localboot.inc"       ; Disk-based local boot
 
index aeafb96..c289ae2 100644 (file)
@@ -32,6 +32,7 @@ ontimeout
 onerror
 noescape
 nocomplete
+nohalt
 f0
 f1
 f2
index 4923441..d0f7db3 100644 (file)
@@ -77,6 +77,7 @@ keywd_table:
                keyword allowoptions,   pc_setint16,    AllowOptions
                keyword noescape,       pc_setint16,    NoEscape
                keyword nocomplete,     pc_setint16,    NoComplete
+               keyword nohalt,         pc_setint16,    NoHalt
                keyword f1,             pc_filename,    FKeyN(1)
                keyword f2,             pc_filename,    FKeyN(2)
                keyword f3,             pc_filename,    FKeyN(3)
index 4da9c15..ba7e804 100644 (file)
@@ -50,16 +50,6 @@ DIRENT_SIZE  equ (1 << DIRENT_SHIFT)
 
 ROOT_DIR_WORD  equ 0x002F
 
-;
-; This is what we need to do when idle
-;
-%macro RESET_IDLE 0
-       ; Nothing
-%endmacro
-%macro DO_IDLE 0
-       ; Nothing
-%endmacro
-
 ;
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
@@ -1385,6 +1375,7 @@ getfatsector:
 %include "highmem.inc"         ; High memory sizing
 %include "strcpy.inc"           ; strcpy()
 %include "cache.inc"           ; Metadata disk cache
+%include "idle.inc"            ; Idle handling
 %include "adv.inc"             ; Auxillary Data Vector
 %include "localboot.inc"       ; Disk-based local boot
 
index fd1c651..61e7b33 100644 (file)
@@ -178,9 +178,8 @@ pc_include: inc word [IncludeLevel]
 pc_serial:     call getint
                jc .err
                push bx                         ; Serial port #
-               xor ax,ax
-               mov [FlowControl],ax            ; Default to no flow control
-               mov [FlowIgnore],al
+               xor eax,eax
+               mov [FlowControl],eax           ; Default to no flow control
                call skipspace
                jc .nobaud
                call ungetc
@@ -200,7 +199,7 @@ pc_serial:  call getint
                shl bh,4
                mov [FlowIgnore],bh
                mov bh,bl
-               and bx,0F003h                   ; Valid bits
+               and bx,0F00Bh                   ; Valid bits
                mov [FlowControl],bx
                pop ebx                         ; Baud rate
                jmp short .parse_baud
@@ -247,7 +246,8 @@ pc_serial:  call getint
                jne .err                        ; Assume serial port busted
                dec dx
                dec dx                          ; DX -> IER
-               xor al,al                       ; IRQ disable
+               test byte [FlowOutput],8
+               setnz al                        ; Bit 0 -> input available IRQ
                call slow_out
 
                inc dx                          ; DX -> FCR/IIR
@@ -262,8 +262,7 @@ pc_serial:  call getint
 
                inc dx
                inc dx                          ; DX -> MCR
-               in al,dx
-               or al,[FlowOutput]              ; Assert bits
+               mov al,[FlowOutput]             ; Assert bits
                call slow_out
 
                ; Show some life
index 0e0e8b2..f661b57 100644 (file)
@@ -1,6 +1,7 @@
 ;; -*- fundamental -*- ---------------------------------------------------
 ;;
 ;;   Copyright 2008 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
@@ -48,7 +49,7 @@ pxe_detect_nic_type:
                ret
 
 .found_device:
-               and byte [feature_flags],~2
+               mov word [IdleHook],check_for_arp
                jmp .done
 
 ;;
@@ -90,3 +91,34 @@ pxenv_get_nic_type:
 .sdid:         resw 1
 
                section .text
+;
+; Call the receive loop while idle.  This is done mostly so we can respond to
+; ARP messages, but perhaps in the future this can be used to do network
+; console.
+;
+; hpa sez: people using automatic control on the serial port get very
+; unhappy if we poll for ARP too often (the PXE stack is pretty slow,
+; typically.)  Therefore, only poll if at least 4 BIOS timer ticks have
+; passed since the last poll, and reset this when a character is
+; received (call reset_idle).
+;
+; Note: we only do this if pxe_detect_nic_type has set the IdleHook
+; to point to this routine.
+;
+check_for_arp:
+               pushad
+               mov di,packet_buf
+               mov [pxe_udp_read_pkt.buffer],di
+               mov [pxe_udp_read_pkt.buffer+2],ds
+               mov word [pxe_udp_read_pkt.buffersize],packet_buf_size
+               mov eax,[MyIP]
+               mov [pxe_udp_read_pkt.dip],eax
+               mov word [pxe_udp_read_pkt.lport],htons(9)      ; discard port
+               mov di,pxe_udp_read_pkt
+               mov bx,PXENV_UDP_READ
+               call pxenv
+               ; Ignore result...
+               pop es
+               pop ds
+               popad
+               ret
index 3a73e10..ad1686c 100644 (file)
@@ -53,24 +53,6 @@ TFTP_BLOCKSIZE       equ (1 << TFTP_BLOCKSIZE_LG2)
 SECTOR_SHIFT   equ TFTP_BLOCKSIZE_LG2
 SECTOR_SIZE    equ TFTP_BLOCKSIZE
 
-%define HAVE_IDLE 1                    ; idle is not a noop
-
-%if HAVE_IDLE
-%macro RESET_IDLE 0
-       call reset_idle
-%endmacro
-%macro DO_IDLE 0
-       call check_for_arp
-%endmacro
-%else
-%macro RESET_IDLE 0
-       ; Nothing
-%endmacro
-%macro DO_IDLE 0
-       ; Nothing
-%endmacro
-%endif
-
 ;
 ; TFTP operation codes
 ;
@@ -195,7 +177,6 @@ PXEStack    resd 1                  ; Saved stack during PXE call
 RebootTime     resd 1                  ; Reboot timeout, if set by option
 StrucPtr       resd 1                  ; Pointer to PXENV+ or !PXE structure
 APIVer         resw 1                  ; PXE API version found
-IdleTimer      resw 1                  ; Time to check for ARP?
 LocalBootType  resw 1                  ; Local boot return code
 RealBaseMem    resw 1                  ; Amount of DOS memory after freeing
 OverLoad       resb 1                  ; Set if DHCP packet uses "overloading"
@@ -619,7 +600,7 @@ udp_init:
 ; Detect NIC type and initialize the idle mechanism
 ;
                call pxe_detect_nic_type
-               RESET_IDLE
+               call reset_idle
 
 ;
 ; Now we're all set to start with our *real* business. First load the
@@ -2546,64 +2527,6 @@ genipopt:
                popad
                ret
 
-;
-; Call the receive loop while idle.  This is done mostly so we can respond to
-; ARP messages, but perhaps in the future this can be used to do network
-; console.
-;
-; hpa sez: people using automatic control on the serial port get very
-; unhappy if we poll for ARP too often (the PXE stack is pretty slow,
-; typically.)  Therefore, only poll if at least 4 BIOS timer ticks have
-; passed since the last poll, and reset this when a character is
-; received (RESET_IDLE).
-;
-; Note: we only do this if pxe_detect_nic_type has cleared the
-; "idle is noop" bit in feature_flags.
-;
-%if HAVE_IDLE
-
-reset_idle:
-               push ax
-               mov ax,[cs:BIOS_timer]
-               mov [cs:IdleTimer],ax
-               pop ax
-               ret
-
-check_for_arp:
-               test byte [cs:feature_flags],2
-               jnz .ret
-               push ax
-               mov ax,[cs:BIOS_timer]
-               sub ax,[cs:IdleTimer]
-               cmp ax,4
-               pop ax
-               jae .need_poll
-.ret:          ret
-.need_poll:    pushad
-               push ds
-               push es
-               mov ax,cs
-               mov ds,ax
-               mov es,ax
-               mov di,packet_buf
-               mov [pxe_udp_read_pkt.buffer],di
-               mov [pxe_udp_read_pkt.buffer+2],ds
-               mov word [pxe_udp_read_pkt.buffersize],packet_buf_size
-               mov eax,[MyIP]
-               mov [pxe_udp_read_pkt.dip],eax
-               mov word [pxe_udp_read_pkt.lport],htons(9)      ; discard port
-               mov di,pxe_udp_read_pkt
-               mov bx,PXENV_UDP_READ
-               call pxenv
-               ; Ignore result...
-               pop es
-               pop ds
-               popad
-               RESET_IDLE
-               ret
-
-%endif ; HAVE_IDLE
-
 ; -----------------------------------------------------------------------------
 ;  Common modules
 ; -----------------------------------------------------------------------------
@@ -2624,7 +2547,8 @@ writestr_early    equ writestr
 %include "strcpy.inc"          ; strcpy()
 %include "rawcon.inc"          ; Console I/O w/o using the console functions
 %include "dnsresolv.inc"       ; DNS resolver
-%include "pxeidle.inc"         ; Idle mechanism
+%include "idle.inc"            ; Idle handling
+%include "pxeidle.inc"         ; PXE-specific idle mechanism
 %include "adv.inc"             ; Auxillary Data Vector
 
 ; -----------------------------------------------------------------------------
index c85383a..a12233c 100644 (file)
@@ -523,7 +523,7 @@ kernel_corrupt: mov si,err_notkernel
 ;
 getchar_timeout:
                call vgashowcursor
-               RESET_IDLE
+               call reset_idle
 
 .loop:
                push word [BIOS_timer]
@@ -532,7 +532,7 @@ getchar_timeout:
                pop ax
                cmp ax,[BIOS_timer]             ; Has the timer advanced?
                je .loop
-               DO_IDLE
+               call do_idle
 
                dec dword [ThisKbdTo]
                jz .timeout
index 9414141..f654bff 100644 (file)
@@ -339,6 +339,7 @@ SERIAL port [[baudrate] flowcontrol]
        "flowcontrol" is a combination of the following bits:
        0x001 - Assert DTR
        0x002 - Assert RTS
+       0x008 - Enable interrupts
        0x010 - Wait for CTS assertion
        0x020 - Wait for DSR assertion
        0x040 - Wait for RI assertion
@@ -366,6 +367,17 @@ SERIAL port [[baudrate] flowcontrol]
        ports detected by the BIOS.  They may or may not correspond to
        the legacy port values 0x3F8, 0x2F8, 0x3E8, 0x2E8.
 
+       Enabling interrupts (setting the 0x008 bit) may give better
+       responsiveness without setting the NOHALT option, but could
+       potentially cause problems with buggy BIOSes.
+
+NOHALT flag_val
+       If flag_val is 1, don't halt the processor while idle.
+       Halting the processor while idle significantly reduces the
+       power consumption, but can cause poor responsiveness to the
+       serial console, especially when using scripts to drive the
+       serial console, as opposed to human interaction.
+
 CONSOLE flag_val
        If flag_val is 0, disable output to the normal video console.
        If flag_val is 1, enable output to the video console (this is