📄 video.s
字号:
/* video.S * * Display adapter & video mode setup, version 2.13 (14-May-99) * * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz> * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson * * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999 * * For further information, look at Documentation/svga.txt. * */#include <linux/config.h> /* for CONFIG_VIDEO_* *//* Enable autodetection of SVGA adapters and modes. */#undef CONFIG_VIDEO_SVGA/* Enable autodetection of VESA modes */#define CONFIG_VIDEO_VESA/* Enable compacting of mode table */#define CONFIG_VIDEO_COMPACT/* Retain screen contents when switching modes */#define CONFIG_VIDEO_RETAIN/* Enable local mode list */#undef CONFIG_VIDEO_LOCAL/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */#undef CONFIG_VIDEO_400_HACK/* Hack that lets you force specific BIOS mode ID and specific dimensions */#undef CONFIG_VIDEO_GFX_HACK#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */#define VIDEO_GFX_BIOS_BX 0x0102#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 *//* This code uses an extended set of video mode numbers. These include: * Aliases for standard modes * NORMAL_VGA (-1) * EXTENDED_VGA (-2) * ASK_VGA (-3) * Video modes numbered by menu position -- NOT RECOMMENDED because of lack * of compatibility when extending the table. These are between 0x00 and 0xff. */#define VIDEO_FIRST_MENU 0x0000/* Standard BIOS video modes (BIOS number + 0x0100) */#define VIDEO_FIRST_BIOS 0x0100/* VESA BIOS video modes (VESA number + 0x0200) */#define VIDEO_FIRST_VESA 0x0200/* Video7 special modes (BIOS number + 0x0900) */#define VIDEO_FIRST_V7 0x0900/* Special video modes */#define VIDEO_FIRST_SPECIAL 0x0f00#define VIDEO_80x25 0x0f00#define VIDEO_8POINT 0x0f01#define VIDEO_80x43 0x0f02#define VIDEO_80x28 0x0f03#define VIDEO_CURRENT_MODE 0x0f04#define VIDEO_80x30 0x0f05#define VIDEO_80x34 0x0f06#define VIDEO_80x60 0x0f07#define VIDEO_GFX_HACK 0x0f08#define VIDEO_LAST_SPECIAL 0x0f09/* Video modes given by resolution */#define VIDEO_FIRST_RESOLUTION 0x1000/* The "recalculate timings" flag */#define VIDEO_RECALC 0x8000/* Positions of various video parameters passed to the kernel *//* (see also include/linux/tty.h) */#define PARAM_CURSOR_POS 0x00#define PARAM_VIDEO_PAGE 0x04#define PARAM_VIDEO_MODE 0x06#define PARAM_VIDEO_COLS 0x07#define PARAM_VIDEO_EGA_BX 0x0a#define PARAM_VIDEO_LINES 0x0e#define PARAM_HAVE_VGA 0x0f#define PARAM_FONT_POINTS 0x10#define PARAM_LFB_WIDTH 0x12#define PARAM_LFB_HEIGHT 0x14#define PARAM_LFB_DEPTH 0x16#define PARAM_LFB_BASE 0x18#define PARAM_LFB_SIZE 0x1c#define PARAM_LFB_LINELENGTH 0x24#define PARAM_LFB_COLORS 0x26#define PARAM_VESAPM_SEG 0x2e#define PARAM_VESAPM_OFF 0x30#define PARAM_LFB_PAGES 0x32#define PARAM_VESA_ATTRIB 0x34/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */#ifdef CONFIG_VIDEO_RETAIN#define DO_STORE call store_screen#else#define DO_STORE#endif /* CONFIG_VIDEO_RETAIN */# This is the main entry point called by setup.S# %ds *must* be pointing to the bootsectorvideo: pushw %ds # We use different segments pushw %ds # FS contains original DS popw %fs pushw %cs # DS is equal to CS popw %ds pushw %cs # ES is equal to CS popw %es xorw %ax, %ax movw %ax, %gs # GS is zero cld call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)#ifdef CONFIG_VIDEO_SELECT movw %fs:(0x01fa), %ax # User selected video mode cmpw $ASK_VGA, %ax # Bring up the menu jz vid2 call mode_set # Set the mode jc vid1 leaw badmdt, %si # Invalid mode ID call prtstrvid2: call mode_menuvid1:#ifdef CONFIG_VIDEO_RETAIN call restore_screen # Restore screen contents#endif /* CONFIG_VIDEO_RETAIN */ call store_edid#endif /* CONFIG_VIDEO_SELECT */ call mode_params # Store mode parameters popw %ds # Restore original DS ret# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.basic_detect: movb $0, %fs:(PARAM_HAVE_VGA) movb $0x12, %ah # Check EGA/VGA movb $0x10, %bl int $0x10 movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card. je basret incb adapter movw $0x1a00, %ax # Check EGA or VGA? int $0x10 cmpb $0x1a, %al # 1a means VGA... jne basret # anything else is EGA. incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA incb adapterbasret: ret# Store the video mode parameters for later usage by the kernel.# This is done by asking the BIOS except for the rows/columns# parameters in the default 80x25 mode -- these are set directly,# because some very obscure BIOSes supply insane values.mode_params:#ifdef CONFIG_VIDEO_SELECT cmpb $0, graphic_mode jnz mopar_gr#endif movb $0x03, %ah # Read cursor position xorb %bh, %bh int $0x10 movw %dx, %fs:(PARAM_CURSOR_POS) movb $0x0f, %ah # Read page/mode/width int $0x10 movw %bx, %fs:(PARAM_VIDEO_PAGE) movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width cmpb $0x7, %al # MDA/HGA => segment differs jnz mopar0 movw $0xb000, video_segmentmopar0: movw %gs:(0x485), %ax # Font size movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA) movw force_size, %ax # Forced size? orw %ax, %ax jz mopar1 movb %ah, %fs:(PARAM_VIDEO_COLS) movb %al, %fs:(PARAM_VIDEO_LINES) retmopar1: movb $25, %al cmpb $0, adapter # If we are on CGA/MDA/HGA, the jz mopar2 # screen must have 25 lines. movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS incb %al # location of max lines.mopar2: movb %al, %fs:(PARAM_VIDEO_LINES) ret#ifdef CONFIG_VIDEO_SELECT# Fetching of VESA frame buffer parametersmopar_gr: leaw modelist+1024, %di movb $0x23, %fs:(PARAM_HAVE_VGA) movw 16(%di), %ax movw %ax, %fs:(PARAM_LFB_LINELENGTH) movw 18(%di), %ax movw %ax, %fs:(PARAM_LFB_WIDTH) movw 20(%di), %ax movw %ax, %fs:(PARAM_LFB_HEIGHT) movb 25(%di), %al movb $0, %ah movw %ax, %fs:(PARAM_LFB_DEPTH) movb 29(%di), %al movb $0, %ah movw %ax, %fs:(PARAM_LFB_PAGES) movl 40(%di), %eax movl %eax, %fs:(PARAM_LFB_BASE) movl 31(%di), %eax movl %eax, %fs:(PARAM_LFB_COLORS) movl 35(%di), %eax movl %eax, %fs:(PARAM_LFB_COLORS+4) movw 0(%di), %ax movw %ax, %fs:(PARAM_VESA_ATTRIB)# get video mem size leaw modelist+1024, %di movw $0x4f00, %ax int $0x10 xorl %eax, %eax movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE)# switching the DAC to 8-bit is for <= 8 bpp only movw %fs:(PARAM_LFB_DEPTH), %ax cmpw $8, %ax jg dac_done# get DAC switching capability xorl %eax, %eax movb 10(%di), %al testb $1, %al jz dac_set# attempt to switch DAC to 8-bit movw $0x4f08, %ax movw $0x0800, %bx int $0x10 cmpw $0x004f, %ax jne dac_set movb %bh, dac_size # store actual DAC sizedac_set:# set color size to DAC size movb dac_size, %al movb %al, %fs:(PARAM_LFB_COLORS+0) movb %al, %fs:(PARAM_LFB_COLORS+2) movb %al, %fs:(PARAM_LFB_COLORS+4) movb %al, %fs:(PARAM_LFB_COLORS+6)# set color offsets to 0 movb $0, %fs:(PARAM_LFB_COLORS+1) movb $0, %fs:(PARAM_LFB_COLORS+3) movb $0, %fs:(PARAM_LFB_COLORS+5) movb $0, %fs:(PARAM_LFB_COLORS+7)dac_done:# get protected mode interface informations movw $0x4f0a, %ax xorw %bx, %bx xorw %di, %di int $0x10 cmp $0x004f, %ax jnz no_pm movw %es, %fs:(PARAM_VESAPM_SEG) movw %di, %fs:(PARAM_VESAPM_OFF)no_pm: ret# The video mode menumode_menu: leaw keymsg, %si # "Return/Space/Timeout" message call prtstr call flushnokey: call getkt cmpb $0x0d, %al # ENTER ? je listm # yes - manual mode selection cmpb $0x20, %al # SPACE ? je defmd1 # no - repeat call beep jmp nokeydefmd1: ret # No mode chosen? Default 80x25listm: call mode_table # List mode tablelistm0: leaw name_bann, %si # Print adapter name call prtstr movw card_name, %si orw %si, %si jnz an2 movb adapter, %al leaw old_name, %si orb %al, %al jz an1 leaw ega_name, %si decb %al jz an1 leaw vga_name, %si jmp an1an2: call prtstr leaw svga_name, %sian1: call prtstr leaw listhdr, %si # Table header call prtstr movb $0x30, %dl # DL holds mode number leaw modelist, %silm1: cmpw $ASK_VGA, (%si) # End? jz lm2 movb %dl, %al # Menu selection number call prtchr call prtsp2 lodsw call prthw # Mode ID call prtsp2 movb 0x1(%si), %al call prtdec # Rows movb $0x78, %al # the letter 'x' call prtchr lodsw call prtdec # Columns movb $0x0d, %al # New line call prtchr movb $0x0a, %al call prtchr incb %dl # Next character cmpb $0x3a, %dl jnz lm1 movb $0x61, %dl jmp lm1lm2: leaw prompt, %si # Mode prompt call prtstr leaw edit_buf, %di # Editor bufferlm3: call getkey cmpb $0x0d, %al # Enter? jz lment cmpb $0x08, %al # Backspace? jz lmbs cmpb $0x20, %al # Printable? jc lm3 cmpw $edit_buf+4, %di # Enough space? jz lm3 stosb call prtchr jmp lm3lmbs: cmpw $edit_buf, %di # Backspace jz lm3 decw %di movb $0x08, %al call prtchr call prtspc movb $0x08, %al call prtchr jmp lm3 lment: movb $0, (%di) leaw crlft, %si call prtstr leaw edit_buf, %si cmpb $0, (%si) # Empty string = default mode jz lmdef cmpb $0, 1(%si) # One character = menu selection jz mnusel cmpw $0x6373, (%si) # "scan" => mode scanning jnz lmhx cmpw $0x6e61, 2(%si) jz lmscanlmhx: xorw %bx, %bx # Else => mode ID in hexlmhex: lodsb orb %al, %al jz lmuse1 subb $0x30, %al jc lmbad cmpb $10, %al jc lmhx1 subb $7, %al andb $0xdf, %al cmpb $10, %al jc lmbad cmpb $16, %al jnc lmbadlmhx1: shlw $4, %bx orb %al, %bl jmp lmhexlmuse1: movw %bx, %ax jmp lmusemnusel: lodsb # Menu selection xorb %ah, %ah subb $0x30, %al jc lmbad cmpb $10, %al jc lmuse cmpb $0x61-0x30, %al jc lmbad subb $0x61-0x30-10, %al cmpb $36, %al jnc lmbadlmuse: call mode_set jc lmdeflmbad: leaw unknt, %si call prtstr jmp lm2lmscan: cmpb $0, adapter # Scanning only on EGA/VGA jz lmbad movw $0, mt_end # Scanning of modes is movb $1, scanning # done as new autodetection. call mode_table jmp listm0lmdef: ret# Additional parts of mode_set... (relative jumps, you know)setv7: # Video7 extended modes DO_STORE subb $VIDEO_FIRST_V7>>8, %bh movw $0x6f05, %ax int $0x10 stc ret_setrec: jmp setrec # Ugly..._set_80x25: jmp set_80x25# Aliases for backward compatibility.setalias: movw $VIDEO_80x25, %ax incw %bx jz mode_set movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al incw %bx jnz setbad # Fall-through!# Setting of user mode (AX=mode ID) => CF=successmode_set: movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S movw %ax, %bx cmpb $0xff, %ah jz setalias testb $VIDEO_RECALC>>8, %ah jnz _setrec cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah jnc setres cmpb $VIDEO_FIRST_SPECIAL>>8, %ah jz setspc cmpb $VIDEO_FIRST_V7>>8, %ah jz setv7 cmpb $VIDEO_FIRST_VESA>>8, %ah jnc check_vesa orb %ah, %ah jz setmenu decb %ah jz setbiossetbad: clc movb $0, do_restore # The screen needn't be restored retsetvesa: DO_STORE subb $VIDEO_FIRST_VESA>>8, %bh movw $0x4f02, %ax # VESA BIOS mode set call int $0x10 cmpw $0x004f, %ax # AL=4f if implemented jnz setbad # AH=0 if OK stc retsetbios: DO_STORE int $0x10 # Standard BIOS mode set call pushw %bx movb $0x0f, %ah # Check if really set int $0x10 popw %bx cmpb %bl, %al jnz setbad stc retsetspc: xorb %bh, %bh # Set special mode cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl jnc setbad addw %bx, %bx jmp *spec_inits(%bx)setmenu: orb %al, %al # 80x25 is an exception jz _set_80x25 pushw %bx # Set mode chosen from menu call mode_table # Build the mode table popw %ax shlw $2, %ax addw %ax, %si cmpw %di, %si jnc setbad movw (%si), %ax # Fetch mode ID_m_s: jmp mode_setsetres: pushw %bx # Set mode chosen by resolution call mode_table popw %bx xchgb %bl, %bhsetr1: lodsw cmpw $ASK_VGA, %ax # End of the list? jz setbad lodsw cmpw %bx, %ax jnz setr1 movw -4(%si), %ax # Fetch mode ID jmp _m_scheck_vesa: leaw modelist+1024, %di subb $VIDEO_FIRST_VESA>>8, %bh movw %bx, %cx # Get mode information structure movw $0x4f01, %ax int $0x10 addb $VIDEO_FIRST_VESA>>8, %bh cmpw $0x004f, %ax jnz setbad movb (%di), %al # Check capabilities. andb $0x19, %al cmpb $0x09, %al jz setvesa # This is a text mode movb (%di), %al # Check capabilities. andb $0x99, %al cmpb $0x99, %al jnz _setbad # Doh! No linear frame buffer. subb $VIDEO_FIRST_VESA>>8, %bh orw $0x4000, %bx # Use linear frame buffer movw $0x4f02, %ax # VESA BIOS mode set call int $0x10 cmpw $0x004f, %ax # AL=4f if implemented jnz _setbad # AH=0 if OK movb $1, graphic_mode # flag graphic mode movb $0, do_restore # no screen restore stc ret_setbad: jmp setbad # Ugly...# Recalculate vertical display end registers -- this fixes various# inconsistencies of extended modes on many adapters. Called when# the VIDEO_RECALC flag is set in the mode ID.setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode call mode_set jnc rct3 movw %gs:(0x485), %ax # Font size in pixels movb %gs:(0x484), %bl # Number of rows incb %bl mulb %bl # Number of visible decw %ax # scan lines - 1 movw $0x3d4, %dx movw %ax, %bx movb $0x12, %al # Lower 8 bits movb %bl, %ah outw %ax, %dx movb $0x07, %al # Bits 8 and 9 in the overflow register call inidx xchgb %al, %ah andb $0xbd, %ah shrb %bh jnc rct1 orb $0x02, %ahrct1: shrb %bh jnc rct2 orb $0x40, %ahrct2: movb $0x07, %al outw %ax, %dx stcrct3: ret# Table of routines for setting of the special modes.spec_inits: .word set_80x25 .word set_8pixel .word set_80x43 .word set_80x28 .word set_current .word set_80x30 .word set_80x34 .word set_80x60 .word set_gfx# Set the 80x25 mode. If already set, do nothing.set_80x25: movw $0x5019, force_size # Override possibly broken BIOSuse_80x25:#ifdef CONFIG_VIDEO_400_HACK movw $0x1202, %ax # Force 400 scan lines movb $0x30, %bl int $0x10#else movb $0x0f, %ah # Get current mode ID int $0x10 cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available jz st80 # on CGA/MDA/HGA and is also available on EGAM cmpw $0x5003, %ax # Unknown mode, force 80x25 color jnz force3st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25 jz set80 movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc. orb %al, %al # Some buggy BIOS'es set 0 rows
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -