From: H. Peter Anvin Date: Mon, 18 May 2009 20:42:19 +0000 (-0700) Subject: Try to HLT the processor during idle X-Git-Tag: syslinux-3.81-pre4^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4826c90afd85d3bc8ee963de0bf1438340db865a;p=platform%2Fupstream%2Fsyslinux.git Try to HLT the processor during idle 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 --- diff --git a/NEWS b/NEWS index 5e9be21..c7fddff 100644 --- 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. diff --git a/core/comboot.inc b/core/comboot.inc index 4db0b3e..bbb0ad7 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -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 diff --git a/core/conio.inc b/core/conio.inc index 8f5a292..d1b92f5 100644 --- a/core/conio.inc +++ b/core/conio.inc @@ -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 diff --git a/core/extlinux.asm b/core/extlinux.asm index d54bad5..46faac5 100644 --- a/core/extlinux.asm +++ b/core/extlinux.asm @@ -47,16 +47,6 @@ 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 ; Since there is no room in the bottom 64K for all of these, we @@ -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 index 0000000..c2ce134 --- /dev/null +++ b/core/idle.inc @@ -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 diff --git a/core/isolinux.asm b/core/isolinux.asm index 62b1a9c..cc97f47 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -40,16 +40,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 ; Since there is no room in the bottom 64K for all of these, we @@ -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 diff --git a/core/keywords b/core/keywords index aeafb96..c289ae2 100644 --- a/core/keywords +++ b/core/keywords @@ -32,6 +32,7 @@ ontimeout onerror noescape nocomplete +nohalt f0 f1 f2 diff --git a/core/keywords.inc b/core/keywords.inc index 4923441..d0f7db3 100644 --- a/core/keywords.inc +++ b/core/keywords.inc @@ -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) diff --git a/core/ldlinux.asm b/core/ldlinux.asm index 4da9c15..ba7e804 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -51,16 +51,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 ; Since there is no room in the bottom 64K for all of these, we @@ -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 diff --git a/core/parseconfig.inc b/core/parseconfig.inc index fd1c651..61e7b33 100644 --- a/core/parseconfig.inc +++ b/core/parseconfig.inc @@ -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 diff --git a/core/pxeidle.inc b/core/pxeidle.inc index 0e0e8b2..f661b57 100644 --- a/core/pxeidle.inc +++ b/core/pxeidle.inc @@ -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 diff --git a/core/pxelinux.asm b/core/pxelinux.asm index 3a73e10..ad1686c 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -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 ; ----------------------------------------------------------------------------- diff --git a/core/ui.inc b/core/ui.inc index c85383a..a12233c 100644 --- a/core/ui.inc +++ b/core/ui.inc @@ -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 diff --git a/doc/syslinux.txt b/doc/syslinux.txt index 9414141..f654bff 100644 --- a/doc/syslinux.txt +++ b/doc/syslinux.txt @@ -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