diff --git a/src/arch/i386/include/ipxe/vesafb.h b/src/arch/i386/include/ipxe/vesafb.h new file mode 100644 index 00000000..48cd6a7b --- /dev/null +++ b/src/arch/i386/include/ipxe/vesafb.h @@ -0,0 +1,210 @@ +#ifndef _IPXE_VESAFB_H +#define _IPXE_VESAFB_H + +/** @file + * + * VESA frame buffer console + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** INT 10,4f00: return controller information */ +#define VBE_CONTROLLER_INFO 0x4f00 + +/** VBE controller information */ +struct vbe_controller_info { + /** VBE signature */ + uint32_t vbe_signature; + /** VBE minor version */ + uint8_t vbe_minor_version; + /** VBE major version */ + uint8_t vbe_major_version; + /** Pointer to OEM string */ + struct segoff oem_string_ptr; + /** Capabilities of graphics controller */ + uint32_t capabilities; + /** Pointer to video mode list */ + struct segoff video_mode_ptr; + /** Number of 64kB memory blocks */ + uint16_t total_memory; + /** VBE implementation software revision */ + uint16_t oem_software_rev; + /** Pointer to vendor name string */ + struct segoff oem_vendor_name_ptr; + /** Pointer to product name string */ + struct segoff oem_product_name_ptr; + /** Pointer to product revision string */ + struct segoff oem_product_rev_ptr; + /** Reserved for VBE implementation scratch area */ + uint8_t reserved[222]; + /* VBE2.0 defines an additional 256-byte data area for + * including the OEM strings inline within the VBE information + * block; we omit this to reduce the amount of base memory + * required for VBE calls. + */ +} __attribute__ (( packed )); + +/** VBE controller information signature */ +#define VBE_CONTROLLER_SIGNATURE \ + ( ( 'V' << 0 ) | ( 'E' << 8 ) | ( 'S' << 16 ) | ( 'A' << 24 ) ) + +/** VBE mode list end marker */ +#define VBE_MODE_END 0xffff + +/** INT 10,4f01: return VBE mode information */ +#define VBE_MODE_INFO 0x4f01 + +/** VBE mode information */ +struct vbe_mode_info { + /** Mode attributes */ + uint16_t mode_attributes; + /** Window A attributes */ + uint8_t win_a_attributes; + /** Window B attributes */ + uint8_t win_b_attributes; + /** Window granularity */ + uint16_t win_granularity; + /** Window size */ + uint16_t win_size; + /** Window A start segment */ + uint16_t win_a_segment; + /** Window B start segment */ + uint16_t win_b_segment; + /** Pointer to window function */ + struct segoff win_func_ptr; + /** Bytes per scan line */ + uint16_t bytes_per_scan_line; + /** Horizontal resolution in pixels or characters */ + uint16_t x_resolution; + /** Vertical resolution in pixels or characters */ + uint16_t y_resolution; + /** Character cell width in pixels */ + uint8_t x_char_size; + /** Character cell height in pixels */ + uint8_t y_char_size; + /** Number of memory planes */ + uint8_t number_of_planes; + /** Bits per pixel */ + uint8_t bits_per_pixel; + /** Number of banks */ + uint8_t number_of_banks; + /** Memory model type */ + uint8_t memory_model; + /** Bank size in kB */ + uint8_t bank_size; + /** Number of images */ + uint8_t number_of_image_pages; + /** Reserved for page function */ + uint8_t reserved_1; + /** Size of direct colour red mask in bits */ + uint8_t red_mask_size; + /** Bit position of LSB of red mask */ + uint8_t red_field_position; + /** Size of direct colour green mask in bits */ + uint8_t green_mask_size; + /** Bit position of LSB of green mask */ + uint8_t green_field_position; + /** Size of direct colour blue mask in bits */ + uint8_t blue_mask_size; + /** Bit position of LSB of blue mask */ + uint8_t blue_field_position; + /** Size of direct colour reserved mask in bits */ + uint8_t rsvd_mask_size; + /** Bit position of LSB of reserved mask */ + uint8_t rsvd_field_position; + /** Direct colour mode attributes */ + uint8_t direct_colour_mode_info; + /** Physical address for flat memory frame buffer */ + uint32_t phys_base_ptr; + /** Pointer to start of off-screen memory */ + uint32_t off_screen_mem_offset; + /** Amount of off-screen memory in 1kB units */ + uint16_t off_screen_mem_size; + /** Reserved */ + uint8_t reserved_2[206]; +} __attribute__ (( packed )); + +/** VBE mode attributes */ +enum vbe_mode_attributes { + /** Mode supported in hardware */ + VBE_MODE_ATTR_SUPPORTED = 0x0001, + /** TTY output functions supported by BIOS */ + VBE_MODE_ATTR_TTY = 0x0004, + /** Colour mode */ + VBE_MODE_ATTR_COLOUR = 0x0008, + /** Graphics mode */ + VBE_MODE_ATTR_GRAPHICS = 0x0010, + /** Not a VGA compatible mode */ + VBE_MODE_ATTR_NOT_VGA = 0x0020, + /** VGA compatible windowed memory mode is not available */ + VBE_MODE_ATTR_NOT_WINDOWED = 0x0040, + /** Linear frame buffer mode is available */ + VBE_MODE_ATTR_LINEAR = 0x0080, + /** Double scan mode is available */ + VBE_MODE_ATTR_DOUBLE = 0x0100, + /** Interlaced mode is available */ + VBE_MODE_ATTR_INTERLACED = 0x0200, + /** Hardware triple buffering support */ + VBE_MODE_ATTR_TRIPLE_BUF = 0x0400, + /** Hardware stereoscopic display support */ + VBE_MODE_ATTR_STEREO = 0x0800, + /** Dual display start address support */ + VBE_MODE_ATTR_DUAL = 0x1000, +}; + +/** VBE mode memory models */ +enum vbe_mode_memory_model { + /** Text mode */ + VBE_MODE_MODEL_TEXT = 0x00, + /** CGA graphics mode */ + VBE_MODE_MODEL_CGA = 0x01, + /** Hercules graphics mode */ + VBE_MODE_MODEL_HERCULES = 0x02, + /** Planar mode */ + VBE_MODE_MODEL_PLANAR = 0x03, + /** Packed pixel mode */ + VBE_MODE_MODEL_PACKED_PIXEL = 0x04, + /** Non-chain 4, 256 colour mode */ + VBE_MODE_MODEL_NON_CHAIN_4 = 0x05, + /** Direct colour mode */ + VBE_MODE_MODEL_DIRECT_COLOUR = 0x06, + /** YUV mode */ + VBE_MODE_MODEL_YUV = 0x07, +}; + +/** INT 10,4f02: set VBE mode */ +#define VBE_SET_MODE 0x4f02 + +/** VBE linear frame buffer mode bit */ +#define VBE_MODE_LINEAR 0x4000 + +/** INT 10,1130: get font information */ +#define VBE_GET_FONT 0x1130 + +/** Font sets */ +enum vbe_font_set { + /** 8x14 character font */ + VBE_FONT_8x14 = 0x0200, + /** 8x8 double dot font */ + VBE_FONT_8x8_DOUBLE = 0x0300, + /** 8x8 double dot font (high 128 characters) */ + VBE_FONT_8x8_DOUBLE_HIGH = 0x0400, + /** 9x14 alpha alternate font */ + VBE_FONT_9x14_ALPHA_ALT = 0x0500, + /** 8x16 font */ + VBE_FONT_8x16 = 0x0600, + /** 9x16 alternate font */ + VBE_FONT_9x16_ALT = 0x0700, +}; + +/** INT 10,00: set VGA mode */ +#define VBE_SET_VGA_MODE 0x0000 + +/** INT 10,0f: get VGA mode */ +#define VBE_GET_VGA_MODE 0x0f00 + +#endif /* _IPXE_VESAFB_H */ diff --git a/src/arch/i386/interface/pcbios/vesafb.c b/src/arch/i386/interface/pcbios/vesafb.c new file mode 100644 index 00000000..e762a48e --- /dev/null +++ b/src/arch/i386/interface/pcbios/vesafb.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2013 Michael Brown . + * + * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * VESA frame buffer console + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Avoid dragging in BIOS console if not otherwise used */ +extern struct console_driver bios_console; +struct console_driver bios_console __attribute__ (( weak )); + +/* Disambiguate the various error causes */ +#define EIO_FAILED __einfo_error ( EINFO_EIO_FAILED ) +#define EINFO_EIO_FAILED \ + __einfo_uniqify ( EINFO_EIO, 0x01, \ + "Function call failed" ) +#define EIO_HARDWARE __einfo_error ( EINFO_EIO_HARDWARE ) +#define EINFO_EIO_HARDWARE \ + __einfo_uniqify ( EINFO_EIO, 0x02, \ + "Not supported in current configuration" ) +#define EIO_MODE __einfo_error ( EINFO_EIO_MODE ) +#define EINFO_EIO_MODE \ + __einfo_uniqify ( EINFO_EIO, 0x03, \ + "Invalid in current video mode" ) +#define EIO_VBE( code ) \ + EUNIQ ( EINFO_EIO, (code), EIO_FAILED, EIO_HARDWARE, EIO_MODE ) + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_VESAFB ) && CONSOLE_EXPLICIT ( CONSOLE_VESAFB ) ) +#undef CONSOLE_VESAFB +#define CONSOLE_VESAFB ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) +#endif + +/** Font corresponding to selected character width and height */ +#define VESAFB_FONT VBE_FONT_8x16 + +/* Forward declaration */ +struct console_driver vesafb_console __console_driver; + +/** A VESA frame buffer */ +struct vesafb { + /** Frame buffer console */ + struct fbcon fbcon; + /** Pixel geometry */ + struct fbcon_geometry pixel; + /** Colour mapping */ + struct fbcon_colour_map map; + /** Font definition */ + struct fbcon_font font; + /** Total length */ + size_t len; + /** Saved VGA mode */ + uint8_t saved_mode; +}; + +/** The VESA frame buffer */ +static struct vesafb vesafb; + +/** Base memory buffer used for VBE calls */ +union vbe_buffer { + /** VBE controller information block */ + struct vbe_controller_info controller; + /** VBE mode information block */ + struct vbe_mode_info mode; +}; +static union vbe_buffer __bss16 ( vbe_buf ); +#define vbe_buf __use_data16 ( vbe_buf ) + +/** + * Convert VBE status code to iPXE status code + * + * @v status VBE status code + * @ret rc Return status code + */ +static int vesafb_rc ( unsigned int status ) { + unsigned int code; + + if ( ( status & 0xff ) != 0x4f ) + return -ENOTSUP; + code = ( ( status >> 8 ) & 0xff ); + return ( code ? -EIO_VBE ( code ) : 0 ); +} + +/** + * Get font definition + * + */ +static void vesafb_font ( void ) { + struct segoff font; + + /* Get font information + * + * Working around gcc bugs is icky here. The value we want is + * returned in %ebp, but there's no way to specify %ebp in an + * output constraint. We can't put %ebp in the clobber list, + * because this tends to cause random build failures on some + * gcc versions. We can't manually push/pop %ebp and return + * the value via a generic register output constraint, because + * gcc might choose to use %ebp to satisfy that constraint + * (and we have no way to prevent it from so doing). + * + * Work around this hideous mess by using %ecx and %edx as the + * output registers, since they get clobbered anyway. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushw %%bp\n\t" /* gcc bug */ + "int $0x10\n\t" + "movw %%es, %%cx\n\t" + "movw %%bp, %%dx\n\t" + "popw %%bp\n\t" /* gcc bug */ ) + : "=c" ( font.segment ), + "=d" ( font.offset ) + : "a" ( VBE_GET_FONT ), + "b" ( VESAFB_FONT ) ); + DBGC ( &vbe_buf, "VESAFB has font %04x at %04x:%04x\n", + VESAFB_FONT, font.segment, font.offset ); + vesafb.font.start = real_to_user ( font.segment, font.offset ); +} + +/** + * Get VBE mode list + * + * @ret mode_numbers Mode number list (terminated with VBE_MODE_END) + * @ret rc Return status code + * + * The caller is responsible for eventually freeing the mode list. + */ +static int vesafb_mode_list ( uint16_t **mode_numbers ) { + struct vbe_controller_info *controller = &vbe_buf.controller; + userptr_t video_mode_ptr; + uint16_t mode_number; + uint16_t status; + size_t len; + int rc; + + /* Avoid returning uninitialised data on error */ + *mode_numbers = NULL; + + /* Get controller information block */ + controller->vbe_signature = 0; + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( status ) + : "a" ( VBE_CONTROLLER_INFO ), + "D" ( __from_data16 ( controller ) ) + : "memory" ); + if ( ( rc = vesafb_rc ( status ) ) != 0 ) { + DBGC ( &vbe_buf, "VESAFB could not get controller information: " + "%s\n", strerror ( rc ) ); + return rc; + } + if ( controller->vbe_signature != VBE_CONTROLLER_SIGNATURE ) { + DBGC ( &vbe_buf, "VESAFB invalid controller signature " + "\"%c%c%c%c\"\n", ( controller->vbe_signature >> 0 ), + ( controller->vbe_signature >> 8 ), + ( controller->vbe_signature >> 16 ), + ( controller->vbe_signature >> 24 ) ); + DBGC_HDA ( &vbe_buf, 0, controller, sizeof ( *controller ) ); + return -EINVAL; + } + DBGC ( &vbe_buf, "VESAFB found VBE version %d.%d with mode list at " + "%04x:%04x\n", controller->vbe_major_version, + controller->vbe_minor_version, + controller->video_mode_ptr.segment, + controller->video_mode_ptr.offset ); + + /* Calculate length of mode list */ + video_mode_ptr = real_to_user ( controller->video_mode_ptr.segment, + controller->video_mode_ptr.offset ); + len = 0; + do { + copy_from_user ( &mode_number, video_mode_ptr, len, + sizeof ( mode_number ) ); + len += sizeof ( mode_number ); + } while ( mode_number != VBE_MODE_END ); + + /* Allocate and fill mode list */ + *mode_numbers = malloc ( len ); + if ( ! *mode_numbers ) + return -ENOMEM; + copy_from_user ( *mode_numbers, video_mode_ptr, 0, len ); + + return 0; +} + +/** + * Set video mode + * + * @v mode_number Mode number + * @v mode Mode information + * @v pixbuf Background picture (if any) + * @ret rc Return status code + */ +static int vesafb_set_mode ( unsigned int mode_number, + struct vbe_mode_info *mode, + struct pixel_buffer *pixbuf ) { + uint16_t status; + int rc; + + /* Select this mode */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( status ) + : "a" ( VBE_SET_MODE ), + "b" ( mode_number ) ); + if ( ( rc = vesafb_rc ( status ) ) != 0 ) { + DBGC ( &vbe_buf, "VESAFB could not set mode %04x: %s\n", + mode_number, strerror ( rc ) ); + return rc; + } + + /* Record mode parameters */ + vesafb.pixel.width = mode->x_resolution; + vesafb.pixel.height = mode->y_resolution; + vesafb.pixel.len = ( ( mode->bits_per_pixel + 7 ) / 8 ); + vesafb.pixel.stride = mode->bytes_per_scan_line; + DBGC ( &vbe_buf, "VESAFB mode %04x has frame buffer at %08x\n", + mode_number, mode->phys_base_ptr ); + + /* Initialise font colours */ + vesafb.map.red_scale = ( 8 - mode->red_mask_size ); + vesafb.map.green_scale = ( 8 - mode->green_mask_size ); + vesafb.map.blue_scale = ( 8 - mode->blue_mask_size ); + vesafb.map.red_lsb = mode->red_field_position; + vesafb.map.green_lsb = mode->green_field_position; + vesafb.map.blue_lsb = mode->blue_field_position; + + /* Get font data */ + vesafb_font(); + + /* Initialise frame buffer console */ + fbcon_init ( &vesafb.fbcon, phys_to_user ( mode->phys_base_ptr ), + &vesafb.pixel, &vesafb.map, &vesafb.font, pixbuf ); + + return 0; +} + +/** + * Select and set video mode + * + * @v min_width Minimum required width (in pixels) + * @v min_height Minimum required height (in pixels) + * @v min_bpp Minimum required colour depth (in bits per pixel) + * @v pixbuf Background picture (if any) + * @ret rc Return status code + */ +static int vesafb_select_mode ( unsigned int min_width, unsigned int min_height, + unsigned int min_bpp, + struct pixel_buffer *pixbuf ) { + struct vbe_mode_info *mode = &vbe_buf.mode; + uint16_t *mode_numbers; + uint16_t mode_number; + uint16_t status; + int rc; + + /* Get VESA mode list */ + if ( ( rc = vesafb_mode_list ( &mode_numbers ) ) != 0 ) + goto err_mode_list; + + /* Find the first suitable mode */ + while ( ( mode_number = *(mode_numbers++) ) != VBE_MODE_END ) { + + /* Force linear mode variant */ + mode_number |= VBE_MODE_LINEAR; + + /* Get mode information */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( status ) + : "a" ( VBE_MODE_INFO ), + "c" ( mode_number ), + "D" ( __from_data16 ( mode ) ) + : "memory" ); + if ( ( rc = vesafb_rc ( status ) ) != 0 ) { + DBGC ( &vbe_buf, "VESAFB could not get mode %04x " + "information: %s\n", mode_number, + strerror ( rc ) ); + goto err_mode_info; + } + DBGC ( &vbe_buf, "VESAFB mode %04x %dx%d %dbpp(%d:%d:%d:%d) " + "model %02x [x%d]%s%s%s%s%s\n", mode_number, + mode->x_resolution, mode->y_resolution, + mode->bits_per_pixel, mode->rsvd_mask_size, + mode->red_mask_size, mode->green_mask_size, + mode->blue_mask_size, mode->memory_model, + ( mode->number_of_image_pages + 1 ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_SUPPORTED ) ? + "" : " [unsupported]" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_TTY ) ? + " [tty]" : "" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_GRAPHICS ) ? + "" : " [text]" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_LINEAR ) ? + "" : " [nonlinear]" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_TRIPLE_BUF ) ? + " [buf]" : "" ) ); + + /* Skip unusable modes */ + if ( ( mode->mode_attributes & ( VBE_MODE_ATTR_SUPPORTED | + VBE_MODE_ATTR_GRAPHICS | + VBE_MODE_ATTR_LINEAR ) ) != + ( VBE_MODE_ATTR_SUPPORTED | VBE_MODE_ATTR_GRAPHICS | + VBE_MODE_ATTR_LINEAR ) ) { + continue; + } + if ( mode->memory_model != VBE_MODE_MODEL_DIRECT_COLOUR ) + continue; + + /* Skip modes not meeting the requirements */ + if ( ( mode->x_resolution < min_width ) || + ( mode->y_resolution < min_height ) || + ( mode->bits_per_pixel < min_bpp ) ) { + continue; + } + + /* Select this mode */ + if ( ( rc = vesafb_set_mode ( mode_number, mode, + pixbuf ) ) != 0 ) { + goto err_set_mode; + } + + break; + } + + err_set_mode: + err_mode_info: + free ( mode_numbers ); + err_mode_list: + return rc; +} + +/** + * Print a character to current cursor position + * + * @v character Character + */ +static void vesafb_putchar ( int character ) { + + fbcon_putchar ( &vesafb.fbcon, character ); +} + +/** + * Configure console + * + * @v config Console configuration, or NULL to reset + * @ret rc Return status code + */ +static int vesafb_configure ( struct console_configuration *config ) { + uint32_t discard_a; + uint32_t discard_b; + int rc; + + /* Reset console, if applicable */ + if ( ! vesafb_console.disabled ) { + fbcon_fini ( &vesafb.fbcon ); + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( discard_a ) + : "a" ( VBE_SET_VGA_MODE | + vesafb.saved_mode ) ); + DBGC ( &vbe_buf, "VESAFB restored VGA mode %#02x\n", + vesafb.saved_mode ); + bios_console.disabled &= ~CONSOLE_DISABLED_OUTPUT; + } + vesafb_console.disabled = CONSOLE_DISABLED; + + /* Record current video mode */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( vesafb.saved_mode ), "=b" ( discard_b ) + : "a" ( VBE_GET_VGA_MODE ) ); + + /* Do nothing more unless we have a usable configuration */ + if ( ( config == NULL ) || + ( config->width == 0 ) || ( config->height == 0 ) ) { + return 0; + } + + /* Try to select an appropriate mode */ + if ( ( rc = vesafb_select_mode ( config->width, config->height, + config->bpp, config->pixbuf ) ) != 0 ) + return rc; + + /* Mark console as enabled */ + vesafb_console.disabled = 0; + bios_console.disabled |= CONSOLE_DISABLED_OUTPUT; + + return 0; +} + +/** VESA frame buffer console driver */ +struct console_driver vesafb_console __console_driver = { + .usage = CONSOLE_VESAFB, + .putchar = vesafb_putchar, + .configure = vesafb_configure, + .disabled = CONSOLE_DISABLED, +}; diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h index d9cf5c45..acf8c3e3 100644 --- a/src/arch/x86/include/bits/errfile.h +++ b/src/arch/x86/include/bits/errfile.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 ) #define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 ) #define ERRFILE_apm ( ERRFILE_ARCH | ERRFILE_CORE | 0x000b0000 ) +#define ERRFILE_vesafb ( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/config/config.c b/src/config/config.c index b81cfb5c..89809679 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -93,6 +93,9 @@ REQUIRE_OBJECT ( vmconsole ); #ifdef CONSOLE_DEBUGCON REQUIRE_OBJECT ( debugcon ); #endif +#ifdef CONSOLE_VESAFB +REQUIRE_OBJECT ( vesafb ); +#endif /* * Drag in all requested network protocols diff --git a/src/config/console.h b/src/config/console.h index 04be02dc..5d2cc1dc 100644 --- a/src/config/console.h +++ b/src/config/console.h @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONSOLE_SYSLOGS /* Encrypted syslog console */ //#define CONSOLE_VMWARE /* VMware logfile console */ //#define CONSOLE_DEBUGCON /* Debug port console */ +//#define CONSOLE_VESAFB /* VESA framebuffer console */ #define KEYBOARD_MAP us