Using the framebuffer device under Linux

by Karsten Scheibler

This is a short explanation, how you can use the linux frame buffer device in assembler language. Not all of my suggestions/tips written here are realized in the example code below (clearing screen, terminal locking, disabling cursor and blanking ...), but i think after reading them you should be able to implement them yourself. If you find mistakes or have suggestions, mail me: karsten.scheibler@bigfoot.de

NOTE: Nearly all of the %assign's and struc's listed here can be found in the kernel source in C syntax.

short procedure:

  1. open() the device
  2. determine screen parameters via ioctl()
  3. map the device to the memory of your process via mmap()
  4. use the pointer given back from mmap as base address of the frame buffer and draw what you like

If you use color depths <= 8 bpp you have to set a color palette in order to see that what you draw (default: first 16 colors are set to the normal terminal ANSI colors, the rest should be black). Linux uses 16 bit for every color component (red, green, blue, transparent).

Suggestions/Tips:


-[sample Makefile for this code]---------------------------------------------
NASM=nasm -w+orphan-labels -f elf
STRIP=strip -R .note -R .comment
LD=ld -s
RM=rm -f

.PHONY: all  clean

all: fb

fb: fb.nasm
	${NASM} fb.nasm
	${LD} -e fb_start -o fb fb.o
	${STRIP} fb

clean:
	${RM} *.bak *~ fb fb.o core
-----------------------------------------------------------------------------

;****************************************************************************
;****************************************************************************
;*
;* USING LINUX FRAME BUFFER DEVICE
;*
;* written by Karsten Scheibler, 2000-JUL-24
;*
;****************************************************************************
;****************************************************************************





;you have to specify this as entry point to the linker, as done above in the
;Makefile

global fb_start



;****************************************************************************
;* some assign's ************************************************************
;****************************************************************************
%assign SYS_EXIT	1
%assign SYS_READ	3
%assign SYS_WRITE	4
%assign SYS_OPEN	5
%assign SYS_IOCTL	54
%assign SYS_FCNTL	55
%assign SYS_MMAP	90

%assign PROT_READ	1
%assign PROT_WRITE	2

%assign MAP_SHARED	1

%assign STDIN		0
%assign STDERR		2

%assign O_RDWR		000002q

%assign FBIOGET_VSCREENINFO	04600h
%assign FBIOPUT_VSCREENINFO	04601h
%assign FBIOGETCMAP		04604h
%assign FBIOPUTCMAP		04605h

				struc tcmap
				alignb 4
tcmap_offset:			resd	1
tcmap_length:			resd	1
tcmap_red:			resd	1
tcmap_green:			resd	1
tcmap_blue:			resd	1
tcmap_transparent:		resd	1
				endstruc



				struc tscreen
				alignb 4
tscreen_x_resolution:		resd	1
tscreen_y_resolution:		resd	1
tscreen_virtual_x_resolution:	resd	1
tscreen_virtual_y_resolution:	resd	1
tscreen_x_offset:		resd	1
tscreen_y_offset:		resd	1
tscreen_bits_per_pixel:		resd	1
tscreen_grayscale:		resd	1
tscreen_red_offset:		resd	1
tscreen_red_length:		resd	1
tscreen_red_msb_right:		resd	1
tscreen_green_offset:		resd	1
tscreen_green_length:		resd	1
tscreen_green_msb_right:	resd	1
tscreen_blue_offset:		resd	1
tscreen_blue_length:		resd	1
tscreen_blue_msb_right:		resd	1
tscreen_transparent_offset:	resd	1
tscreen_transparent_length:	resd	1
tscreen_transparent_msb_right:	resd	1
tscreen_non_standard_format:	resd	1
tscreen_activate:		resd	1
tscreen_height:			resd	1
tscreen_width:			resd	1
tscreen_acceleration_flags:	resd	1
tscreen_pixel_clock:		resd	1
tscreen_left_margin:		resd	1
tscreen_right_margin:		resd	1
tscreen_upper_margin:		resd	1
tscreen_lower_margin:		resd	1
tscreen_hsync_length:		resd	1
tscreen_vsync_length:		resd	1
tscreen_sync:			resd	1
tscreen_vmode:			resd	1
tscreen_reserved:		resd	6
				endstruc


%assign FB_SCREENINFO_SAVED	001h
%assign FB_COLORMAP_SAVED	002h

section .data
			align	4
fb_flags:		dd	0
fb_handle:		dd	0
fb_address:		dd	0
screeninfo_saved:	istruc tscreen
			iend
screeninfo_data:	istruc tscreen
			iend
colormap_saved:		istruc tcmap
			at tcmap_offset,	dd 0
			at tcmap_length,	dd 010h
			at tcmap_red,		dd red_saved
			at tcmap_green,		dd green_saved
			at tcmap_blue,		dd blue_saved
			at tcmap_transparent,	dd transparent_saved
			iend
colormap_data:		istruc tcmap
			at tcmap_offset,	dd 0
			at tcmap_length,	dd 010h
			at tcmap_red,		dd grey_scale
			at tcmap_green,		dd grey_scale
			at tcmap_blue,		dd grey_scale
			at tcmap_transparent,	dd transparent_saved
			iend

			;remember: 16 bit components

grey_scale:		dw	00000h, 01000h, 02000h, 03000h
			dw	04000h, 05000h, 06000h, 07000h
			dw	08000h, 09000h, 0a000h, 0b000h
			dw	0c000h, 0d000h, 0e000h, 0f000h

section .bss
			align	4
red_saved:		resw	010h
green_saved:		resw	010h
blue_saved:		resw	010h
transparent_saved:	resw	010h



;****************************************************************************
;* initialization  **********************************************************
;****************************************************************************
section .text
fb_start:
			;open

			mov	dword eax, SYS_OPEN
			mov	dword ebx, .device
			mov	dword ecx, O_RDWR
			int	byte  080h
			test	dword eax, eax
			js	near  fb_error
			mov	dword [fb_handle], eax
			mov	dword [mmap_data.file_handle], eax

			;get screen parameters

			mov	dword ebx, eax
			mov	dword eax, SYS_IOCTL
			mov	dword ecx, FBIOGET_VSCREENINFO
			mov	dword edx, screeninfo_saved
			int	byte  080h
			test	dword eax, eax
			js	near  fb_error
			xor	dword eax, eax
			mov	dword [screeninfo_saved + tscreen_x_offset], eax
			mov	dword [screeninfo_saved + tscreen_y_offset], eax
			mov	dword esi, screeninfo_saved
			mov	dword edi, screeninfo_data
			mov	dword ecx, (tscreen_size / 4)
			cld
			rep movsd
			or	dword  [fb_flags], FB_SCREENINFO_SAVED

			;get actual colormap

			mov	dword eax, SYS_IOCTL
			mov	dword ebx, [fb_handle]
			mov	dword ecx, FBIOGETCMAP
			mov	dword edx, colormap_saved
			int	byte  080h
			test	dword eax, eax
			js	.no_colormap_saved
			or	dword [fb_flags], FB_COLORMAP_SAVED
.no_colormap_saved:
			;set screen parameters

			mov	dword eax, [screeninfo_data + tscreen_x_resolution]
			mov	dword ebx, [screeninfo_data + tscreen_y_resolution]
			mov	dword ecx, 8
			mov	dword [screeninfo_data + tscreen_virtual_x_resolution], eax
			mov	dword [screeninfo_data + tscreen_virtual_y_resolution], ebx
			mov	dword [screeninfo_data + tscreen_bits_per_pixel], ecx
			mov	dword eax, SYS_IOCTL
			mov	dword ebx, [fb_handle]
			mov	dword ecx, FBIOPUT_VSCREENINFO
			mov	dword edx, screeninfo_data
			int	byte  080h
			test	dword eax, eax
			js	near  fb_error
			cmp	dword [screeninfo_data + tscreen_bits_per_pixel], 8
			jne	near  fb_error

			;set colormap

			mov	dword eax, SYS_IOCTL
			mov	dword ebx, [fb_handle]
			mov	dword ecx, FBIOPUTCMAP
			mov	dword edx, colormap_data
			int	byte  080h

			;mmap

			mov	dword eax, [screeninfo_data + tscreen_y_resolution]
			mul	dword [screeninfo_data + tscreen_virtual_x_resolution]
			mov	dword [mmap_data.length], eax
			mov	dword eax, SYS_MMAP
			mov	dword ebx, mmap_data
			int	byte  080h
			test	dword eax, eax
			js	near  fb_error
			mov	dword [fb_address], eax

			;draw something

			mov	dword edi, [fb_address]
			mov	dword ebp, [screeninfo_data + tscreen_virtual_x_resolution]
			xor	dword eax, eax
			xor	dword ebx, ebx
			mov	byte  bl, 0feh
.draw_line:		xor	dword ecx, ecx
			mov	byte  cl, 0feh
.draw_pixel:		mov	byte [edi + ecx], al
			inc	dword eax
			and	byte  al, 00fh
			dec	dword ecx
			jnz	.draw_pixel
			add	dword edi, ebp
			dec	dword ebx
			jnz	.draw_line

			;"press enter to continue ..."

			sub	dword esp, 00100h
			mov	dword eax, SYS_READ
			mov	dword ebx, STDIN
			mov	dword ecx, esp
			mov	dword edx, 00100h
			int	byte  080h
			jmp	fb_end

.device:		db	"/dev/fb0", 0

section .data
			align	4
mmap_data:
.start:			dd	0
.length:		dd	0
.protection:		dd	(PROT_READ | PROT_WRITE)
.flags:			dd	MAP_SHARED
.file_handle:		dd	0
.offset:		dd	0



;****************************************************************************
;* restore old values *******************************************************
;****************************************************************************
section .text
fb_restore:
			test	dword [fb_flags], FB_SCREENINFO_SAVED
			jz	.skip_screeninfo
			mov	dword eax, SYS_IOCTL
			mov	dword ebx, [fb_handle]
			mov	dword ecx, FBIOPUT_VSCREENINFO
			mov	dword edx, screeninfo_saved
			int	byte  080h
.skip_screeninfo:	test	dword [fb_flags], FB_COLORMAP_SAVED
			jz	.skip_colormap
			mov	dword eax, SYS_IOCTL
			mov	dword ebx, [fb_handle]
			mov	dword ecx, FBIOPUTCMAP
			mov	dword edx, colormap_saved
			int	byte  080h
.skip_colormap:		ret



;****************************************************************************
;* error handler ************************************************************
;****************************************************************************
section .text
fb_error:
			call	fb_restore
			mov	dword eax, SYS_WRITE
			mov	dword ebx, STDERR
			mov	dword ecx, .text
			mov	dword edx, .text_length
			int	byte  080h
			jmp	fb_end

.text:			db	"something went wrong!", 10
.text_length		equ	$ - .text



;****************************************************************************
;* end **********************************************************************
;****************************************************************************
section .text
fb_end:
			call	fb_restore
			xor	dword eax, eax
			mov	dword ebx, eax
			inc	dword eax
			int	byte  080h
;********************************************* karsten.scheibler@bigfoot.de *