Hi, I have attached patch here that adds simple terminal that uses VESA BIOS Extension 2.0+ for rendering terminal. It is not meant to be included as is in GRUB 2, but I would hope that people would test it, so I could try to improve it for greater compatibility (even though I have tried to follow the standards, there might be some glitches between implementations).
This terminal driver is based on vga terminal module and contains some common code from there, though many parts has been rewritten. When testing this patch, make sure that you have latest CVS version of GRUB 2. There are couple of things that I do not like in this patch. First one is that there should be common virtual terminal for all arch's and then separate graphics drivers that will do the actual drawing. In this patch this is all implemented in one module and it is not as pretty as it could be. Second one is that this patch uses VGA BIOS fonts to draw characters and it might cause some problems in some cards. Third one is that there are some testing functionality (vbe_test, vbe_list_modes) in same module, what would be best place to move those? Now how to get started on testing: - insmod vesafb - Use vbe_list_modes to find mode number (eg. 0x111) that you want to use. - set vbe_mode varible ('set vbe_mode=0x111') To test mode: - vbe_test To use it in terminal: - insmod terminal - terminal vesafb Thanks, Vesa Jääskeläinen
Index: ChangeLog =================================================================== RCS file: /cvsroot/grub/grub2/ChangeLog,v retrieving revision 1.149 diff -u -r1.149 ChangeLog --- ChangeLog 14 Aug 2005 11:04:12 -0000 1.149 +++ ChangeLog 14 Aug 2005 11:31:51 -0000 @@ -1,5 +1,13 @@ 2005-08-14 Vesa Jaaskelainen <[EMAIL PROTECTED]> + * DISTLIST: Added term/i386/pc/vesafb.c + * term/i386/pc/vesafb: New file. + * conf/i386-pc.rmk (pkgdata_MODULES): Added vesafb.mod. + (vesafb_mod_SOURCES): Added. + (vesafb_mod_CFLAGS): Likewise. + +2005-08-14 Vesa Jaaskelainen <[EMAIL PROTECTED]> + * DISTLIST: Added include/grub/i386/pc/vbe.h. 2005-08-13 Yoshinori K. Okuji <[EMAIL PROTECTED]> Index: DISTLIST =================================================================== RCS file: /cvsroot/grub/grub2/DISTLIST,v retrieving revision 1.9 diff -u -r1.9 DISTLIST --- DISTLIST 14 Aug 2005 11:04:12 -0000 1.9 +++ DISTLIST 14 Aug 2005 11:31:51 -0000 @@ -163,6 +163,7 @@ partmap/pc.c partmap/sun.c term/i386/pc/console.c +term/i386/pc/vesafb.c term/i386/pc/vga.c term/ieee1275/ofconsole.c util/i386/pc/biosdisk.c Index: conf/i386-pc.rmk =================================================================== RCS file: /cvsroot/grub/grub2/conf/i386-pc.rmk,v retrieving revision 1.39 diff -u -r1.39 i386-pc.rmk --- conf/i386-pc.rmk 12 Aug 2005 19:53:32 -0000 1.39 +++ conf/i386-pc.rmk 14 Aug 2005 11:31:56 -0000 @@ -111,7 +111,7 @@ font.mod _multiboot.mod ls.mod boot.mod cmp.mod cat.mod \ terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \ apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \ - help.mod default.mod timeout.mod configfile.mod + help.mod default.mod timeout.mod configfile.mod vesafb.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -251,3 +251,7 @@ # For configfile.mod configfile_mod_SOURCES = commands/configfile.c configfile_mod_CFLAGS = $(COMMON_CFLAGS) + +# For vesafb.mod. +vesafb_mod_SOURCES = term/i386/pc/vesafb.c +vesafb_mod_CFLAGS = $(COMMON_CFLAGS) Index: term/i386/pc/vesafb.c =================================================================== RCS file: term/i386/pc/vesafb.c diff -N term/i386/pc/vesafb.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ term/i386/pc/vesafb.c 14 Aug 2005 11:31:56 -0000 @@ -0,0 +1,1169 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <grub/machine/memory.h> +#include <grub/machine/vga.h> +#include <grub/machine/vbe.h> +#include <grub/machine/console.h> +#include <grub/term.h> +#include <grub/types.h> +#include <grub/dl.h> +#include <grub/misc.h> +#include <grub/normal.h> +#include <grub/font.h> +#include <grub/arg.h> +#include <grub/mm.h> +#include <grub/env.h> + +#define DEFAULT_VBE_MODE 0x101 +#define DEFAULT_CHAR_WIDTH 8 +#define DEFAULT_CHAR_HEIGHT 16 + +#define DEFAULT_FG_COLOR 0xa +#define DEFAULT_BG_COLOR 0x0 + +struct grub_colored_char +{ + /* An Unicode codepoint. */ + grub_uint32_t code; + + /* Color indexes. */ + unsigned char fg_color; + unsigned char bg_color; + + /* The width of this character minus one. */ + unsigned char width; + + /* The column index of this character. */ + unsigned char index; +}; + +struct grub_virtual_screen +{ + /* Dimensions of the virual screen. */ + grub_uint32_t width; + grub_uint32_t height; + + /* Offset in the display. */ + grub_uint32_t offset_x; + grub_uint32_t offset_y; + + /* TTY Character sizes. */ + grub_uint32_t char_width; + grub_uint32_t char_height; + + /* Virtual screen TTY size. */ + grub_uint32_t columns; + grub_uint32_t rows; + + /* Current cursor details. */ + grub_uint32_t cursor_x; + grub_uint32_t cursor_y; + grub_uint8_t cursor_state; + grub_uint8_t fg_color; + grub_uint8_t bg_color; + + /* Text buffer for virual screen. Contains (columns * rows) number + of entries. */ + struct grub_colored_char *text_buffer; +}; + +/* Specify "standard" VGA palette, some video cards may + need this and this will also be used when using RGB modes. */ +static struct grub_vbe_palette_data vga_colors[16] = + { + // {B, G, R, A} + {0x00, 0x00, 0x00, 0x00}, // 0 = black + {0xA8, 0x00, 0x00, 0x00}, // 1 = blue + {0x00, 0xA8, 0x00, 0x00}, // 2 = green + {0xA8, 0xA8, 0x00, 0x00}, // 3 = cyan + {0x00, 0x00, 0xA8, 0x00}, // 4 = red + {0xA8, 0x00, 0xA8, 0x00}, // 5 = magenta + {0x00, 0x54, 0xA8, 0x00}, // 6 = brown + {0xA8, 0xA8, 0xA8, 0x00}, // 7 = ligth gray + + {0x54, 0x54, 0x54, 0x00}, // 8 = dark gray + {0xFE, 0x54, 0x54, 0x00}, // 9 = bright blue + {0x54, 0xFE, 0x54, 0x00}, // 10 = bright green + {0xFE, 0xFE, 0x54, 0x00}, // 11 = bright cyan + {0x54, 0x54, 0xFE, 0x00}, // 12 = bright red + {0xFE, 0x54, 0xFE, 0x00}, // 13 = bright magenta + {0x54, 0xFE, 0xFE, 0x00}, // 14 = yellow + {0xFE, 0xFE, 0xFE, 0x00} // 15 = white + }; + +/* Make seure text buffer is not marked as allocated. */ +static struct grub_virtual_screen virtual_screen = + { + .text_buffer = 0 + }; + +static grub_dl_t my_mod; +static unsigned char *vga_font = 0; + +static int vbe_detected = 0; +static int index_color_mode = 0; + +static struct grub_vbe_info_block controller_info; +static struct grub_vbe_mode_info_block active_mode_info; + +static grub_uint32_t old_mode = 0; +static grub_uint32_t active_mode = 0; + +static grub_uint8_t *framebuffer = 0; +static grub_uint32_t bytes_per_scan_line = 0; + +// prototypes for helper functions +static grub_err_t grub_vesafb_probe (void); +static grub_err_t grub_vesafb_set_mode (grub_uint32_t mode); +static grub_err_t grub_vesafb_get_mode (grub_uint32_t *mode); +static grub_err_t grub_vesafb_get_mode_info (grub_uint32_t mode, struct grub_vbe_mode_info_block *mode_info); + +static grub_err_t +grub_vesafb_probe (void) +{ + struct grub_vbe_info_block *vbe_ib; + grub_uint32_t rc; + + /* Do not probe more than one time. */ + if (vbe_detected != 0) + { + return GRUB_ERR_NONE; + } + + /* Clear old copy of controller info block. */ + grub_memset (&controller_info, 0, sizeof(struct grub_vbe_info_block)); + + /* Mark VESA BIOS extension as undetected. */ + vbe_detected = 0; + + /* Use low memory scratch area as temporary storage for VESA BIOS call. */ + vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + /* Prepare info block. */ + grub_memset (vbe_ib, 0, sizeof(struct grub_vbe_info_block)); + + vbe_ib->signature[0] = 'V'; + vbe_ib->signature[1] = 'B'; + vbe_ib->signature[2] = 'E'; + vbe_ib->signature[3] = '2'; + + /* Try to get controller info block. */ + rc = grub_vbe_get_controller_info (vbe_ib); + if (rc != 0x004F) + { + return GRUB_ERR_BAD_DEVICE; + } + + /* Copy it for later usage. */ + grub_memcpy (&controller_info, + vbe_ib, + sizeof(struct grub_vbe_info_block)); + + /* Mark VESA BIOS extension as detected. */ + vbe_detected = 1; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_vesafb_set_mode (grub_uint32_t mode) +{ + grub_uint32_t rc; + + /* If grub_vesafb_probe has not been called or no VBE, abort. */ + if (vbe_detected == 0) + { + return GRUB_ERR_BAD_DEVICE; + } + + /* Try to get mode info. */ + rc = grub_vesafb_get_mode_info (mode, &active_mode_info); + if (rc != GRUB_ERR_NONE) + { + return rc; + } + + /* For all VESA BIOS modes, force linear frame buffer. */ + if (mode >= 0x100) + { + /* We only want linear frame buffer modes. */ + mode |= 1 << 14; + + /* Determine frame buffer pixel format. */ + switch(active_mode_info.memory_model) + { + case 0x04: + index_color_mode = 1; + break; + + case 0x06: + index_color_mode = 0; + break; + + default: + return GRUB_ERR_BAD_DEVICE; + } + } + + /* Try to set video mode. */ + rc = grub_vbe_set_mode (mode, 0); + if (rc != 0x004F) + { + return GRUB_ERR_BAD_DEVICE; + } + + /* Save information for later usage. */ + active_mode = mode; + + if (mode < 0x100) + { + /* If this is not a VESA mode, guess address. */ + framebuffer = (grub_uint8_t *)0xA0000; + index_color_mode = 1; + } + else + { + framebuffer = (grub_uint8_t *)active_mode_info.phys_base_addr; + + if (controller_info.version >= 0x300) + { + bytes_per_scan_line = active_mode_info.lin_bytes_per_scan_line; + } + else + { + bytes_per_scan_line = active_mode_info.bytes_per_scan_line; + } + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_vesafb_get_mode (grub_uint32_t *mode) +{ + grub_uint32_t rc; + + /* If grub_vesafb_probe has not been called or no VBE, abort. */ + if (vbe_detected == 0) + { + return GRUB_ERR_BAD_DEVICE; + } + + /* Try to query current mode from VESA BIOS. */ + rc = grub_vbe_get_mode (mode); + if (rc != 0x004F) + { + return GRUB_ERR_BAD_DEVICE; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_vesafb_get_mode_info (grub_uint32_t mode, struct grub_vbe_mode_info_block *mode_info) +{ + struct grub_vbe_mode_info_block *mi_tmp = (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_uint32_t rc; + + /* If grub_vesafb_probe has not been called or no VBE, abort. */ + if (vbe_detected == 0) + { + return GRUB_ERR_BAD_DEVICE; + } + + /* If mode is not VESA mode, skip mode info query. */ + if (mode >= 0x100) + { + /* Try to get mode info from VESA BIOS. */ + rc = grub_vbe_get_mode_info (mode, mi_tmp); + if (rc != 0x004F) + { + return GRUB_ERR_BAD_DEVICE; + } + + /* Make copy of mode info block. */ + grub_memcpy (mode_info, + mi_tmp, + sizeof(struct grub_vbe_mode_info_block)); + } + else + { + /* Just clear mode info block if it isn't a VESA mode. */ + grub_memset (mode_info, + 0, + sizeof(struct grub_vbe_mode_info_block)); + } + + return GRUB_ERR_NONE; +} + +static void +grub_vesafb_set_pixel_rgb (grub_uint32_t x, grub_uint32_t y, grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue) +{ + grub_uint32_t value; + + if (x >= active_mode_info.x_resolution) + return; + + if (y >= active_mode_info.y_resolution) + return; + + if (controller_info.version >= 0x300) + { + red >>= 8 - active_mode_info.lin_red_mask_size; + green >>= 8 - active_mode_info.lin_green_mask_size; + blue >>= 8 - active_mode_info.lin_blue_mask_size; + + value = red << active_mode_info.lin_red_field_position; + value |= green << active_mode_info.lin_green_field_position; + value |= blue << active_mode_info.lin_blue_field_position; + } + else + { + red >>= 8 - active_mode_info.red_mask_size; + green >>= 8 - active_mode_info.green_mask_size; + blue >>= 8 - active_mode_info.blue_mask_size; + + value = red << active_mode_info.red_field_position; + value |= green << active_mode_info.green_field_position; + value |= blue << active_mode_info.blue_field_position; + } + + if (active_mode_info.bits_per_pixel == 32) + { + grub_uint32_t *ptr = (grub_uint32_t *)(framebuffer + y * bytes_per_scan_line + x * 4); + + *ptr = value; + } + else if (active_mode_info.bits_per_pixel == 24) + { + grub_uint8_t *ptr = (grub_uint8_t *)(framebuffer + y * bytes_per_scan_line + x * 3); + grub_uint8_t *ptr2 = (grub_uint8_t *)&value; + + ptr[0] = ptr2[0]; + ptr[1] = ptr2[1]; + ptr[2] = ptr2[2]; + } + else if ((active_mode_info.bits_per_pixel == 16) || + (active_mode_info.bits_per_pixel == 15)) + { + grub_uint16_t *ptr = (grub_uint16_t *)(framebuffer + y * bytes_per_scan_line + x * 2); + + *ptr = (grub_uint16_t)(value & 0xFFFF); + } +} + +static void +grub_vesafb_set_pixel_index(grub_uint32_t x, grub_uint32_t y, grub_uint8_t color) +{ + if (x >= active_mode_info.x_resolution) + return; + + if (y >= active_mode_info.y_resolution) + return; + + if (index_color_mode == 1) + { + grub_uint8_t *ptr = (grub_uint8_t *)(framebuffer + y * bytes_per_scan_line + x); + + *ptr = color; + } + else + { + color &= 0x0F; + + if (color < 16) + { + grub_vesafb_set_pixel_rgb (x, + y, + vga_colors[color].red, + vga_colors[color].green, + vga_colors[color].blue); + } + else + { + grub_vesafb_set_pixel_rgb (x, + y, + 0, + 0, + 0xFF); + } + } +} + +static void +grub_virtual_screen_free (void) +{ + /* If virtual screen has been allocated, free it. */ + if (virtual_screen.text_buffer != 0) + { + grub_free (virtual_screen.text_buffer); + } + + /* Reset virtual screen data. */ + grub_memset (&virtual_screen, 0, sizeof(virtual_screen)); +} + +static grub_err_t +grub_virtual_screen_setup (grub_uint32_t width, + grub_uint32_t height) +{ + /* Free old virtual screen. */ + grub_virtual_screen_free (); + + /* Initialize with default data. */ + virtual_screen.width = width; + virtual_screen.height = height; + virtual_screen.offset_x = 0; + virtual_screen.offset_y = 0; + virtual_screen.char_width = DEFAULT_CHAR_WIDTH; + virtual_screen.char_height = DEFAULT_CHAR_HEIGHT; + virtual_screen.cursor_x = 0; + virtual_screen.cursor_y = 0; + virtual_screen.cursor_state = 1; + virtual_screen.fg_color = DEFAULT_FG_COLOR; + virtual_screen.bg_color = DEFAULT_BG_COLOR; + + /* Calculate size of text buffer. */ + virtual_screen.columns = virtual_screen.width / virtual_screen.char_width; + virtual_screen.rows = virtual_screen.height / virtual_screen.char_height; + + /* Allocate memory for text buffer. */ + virtual_screen.text_buffer = + (struct grub_colored_char *)grub_malloc (virtual_screen.columns * + virtual_screen.rows * + sizeof(struct grub_colored_char)); + if (virtual_screen.text_buffer == 0) + { + return GRUB_ERR_OUT_OF_MEMORY; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_vesafb_init (void) +{ + grub_uint32_t rc; + grub_uint32_t use_mode = DEFAULT_VBE_MODE; + char *modevar; + + /* Use fonts from VGA bios. */ + vga_font = grub_vga_get_font (); + + /* Check if we have VESA BIOS installed. */ + rc = grub_vesafb_probe (); + if (rc != GRUB_ERR_NONE) + { + return rc; + } + + /* Check existence of vbe_mode environment variable. */ + modevar = grub_env_get ("vbe_mode"); + + if (modevar != 0) + { + unsigned long value = 0; + + if ((grub_strncmp (modevar, "0x", 2) == 0) || + (grub_strncmp (modevar, "0X", 2) == 0)) + { + /* Convert HEX mode number. */ + value = grub_strtoul (modevar + 2, 0, 16); + } + else + { + /* Convert DEC mode number. */ + value = grub_strtoul (modevar, 0, 10); + } + + if (value != 0) + { + use_mode = value; + } + } + + /* Store initial video mode. */ + rc = grub_vesafb_get_mode (&old_mode); + + /* Setup desired graphics mode. */ + rc = grub_vesafb_set_mode (use_mode); + if (rc != GRUB_ERR_NONE) + { + return rc; + } + + /* Create virtual screen. */ + rc = grub_virtual_screen_setup (active_mode_info.x_resolution, + active_mode_info.y_resolution); + if (rc != GRUB_ERR_NONE) + { + grub_vesafb_set_mode (old_mode); + return rc; + } + + /* Make sure frame buffer is black. */ + grub_memset (framebuffer, + 0, + bytes_per_scan_line * active_mode_info.y_resolution); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_vesafb_fini (void) +{ + grub_virtual_screen_free (); + + grub_vesafb_set_mode (old_mode); + + return GRUB_ERR_NONE; +} + +static int +grub_virtual_screen_get_glyph (grub_uint32_t code, + unsigned char bitmap[32], + unsigned *width) +{ + if (code > 0x7f) + { + /* Map some unicode characters to the VGA font, if possible. */ + switch (code) + { + case 0x2190: /* left arrow */ + code = 0x1b; + break; + case 0x2191: /* up arrow */ + code = 0x18; + break; + case 0x2192: /* right arrow */ + code = 0x1a; + break; + case 0x2193: /* down arrow */ + code = 0x19; + break; + case 0x2501: /* horizontal line */ + code = 0xc4; + break; + case 0x2503: /* vertical line */ + code = 0xb3; + break; + case 0x250F: /* upper-left corner */ + code = 0xda; + break; + case 0x2513: /* upper-right corner */ + code = 0xbf; + break; + case 0x2517: /* lower-left corner */ + code = 0xc0; + break; + case 0x251B: /* lower-right corner */ + code = 0xd9; + break; + + default: + return grub_font_get_glyph (code, bitmap, width); + } + } + + if (bitmap) + grub_memcpy (bitmap, + vga_font + code * virtual_screen.char_height, + virtual_screen.char_height); + *width = 1; + return 1; +} + +static void +grub_virtual_screen_invalidate_char (struct grub_colored_char *p) +{ + p->code = 0xFFFF; + + if (p->width) + { + struct grub_colored_char *q; + + for (q = p + 1; q <= p + p->width; q++) + { + q->code = 0xFFFF; + q->width = 0; + q->index = 0; + } + } + + p->width = 0; +} + +static void +write_char (void) +{ + struct grub_colored_char *p; + unsigned char bitmap[32]; + unsigned width; + + p = (virtual_screen.text_buffer + + virtual_screen.cursor_x + + (virtual_screen.cursor_y * virtual_screen.columns)); + + p -= p->index; + + if (! grub_virtual_screen_get_glyph (p->code, bitmap, &width)) + { + grub_virtual_screen_invalidate_char (p); + width = 0; + } + + unsigned y; + unsigned offset; + + for (y = 0, offset = 0; + y < virtual_screen.char_height; + y++, offset++) + { + unsigned i; + + for (i = 0; + (i < width * virtual_screen.char_width) && (offset < 32); + i++) + { + unsigned char color; + + if (bitmap[offset] & (1<<(8-i))) + { + color = p->fg_color; + } + else + { + color = p->bg_color; + } + + grub_vesafb_set_pixel_index(i + (virtual_screen.cursor_x * virtual_screen.char_width), + y + (virtual_screen.cursor_y * virtual_screen.char_height), + color); + } + } +} + +static void +write_cursor (void) +{ + grub_uint32_t x; + grub_uint32_t y; + + for (y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3; + y < ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 1; + y++) + { + for (x = virtual_screen.cursor_x * virtual_screen.char_width; + x < (virtual_screen.cursor_x + 1) * virtual_screen.char_width; + x++) + { + grub_vesafb_set_pixel_index(x, y, 10); + } + } +} + +static void +scroll_up (void) +{ + grub_uint32_t i; + + /* Scroll text buffer with one line to up. */ + grub_memmove (virtual_screen.text_buffer, + virtual_screen.text_buffer + virtual_screen.columns, + sizeof (struct grub_colored_char) * + virtual_screen.columns * + (virtual_screen.rows - 1)); + + /* Clear last line in text buffer. */ + for (i = virtual_screen.columns * (virtual_screen.rows - 1); + i < virtual_screen.columns * virtual_screen.rows; + i++) + { + virtual_screen.text_buffer[i].code = ' '; + virtual_screen.text_buffer[i].fg_color = 0; + virtual_screen.text_buffer[i].bg_color = 0; + virtual_screen.text_buffer[i].width = 0; + virtual_screen.text_buffer[i].index = 0; + } + + /* Scroll frambuffer with one line to up. */ + grub_memmove (framebuffer, + framebuffer + bytes_per_scan_line * virtual_screen.char_height, + bytes_per_scan_line * + (active_mode_info.y_resolution - virtual_screen.char_height)); + + /* Clear last line in framebuffer. */ + grub_memset (framebuffer + + (bytes_per_scan_line * + (active_mode_info.y_resolution - virtual_screen.char_height)), + 0, + bytes_per_scan_line * virtual_screen.char_height); +} + +static void +grub_vesafb_putchar (grub_uint32_t c) +{ + if (c == '\a') + /* FIXME */ + return; + + if (c == '\b' || c == '\n' || c == '\r') + { + /* Erase current cursor, if any. */ + if (virtual_screen.cursor_state) + write_char (); + + switch (c) + { + case '\b': + if (virtual_screen.cursor_x > 0) + virtual_screen.cursor_x--; + break; + + case '\n': + if (virtual_screen.cursor_y >= virtual_screen.rows - 1) + scroll_up (); + else + virtual_screen.cursor_y++; + break; + + case '\r': + virtual_screen.cursor_x = 0; + break; + } + + if (virtual_screen.cursor_state) + write_cursor (); + } + else + { + unsigned width; + struct grub_colored_char *p; + + grub_virtual_screen_get_glyph (c, 0, &width); + + if (virtual_screen.cursor_x + width > virtual_screen.columns) + grub_putchar ('\n'); + + p = virtual_screen.text_buffer + + virtual_screen.cursor_x + + virtual_screen.cursor_y * virtual_screen.columns; + p->code = c; + p->fg_color = virtual_screen.fg_color; + p->bg_color = virtual_screen.bg_color; + p->width = width - 1; + p->index = 0; + + if (width > 1) + { + unsigned i; + + for (i = 1; i < width; i++) + { + p[i].code = ' '; + p[i].width = width - 1; + p[i].index = i; + } + } + + write_char (); + + virtual_screen.cursor_x += width; + if (virtual_screen.cursor_x >= virtual_screen.columns) + { + virtual_screen.cursor_x = 0; + + if (virtual_screen.cursor_y >= virtual_screen.rows - 1) + scroll_up (); + else + virtual_screen.cursor_y++; + } + + if (virtual_screen.cursor_state) + write_cursor (); + } +} + +static grub_uint16_t +grub_virtual_screen_getwh (void) +{ + return (virtual_screen.columns << 8) | virtual_screen.rows; +} + +static grub_uint16_t +grub_virtual_screen_getxy (void) +{ + return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y); +} + +static void +grub_vesafb_gotoxy (grub_uint8_t x, grub_uint8_t y) +{ + if (x >= virtual_screen.columns || y >= virtual_screen.rows) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", + (unsigned) x, (unsigned) y); + return; + } + + if (virtual_screen.cursor_state) + write_char (); + + virtual_screen.cursor_x = x; + virtual_screen.cursor_y = y; + + if (virtual_screen.cursor_state) + write_cursor (); +} + +static void +grub_virtual_screen_cls (void) +{ + grub_uint32_t i; + + for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) + { + virtual_screen.text_buffer[i].code = ' '; + virtual_screen.text_buffer[i].fg_color = 0; + virtual_screen.text_buffer[i].bg_color = 0; + virtual_screen.text_buffer[i].width = 0; + virtual_screen.text_buffer[i].index = 0; + } + + virtual_screen.cursor_x = virtual_screen.cursor_y = 0; +} + +static void +grub_vesafb_cls (void) +{ + grub_virtual_screen_cls (); + + grub_memset (framebuffer, + 0, + active_mode_info.y_resolution * bytes_per_scan_line); +} + +static void +grub_virtual_screen_setcolorstate (grub_term_color_state state) +{ + switch (state) + { + case GRUB_TERM_COLOR_STANDARD: + case GRUB_TERM_COLOR_NORMAL: + virtual_screen.fg_color = DEFAULT_FG_COLOR; + virtual_screen.bg_color = DEFAULT_BG_COLOR; + break; + case GRUB_TERM_COLOR_HIGHLIGHT: + virtual_screen.fg_color = DEFAULT_BG_COLOR; + virtual_screen.bg_color = DEFAULT_FG_COLOR; + break; + default: + break; + } +} + +static void +grub_virtual_screen_setcolor (grub_uint8_t normal_color __attribute__ ((unused)), + grub_uint8_t highlight_color __attribute__ ((unused))) +{ + /* FIXME */ +} + +static void +grub_vesafb_setcursor (int on) +{ + if (virtual_screen.cursor_state != on) + { + if (virtual_screen.cursor_state) + write_char (); + else + write_cursor (); + + virtual_screen.cursor_state = on; + } +} + +static void +*real2pm(grub_vbe_farptr_t ptr) +{ + return (void *)((((unsigned long)ptr & 0xFFFF0000) >> 12UL) + + ((unsigned long)ptr & 0x0000FFFF)); +} + +static grub_err_t +grub_cmd_vbe_list_modes(struct grub_arg_list *state __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_uint32_t rc; + grub_uint16_t *sptr; + + grub_printf ("List of compatible video modes:\n"); + + rc = grub_vesafb_probe (); + + if (rc != GRUB_ERR_NONE) + { + grub_printf ("VESA BIOS Extension not detected!\n"); + return rc; + } + + sptr = real2pm (controller_info.video_mode_ptr); + + struct grub_vbe_mode_info_block mode_info; + + for (;*sptr != 0xFFFF; sptr++) + { + int valid_mode = 1; + + rc = grub_vesafb_get_mode_info (*sptr, &mode_info); + if (rc != GRUB_ERR_NONE) continue; + + if ((mode_info.mode_attributes & 0x080) == 0) + { + // we support only linear frame buffer modes + continue; + } + + if ((mode_info.mode_attributes & 0x010) == 0) + { + // we allow only graphic modes + continue; + } + + switch(mode_info.memory_model) + { + case 0x04: + case 0x06: + break; + + default: + valid_mode = 0; + break; + } + + if (valid_mode == 0) continue; + + grub_printf ("0x%03x: %d x %d x %d bpp\n", + *sptr, + mode_info.x_resolution, + mode_info.y_resolution, + mode_info.bits_per_pixel); + } + + char *modevar; + + // Check existence of vbe_mode environment variable + modevar = grub_env_get ("vbe_mode"); + + grub_uint32_t use_mode = DEFAULT_VBE_MODE; + + if (modevar != 0) + { + unsigned long value = 0; + + if ((grub_strncmp (modevar, "0x", 2) == 0) || + (grub_strncmp (modevar, "0X", 2) == 0)) + { + // hex version + value = grub_strtoul (modevar+2, 0, 16); + } + else + { + // dec version + value = grub_strtoul (modevar, 0, 10); + } + + if (value != 0) + { + use_mode = value; + } + } + + grub_printf ("Configured VBE mode (vbe_mode) = 0x%03x\n", use_mode); + + return 0; +} + +static grub_err_t +grub_cmd_vbe_test(struct grub_arg_list *state __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_uint32_t rc; + grub_uint16_t *sptr; + char *modevar; + struct grub_vbe_mode_info_block mode_info; + grub_uint32_t use_mode = DEFAULT_VBE_MODE; + unsigned char *ptr; + int i; + + grub_printf ("Probing for VESA BIOS Extension ... "); + + // Check if VESA BIOS exists + rc = grub_vesafb_probe(); + if (rc != GRUB_ERR_NONE) + { + grub_printf ("not found!\n"); + return rc; + } + grub_printf ("found!\n"); + + // dump out controller information + grub_printf ("vbe signature = %c%c%c%c\n", + controller_info.signature[0], + controller_info.signature[1], + controller_info.signature[2], + controller_info.signature[3]); + + grub_printf ("vbe ver = %d.%d\n", + controller_info.version >> 8, + controller_info.version & 0xFF); + grub_printf ("oem string ptr = %08x\n", + controller_info.oem_string_ptr); + grub_printf ("total memory = %d\n", + controller_info.total_memory); + + sptr = real2pm(controller_info.video_mode_ptr); + + rc = grub_vesafb_get_mode(&old_mode); + grub_printf ("get mode rc = %04x\n", rc); + + if (rc == GRUB_ERR_NONE) + { + grub_printf ("old mode = %04x\n", old_mode); + } + + // Check existence of vbe_mode environment variable + modevar = grub_env_get ("vbe_mode"); + if (modevar != 0) + { + unsigned long value = 0; + + if ((grub_strncmp (modevar, "0x", 2) == 0) || + (grub_strncmp (modevar, "0X", 2) == 0)) + { + // hex version + value = grub_strtoul (modevar+2, 0, 16); + } + else + { + // dec version + value = grub_strtoul (modevar, 0, 10); + } + + if (value != 0) + { + use_mode = value; + } + } + + rc = grub_vesafb_get_mode_info (use_mode, &mode_info); + + grub_printf ("mode: 0x%03x\n", + use_mode); + grub_printf ("width : %d\n", + mode_info.x_resolution); + grub_printf ("height: %d\n", + mode_info.y_resolution); + grub_printf ("memory model: %02x\n", + mode_info.memory_model); + grub_printf ("bytes/scanline: %d\n", + mode_info.bytes_per_scan_line); + grub_printf ("bytes/scanline (lin): %d\n", + mode_info.lin_bytes_per_scan_line); + grub_printf ("base address: %08x\n", + mode_info.phys_base_addr); + grub_printf ("red mask/pos: %d/%d\n", + mode_info.red_mask_size, + mode_info.red_field_position); + grub_printf ("green mask/pos: %d/%d\n", + mode_info.green_mask_size, + mode_info.green_field_position); + grub_printf ("blue mask/pos: %d/%d\n", + mode_info.blue_mask_size, + mode_info.blue_field_position); + + grub_getkey (); + + // setup gfx mode + rc = grub_vesafb_set_mode (use_mode); + + rc = grub_vbe_set_palette_data (16, 0, vga_colors); + + ptr = framebuffer; + + for (i = 0; i < 256 * 256; i++) + { + ptr[i] = i & 0x0F; + } + + for (i = 0; i < 100; i++) + { + ptr[active_mode_info.bytes_per_scan_line * 50 + i] = 0x0F; + } + + grub_memset (ptr + bytes_per_scan_line * 51, 0xff, bytes_per_scan_line); + + grub_getkey (); + + grub_vesafb_set_mode (old_mode); + + return 0; +} + +static struct grub_term grub_vesafb_term = + { + .name = "vesafb", + .init = grub_vesafb_init, + .fini = grub_vesafb_fini, + .putchar = grub_vesafb_putchar, + .checkkey = grub_console_checkkey, + .getkey = grub_console_getkey, + .getwh = grub_virtual_screen_getwh, + .getxy = grub_virtual_screen_getxy, + .gotoxy = grub_vesafb_gotoxy, + .cls = grub_vesafb_cls, + .setcolorstate = grub_virtual_screen_setcolorstate, + .setcolor = grub_virtual_screen_setcolor, + .setcursor = grub_vesafb_setcursor, + .flags = 0, + .next = 0 + }; + +GRUB_MOD_INIT +{ + my_mod = mod; + grub_term_register (&grub_vesafb_term); + + grub_register_command ("vbe_list_modes", grub_cmd_vbe_list_modes, GRUB_COMMAND_FLAG_BOTH, + "vbe_list_modes", "List's compatible VESA BIOS extension modes.", 0); + + grub_register_command ("vbe_test", grub_cmd_vbe_test, GRUB_COMMAND_FLAG_BOTH, + "vbe_test", "Test VBE", 0); +} + +GRUB_MOD_FINI +{ + grub_unregister_command ("vbe_test"); + grub_unregister_command ("vbe_list_modes"); + grub_term_unregister (&grub_vesafb_term); +}
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel