2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief VESA frame buffer driver back end
|
|
|
|
* \author Sebastian Sumpf
|
|
|
|
* \author Christian Helmuth
|
|
|
|
* \date 2007-09-11
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2007-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/sleep.h>
|
|
|
|
#include <base/stdint.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <base/snprintf.h>
|
|
|
|
#include <io_mem_session/connection.h>
|
|
|
|
|
|
|
|
#include "framebuffer.h"
|
|
|
|
#include "ifx86emu.h"
|
|
|
|
#include "vesa.h"
|
|
|
|
#include "vbe.h"
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
using namespace Vesa;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Frame buffer I/O memory dataspace
|
|
|
|
*/
|
|
|
|
static Dataspace_capability io_mem_cap;
|
|
|
|
|
|
|
|
static const bool verbose = false;
|
|
|
|
|
|
|
|
/***************
|
|
|
|
** Utilities **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
|
|
|
|
static inline uint32_t to_phys(uint32_t addr)
|
|
|
|
{
|
|
|
|
return (addr & 0xFFFF) + ((addr >> 12) & 0xFFFF0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info,
|
2014-09-25 18:30:50 +02:00
|
|
|
unsigned long &width, unsigned long &height,
|
2011-12-22 16:19:25 +01:00
|
|
|
unsigned long depth, bool verbose)
|
|
|
|
{
|
2014-09-25 18:30:50 +02:00
|
|
|
bool choose_highest_resolution_mode = ((width == 0) || (height == 0));
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
uint16_t ret = 0;
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
printf("Supported mode list\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The virtual address of the ctrl_info mapping may change on x86_cmd
|
|
|
|
* execution. Therefore, we resolve the address on each iteration.
|
|
|
|
*/
|
|
|
|
#define MODE_PTR(off) (X86emu::virt_addr<uint16_t>(to_phys(ctrl_info->video_mode)) + off)
|
|
|
|
for (unsigned off = 0; *MODE_PTR(off) != 0xFFFF; ++off) {
|
|
|
|
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, *MODE_PTR(off), VESA_MODE_OFFS) != VBE_SUPPORTED)
|
|
|
|
continue;
|
|
|
|
|
2013-12-04 15:41:57 +01:00
|
|
|
enum { DIRECT_COLOR = 0x06 };
|
|
|
|
if (mode_info->memory_model != DIRECT_COLOR)
|
|
|
|
continue;
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
if (verbose)
|
|
|
|
printf(" 0x%03x %ux%u@%u\n", *MODE_PTR(off), mode_info->x_resolution,
|
|
|
|
mode_info->y_resolution,
|
|
|
|
mode_info->bits_per_pixel);
|
|
|
|
|
2014-09-25 18:30:50 +02:00
|
|
|
if (choose_highest_resolution_mode) {
|
|
|
|
if ((mode_info->bits_per_pixel == depth) &&
|
|
|
|
((mode_info->x_resolution > width) ||
|
|
|
|
((mode_info->x_resolution == width) &&
|
|
|
|
(mode_info->y_resolution > height)))) {
|
|
|
|
|
|
|
|
width = mode_info->x_resolution;
|
|
|
|
height = mode_info->y_resolution;
|
|
|
|
ret = *MODE_PTR(off);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mode_info->x_resolution == width &&
|
|
|
|
mode_info->y_resolution == height &&
|
|
|
|
mode_info->bits_per_pixel == depth)
|
|
|
|
ret = *MODE_PTR(off);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
#undef MODE_PTR
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
PWRN("Searching in default vesa modes");
|
|
|
|
|
2014-09-25 18:30:50 +02:00
|
|
|
if (choose_highest_resolution_mode) {
|
|
|
|
/*
|
|
|
|
* We did not find any mode for the given color depth so far.
|
|
|
|
* Default to 1024x768 for now.
|
|
|
|
*/
|
|
|
|
ret = get_default_vesa_mode(1024, 768, depth);
|
|
|
|
if (ret != 0) {
|
|
|
|
width = 1024;
|
|
|
|
height = 768;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
return get_default_vesa_mode(width, height, depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
** Driver API **
|
|
|
|
****************/
|
|
|
|
|
|
|
|
Dataspace_capability Framebuffer_drv::hw_framebuffer()
|
|
|
|
{
|
|
|
|
return io_mem_cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Framebuffer_drv::map_io_mem(addr_t base, size_t size, bool write_combined,
|
|
|
|
void **out_addr, addr_t addr,
|
|
|
|
Dataspace_capability *out_io_ds)
|
|
|
|
{
|
|
|
|
Io_mem_connection io_mem(base, size, write_combined);
|
|
|
|
io_mem.on_destruction(Io_mem_connection::KEEP_OPEN);
|
|
|
|
Io_mem_dataspace_capability io_ds = io_mem.dataspace();
|
|
|
|
if (!io_ds.valid())
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
try {
|
|
|
|
*out_addr = env()->rm_session()->attach(io_ds, size, 0, addr != 0, addr);
|
|
|
|
} catch (Rm_session::Attach_failed) {
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
2012-06-18 15:20:31 +02:00
|
|
|
PDBG("fb mapped to %p", *out_addr);
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
if (out_io_ds)
|
|
|
|
*out_io_ds = io_ds;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-25 18:30:50 +02:00
|
|
|
int Framebuffer_drv::set_mode(unsigned long &width, unsigned long &height,
|
2011-12-22 16:19:25 +01:00
|
|
|
unsigned long mode)
|
|
|
|
{
|
|
|
|
mb_vbe_ctrl_t *ctrl_info;
|
|
|
|
mb_vbe_mode_t *mode_info;
|
|
|
|
char * oem_string;
|
|
|
|
uint16_t vesa_mode;
|
|
|
|
|
|
|
|
/* set location of data types */
|
|
|
|
ctrl_info = reinterpret_cast<mb_vbe_ctrl_t*>(X86emu::x86_mem.data_addr()
|
|
|
|
+ VESA_CTRL_OFFS);
|
|
|
|
mode_info = reinterpret_cast<mb_vbe_mode_t*>(X86emu::x86_mem.data_addr()
|
|
|
|
+ VESA_MODE_OFFS);
|
|
|
|
|
2013-12-04 15:41:57 +01:00
|
|
|
/* request VBE 2.0 information */
|
|
|
|
memcpy(ctrl_info->signature, "VBE2", 4);
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/* retrieve controller information */
|
|
|
|
if (X86emu::x86emu_cmd(VBE_CONTROL_FUNC, 0, 0, VESA_CTRL_OFFS) != VBE_SUPPORTED) {
|
|
|
|
PWRN("VBE Bios not present");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* retrieve vesa mode hex value */
|
|
|
|
if (!(vesa_mode = get_vesa_mode(ctrl_info, mode_info, width, height, mode, verbose))) {
|
|
|
|
PWRN("graphics mode %lux%lu@%lu not found", width, height, mode);
|
2014-09-25 18:30:50 +02:00
|
|
|
/* print available modes */
|
|
|
|
get_vesa_mode(ctrl_info, mode_info, width, height, mode, true);
|
2011-12-22 16:19:25 +01:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* use current refresh rate, set flat framebuffer model */
|
|
|
|
vesa_mode = (vesa_mode & VBE_CUR_REFRESH_MASK) | VBE_SET_FLAT_FB;
|
|
|
|
|
|
|
|
/* determine VBE version and OEM string */
|
|
|
|
oem_string = X86emu::virt_addr<char>(to_phys(ctrl_info->oem_string));
|
|
|
|
|
|
|
|
printf("Found: VESA BIOS version %d.%d\nOEM: %s\n",
|
|
|
|
ctrl_info->version >> 8, ctrl_info->version & 0xFF,
|
|
|
|
ctrl_info->oem_string ? oem_string : "[unknown]");
|
|
|
|
|
|
|
|
if (ctrl_info->version < 0x200) {
|
|
|
|
PWRN("VESA Bios version 2.0 or later required");
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get mode info */
|
|
|
|
/* 0x91 tests MODE SUPPORTED (0x1) | GRAPHICS MODE (0x10) | LINEAR
|
|
|
|
* FRAME BUFFER (0x80) bits */
|
|
|
|
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode, VESA_MODE_OFFS) != VBE_SUPPORTED
|
|
|
|
|| (mode_info->mode_attributes & 0x91) != 0x91) {
|
|
|
|
PWRN("graphics mode %lux%lu@%lu not supported", width, height, mode);
|
2014-09-25 18:30:50 +02:00
|
|
|
/* print available modes */
|
|
|
|
get_vesa_mode(ctrl_info, mode_info, width, height, mode, true);
|
2011-12-22 16:19:25 +01:00
|
|
|
return -4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set mode */
|
|
|
|
if ((X86emu::x86emu_cmd(VBE_MODE_FUNC, vesa_mode) & 0xFF00) != VBE_SUCCESS) {
|
|
|
|
PDBG("VBE SET error");
|
|
|
|
return -5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* map framebuffer */
|
|
|
|
void *fb;
|
|
|
|
if (!io_mem_cap.valid()) {
|
|
|
|
X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode, VESA_MODE_OFFS);
|
|
|
|
|
|
|
|
printf("Found: physical frame buffer at 0x%08x size: 0x%08x\n",
|
|
|
|
mode_info->phys_base,
|
|
|
|
ctrl_info->total_memory << 16);
|
|
|
|
map_io_mem(mode_info->phys_base, ctrl_info->total_memory << 16, true,
|
|
|
|
&fb, 0, &io_mem_cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
X86emu::print_regions();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
** Driver startup **
|
|
|
|
********************/
|
|
|
|
|
|
|
|
int Framebuffer_drv::init()
|
|
|
|
{
|
|
|
|
if (X86emu::init())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|