The great graphics merge! We're now officially working on version 1.60.
authorhpa <hpa>
Thu, 5 Apr 2001 06:20:43 +0000 (06:20 +0000)
committerhpa <hpa>
Thu, 5 Apr 2001 06:20:43 +0000 (06:20 +0000)
Makefile
Makefile.private
NEWS
ldlinux.asm
ppmtolss16 [new file with mode: 0755]
pxelinux.asm
sample/Makefile [new file with mode: 0644]
sample/sample.msg [new file with mode: 0644]
sample/syslogo.png [new file with mode: 0644]
syslinux.doc
version

index acf1371..37a0c25 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ SOURCES = ldlinux.asm syslinux.asm syslinux.c copybs.asm \
          pxelinux.asm pxe.inc mbr.asm gethostip.c
 BTARGET = bootsect.bin ldlinux.sys ldlinux.bin ldlinux.lst pxelinux.0 mbr.bin
 ITARGET = syslinux.com syslinux copybs.com gethostip
-DOCS    = COPYING NEWS README TODO *.doc
+DOCS    = COPYING NEWS README TODO *.doc sample
 OTHER   = Makefile bin2c.pl now.pl genstupid.pl keytab-lilo.pl version \
          sys2ansi.pl
 OBSOLETE = pxelinux.bin
@@ -44,12 +44,15 @@ OBSOLETE = pxelinux.bin
 # Things to install in /usr/bin
 INSTALL_BIN = syslinux gethostip
 
-all:   $(BTARGET) $(ITARGET)
+all:   $(BTARGET) $(ITARGET) samples
        ls -l $(BTARGET) $(ITARGET)
 
-installer: $(ITARGET)
+installer: $(ITARGET) samples
        ls -l $(BTARGET) $(ITARGET)
 
+samples:
+       $(MAKE) -C sample all
+
 # The DATE is set on the make command line when building binaries for
 # official release.  Otherwise, substitute a hex string that is pretty much
 # guaranteed to be unique to be unique from build to build.
@@ -116,6 +119,7 @@ tidy:
 
 clean: tidy
        rm -f $(ITARGET)
+       $(MAKE) -C sample clean
 
 dist: tidy
        rm -f *~ \#* core
index 97c7418..56412c2 100644 (file)
@@ -30,7 +30,7 @@ release:
        -rm -rf release/syslinux-$(VERSION)
        -rm -f release/syslinux-$(VERSION).*
        mkdir -p release/syslinux-$(VERSION)
-       cp $(SOURCES) $(DOCS) $(OTHER) release/syslinux-$(VERSION)
+       cp -r $(SOURCES) $(DOCS) $(OTHER) release/syslinux-$(VERSION)
        ln $(PRIVATE) release/syslinux-$(VERSION)
        cd release/syslinux-$(VERSION) && $(MAKE) official
        cd release/syslinux-$(VERSION) && rm -f $(PRIVATE)
@@ -50,7 +50,7 @@ prerel:
        -rm -rf $(PRERELDIR)/$(PREREL)
        -rm -f $(PRERELDIR)/$(PREREL).*
        mkdir -p $(PRERELDIR)/$(PREREL)
-       cp $(SOURCES) $(DOCS) $(OTHER) $(PRERELDIR)/$(PREREL)
+       cp -r $(SOURCES) $(DOCS) $(OTHER) $(PRERELDIR)/$(PREREL)
        make -C $(PRERELDIR)/$(PREREL) spotless
        make -C $(PRERELDIR)/$(PREREL) all DATE=`printf '%s-pre%d          ' $(VERSION) $(PRERELNO) | dd bs=10 count=1 2>/dev/null`
        make -C $(PRERELDIR)/$(PREREL) dist
diff --git a/NEWS b/NEWS
index 9c0e90d..cce8d88 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
 Starting with 1.47, changes marked with SYSLINUX/PXELINUX apply to
 that specific program only; other changes apply to both.
 
+Changes in 1.60:
+       * Add support for graphical splash screens.
+
 Changes in 1.54:
        * PXELINUX: Fix code for finding !PXE from PXENV+.  This was
          due to a spec bug; match the most recent spec since that
index e701b38..12ab164 100644 (file)
@@ -152,7 +152,7 @@ vk_end:             equ $                   ; Should be <= vk_size
 ; 7000h - real_mode_seg
 ;
 fat_seg                equ 5000h               ; 128K area for FAT (2x64K)
-vk_seg          equ 4000h              ; This is where we stick'em
+vk_seg          equ 4000h              ; Virtual kernels
 xfer_buf_seg   equ 3000h               ; Bounce buffer for I/O to high mem
 comboot_seg    equ 2000h               ; COMBOOT image loading zone
 
@@ -245,7 +245,20 @@ trackbuf   equ $                   ; Track buffer goes here
 trackbufsize   equ 16384               ; Safe size of track buffer
 ;              trackbuf ends at 5000h
 
-                absolute 6000h          ; Here we keep our BSS stuff
+
+;
+; Constants for the xfer_buf_seg
+;
+; The xfer_buf_seg is also used to store message file buffers.  We
+; need two trackbuffers (text and graphics), plus a work buffer
+; for the graphics decompressor.
+;
+xbs_textbuf    equ 0                   ; Also hard-coded, do not change
+xbs_vgabuf     equ trackbufsize
+xbs_vgatmpbuf  equ 2*trackbufsize
+
+
+                absolute 5000h          ; Here we keep our BSS stuff
 StackBuf       equ $                   ; Start the stack here (grow down - 4K)
 VKernelBuf:    resb vk_size            ; "Current" vkernel
                alignb 4
@@ -298,6 +311,10 @@ SetupSecs  resw 1                  ; Number of setup sectors
 SavedSP                resw 1                  ; Our SP while running a COMBOOT image
 A20Test                resw 1                  ; Counter for testing status of A20
 CmdLineLen     resw 1                  ; Length of command line including null
+GraphXSize     resw 1                  ; Width of splash screen file
+VGAPos         resw 1                  ; Pointer into VGA memory
+VGACluster     resw 1                  ; Cluster pointer for VGA image file
+VGAFilePtr     resw 1                  ; Pointer into VGAFileBuf
 TextAttrBX      equ $
 TextAttribute   resb 1                 ; Text attribute for message file
 TextPage        resb 1                 ; Active display page
@@ -316,6 +333,10 @@ MNameBuf        resb 11                    ; Generic mangled file name buffer
 InitRD          resb 11                 ; initrd= mangled name
 KernelCName     resb 13                 ; Unmangled kernel name
 InitRDCName     resb 13                ; Unmangled initrd name
+TextColorReg   resb 17                 ; VGA color registers for text mode
+VGAFileBuf     resb 13                 ; Unmangled VGA image name
+VGAFileBufEnd  equ $
+VGAFileMBuf    resb 11                 ; Mangled VGA image name
 
                section .text
                 org 7C00h
@@ -1117,6 +1138,25 @@ is_486:
 ; Initialization that does not need to go into the any of the pre-load
 ; areas
 ;
+
+               ; Get ROM 8x16 font in case we switch to graphics mode
+               xor cx,cx
+               mov ax,1130h
+               mov bh,6                        ; Get ROM 8x16 font
+               int 10h
+               push es
+               pop fs
+               push ds
+               pop es
+               cmp cx,16
+               jne not_vga                     ; If not VGA we don't care
+               mov si,bp
+               mov di,vgafontbuf
+               mov cx,(16*256) >> 2
+               fs rep movsd
+not_vga:
+
+               ; Now set up screen parameters
                call adjust_screen
 ;
 ; Now, everything is "up and running"... patch kaboom for more
@@ -1406,7 +1446,9 @@ clear_buffer:     mov ah,1                        ; Check for pending char
                xor ax,ax                       ; Get char
                int 16h
                jmp short clear_buffer
-get_char_time: mov cx,[KbdTimeOut]
+get_char_time: 
+               call vgashowcursor
+               mov cx,[KbdTimeOut]
                and cx,cx
                jz get_char                     ; Timeout == 0 -> no timeout
                inc cx                          ; The first loop will happen
@@ -1423,10 +1465,14 @@ tick_loop:      push dx
                je tick_loop
                pop cx
                loop time_loop                  ; If so, decrement counter
+               call vgahidecursor
                jmp command_done                ; Timeout!
 
 get_char_pop:  pop eax                         ; Clear stack
-get_char:      call getchar
+get_char:
+               call vgashowcursor
+               call getchar
+               call vgahidecursor
                and al,al
                jz func_key
 
@@ -2070,6 +2116,8 @@ high_load_done:
 
                mov si,ready_msg
                call cwritestr
+
+               call vgaclearmode               ; We can't trust ourselves after this
 ;
 ; Now, if we were supposed to load "low", copy the kernel down to 10000h
 ; and the real mode stuff to 90000h.  We assume that all bzImage kernels are
@@ -2294,6 +2342,8 @@ comboot_end_cmd: mov al,0Dh               ; CR after last character
                sub al,cl
                mov [es:80h], al        ; Store command line length
 
+               call vgaclearmode       ; Reset video
+
                mov ax,es
                mov ds,ax
                mov ss,ax
@@ -2370,6 +2420,8 @@ load_bootsec:
 ;
 ; Okay, here we go... copy over our own boot sector and run the new one
 ;
+               call vgaclearmode       ; Reset video
+
                cli                     ; Point of no return
        
                mov dl,[bsDriveNumber]  ; May not be in new bootsector!
@@ -2912,7 +2964,7 @@ loadfont:
                jne bf_ret
 
                mov al,[trackbuf+2]             ; File mode
-               cmp al,3                        ; Font modes 0-3 supported
+               cmp al,5                        ; Font modes 0-5 supported
                ja bf_ret
 
                mov bh,byte [trackbuf+3]        ; Height of font
@@ -2921,8 +2973,18 @@ loadfont:
                cmp bh,32                       ; VGA maximum
                ja bf_ret
 
-               mov bp,trackbuf+4               ; Address of font data
-               xor bl,bl
+               ; Copy to font buffer
+               mov si,trackbuf+4               ; Start of font data
+               mov [VGAFontSize],bh
+               mov di,vgafontbuf
+               mov bp,di                       ; Address of font data for INT 10h
+               mov cx,(32*256) >> 2            ; Maximum size
+               rep movsd
+
+               xor bl,bl                       ; Needed by both INT 10h calls
+               cmp [UsingVGA], byte 1          ; Are we in graphics mode?
+               je .graphics
+
                mov cx,256
                xor dx,dx
                mov ax,1110h
@@ -2934,6 +2996,18 @@ loadfont:
 
                jmp short adjust_screen
 
+.graphics:
+               ; CX = 0 on entry
+               mov cl,bh                       ; CX = bytes/character
+               mov ax,640
+               div cl                          ; Compute char rows per screen
+               mov dl,al
+               mov [VidRows],al
+               mov ax,1121h                    ; Set user character table
+               int 10h
+               ; VidCols = 80, TextPage = 0 set by graphics mode select
+               ret     ; No need to call adjust_screen
+
 ;
 ; loadkeys:    Load a LILO-style keymap; SI and DX:AX set by searchdir
 ;
@@ -2960,46 +3034,43 @@ loadkeys_ret:   ret
 ;               set by routine searchdir
 ;
 get_msg_file:
-                mov word [NextCharJump],msg_putchar ; State machine for color
-                mov byte [TextAttribute],07h   ; Default grey on white
-                pusha
-                mov bh,[TextPage]
-                mov ah,03h                      ; Read cursor position
-                int 10h
-                mov [CursorDX],dx
-                popa
-get_msg_chunk:  push ax                         ; DX:AX = length of file
-                push dx
-               mov bx,trackbuf
+               push es
+               shl edx,16                      ; EDX <- DX:AX (length of file)
+               mov dx,ax
+               mov ax,xfer_buf_seg             ; Use for temporary storage
+               mov es,ax
+
+               call msg_initvars
+
+get_msg_chunk:  push edx                       ; EDX = length of file
+               xor bx,bx                       ; == xbs_textbuf
                mov cx,[BufSafe]
                call getfssec
-                pop dx
-                pop ax
+               pop edx
                push si                         ; Save current cluster
-               mov si,trackbuf
-               mov cx,[BufSafeBytes]           ; No more than many bytes
-print_msg_file: push cx
-                push ax
-               push dx
-               lodsb
-                cmp al,1Ah                      ; ASCII EOF?
+               xor si,si                       ; == xbs_textbuf
+               mov cx,[BufSafeBytes]           ; Number of bytes left in chunk
+print_msg_file:
+               push cx
+               push edx
+               es lodsb
+                cmp al,1Ah                      ; DOS EOF?
                je msg_done_pop
+               push si
                 call [NextCharJump]            ; Do what shall be done
-               pop dx
-               pop ax
+               pop si
+               pop edx
                 pop cx
-               sub ax,byte 1
-               sbb dx,byte 0
-               mov bx,ax
-               or bx,dx
+               dec edx
                jz msg_done
                loop print_msg_file
                pop si
                jmp short get_msg_chunk
 msg_done_pop:
-                add sp,byte 6                  ; Lose 3 words on the stack
+                add sp,byte 6                  ; Drop pushed EDX, CX
 msg_done:
                pop si
+               pop es
                ret
 msg_putchar:                                    ; Normal character
                 cmp al,0Fh                      ; ^O = color code follows
@@ -3010,6 +3081,8 @@ msg_putchar:                                    ; Normal character
                 je msg_newline
                 cmp al,0Ch                      ; <FF> = clear screen
                 je msg_formfeed
+               cmp al,18h                      ; <CAN> = VGA filename follows
+               je near msg_vga
 
 msg_normal:    call write_serial               ; Write to serial port
                 mov bx,[TextAttrBX]
@@ -3031,10 +3104,8 @@ msg_ctrl_o:                                     ; ^O = color code follows
                 mov word [NextCharJump],msg_setbg
                 ret
 msg_newline:                                    ; Newline char or end of line
-               push si
                mov si,crlf_msg
                call write_serial_str
-               pop si
 msg_line_wrap:                                 ; Screen wraparound
                 mov byte [CursorCol],0
                 mov al,[CursorRow]
@@ -3051,10 +3122,8 @@ msg_scroll:     xor cx,cx                       ; Upper left hand corner
                 int 10h
                 jmp short msg_gotoxy
 msg_formfeed:                                   ; Form feed character
-               push si
                mov si,crff_msg
                call write_serial_str
-               pop si
                 xor cx,cx
                 mov [CursorDX],cx              ; Upper lefthand corner
                 mov dx,[ScreenSize]
@@ -3073,12 +3142,58 @@ msg_setfg:                                      ; Color foreground character
                 call unhexchar
                 jc msg_color_bad
                 or [TextAttribute],al          ; setbg set foreground to 0
-                mov word [NextCharJump],msg_putchar
-                ret
+               jmp short msg_putcharnext
+msg_vga:
+               mov word [NextCharJump],msg_filename
+               mov di, VGAFileBuf
+               jmp short msg_setvgafileptr
+
 msg_color_bad:
                 mov byte [TextAttribute],07h   ; Default attribute
+msg_putcharnext:
                 mov word [NextCharJump],msg_putchar
-                ret
+               ret
+
+msg_filename:                                  ; Getting VGA filename
+               cmp al,0Ah                      ; <LF> = end of filename
+               je msg_viewimage
+               cmp al,' '
+               jbe msg_ret                     ; Ignore space/control char
+               mov di,[VGAFilePtr]
+               cmp di,VGAFileBufEnd
+               jnb msg_ret
+               mov [di],al                     ; Can't use stosb (DS:)
+               inc di
+msg_setvgafileptr:
+               mov [VGAFilePtr],di
+msg_ret:       ret
+
+msg_viewimage:
+               push es
+               push ds
+               pop es                          ; ES <- DS
+               mov si,VGAFileBuf
+               mov di,VGAFileMBuf
+               push di
+               call mangle_name
+               pop di
+               call searchdir
+               pop es
+               jz msg_putcharnext              ; Not there
+               call vgadisplayfile
+               ; Fall through
+
+               ; Subroutine to initialize variables, also needed
+               ; after loading a graphics file
+msg_initvars:
+                mov byte [TextAttribute],07h   ; Default grey on white
+                pusha
+                mov bh,[TextPage]
+                mov ah,03h                      ; Read cursor position
+                int 10h
+                mov [CursorDX],dx
+                popa
+               jmp short msg_putcharnext       ; Initialize state machine
 
 ;
 ; write_serial:        If serial output is enabled, write character on serial port
@@ -3678,6 +3793,308 @@ lc_1:           cmp al,lcase_low
 lc_ret:         ret
 
 ; ----------------------------------------------------------------------------------
+;  VGA splash screen code
+; ----------------------------------------------------------------------------------
+
+;
+; vgadisplayfile:
+;      Display a graphical splash screen.
+;
+; Input:
+;
+; SI   = cluster/socket pointer
+;
+vgadisplayfile:
+               mov [VGACluster],si
+               push es
+
+               ; This is a cheap and easy way to make sure the screen is
+               ; cleared in case we were in graphics mode already
+               call vgaclearmode
+               call vgasetmode
+               jnz .error_nz
+
+.graphalready:
+               mov ax,xfer_buf_seg             ; Use as temporary storage
+               mov es,ax
+               mov fs,ax
+
+               call vgagetchunk                ; Get the first chunk
+
+               ; The header WILL be in the first chunk.
+               cmp dword [es:xbs_vgabuf],0x1413f33d    ; Magic number
+.error_nz:     jne near .error
+               mov ax,[es:xbs_vgabuf+4]
+               mov [GraphXSize],ax
+
+               mov dx,xbs_vgabuf+8             ; Color map offset
+               mov ax,1012h                    ; Set RGB registers
+               xor bx,bx                       ; First register number
+               mov cx,16                       ; 16 registers
+               int 10h
+       
+.movecursor:
+               mov ax,[es:xbs_vgabuf+6]        ; Number of pixel rows
+               mov dx,[VGAFontSize]
+               add ax,dx
+               dec ax
+               div dl
+               xor dx,dx                       ; Set column to 0
+               cmp al,[VidRows]
+               jb .rowsok
+               mov al,[VidRows]
+               dec al
+.rowsok:
+               mov dh,al
+               mov ah,2
+               xor bx,bx
+               int 10h                         ; Set cursor below image
+
+               mov cx,[es:xbs_vgabuf+6]        ; Number of graphics rows
+
+               mov si,xbs_vgabuf+8+3*16        ; Beginning of pixel data
+               mov word [VGAPos],0
+
+.drawpixelrow:
+               push cx
+               mov cx,[GraphXSize]
+               mov di,xbs_vgatmpbuf            ; Row buffer
+               call rledecode                  ; Decode one row
+               push si
+               mov si,xbs_vgatmpbuf
+               mov di,si
+               add di,[GraphXSize]
+               mov cx,640/4
+               xor eax,eax
+               rep stosd                       ; Clear rest of row
+               mov di,0A000h                   ; VGA segment
+               mov es,di
+               mov di,[VGAPos]
+               mov bp,640
+               call packedpixel2vga
+               add word [VGAPos],byte 80       ; Advance to next pixel row
+               push fs
+               pop es
+               pop si
+               pop cx
+               loop .drawpixelrow
+
+.error:
+               pop es
+               ret
+
+;
+; rledecode:
+;      Decode a pixel row in RLE16 format.
+;
+; FS:SI        -> input
+; CX -> pixel count
+; ES:DI -> output (packed pixel)
+;
+rledecode:
+               shl esi,1               ; Nybble pointer
+               xor dl,dl               ; Last pixel
+.loop:
+               call .getnybble
+               cmp al,dl
+               je .run                 ; Start of run sequence
+               stosb
+               mov dl,al
+               dec cx
+               jnz .loop
+.done:
+               shr esi,1
+               adc si,byte 0
+               ret
+.run:
+               xor bx,bx
+               call .getnybble
+               and al,al
+               jz .longrun
+               mov bl,al
+.dorun:
+               push cx
+               mov cx,bx
+               mov al,dl
+               rep stosb
+               pop cx
+               sub cx,bx
+               ja .loop
+               jmp short .done
+.longrun:
+               call .getnybble
+               mov ah,al
+               call .getnybble
+               shl al,4
+               or al,ah
+               mov bl,al
+               add bx,16
+               jmp short .dorun
+.getnybble:
+               shr esi,1
+               fs lodsb
+               jc .high
+               dec si
+               and al,0Fh
+               stc
+               rcl esi,1
+               ret
+.high:
+               shr al,4
+               cmp si,xbs_vgabuf+trackbufsize  ; Chunk overrun
+               jb .nonewchunk
+               call vgagetchunk
+               mov si,xbs_vgabuf               ; Start at beginning of buffer
+.nonewchunk:
+               shl esi,1
+               ret
+
+;
+; vgagetchunk:
+;      Get a new trackbufsize chunk of VGA image data
+;
+; On input, ES is assumed to point to the buffer segment.
+;
+vgagetchunk:
+               pushad
+               mov si,[VGACluster]
+               and si,si
+               jz .eof                         ; EOF overrun, not much to do...
+
+               mov cx,[BufSafe]                ; One trackbuf worth of data
+               mov bx,xbs_vgabuf
+               call getfssec
+
+               jnc .noteof
+               xor si,si
+.noteof:       mov [VGACluster],si
+
+.eof:          popad
+               ret
+
+;
+; packedpixel2vga:
+;      Convert packed-pixel to VGA bitplanes
+;
+; FS:SI -> packed pixel string
+; BP    -> pixel count (multiple of 8)
+; ES:DI -> output
+;
+packedpixel2vga:
+               mov dx,3C4h     ; VGA Sequencer Register select port
+               mov al,2        ; Sequencer mask
+               out dx,al       ; Select the sequencer mask
+               inc dx          ; VGA Sequencer Register data port
+               mov al,1
+               mov bl,al
+.planeloop:
+               pusha
+               out dx,al
+.loop1:
+               mov cx,8
+.loop2:
+               xchg cx,bx
+               fs lodsb
+               shr al,cl
+               rcl ch,1        ; VGA is bigendian.  Sigh.
+               xchg cx,bx
+               loop .loop2
+               mov al,bh
+               stosb
+               sub bp,byte 8
+               ja .loop1
+               popa
+               inc bl
+               shl al,1
+               cmp bl,4
+               jbe .planeloop
+               ret
+
+;
+; vgasetmode:
+;      Enable VGA graphics, if possible; return ZF=1 on success
+;      DS must be set to the base segment.
+;
+vgasetmode:
+               push ds
+               pop es
+               mov ax,1A00h            ; Get video card and monitor
+               xor bx,bx
+               int 10h
+               cmp bl, 8               ; If not VGA card/VGA monitor, give up
+               jne .error              ; ZF=0
+;              mov bx,TextColorReg
+;              mov dx,1009h            ; Read color registers
+;              int 10h
+               mov ax,0012h            ; Set mode = 640x480 VGA 16 colors
+               int 10h
+               mov dx,linear_color
+               mov ax,1002h            ; Write color registers
+               int 10h
+               mov [UsingVGA], byte 1
+
+               mov [VidCols], byte 80  ; Always 80 chars/screen
+               mov [TextPage], byte 0  ; Always page 0
+
+               mov cx,[VGAFontSize]
+               mov ax,640
+               div cl
+               mov [VidRows],al
+               mov dl,al
+               mov bp,vgafontbuf
+               xor bx,bx
+               mov ax,1121h            ; Set graphics font
+               int 10h
+
+               xor ax,ax               ; Set ZF
+.error:
+               ret
+
+;
+; vgaclearmode:
+;      Disable VGA graphics.  It is not safe to assume any value for DS.
+;
+vgaclearmode:
+               pushad
+               cmp [cs:UsingVGA], byte 1
+               jne .done
+               mov ax,0003h            ; Return to normal video mode
+               int 10h
+;              mov dx,TextColorReg     ; Restore color registers
+;              mov ax,1002h
+;              int 10h
+.done:
+               popad
+               ret
+
+;
+; vgashowcursor/vgahidecursor:
+;      If VGA graphics is enabled, draw a cursor/clear a cursor
+;
+vgashowcursor:
+               pushad
+               mov al,'_'
+               jmp short vgacursorcommon
+vgahidecursor:
+               pushad
+               mov al,' '
+vgacursorcommon:
+               cmp [UsingVGA], byte 1
+               jne .done
+               mov ah,09h
+               mov bx,0007h
+               mov cx,1
+               int 10h
+.done:
+               popad
+               ret
+
+
+               ; Map colors to consecutive DAC registers
+linear_color   db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
+UsingVGA       db 0
+
+; ----------------------------------------------------------------------------------
 ;  Begin data section
 ; ----------------------------------------------------------------------------------
 
@@ -3804,6 +4221,7 @@ SerialPort        dw 0                    ; Serial port base (or 0 for no serial port)
 A20List                dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
 A20DList       dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
 A20Type                dw A20_DUNNO            ; A20 type unknown
+VGAFontSize    dw 16                   ; Defaults to 16 byte font
 ;
 ; Stuff for the command line; we do some trickery here with equ to avoid
 ; tons of zeros appended to our file and wasting space
@@ -3823,3 +4241,13 @@ ldlinux_len      equ ldlinux_end-ldlinux_magic
 ;
 end_of_code    equ (ldlinux_end-bootsec)+7C00h
 getcbuf                equ (end_of_code + 511) & 0FE00h
+
+; VGA font buffer at the end of memory (so loading a font works even
+; in graphics mode.)
+vgafontbuf     equ 0E000h
+
+; This is a compile-time assert that we didn't run out of space
+%if (getcbuf+trackbufsize) > vgafontbuf
+%error "Out of memory, better reorganize something..."
+%endif
+
diff --git a/ppmtolss16 b/ppmtolss16
new file mode 100755 (executable)
index 0000000..efbd765
--- /dev/null
@@ -0,0 +1,286 @@
+#!/usr/bin/perl
+#ident "$Id$"
+## -----------------------------------------------------------------------
+##   
+##   Copyright 2001 H. Peter Anvin - All Rights Reserved
+##
+##   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., 675 Mass Ave, Cambridge MA 02139,
+##   USA; either version 2 of the License, or (at your option) any later
+##   version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## ppmtolss16
+##
+## Convert a "raw" PPM file with max 16 colors to a simple RLE-based format:
+##
+## uint32 0x1413f33d    ; magic (littleendian)
+## uint16 xsize                ; littleendian
+## uint16 ysize                ; littleendian
+## 16 x uint8 r,g,b    ; color map, in 6-bit format (each byte is 0..63)
+##
+## Then, a sequence of nybbles:
+##
+## N   ... if N is != previous pixel, one pixel of color N
+## ... otherwise run sequence follows ...
+## M    ... if M > 0 then run length is M+1
+## ... otherwise run sequence is encoded in two nybbles,
+##     littleendian, +17
+##
+## The nybble sequences are on a per-row basis; runs may not extend
+## across rows and odd-nybble rows are zero-padded.
+##
+## At the start of row, the "previous pixel" is assumed to be zero.
+##
+## BUG: This program does not handle comments in the header, nor
+## "plain" ppm format.
+##
+## Usage:
+##
+##     ppmtorle16 [#rrggbb=i ...] < input.ppm > output.rle
+##
+## Command line options of the form #rrggbb=i indicate that
+## the color #rrggbb (hex) should be assigned index i (decimal)
+##
+
+$magic = 0x1413f33d;
+
+foreach $arg ( @ARGV ) {
+    if ( $arg =~ /^\#([0-9a-f])([0-9a-f])([0-9a-f])=([0-9]+)$/i ) {
+       $r = hex($1) << 2;
+       $g = hex($2) << 2;
+       $b = hex($3) << 2;
+       $i = $4 + 0;
+    } elsif ( $arg =~ /^\#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})=([0-9]+)$/i ) {
+       $r = hex($1) >> 2;
+       $g = hex($2) >> 2;
+       $b = hex($3) >> 2;
+       $i = $4 + 0;
+    } elsif ( $arg =~ /^\#([0-9a-f]{3})([0-9a-f]{3})([0-9a-f]{3})=([0-9]+)$/i ) {
+       $r = hex($1) >> 6;
+       $g = hex($2) >> 6;
+       $b = hex($3) >> 6;
+       $i = $4 + 0;
+    } elsif ( $arg =~ /^\#([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})=([0-9]+)$/i ) {
+       $r = hex($1) >> 10;
+       $g = hex($2) >> 10;
+       $b = hex($3) >> 10;
+       $i = $4 + 0;
+    } else {
+       # print STDERR "$0: Unknown argument: $arg\n";
+       next;
+    }
+
+    if ( $i > 15 ) {
+       # print STDERR "$0: Color index out of range: $arg\n";
+       next;
+    }
+
+    $rgb = pack("CCC", $r, $g, $b);
+
+    if ( defined($index_forced{$i}) ) {
+       # print STDERR "$0: More than one color index $i\n";
+       exit(1);
+    }
+    $index_forced{$i} = $rgb;
+    $force_index{$rgb} = $i;
+}
+
+$form = <STDIN>;
+die "$0: stdin is not a raw PPM file" if ( $form ne "P6\n" );
+$sizes = <STDIN>;
+chomp $sizes;
+if ( $sizes !~ /^([0-9]+)\s+([0-9]+)\s*$/ ) {
+    die "$0: Input format error 1\n";
+}
+$xsize = $1 + 0;
+$ysize = $2 + 0;
+$maxcol = <STDIN>;
+chomp $maxcol;
+if ( $maxcol !~ /^([0-9]+)\s*$/ ) {
+    die "$0: Input format error 2\n";
+}
+$maxcol = $1 + 0;
+$maxmult = 64/($maxcol+1);     # Equal buckets conversion
+
+@data = ();
+
+for ( $y = 0 ; $y < $ysize ; $y++ ) {
+    for ( $x = 0 ; $x < $xsize ; $x++ ) {
+       die "$0: Premature EOF at ($x,$y) of ($xsize,$ysize)\n"
+           if ( read(STDIN, $rgb, 3) != 3 );
+       # Convert to 6-bit representation
+       ($r, $g, $b) = unpack("CCC", $rgb);
+       $r = int($r*$maxmult+0.5);
+       $g = int($g*$maxmult+0.5);
+       $b = int($b*$maxmult+0.5);
+       $rgb = pack("CCC", $r, $g, $b);
+       $color_count{$rgb}++;
+       push(@data, $rgb);
+    }
+}
+
+# Sort list of colors according to freqency
+@colors = sort { $color_count{$b} <=> $color_count{$a} } keys(%color_count);
+
+if ( scalar(@colors) > 16 ) {
+    # print STDERR "$0: Warning: input > 16 colors\n";
+    @colors = @colors[0..15];
+}
+
+# Now we have our pick of colors.  Sort according to intensity;
+# this is more or less an ugly hack to cover for the fact that
+# using PPM as input doesn't let the user set the color map,
+# which the user really needs to be able to do.
+
+sub by_intensity() {
+    my($ra,$ga,$ba) = unpack("CCC", $a);
+    my($rb,$gb,$bb) = unpack("CCC", $b);
+
+    my($ia) = $ra*0.299 + $ga*0.587 + $ba*0.114;
+    my($ib) = $rb*0.299 + $gb*0.587 + $bb*0.114;
+
+    return ( $ia <=> $ib ) if ( $ia != $ib );
+
+    # If same, sort based on RGB components,
+    # with highest priority given to G, then R, then B.
+    
+    return ( $ga <=> $gb ) if ( $ga != $gb );
+    return ( $ra <=> $rb ) if ( $ra != $rb );
+    return ( $ba <=> $bb );
+}
+
+@icolors = sort by_intensity @colors;
+
+# Insert forced colors into "final" array
+@colors = (undef) x 16;
+foreach $rgb ( @icolors ) {
+    if ( defined($force_index{$rgb}) ) {
+       $colors[$force_index{$rgb}] = $rgb;
+    }
+}
+
+# Insert remaining colors in the remaining slots,
+# in luminosity-sorted order
+$nix = 0;
+foreach $rgb ( @icolors ) {
+    if ( ! defined($force_index{$rgb}) ) {
+       # Advance to the next free slot
+       $nix++ while ( defined($colors[$nix]) );
+       $colors[$nix] = $rgb;
+    }
+}
+
+undef @icolors;
+
+# Generate color index hash
+for ( $i = 0 ; $i < scalar @colors ; $i++ ) {
+    $color_index{$colors[$i]} = $i;
+}
+
+# Output header
+print pack("Vvv", $magic, $xsize, $ysize);
+
+# Output color map
+for ( $i = 0 ; $i < 16 ; $i++ ) {
+    if ( defined($colors[$i]) ) {
+       print $colors[$i];
+    } else {
+       # Padding for unused color entries
+       print pack("CCC", 63*$i/15, 63*$i/15, 63*$i/15);
+    }
+}
+
+sub output_nybble($) {
+    my($ny) = @_;
+
+    if ( !defined($ny) ) {
+       if ( defined($nybble_tmp) ) {
+           $ny = 0;            # Force the last byte out
+       } else {
+           return;
+       }
+    }
+
+    $ny = $ny & 0x0F;
+
+    # printf STDERR "%x", $ny;
+
+    if ( defined($nybble_tmp) ) {
+       $ny = ($ny << 4) | $nybble_tmp;
+       print chr($ny);
+       $bytes++;
+       undef $nybble_tmp;
+    } else {
+       $nybble_tmp = $ny;
+    }
+}
+
+sub output_run($$$) {
+    my($last,$this,$run) = @_;
+
+    # printf STDERR "Color %2d Run %3d = ", $this, $run;
+
+    if ( $this != $last ) {
+       output_nybble($this);
+       $run--;
+    }
+    while ( $run ) {
+       if ( $run >= 16 ) {
+           output_nybble($this);
+           output_nybble(0);
+           if ( $run > 271 ) {
+               $erun = 255;
+               $run -= 271;
+           } else {
+               $erun = $run-16;
+               $run = 0;
+           }
+           output_nybble($erun);
+           output_nybble($erun >> 4);
+       } else {
+           output_nybble($this);
+           output_nybble($run);
+           $run = 0;
+       }
+    }
+    # print STDERR "\n";
+}
+    
+$bytes  = 0;
+undef $nybble_tmp;
+
+for ( $y = 0 ; $y < $ysize ; $y++ ) {
+    $last = $prev = 0;
+    $run = 0;
+    # printf STDERR "*** Row %3d ***\n", $y;
+    for ( $x = 0 ; $x < $xsize ; $x++ ) {
+       $rgb = shift(@data);
+       $i   = $color_index{$rgb} + 0;
+       if ( $i == $last ) {
+           $run++;
+       } else {
+           output_run($prev, $last, $run);
+           $prev = $last;
+           $last = $i;
+           $run  = 1;
+       }
+    }
+    # Output final datum for row; we're always at least one pixel behind
+    output_run($prev, $last, $run);
+    # printf STDERR "Row termination  = ";
+    output_nybble(undef);      # Flush row
+    # print STDERR "\n";
+}
+
+$pixels = $xsize * $ysize;
+$size = ($pixels+1)/2;
+printf STDERR "%d pixels, %d bytes, (%2.2f%% compression)\n",
+    $pixels, $bytes, 100*($size-$bytes)/$size;
+
+
+
+
index 70014e1..cbd7584 100644 (file)
@@ -174,7 +174,7 @@ vk_end:             equ $                   ; Should be <= vk_size
 ; 0000h - main code/data segment (and BIOS segment)
 ; 5000h - real_mode_seg
 ;
-vk_seg          equ 4000h              ; This is where we stick'em
+vk_seg          equ 4000h              ; Virtual kernels
 xfer_buf_seg   equ 3000h               ; Bounce buffer for I/O to high mem
 comboot_seg    equ 2000h               ; COMBOOT image loading zone
 
@@ -305,10 +305,21 @@ BIOS_vidrows    resb 1                    ; Number of screen rows
 ; Memory below this point is reserved for the BIOS and the MBR
 ;
                absolute 1000h
-trackbuf       resb 16384              ; Track buffer goes here
+trackbuf       resb 8192               ; Track buffer goes here
 trackbufsize   equ $-trackbuf
+;              trackbuf ends at 3000h
 
-;              trackbuf ends at 5000h
+
+;
+; Constants for the xfer_buf_seg
+;
+; The xfer_buf_seg is also used to store message file buffers.  We
+; need two trackbuffers (text and graphics), plus a work buffer
+; for the graphics decompressor.
+;
+xbs_textbuf    equ 0                   ; Also hard-coded, do not change
+xbs_vgabuf     equ trackbufsize
+xbs_vgatmpbuf  equ 2*trackbufsize
 
                 absolute 5000h          ; Here we keep our BSS stuff
 VKernelBuf:    resb vk_size            ; "Current" vkernel
@@ -352,6 +363,10 @@ NextCharJump    resw 1                     ; Routine to interpret next print char
 SetupSecs      resw 1                  ; Number of setup sectors
 A20Test                resw 1                  ; Counter for testing status of A20
 CmdLineLen     resw 1                  ; Length of command line including null
+GraphXSize     resw 1                  ; Width of splash screen file
+VGAPos         resw 1                  ; Pointer into VGA memory
+VGACluster     resw 1                  ; Cluster pointer for VGA image file
+VGAFilePtr     resw 1                  ; Pointer into VGAFileBuf
 ConfigFile     resw 1                  ; Socket for config file
 PktTimeout     resw 1                  ; Timeout for current packet
 KernelExtPtr   resw 1                  ; During search, final null pointer
@@ -372,6 +387,10 @@ LoadFlags  resb 1                  ; Loadflags from kernel
 A20Tries       resb 1                  ; Times until giving up on A20
 FuncFlag       resb 1                  ; == 1 if <Ctrl-F> pressed
 OverLoad       resb 1                  ; Set if DHCP packet uses "overloading"
+TextColorReg   resb 17                 ; VGA color registers for text mode
+VGAFileBuf     resb FILENAME_MAX       ; Unmangled VGA image name
+VGAFileBufEnd  equ $
+VGAFileMBuf    resb FILENAME_MAX       ; Mangled VGA image name
 
                alignb tftp_port_t_size
 Sockets                resb MAX_SOCKETS*tftp_port_t_size
@@ -414,6 +433,25 @@ _start1:
 ;
 ; Initialize screen (if we're using one)
 ;
+
+               ; Get ROM 8x16 font in case we switch to graphics mode
+               xor cx,cx
+               mov ax,1130h
+               mov bh,6                        ; Get ROM 8x16 font
+               int 10h
+               push es
+               pop fs
+               push ds
+               pop es
+               cmp cx,16
+               jne not_vga                     ; If not VGA we don't care
+               mov si,bp
+               mov di,vgafontbuf
+               mov cx,(16*256) >> 2
+               fs rep movsd
+not_vga:
+
+               ; Now set up screen parameters
                call adjust_screen
 ;
 ; Tell the user we got this far
@@ -1114,7 +1152,9 @@ clear_buffer:     mov ah,1                        ; Check for pending char
                xor ax,ax                       ; Get char
                int 16h
                jmp short clear_buffer
-get_char_time: mov cx,[KbdTimeOut]
+get_char_time: 
+               call vgashowcursor
+               mov cx,[KbdTimeOut]
                and cx,cx
                jz get_char                     ; Timeout == 0 -> no timeout
                inc cx                          ; The first loop will happen
@@ -1130,10 +1170,14 @@ tick_loop:      push dx
                je tick_loop
                pop cx
                loop time_loop                  ; If so, decrement counter
+               call vgahidecursor
                jmp command_done                ; Timeout!
 
 get_char_pop:  pop eax                         ; Clear stack
-get_char:      call getchar
+get_char:
+               call vgashowcursor
+               call getchar
+               call vgahidecursor
                and al,al
                jz func_key
 
@@ -1804,6 +1848,8 @@ nk_noinitrd:
 
                mov si,ready_msg
                call cwritestr
+
+               call vgaclearmode               ; We can't trust ourselves after this
 ;
 ; Unload PXE stack
 ;
@@ -2041,6 +2087,8 @@ comboot_end_cmd: mov al,0Dh               ; CR after last character
                mov ax,ss               ; Save away SS:SP
                mov [SavedSSSP+2],ax
 
+               call vgaclearmode       ; Reset video
+
                mov ax,es
                mov ds,ax
                mov ss,ax
@@ -2949,7 +2997,7 @@ loadfont:
                jne bf_ret
 
                mov al,[trackbuf+2]             ; File mode
-               cmp al,3                        ; Font modes 0-3 supported
+               cmp al,5                        ; Font modes 0-5 supported
                ja bf_ret
 
                mov bh,byte [trackbuf+3]        ; Height of font
@@ -2958,8 +3006,18 @@ loadfont:
                cmp bh,32                       ; VGA maximum
                ja bf_ret
 
-               mov bp,trackbuf+4               ; Address of font data
-               xor bl,bl
+               ; Copy to font buffer
+               mov si,trackbuf+4               ; Start of font data
+               mov [VGAFontSize],bh
+               mov di,vgafontbuf
+               mov bp,di                       ; Address of font data for INT 10h
+               mov cx,(32*256) >> 2            ; Maximum size
+               rep movsd
+
+               xor bl,bl                       ; Needed by both INT 10h calls
+               cmp [UsingVGA], byte 1          ; Are we in graphics mode?
+               je .graphics
+
                mov cx,256
                xor dx,dx
                mov ax,1110h
@@ -2971,6 +3029,18 @@ loadfont:
 
                jmp short adjust_screen
 
+.graphics:
+               ; CX = 0 on entry
+               mov cl,bh                       ; CX = bytes/character
+               mov ax,640
+               div cl                          ; Compute char rows per screen
+               mov dl,al
+               mov [VidRows],al
+               mov ax,1121h                    ; Set user character table
+               int 10h
+               ; VidCols = 80, TextPage = 0 set by graphics mode select
+               ret     ; No need to call adjust_screen
+
 ;
 ; loadkeys:    Load a LILO-style keymap; SI and DX:AX set by searchdir
 ;
@@ -2997,46 +3067,43 @@ loadkeys_ret:   ret
 ;               set by routine searchdir
 ;
 get_msg_file:
-                mov word [NextCharJump],msg_putchar ; State machine for color
-                mov byte [TextAttribute],07h   ; Default grey on white
-                pusha
-                mov bh,[TextPage]
-                mov ah,03h                      ; Read cursor position
-                int 10h
-                mov [CursorDX],dx
-                popa
-get_msg_chunk:  push ax                         ; DX:AX = length of file
-                push dx
-               mov bx,trackbuf
+               push es
+               shl edx,16                      ; EDX <- DX:AX (length of file)
+               mov dx,ax
+               mov ax,xfer_buf_seg             ; Use for temporary storage
+               mov es,ax
+
+               call msg_initvars
+
+get_msg_chunk:  push edx                       ; EDX = length of file
+               xor bx,bx                       ; == xbs_textbuf
                mov cx,[BufSafe]
                call getfssec
-                pop dx
-                pop ax
+               pop edx
                push si                         ; Save current cluster
-               mov si,trackbuf
-               mov cx,[BufSafeBytes]           ; No more than many bytes
-print_msg_file: push cx
-                push ax
-               push dx
-               lodsb
-                cmp al,1Ah                      ; ASCII EOF?
+               xor si,si                       ; == xbs_textbuf
+               mov cx,[BufSafeBytes]           ; Number of bytes left in chunk
+print_msg_file:
+               push cx
+               push edx
+               es lodsb
+                cmp al,1Ah                      ; DOS EOF?
                je msg_done_pop
+               push si
                 call [NextCharJump]            ; Do what shall be done
-               pop dx
-               pop ax
+               pop si
+               pop edx
                 pop cx
-               sub ax,byte 1
-               sbb dx,byte 0
-               mov bx,ax
-               or bx,dx
+               dec edx
                jz msg_done
                loop print_msg_file
                pop si
                jmp short get_msg_chunk
 msg_done_pop:
-                add sp,byte 6                  ; Lose 3 words on the stack
+                add sp,byte 6                  ; Drop pushed EDX, CX
 msg_done:
                pop si
+               pop es
                ret
 msg_putchar:                                    ; Normal character
                 cmp al,0Fh                      ; ^O = color code follows
@@ -3047,6 +3114,8 @@ msg_putchar:                                    ; Normal character
                 je msg_newline
                 cmp al,0Ch                      ; <FF> = clear screen
                 je msg_formfeed
+               cmp al,18h                      ; <CAN> = VGA filename follows
+               je near msg_vga
 
 msg_normal:    call write_serial               ; Write to serial port
                 mov bx,[TextAttrBX]
@@ -3068,10 +3137,8 @@ msg_ctrl_o:                                     ; ^O = color code follows
                 mov word [NextCharJump],msg_setbg
                 ret
 msg_newline:                                    ; Newline char or end of line
-               push si
                mov si,crlf_msg
                call write_serial_str
-               pop si
 msg_line_wrap:                                 ; Screen wraparound
                 mov byte [CursorCol],0
                 mov al,[CursorRow]
@@ -3088,10 +3155,8 @@ msg_scroll:     xor cx,cx                       ; Upper left hand corner
                 int 10h
                 jmp short msg_gotoxy
 msg_formfeed:                                   ; Form feed character
-               push si
                mov si,crff_msg
                call write_serial_str
-               pop si
                 xor cx,cx
                 mov [CursorDX],cx              ; Upper lefthand corner
                 mov dx,[ScreenSize]
@@ -3110,12 +3175,58 @@ msg_setfg:                                      ; Color foreground character
                 call unhexchar
                 jc msg_color_bad
                 or [TextAttribute],al          ; setbg set foreground to 0
-                mov word [NextCharJump],msg_putchar
-                ret
+               jmp short msg_putcharnext
+msg_vga:
+               mov word [NextCharJump],msg_filename
+               mov di, VGAFileBuf
+               jmp short msg_setvgafileptr
+
 msg_color_bad:
                 mov byte [TextAttribute],07h   ; Default attribute
+msg_putcharnext:
                 mov word [NextCharJump],msg_putchar
-                ret
+               ret
+
+msg_filename:                                  ; Getting VGA filename
+               cmp al,0Ah                      ; <LF> = end of filename
+               je msg_viewimage
+               cmp al,' '
+               jbe msg_ret                     ; Ignore space/control char
+               mov di,[VGAFilePtr]
+               cmp di,VGAFileBufEnd
+               jnb msg_ret
+               mov [di],al                     ; Can't use stosb (DS:)
+               inc di
+msg_setvgafileptr:
+               mov [VGAFilePtr],di
+msg_ret:       ret
+
+msg_viewimage:
+               push es
+               push ds
+               pop es                          ; ES <- DS
+               mov si,VGAFileBuf
+               mov di,VGAFileMBuf
+               push di
+               call mangle_name
+               pop di
+               call searchdir
+               pop es
+               jz msg_putcharnext              ; Not there
+               call vgadisplayfile
+               ; Fall through
+
+               ; Subroutine to initialize variables, also needed
+               ; after loading a graphics file
+msg_initvars:
+                mov byte [TextAttribute],07h   ; Default grey on white
+                pusha
+                mov bh,[TextPage]
+                mov ah,03h                      ; Read cursor position
+                int 10h
+                mov [CursorDX],dx
+                popa
+               jmp short msg_putcharnext       ; Initialize state machine
 
 ;
 ; write_serial:        If serial output is enabled, write character on serial port
@@ -4107,6 +4218,308 @@ genipopt:
                ret
 
 ; ----------------------------------------------------------------------------------
+;  VGA splash screen code
+; ----------------------------------------------------------------------------------
+
+;
+; vgadisplayfile:
+;      Display a graphical splash screen.
+;
+; Input:
+;
+; SI   = cluster/socket pointer
+;
+vgadisplayfile:
+               mov [VGACluster],si
+               push es
+
+               ; This is a cheap and easy way to make sure the screen is
+               ; cleared in case we were in graphics mode already
+               call vgaclearmode
+               call vgasetmode
+               jnz .error_nz
+
+.graphalready:
+               mov ax,xfer_buf_seg             ; Use as temporary storage
+               mov es,ax
+               mov fs,ax
+
+               call vgagetchunk                ; Get the first chunk
+
+               ; The header WILL be in the first chunk.
+               cmp dword [es:xbs_vgabuf],0x1413f33d    ; Magic number
+.error_nz:     jne near .error
+               mov ax,[es:xbs_vgabuf+4]
+               mov [GraphXSize],ax
+
+               mov dx,xbs_vgabuf+8             ; Color map offset
+               mov ax,1012h                    ; Set RGB registers
+               xor bx,bx                       ; First register number
+               mov cx,16                       ; 16 registers
+               int 10h
+       
+.movecursor:
+               mov ax,[es:xbs_vgabuf+6]        ; Number of pixel rows
+               mov dx,[VGAFontSize]
+               add ax,dx
+               dec ax
+               div dl
+               xor dx,dx                       ; Set column to 0
+               cmp al,[VidRows]
+               jb .rowsok
+               mov al,[VidRows]
+               dec al
+.rowsok:
+               mov dh,al
+               mov ah,2
+               xor bx,bx
+               int 10h                         ; Set cursor below image
+
+               mov cx,[es:xbs_vgabuf+6]        ; Number of graphics rows
+
+               mov si,xbs_vgabuf+8+3*16        ; Beginning of pixel data
+               mov word [VGAPos],0
+
+.drawpixelrow:
+               push cx
+               mov cx,[GraphXSize]
+               mov di,xbs_vgatmpbuf            ; Row buffer
+               call rledecode                  ; Decode one row
+               push si
+               mov si,xbs_vgatmpbuf
+               mov di,si
+               add di,[GraphXSize]
+               mov cx,640/4
+               xor eax,eax
+               rep stosd                       ; Clear rest of row
+               mov di,0A000h                   ; VGA segment
+               mov es,di
+               mov di,[VGAPos]
+               mov bp,640
+               call packedpixel2vga
+               add word [VGAPos],byte 80       ; Advance to next pixel row
+               push fs
+               pop es
+               pop si
+               pop cx
+               loop .drawpixelrow
+
+.error:
+               pop es
+               ret
+
+;
+; rledecode:
+;      Decode a pixel row in RLE16 format.
+;
+; FS:SI        -> input
+; CX -> pixel count
+; ES:DI -> output (packed pixel)
+;
+rledecode:
+               shl esi,1               ; Nybble pointer
+               xor dl,dl               ; Last pixel
+.loop:
+               call .getnybble
+               cmp al,dl
+               je .run                 ; Start of run sequence
+               stosb
+               mov dl,al
+               dec cx
+               jnz .loop
+.done:
+               shr esi,1
+               adc si,byte 0
+               ret
+.run:
+               xor bx,bx
+               call .getnybble
+               and al,al
+               jz .longrun
+               mov bl,al
+.dorun:
+               push cx
+               mov cx,bx
+               mov al,dl
+               rep stosb
+               pop cx
+               sub cx,bx
+               ja .loop
+               jmp short .done
+.longrun:
+               call .getnybble
+               mov ah,al
+               call .getnybble
+               shl al,4
+               or al,ah
+               mov bl,al
+               add bx,16
+               jmp short .dorun
+.getnybble:
+               shr esi,1
+               fs lodsb
+               jc .high
+               dec si
+               and al,0Fh
+               stc
+               rcl esi,1
+               ret
+.high:
+               shr al,4
+               cmp si,xbs_vgabuf+trackbufsize  ; Chunk overrun
+               jb .nonewchunk
+               call vgagetchunk
+               mov si,xbs_vgabuf               ; Start at beginning of buffer
+.nonewchunk:
+               shl esi,1
+               ret
+
+;
+; vgagetchunk:
+;      Get a new trackbufsize chunk of VGA image data
+;
+; On input, ES is assumed to point to the buffer segment.
+;
+vgagetchunk:
+               pushad
+               mov si,[VGACluster]
+               and si,si
+               jz .eof                         ; EOF overrun, not much to do...
+
+               mov cx,[BufSafe]                ; One trackbuf worth of data
+               mov bx,xbs_vgabuf
+               call getfssec
+
+               jnc .noteof
+               xor si,si
+.noteof:       mov [VGACluster],si
+
+.eof:          popad
+               ret
+
+;
+; packedpixel2vga:
+;      Convert packed-pixel to VGA bitplanes
+;
+; FS:SI -> packed pixel string
+; BP    -> pixel count (multiple of 8)
+; ES:DI -> output
+;
+packedpixel2vga:
+               mov dx,3C4h     ; VGA Sequencer Register select port
+               mov al,2        ; Sequencer mask
+               out dx,al       ; Select the sequencer mask
+               inc dx          ; VGA Sequencer Register data port
+               mov al,1
+               mov bl,al
+.planeloop:
+               pusha
+               out dx,al
+.loop1:
+               mov cx,8
+.loop2:
+               xchg cx,bx
+               fs lodsb
+               shr al,cl
+               rcl ch,1        ; VGA is bigendian.  Sigh.
+               xchg cx,bx
+               loop .loop2
+               mov al,bh
+               stosb
+               sub bp,byte 8
+               ja .loop1
+               popa
+               inc bl
+               shl al,1
+               cmp bl,4
+               jbe .planeloop
+               ret
+
+;
+; vgasetmode:
+;      Enable VGA graphics, if possible; return ZF=1 on success
+;      DS must be set to the base segment.
+;
+vgasetmode:
+               push ds
+               pop es
+               mov ax,1A00h            ; Get video card and monitor
+               xor bx,bx
+               int 10h
+               cmp bl, 8               ; If not VGA card/VGA monitor, give up
+               jne .error              ; ZF=0
+;              mov bx,TextColorReg
+;              mov dx,1009h            ; Read color registers
+;              int 10h
+               mov ax,0012h            ; Set mode = 640x480 VGA 16 colors
+               int 10h
+               mov dx,linear_color
+               mov ax,1002h            ; Write color registers
+               int 10h
+               mov [UsingVGA], byte 1
+
+               mov [VidCols], byte 80  ; Always 80 chars/screen
+               mov [TextPage], byte 0  ; Always page 0
+
+               mov cx,[VGAFontSize]
+               mov ax,640
+               div cl
+               mov [VidRows],al
+               mov dl,al
+               mov bp,vgafontbuf
+               xor bx,bx
+               mov ax,1121h            ; Set graphics font
+               int 10h
+
+               xor ax,ax               ; Set ZF
+.error:
+               ret
+
+;
+; vgaclearmode:
+;      Disable VGA graphics.  It is not safe to assume any value for DS.
+;
+vgaclearmode:
+               pushad
+               cmp [cs:UsingVGA], byte 1
+               jne .done
+               mov ax,0003h            ; Return to normal video mode
+               int 10h
+;              mov dx,TextColorReg     ; Restore color registers
+;              mov ax,1002h
+;              int 10h
+.done:
+               popad
+               ret
+
+;
+; vgashowcursor/vgahidecursor:
+;      If VGA graphics is enabled, draw a cursor/clear a cursor
+;
+vgashowcursor:
+               pushad
+               mov al,'_'
+               jmp short vgacursorcommon
+vgahidecursor:
+               pushad
+               mov al,' '
+vgacursorcommon:
+               cmp [UsingVGA], byte 1
+               jne .done
+               mov ah,09h
+               mov bx,0007h
+               mov cx,1
+               int 10h
+.done:
+               popad
+               ret
+
+
+               ; Map colors to consecutive DAC registers
+linear_color   db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
+UsingVGA       db 0
+
+; ----------------------------------------------------------------------------------
 ;  Begin data section
 ; ----------------------------------------------------------------------------------
 
@@ -4308,6 +4721,7 @@ NextSocket        dw 49152                ; Counter for allocating socket numbers
 A20List                dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
 A20DList       dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
 A20Type                dw A20_DUNNO            ; A20 type unknown
+VGAFontSize    dw 16                   ; Defaults to 16 byte font
 ;
 ; TFTP commands
 ;
@@ -4364,3 +4778,13 @@ kern_cmd_len    equ ldlinux_end-command_line
 ;
 end_of_code    equ (ldlinux_end-bootsec)+7C00h
 getcbuf                equ (end_of_code + 511) & 0FE00h
+
+; VGA font buffer at the end of memory (so loading a font works even
+; in graphics mode.)
+vgafontbuf     equ 0E000h
+
+; This is a compile-time assert that we didn't run out of space
+%if (getcbuf+trackbufsize) > vgafontbuf
+%error "Out of memory, better reorganize something..."
+%endif
+
diff --git a/sample/Makefile b/sample/Makefile
new file mode 100644 (file)
index 0000000..d38d5a3
--- /dev/null
@@ -0,0 +1,29 @@
+#ident "$Id$"
+## -----------------------------------------------------------------------
+##   
+##   Copyright 2001 H. Peter Anvin - All Rights Reserved
+##
+##   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., 675 Mass Ave, Cambridge MA 02139,
+##   USA; either version 2 of the License, or (at your option) any later
+##   version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## samples for syslinux users
+##
+
+PPMTOLSS16 =   ../ppmtolss16
+
+all: syslogo.lss
+
+syslogo.lss:   syslogo.png $(PPMTOLSS16)
+       pngtopnm syslogo.png | \
+               $(PPMTOLSS16) \#000000=0 \#d0d0d0=7 \#f6f6f6=15 \
+               > syslogo.lss
+
+
+clean:
+       rm -f *.lss
diff --git a/sample/sample.msg b/sample/sample.msg
new file mode 100644 (file)
index 0000000..5a8602a
--- /dev/null
@@ -0,0 +1,8 @@
+$Id$
+This message is displayed before the image.
+\18syslogo.lss
+This message is displayed after the image.
+\ f04 RED \ f07 \ f02 GREEN \ f07 \ f01 BLUE \ f07
+\ f47 RED \ f07 \ f27 GREEN \ f07 \ f17 BLUE \ f07
+
+
diff --git a/sample/syslogo.png b/sample/syslogo.png
new file mode 100644 (file)
index 0000000..45b4b5e
Binary files /dev/null and b/sample/syslogo.png differ
index a886f08..bee604f 100644 (file)
@@ -319,6 +319,25 @@ are interpreted:
 
        Colors are not visible over the serial console.
 
+<CAN>filename<newline>                 <CAN> = <Ctrl-X> = ASCII 24
+       If a VGA display is present, enter graphics mode and display
+       the graphic included in the specified file.  The file format
+       is an ad hoc format called LSS16; the included Perl program
+       "ppmtolss16" can be used to produce these images.  This Perl
+       program also includes the file format specification.
+
+       The image is displayed in 640x480 16-color mode.  Once in
+       graphics mode, the display attributes (set by <SI> code
+       sequences) work slightly differently: the background color is
+       ignored, and the foreground colors are the 16 colors specified
+       in the image file.  For that reason, ppmtolss16 allows you to
+       specify that certain colors should be assigned to specific
+       color indicies.
+
+       Color indicies 0 and 7, in particular, should be chosen with
+       care: 0 is the background color, and 7 is the color used for
+       the text printed by SYSLINUX itself.
+
 <SUB>                                   <SUB> = <Ctrl-Z> = ASCII 26
         End of file (DOS convention).
 
diff --git a/version b/version
index 108a9ad..64d00e7 100644 (file)
--- a/version
+++ b/version
@@ -1 +1 @@
-1.54
+1.60