/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/video_fb.h>
GRUB_MOD_LICENSE ("GPLv3+");
/* Track last mode to support cards which fail on get_mode. */
static struct
{
int mtrr;
} framebuffer;
static void *
{
+ ((unsigned long) ptr & 0x0000FFFF));
}
asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
: "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
: "0" (num))
/* Try to set up a variable-range write-combining MTRR for a memory region.
This is best-effort; if it seems too hard, we just accept the performance
degradation rather than risking undefined behaviour. It is intended
exclusively to work around BIOS bugs, as the BIOS should already be
setting up a suitable MTRR. */
static void
{
}
static void
{
int var_mtrrs;
/* Check that fb_base and fb_size can be represented using a single
MTRR. */
return; /* under 1MB, so covered by fixed-range MTRRs */
return; /* over 36 bits, so out of range */
return; /* variable-range MTRRs must cover at least 4KB */
while (size_bits > 1)
size_bits >>= 1;
if (size_bits != 1)
return; /* not a power of two */
return; /* not aligned on size boundary */
/* Check CPU capabilities. */
if (! grub_cpu_is_cpuid_supported ())
return;
return;
return;
if (max_extended_cpuid >= 0x80000008)
{
}
else
maxphyaddr = 36;
/* Check whether an MTRR already covers this region. If not, take an
unused one if possible. */
for (i = 0; i < var_mtrrs; i++)
{
{
return; /* existing MTRR overlaps this region */
}
else if (first_unused < 0)
first_unused = i;
}
if (first_unused < 0)
return; /* all MTRRs in use */
/* Set up the first unused MTRR we found. */
}
static void
{
}
/* Call VESA BIOS 0x4f09 to set palette data, return status. */
static grub_vbe_status_t
struct grub_vbe_palette_data *palette_data)
{
}
/* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status. */
{
/* Store *controller_info to %es:%di. */
}
/* Call VESA BIOS 0x4f01 to get VBE Mode Information, return status. */
struct grub_vbe_mode_info_block *mode_info)
{
/* Store *mode_info to %es:%di. */
}
/* Call VESA BIOS 0x4f02 to set video mode, return status. */
static grub_vbe_status_t
struct grub_vbe_crtc_info_block *crtc_info)
{
/* Store *crtc_info to %es:%di. */
}
/* Call VESA BIOS 0x4f03 to return current VBE Mode, return status. */
{
}
{
}
/* Call VESA BIOS 0x4f05 to set memory window, return status. */
{
/* BL = window, BH = 0, Set memory window. */
}
/* Call VESA BIOS 0x4f05 to return memory window, return status. */
{
/* BH = 1, Get memory window. BL = window. */
}
/* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status. */
{
/* BL = 2, Set Scan Line in Bytes. */
}
/* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status. */
{
/* BL = 1, Get Scan Line Length (in bytes). */
}
/* Call VESA BIOS 0x4f07 to set display start, return status. */
static grub_vbe_status_t
{
if (framebuffer.mtrr >= 0)
/* Store x in %ecx. */
/* BL = 80h, Set Display Start during Vertical Retrace. */
if (framebuffer.mtrr >= 0)
}
/* Call VESA BIOS 0x4f07 to get display start, return status. */
grub_uint32_t *y)
{
/* BL = 1, Get Display Start. */
}
/* Call VESA BIOS 0x4f0a. */
{
{
*segment = 0;
*offset = 0;
*length = 0;
}
}
/* Call VESA BIOS 0x4f11 to get flat panel information, return status. */
static grub_vbe_status_t
{
}
/* Call VESA BIOS 0x4f15 to get DDC availability, return status. */
static grub_vbe_status_t
{
}
/* Call VESA BIOS 0x4f15 to read EDID information, return status. */
static grub_vbe_status_t
{
}
{
/* Clear caller's controller info block. */
if (info_block)
/* Do not probe more than one time, if not necessary. */
{
/* Clear old copy of controller info block. */
/* Mark VESA BIOS extension as undetected. */
vbe_detected = 0;
/* Use low memory scratch area as temporary storage
for VESA BIOS call. */
/* Prepare info block. */
/* Try to get controller info block. */
if (status == GRUB_VBE_STATUS_OK)
{
/* Copy it for later usage. */
/* Mark VESA BIOS extension as detected. */
vbe_detected = 1;
}
}
if (! vbe_detected)
/* Make copy of controller info block to caller. */
if (info_block)
return GRUB_ERR_NONE;
}
static grub_err_t
{
/* Use low memory scratch area as temporary storage for VESA BIOS calls. */
(struct grub_video_edid_info *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
return GRUB_ERR_NONE;
}
static grub_err_t
{
/* Use low memory scratch area as temporary storage for VESA BIOS calls. */
flat_panel_info = (struct grub_vbe_flat_panel_info *)
(GRUB_MEMORY_MACHINE_SCRATCH_ADDR + sizeof (struct grub_video_edid_info));
{
== GRUB_ERR_NONE)
return GRUB_ERR_NONE;
}
if (status == GRUB_VBE_STATUS_OK)
{
return GRUB_ERR_NONE;
}
}
struct grub_vbe_mode_info_block *vbe_mode_info)
{
/* Make sure that VBE is supported. */
grub_vbe_probe (0);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* Try to get mode info. */
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* For all VESA BIOS modes, force linear frame buffer. */
if (vbe_mode >= 0x100)
{
/* We only want linear frame buffer modes. */
/* Determine frame buffer pixel format. */
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported pixel format 0x%x",
}
/* Get current mode. */
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* Try to set video mode. */
if (status != GRUB_VBE_STATUS_OK)
if (vbe_mode < 0x100)
{
/* If this is not a VESA mode, guess address. */
}
else
{
}
/* Check whether mode is text mode or graphics mode. */
{
/* Text mode. */
/* No special action needed for text mode as it is not supported for
graphical support. */
}
else
{
/* Graphics mode. */
/* If video mode is in indexed color, setup default VGA palette. */
{
= (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
unsigned i;
/* Make sure that the BIOS can reach the palette. */
for (i = 0; i < GRUB_VIDEO_FBSTD_NUMCOLORS; i++)
{
}
0, palette);
/* Just ignore the status. */
if (err)
return err;
}
}
/* Copy mode info for caller. */
if (vbe_mode_info)
return GRUB_ERR_NONE;
}
{
/* Make sure that VBE is supported. */
grub_vbe_probe (0);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* Try to query current mode from VESA BIOS. */
/* XXX: ATI cards don't support get_mode. */
if (status != GRUB_VBE_STATUS_OK)
*mode = last_set_mode;
return GRUB_ERR_NONE;
}
struct grub_vbe_mode_info_block *mode_info)
{
= (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
/* Make sure that VBE is supported. */
grub_vbe_probe (0);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* If mode is not VESA mode, skip mode info query. */
if (mode >= 0x100)
{
/* Try to get mode info from VESA BIOS. */
if (status != GRUB_VBE_STATUS_OK)
return grub_error (GRUB_ERR_BAD_DEVICE,
"cannot get information on the mode %x", mode);
/* Make copy of mode info block. */
}
else
/* Just clear mode info block if it isn't a VESA mode. */
return GRUB_ERR_NONE;
}
static grub_err_t
grub_video_vbe_init (void)
{
grub_uint16_t *p;
/* Check if there is adapter present.
Firmware note: There has been a report that some cards store video mode
list in temporary memory. So we must first use vbe probe to get
refreshed information to receive valid pointers and data, and then
copy this information to somewhere safe. */
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* Copy modelist to local memory. */
while(*p++ != 0xFFFF)
;
if (! vbe_mode_list)
return grub_errno;
/* Adapter could be found, figure out initial video mode. */
if (grub_errno != GRUB_ERR_NONE)
{
/* Free allocated resources. */
return grub_errno;
}
/* Reset frame buffer. */
return grub_video_fb_init ();
}
static grub_err_t
grub_video_vbe_fini (void)
{
/* Restore old video mode. */
if (last_set_mode != initial_vbe_mode)
{
if (status != GRUB_VBE_STATUS_OK)
/* TODO: Decide, is this something we want to do. */
return grub_errno;
}
/* TODO: Free any resources allocated by driver. */
err = grub_video_fb_fini ();
if (framebuffer.mtrr >= 0)
{
}
return err;
}
/*
Set framebuffer render target page and display the proper page, based on
`doublebuf_state.render_page' and `doublebuf_state.displayed_page',
respectively.
*/
static grub_err_t
{
/* Tell the video adapter to display the new front page. */
if (vbe_err != GRUB_VBE_STATUS_OK)
return 0;
}
static void
const struct grub_vbe_mode_info_block *vbeinfo,
struct grub_video_mode_info *mode_info)
{
switch (vbeinfo->memory_model)
{
break;
/* CGA is basically 4-bit packed pixel. */
break;
break;
/* Non chain 4 is a special case of planar. */
break;
break;
break;
default:
break;
}
/* Calculate bytes_per_pixel value. */
switch(vbeinfo->bits_per_pixel)
{
case 32:
break;
case 24:
break;
case 16:
break;
case 15:
break;
case 8:
break;
case 4:
mode_info->bytes_per_pixel = 0;
break;
}
else
}
static int
{
grub_uint16_t *p;
for (p = vbe_mode_list; *p != 0xFFFF; p++)
{
if (grub_errno != GRUB_ERR_NONE)
{
/* Could not retrieve mode info, retreat. */
break;
}
return 1;
}
return 0;
}
static grub_err_t
{
grub_uint16_t *p;
int depth;
int preferred_mode = 0;
/* Decode depth from mode_type. If it is zero, then autodetect. */
{
if (grub_errno == GRUB_ERR_NONE)
preferred_mode = 1;
else
{
/* Fall back to 640x480. This is conservative, but the largest
mode supported by the graphics card may not be safe for the
display device. */
width = 640;
height = 480;
}
}
/* Walk thru mode list and try to find matching mode. */
for (p = vbe_mode_list; *p != 0xFFFF; p++)
{
if (grub_errno != GRUB_ERR_NONE)
{
/* Could not retrieve mode info, retreat. */
break;
}
/* If not available, skip it. */
continue;
/* Monochrome is unusable. */
continue;
/* We support only linear frame buffer modes. */
continue;
/* We allow only graphical modes. */
continue;
/* Not compatible memory model. */
continue;
/* Unsupported bitdepth . */
continue;
if (preferred_mode)
{
/* Resolution exceeds that of preferred mode. */
continue;
}
else
{
/* Non matching resolution. */
continue;
}
/* Check if user requested RGB or index color mode. */
if ((mode_mask & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0)
{
unsigned my_mode_type = 0;
if ((my_mode_type & mode_mask
continue;
}
/* If there is a request for specific depth, ignore others. */
continue;
/* Select mode with most of "volume" (size of framebuffer in bits). */
if (best_vbe_mode != 0)
continue;
/* Save so far best mode information for later use. */
}
/* Try to initialize best mode found. */
if (best_vbe_mode != 0)
{
/* If this fails, then we have mode selection heuristics problem,
or adapter failure. */
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* Fill mode info details. */
{
/* Get video RAM size in bytes. */
else
framebuffer.ptr, 0, 0);
}
/* Copy default palette to initialize emulated palette. */
return err;
}
/* Couldn't found matching mode. */
}
static grub_err_t
struct grub_video_palette_data *palette_data)
{
{
/* TODO: Implement setting indexed color mode palette to hardware. */
//status = grub_vbe_bios_set_palette_data (sizeof (vga_colors)
// / sizeof (struct grub_vbe_palette_data),
// 0,
// palette);
}
/* Then set color to emulated palette. */
}
static grub_err_t
void **framebuf)
{
if (err)
return err;
if (framebuffer.mtrr >= 0)
{
}
return GRUB_ERR_NONE;
}
static void
{
/* The total_memory field is in 64 KiB units. */
}
{
.name = "VESA BIOS Extension Video Driver",
.next = 0
};
{
}
{
}