summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--Makefile.private4
-rw-r--r--NEWS3
-rw-r--r--ldlinux.asm510
-rwxr-xr-xppmtolss16286
-rw-r--r--pxelinux.asm508
-rw-r--r--sample/Makefile29
-rw-r--r--sample/sample.msg8
-rw-r--r--sample/syslogo.pngbin0 -> 19847 bytes
-rw-r--r--syslinux.doc19
-rw-r--r--version2
11 files changed, 1290 insertions, 89 deletions
diff --git a/Makefile b/Makefile
index acf1371b..37a0c25e 100644
--- 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
diff --git a/Makefile.private b/Makefile.private
index 97c7418e..56412c2b 100644
--- a/Makefile.private
+++ b/Makefile.private
@@ -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 9c0e90df..cce8d884 100644
--- 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
diff --git a/ldlinux.asm b/ldlinux.asm
index e701b38b..12ab1641 100644
--- a/ldlinux.asm
+++ b/ldlinux.asm
@@ -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
index 00000000..efbd7658
--- /dev/null
+++ b/ppmtolss16
@@ -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;
+
+
+
+
diff --git a/pxelinux.asm b/pxelinux.asm
index 70014e13..cbd75843 100644
--- a/pxelinux.asm
+++ b/pxelinux.asm
@@ -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
index 00000000..d38d5a37
--- /dev/null
+++ b/sample/Makefile
@@ -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
index 00000000..5a8602a0
--- /dev/null
+++ b/sample/sample.msg
@@ -0,0 +1,8 @@
+$Id$
+This message is displayed before the image.
+syslogo.lss
+This message is displayed after the image.
+04 RED 07 02 GREEN 07 01 BLUE 07
+47 RED 07 27 GREEN 07 17 BLUE 07
+
+
diff --git a/sample/syslogo.png b/sample/syslogo.png
new file mode 100644
index 00000000..45b4b5ec
--- /dev/null
+++ b/sample/syslogo.png
Binary files differ
diff --git a/syslinux.doc b/syslinux.doc
index a886f082..bee604ff 100644
--- a/syslinux.doc
+++ b/syslinux.doc
@@ -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 108a9ade..64d00e7d 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.54
+1.60