Adapt VESA framebuffer driver to component API

Issue #1987
This commit is contained in:
Christian Helmuth 2017-01-02 14:24:00 +01:00 committed by Norman Feske
parent d10a69c7bc
commit e2a23a0ab3
9 changed files with 491 additions and 470 deletions

View File

@ -6,23 +6,24 @@
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-2017 Genode Labs GmbH
*
* 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>
/* Genode includes */
#include <base/log.h>
#include <base/snprintf.h>
#include <io_mem_session/connection.h>
#include <platform_session/connection.h>
/* local includes */
#include "framebuffer.h"
#include "ifx86emu.h"
#include "hw_emul.h"
#include "vesa.h"
#include "vbe.h"
#include "genode_env.h"
using namespace Genode;
using namespace Vesa;
@ -47,8 +48,8 @@ static inline uint32_t to_phys(uint32_t addr)
static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info,
unsigned long &width, unsigned long &height,
unsigned long depth, bool verbose)
unsigned &width, unsigned &height, unsigned depth,
bool verbose)
{
bool choose_highest_resolution_mode = ((width == 0) || (height == 0));
@ -143,25 +144,25 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
** Driver API **
****************/
Dataspace_capability Framebuffer_drv::hw_framebuffer()
Dataspace_capability Framebuffer::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)
int Framebuffer::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 = *new (env()->heap())
Io_mem_connection(base, size, write_combined);
Io_mem_connection &io_mem = *new (alloc())
Io_mem_connection(genode_env(), base, size, write_combined);
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);
*out_addr = genode_env().rm().attach(io_ds, size, 0, addr != 0, addr);
} catch (Rm_session::Attach_failed) {
return -3;
}
@ -175,8 +176,7 @@ int Framebuffer_drv::map_io_mem(addr_t base, size_t size, bool write_combined,
}
int Framebuffer_drv::set_mode(unsigned long &width, unsigned long &height,
unsigned long mode)
int Framebuffer::set_mode(unsigned &width, unsigned &height, unsigned mode)
{
mb_vbe_ctrl_t *ctrl_info;
mb_vbe_mode_t *mode_info;
@ -260,10 +260,19 @@ int Framebuffer_drv::set_mode(unsigned long &width, unsigned long &height,
** Driver startup **
********************/
int Framebuffer_drv::init()
void Framebuffer::init(Genode::Env &env, Genode::Allocator &heap)
{
if (X86emu::init())
return -1;
local_init_genode_env(env, heap);
return 0;
{
/*
* Wait until Acpi/Pci driver initialization is done to avoid
* potentially concurrent access by this driver and the Acpi/Pci driver
* to the graphics device, i.e., to the PCI config space.
*/
Platform::Connection sync(env);
}
hw_emul_init(env);
X86emu::init(env, heap);
}

View File

@ -11,16 +11,18 @@
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
* Copyright (C) 2010-2017 Genode Labs GmbH
*
* 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/sleep.h>
/* Genode includes */
#include <base/log.h>
#include <util/retry.h>
/* local includes */
#include "framebuffer.h"
#include "hw_emul.h"
using namespace Genode;
@ -40,24 +42,22 @@ enum {
};
/**
* Helper for the formatted output of a (bus, device, function) triple
*/
struct Devfn
{
unsigned short devfn;
unsigned char b, d, f;
explicit Devfn(unsigned short devfn) : devfn(devfn) { }
Devfn(Platform::Device &device) { device.bus_address(&b, &d, &f); }
Devfn(unsigned short devfn)
: b((devfn >> 8) & 0xff), d((devfn >> 3) & 0x1f), f(devfn & 7) { }
unsigned short devfn() const { return b << 8 | d << 3 | f; }
void print(Genode::Output &out) const
{
unsigned char const bus = devfn >> 8,
dev = (devfn >> 3) & 0x1f,
fn = devfn & 0x7;
Genode::print(out, Hex(bus, Hex::OMIT_PREFIX, Hex::PAD), ":",
Hex(dev, Hex::OMIT_PREFIX, Hex::PAD), ".",
Hex(fn, Hex::OMIT_PREFIX));
Genode::print(out, Hex(b, Hex::OMIT_PREFIX, Hex::PAD), ":",
Hex(d, Hex::OMIT_PREFIX, Hex::PAD), ".",
Hex(f, Hex::OMIT_PREFIX));
}
};
@ -68,7 +68,7 @@ class Pci_card
Platform::Connection _pci_drv;
Platform::Device_client _device;
unsigned short _devfn;
Devfn _devfn;
Platform::Device_capability _first_device()
{
@ -110,8 +110,8 @@ class Pci_card
}
if (!device_cap.valid()) {
Genode::error("PCI VGA card not found. Sleeping...");
sleep_forever();
Genode::error("PCI VGA card not found.");
throw Framebuffer::Fatal();
}
return device_cap;
@ -119,27 +119,18 @@ class Pci_card
public:
Pci_card() : _device(_find_vga_card())
Pci_card(Genode::Env &env)
: _pci_drv(env), _device(_find_vga_card()), _devfn(_device)
{
unsigned char bus = 0, dev = 0, fn = 0;
_device.bus_address(&bus, &dev, &fn);
_devfn = bus << 8 | dev << 3 | fn;
if (verbose)
Genode::log("Found PCI VGA at ", Devfn(_devfn));
Genode::log("Found PCI VGA at ", _devfn);
}
Platform::Device_client &device() { return _device; }
unsigned short devfn() const { return _devfn; }
Platform::Device &device() { return _device; }
unsigned short devfn() const { return _devfn.devfn(); }
};
static Pci_card *pci_card()
{
static Pci_card _pci_card;
return &_pci_card;
}
static Constructible<Pci_card> pci_card;
/**
@ -166,7 +157,7 @@ static bool handle_pci_port_write(unsigned short port, T val)
}
unsigned const devfn = (val >> 8) & 0xffff;
if (devfn != pci_card()->devfn()) {
if (devfn != pci_card->devfn()) {
if (verbose)
warning("accessing unknown PCI device ", Devfn(devfn));
pci_cfg_addr_valid = false;
@ -219,13 +210,13 @@ static bool handle_pci_port_read(unsigned short port, T *val)
switch (pci_cfg_addr) {
case 0: /* vendor / device ID */
raw_val = pci_card()->device().vendor_id() |
(pci_card()->device().device_id() << 16);
raw_val = pci_card->device().vendor_id() |
(pci_card->device().device_id() << 16);
break;
case 4: /* status and command */
case 8: /* class code / revision ID */
raw_val = pci_card()->device().config_read(pci_cfg_addr,
raw_val = pci_card->device().config_read(pci_cfg_addr,
Platform::Device::ACCESS_32BIT);
break;
@ -237,7 +228,7 @@ static bool handle_pci_port_read(unsigned short port, T *val)
case 0x24: /* base address register 5 */
{
unsigned bar = (pci_cfg_addr - 0x10) / 4;
Platform::Device::Resource res = pci_card()->device().resource(bar);
Platform::Device::Resource res = pci_card->device().resource(bar);
if (res.type() == Platform::Device::Resource::INVALID) {
warning("requested PCI resource ", bar, " invalid");
*val = 0;
@ -349,3 +340,6 @@ bool hw_emul_handle_port_write(unsigned short port, T val)
return false;
}
void hw_emul_init(Genode::Env &env) { pci_card.construct(env); }

View File

@ -6,28 +6,29 @@
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/printf.h>
#include <base/env.h>
#include <base/sleep.h>
#include <base/attached_ram_dataspace.h>
#include <base/attached_io_mem_dataspace.h>
#include <util/avl_tree.h>
#include <util/misc_math.h>
#include <os/attached_ram_dataspace.h>
#include <util/reconstructible.h>
#include <io_port_session/connection.h>
#include <io_mem_session/connection.h>
#include <platform_session/connection.h>
#include <base/printf.h> /* XXX for emulating X86emu::printk() */
/* local includes */
#include "ifx86emu.h"
#include "framebuffer.h"
#include "vesa.h"
#include "hw_emul.h"
#include "genode_env.h"
namespace X86emu {
@ -133,163 +134,134 @@ class Region : public Avl_node<Region>
template <typename TYPE>
class Region_database : public Avl_tree<Region>
struct Region_database : Avl_tree<Region>
{
public:
Genode::Env &env;
Genode::Allocator &heap;
TYPE * match(addr_t base, size_t size)
{
if (!first()) return 0;
Region_database(Genode::Env &env, Genode::Allocator &heap)
: env(env), heap(heap) { }
return static_cast<TYPE *>(first()->match(base, size));
TYPE * match(addr_t base, size_t size)
{
if (!first()) return 0;
return static_cast<TYPE *>(first()->match(base, size));
}
TYPE * meet(addr_t base, size_t size)
{
if (!first()) return 0;
return static_cast<TYPE *>(first()->meet(base, size));
}
TYPE * get_region(addr_t base, size_t size)
{
TYPE *region;
/* look for match and return if found */
if ((region = match(base, size)))
return region;
/*
* We try to create a new port region, but first we look if any overlapping
* resp. meeting regions already exist. These are freed and merged into a
* new super region including the new port region.
*/
addr_t beg = base, end = base + size;
while ((region = meet(beg, end - beg))) {
/* merge region into super region */
beg = min(beg, static_cast<addr_t>(region->base()));
end = max(end, static_cast<addr_t>(region->base() + region->size()));
/* destroy old region */
remove(region);
destroy(heap, region);
}
TYPE * meet(addr_t base, size_t size)
{
if (!first()) return 0;
return static_cast<TYPE *>(first()->meet(base, size));
try {
region = new (heap) TYPE(env, beg, end - beg);
insert(region);
return region;
} catch (...) {
Genode::error("access to I/O region ",
Hex_range<addr_t>(beg, end - beg), " denied");
return 0;
}
}
TYPE * get_region(addr_t base, size_t size)
{
TYPE *region;
void print_regions()
{
if (!first()) return;
/* look for match and return if found */
if ((region = match(base, size)))
return region;
/*
* We try to create a new port region, but first we look if any overlapping
* resp. meeting regions already exist. These are freed and merged into a
* new super region including the new port region.
*/
addr_t beg = base, end = base + size;
while ((region = meet(beg, end - beg))) {
/* merge region into super region */
beg = min(beg, static_cast<addr_t>(region->base()));
end = max(end, static_cast<addr_t>(region->base() + region->size()));
/* destroy old region */
remove(region);
destroy(env()->heap(), region);
}
try {
region = new (env()->heap()) TYPE(beg, end - beg);
insert(region);
return region;
} catch (...) {
Genode::error("access to I/O region ",
Hex_range<addr_t>(beg, end - beg), " denied");
return 0;
}
}
void print_regions()
{
if (!first()) return;
first()->print_regions();
}
first()->print_regions();
}
};
/**
* I/O port region including corresponding IO_PORT connection
*/
class Port_region : public Region, public Io_port_connection
struct Port_region : Region, Io_port_connection
{
public:
Port_region(Genode::Env &env, unsigned short port_base, size_t port_size)
:
Region(port_base, port_size),
Io_port_connection(env, port_base, port_size)
{
if (verbose) Genode::log("add port ", *this);
}
void print(Genode::Output &out) const
{
unsigned const beg = base(), end = beg + size();
Genode::print(out, Hex_range<uint16_t>(beg, end - beg));
}
~Port_region()
{
if (verbose) Genode::log("del port ", *this);
}
Port_region(unsigned short port_base, size_t port_size)
: Region(port_base, port_size), Io_port_connection(port_base, port_size)
{
if (verbose)
Genode::log("add port ", *this);
}
~Port_region()
{
if (verbose)
Genode::log("del port ", *this);
}
void print(Genode::Output &out) const
{
unsigned const beg = base(), end = beg + size();
Genode::print(out, Hex_range<uint16_t>(beg, end - beg));
}
};
/**
* I/O memory region including corresponding IO_MEM connection
*/
class Mem_region : public Region
struct Mem_region : Region, Attached_io_mem_dataspace
{
private:
Mem_region(Genode::Env &env, addr_t mem_base, size_t mem_size)
:
Region(mem_base, mem_size),
Attached_io_mem_dataspace(env, mem_base, mem_size)
{
if (verbose) Genode::log("add mem ", *this, " @ ", local_addr<void>());
}
class Io_mem_dataspace : public Io_mem_connection
{
private:
~Mem_region()
{
if (verbose) Genode::log("del mem ", *this);
}
void *_local_addr;
template <typename T>
T * virt_addr(addr_t addr)
{
return reinterpret_cast<T *>(local_addr<char>() + (addr - base()));
}
public:
Io_mem_dataspace(addr_t base, size_t size)
: Io_mem_connection(base, size)
{
_local_addr = env()->rm_session()->attach(dataspace());
}
~Io_mem_dataspace()
{
env()->rm_session()->detach(_local_addr);
}
Io_mem_dataspace_capability cap() { return dataspace(); }
template <typename T>
T * local_addr() { return static_cast<T *>(_local_addr); }
};
Io_mem_dataspace _ds;
public:
void print(Genode::Output &out) const
{
addr_t const beg = base(), end = beg + size();
Genode::print(out, Hex_range<addr_t>(beg, end - beg));
}
Mem_region(addr_t mem_base, size_t mem_size)
: Region(mem_base, mem_size), _ds(mem_base, mem_size)
{
if (verbose)
Genode::log("add mem ", *this, " @ ", _ds.local_addr<void>());
}
~Mem_region()
{
if (verbose)
Genode::log("del mem ", *this);
}
template <typename T>
T * virt_addr(addr_t addr)
{
return reinterpret_cast<T *>(_ds.local_addr<char>() + (addr - base()));
}
void print(Genode::Output &out) const
{
addr_t const beg = base(), end = beg + size();
Genode::print(out, Hex_range<addr_t>(beg, end - beg));
}
};
static Region_database<Port_region> port_region_db;
static Region_database<Mem_region> mem_region_db;
static Genode::Constructible<Region_database<Port_region>> port_region_db;
static Genode::Constructible<Region_database<Mem_region>> mem_region_db;
/**
@ -302,7 +274,7 @@ static int map_code_area(void)
void *dummy;
/* map page0 */
if ((err = Framebuffer_drv::map_io_mem(0x0, PAGESIZE, false, &dummy))) {
if ((err = Framebuffer::map_io_mem(0x0, PAGESIZE, false, &dummy))) {
Genode::error("could not map page zero");
return err;
}
@ -310,7 +282,7 @@ static int map_code_area(void)
/* alloc code pages in RAM */
try {
static Attached_ram_dataspace ram_ds(env()->ram_session(), CODESIZE);
static Attached_ram_dataspace ram_ds(genode_env().ram(), genode_env().rm(), CODESIZE);
dummy = ram_ds.local_addr<void>();
x86_mem.data_addr(dummy);
} catch (...) {
@ -391,7 +363,7 @@ static T X86API inx(X86emu::X86EMU_pioAddr addr)
if (hw_emul_handle_port_read(port, &ret))
return ret;
Port_region *region = port_region_db.get_region(port, sizeof(T));
Port_region *region = port_region_db->get_region(port, sizeof(T));
if (!region) return 0;
@ -423,7 +395,7 @@ static void X86API outx(X86emu::X86EMU_pioAddr addr, T val)
if (hw_emul_handle_port_write(port, val))
return;
Port_region *region = port_region_db.get_region(port, sizeof(T));
Port_region *region = port_region_db->get_region(port, sizeof(T));
if (!region) return;
@ -479,7 +451,7 @@ TYPE * X86emu::virt_addr(ADDR_TYPE addr)
local_addr += (x86_mem.data_addr() - PAGESIZE);
/* any other I/O memory allocated on demand */
else if ((region = mem_region_db.get_region(addr & ~(PAGESIZE-1), PAGESIZE)))
else if ((region = mem_region_db->get_region(addr & ~(PAGESIZE-1), PAGESIZE)))
return region->virt_addr<TYPE>(local_addr);
else {
@ -515,17 +487,35 @@ uint16_t X86emu::x86emu_cmd(uint16_t eax, uint16_t ebx, uint16_t ecx,
}
int X86emu::init(void)
void X86emu::print_regions()
{
/*
* Wait until Acpi/Pci driver initialization is done to avoid potentially
* concurrently accesses by this driver and the Acpi/Pci driver to the
* graphic device (PCI config space).
*/
Platform::Connection conn;
log("I/O port regions:");
port_region_db->print_regions();
if (map_code_area())
return -1;
log("I/O memory regions:");
mem_region_db->print_regions();
}
void X86emu::printk(const char *format, ...)
{
va_list list;
va_start(list, format);
Genode::vprintf(format, list);
va_end(list);
}
void X86emu::init(Genode::Env &env, Allocator &heap)
{
local_init_genode_env(env, heap);
port_region_db.construct(env, heap);
mem_region_db.construct(env, heap);
if (map_code_area()) throw Framebuffer::Fatal();
if (verbose) {
log("--- x86 bios area is ",
@ -537,25 +527,4 @@ int X86emu::init(void)
X86emu::M.x86.debug = 0;
X86emu::X86EMU_setupPioFuncs(&port_funcs);
X86emu::X86EMU_setupMemFuncs(&mem_funcs);
return 0;
}
void X86emu::print_regions()
{
log("I/O port regions:");
port_region_db.print_regions();
log("I/O memory regions:");
mem_region_db.print_regions();
}
void X86emu::printk(const char *format, ...)
{
va_list list;
va_start(list, format);
vprintf(format, list);
va_end(list);
}

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -15,12 +15,19 @@
#ifndef _FRAMEBUFFER_H_
#define _FRAMEBUFFER_H_
#include <base/capability.h>
#include <dataspace/capability.h>
#include <base/stdint.h>
#include "vbe.h"
namespace Framebuffer_drv {
namespace Genode {
struct Env;
struct Allocator;
}
namespace Framebuffer {
struct Fatal { }; /* exception */
/**
* Return capability for h/w framebuffer dataspace
@ -30,7 +37,7 @@ namespace Framebuffer_drv {
/**
* Initialize driver, x86emu lib, set up memory
*/
int init();
void init(Genode::Env &, Genode::Allocator &);
/**
* Set video, initialize framebuffer dataspace
@ -42,7 +49,7 @@ namespace Framebuffer_drv {
* \return 0 on success,
* non-zero otherwise
*/
int set_mode(unsigned long &width, unsigned long &height, unsigned long mode);
int set_mode(unsigned &width, unsigned &height, unsigned mode);
/**
* Map given device memory, return out_addr (map address)

View File

@ -0,0 +1,48 @@
/*
* \brief Utilities for accessing the Genode environment
* \author Norman Feske
* \date 2017-01-10
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _GENODE_ENV_H_
#define _GENODE_ENV_H_
#include <base/component.h>
#include <base/log.h>
static Genode::Env *_env_ptr;
static inline Genode::Env &genode_env()
{
if (_env_ptr)
return *_env_ptr;
Genode::error("genode env accessed prior initialization");
throw 1;
}
static Genode::Allocator *_alloc_ptr;
static inline Genode::Allocator &alloc()
{
if (_alloc_ptr)
return *_alloc_ptr;
Genode::error("allocator accessed prior initialization");
throw 1;
}
static void local_init_genode_env(Genode::Env &env, Genode::Allocator &alloc)
{
_env_ptr = &env;
_alloc_ptr = &alloc;
}
#endif /* _GENODE_ENV_H_ */

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
* Copyright (C) 2010-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -15,6 +15,11 @@
#ifndef _HW_EMUL_H_
#define _HW_EMUL_H_
namespace Genode { struct Env; }
void hw_emul_init(Genode::Env &);
/**
* Handle port-read access
*

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -17,6 +17,12 @@
#include <base/stdint.h>
namespace Genode {
struct Env;
struct Allocator;
}
namespace X86emu {
using Genode::addr_t;
@ -35,9 +41,6 @@ namespace X86emu {
addr_t _bios_addr;
addr_t _data_addr;
/**
* Constructur
*/
X86emu_mem() : _bios_addr(0), _data_addr(0) { }
inline addr_t _addr(addr_t* obj_addr, void* addr = 0)
@ -47,13 +50,8 @@ namespace X86emu {
return *obj_addr;
}
/**
* set/get functions
*/
inline addr_t bios_addr(void *addr = 0) {
return _addr(&_bios_addr, addr); }
inline addr_t data_addr(void *addr = 0) {
return _addr(&_data_addr, addr); }
inline addr_t bios_addr(void *addr = 0) { return _addr(&_bios_addr, addr); }
inline addr_t data_addr(void *addr = 0) { return _addr(&_data_addr, addr); }
};
/**
@ -64,7 +62,7 @@ namespace X86emu {
/**
* Initialization
*/
int init(void);
void init(Genode::Env &, Genode::Allocator &);
/**
* Execute real mode command

View File

@ -7,249 +7,240 @@
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode */
#include <base/env.h>
#include <base/sleep.h>
#include <base/rpc_server.h>
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <base/attached_ram_dataspace.h>
#include <root/component.h>
#include <cap_session/connection.h>
#include <framebuffer_session/framebuffer_session.h>
#include <rom_session/connection.h>
#include <util/xml_node.h>
#include <dataspace/client.h>
#include <util/reconstructible.h>
#include <util/arg_string.h>
#include <blit/blit.h>
#include <os/config.h>
#include <timer_session/connection.h>
#include <framebuffer_session/framebuffer_session.h>
/* Local */
/* local includes */
#include "framebuffer.h"
using namespace Genode;
/***************
** Utilities **
***************/
/**
* Determine session argument value based on config file and session arguments
*
* \param attr_name attribute name of config node
* \param args session argument string
* \param arg_name argument name
* \param default default session argument value if value is neither
* specified in config node nor in session arguments
*/
unsigned long session_arg(const char *attr_name, const char *args,
const char *arg_name, unsigned long default_value)
{
unsigned long result = default_value;
/* try to obtain value from config file */
try { Genode::config()->xml_node().attribute(attr_name).value(&result); }
catch (...) { }
/* check session argument to override value from config file */
result = Arg_string::find_arg(args, arg_name).ulong_value(result);
return result;
}
bool config_attribute(const char *attr_name)
{
return Genode::config()->xml_node().attribute_value(attr_name, false);
}
/***********************************************
** Implementation of the framebuffer service **
***********************************************/
namespace Framebuffer {
struct Session_component;
struct Root;
struct Main;
class Session_component : public Genode::Rpc_object<Session>
{
private:
unsigned _scr_width, _scr_height, _scr_mode;
bool _buffered;
/* dataspace uses a back buffer (if '_buffered' is true) */
Genode::Ram_dataspace_capability _bb_ds;
void *_bb_addr;
/* dataspace of physical frame buffer */
Genode::Dataspace_capability _fb_ds;
void *_fb_addr;
Timer::Connection _timer;
void _refresh_buffered(int x, int y, int w, int h)
{
/* clip specified coordinates against screen boundaries */
int x2 = min(x + w - 1, (int)_scr_width - 1),
y2 = min(y + h - 1, (int)_scr_height - 1);
int x1 = max(x, 0),
y1 = max(y, 0);
if (x1 > x2 || y1 > y2) return;
/* determine bytes per pixel */
int bypp = 0;
if (_scr_mode == 16) bypp = 2;
if (!bypp) return;
/* copy pixels from back buffer to physical frame buffer */
char *src = (char *)_bb_addr + bypp*(_scr_width*y1 + x1),
*dst = (char *)_fb_addr + bypp*(_scr_width*y1 + x1);
blit(src, bypp*_scr_width, dst, bypp*_scr_width,
bypp*(x2 - x1 + 1), y2 - y1 + 1);
}
public:
/**
* Constructor
*/
Session_component(unsigned scr_width, unsigned scr_height, unsigned scr_mode,
Genode::Dataspace_capability fb_ds, bool buffered)
:
_scr_width(scr_width), _scr_height(scr_height), _scr_mode(scr_mode),
_buffered(buffered), _fb_ds(fb_ds)
{
if (!_buffered) return;
if (scr_mode != 16) {
Genode::warning("buffered mode not supported for mode ", (int)scr_mode);
_buffered = false;
}
size_t buf_size = scr_width*scr_height*scr_mode/8;
try { _bb_ds = Genode::env()->ram_session()->alloc(buf_size); }
catch (...) {
Genode::warning("could not allocate back buffer, disabled buffered output");
_buffered = false;
}
if (_buffered && _bb_ds.valid()) {
_bb_addr = Genode::env()->rm_session()->attach(_bb_ds);
_fb_addr = Genode::env()->rm_session()->attach(_fb_ds);
}
if (_buffered)
Genode::log("using buffered output");
}
/**
* Destructor
*/
~Session_component()
{
if (!_buffered) return;
Genode::env()->rm_session()->detach(_bb_addr);
Genode::env()->ram_session()->free(_bb_ds);
Genode::env()->rm_session()->detach(_fb_addr);
}
/***********************************
** Framebuffer session interface **
***********************************/
Dataspace_capability dataspace() override {
return _buffered ? Dataspace_capability(_bb_ds)
: Dataspace_capability(_fb_ds); }
Mode mode() const override
{
return Mode(_scr_width, _scr_height,
_scr_mode == 16 ? Mode::RGB565 : Mode::INVALID);
}
void mode_sigh(Genode::Signal_context_capability) override { }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_timer.sigh(sigh);
_timer.trigger_periodic(10*1000);
}
void refresh(int x, int y, int w, int h) override
{
if (_buffered)
_refresh_buffered(x, y, w, h);
}
};
/**
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Session_component, Genode::Single_client> Root_component;
class Root : public Root_component
{
protected:
Session_component *_create_session(const char *args) override
{
unsigned long scr_width = session_arg("width", args, "fb_width", 0),
scr_height = session_arg("height", args, "fb_height", 0),
scr_mode = session_arg("depth", args, "fb_mode", 16);
bool buffered = config_attribute("buffered");
if (Framebuffer_drv::set_mode(scr_width, scr_height, scr_mode) != 0) {
Genode::warning("Could not set vesa mode ",
scr_width, "x", scr_height, "@", scr_mode);
throw Root::Invalid_args();
}
Genode::log("using video mode: ", scr_width, "x", scr_height, "@", scr_mode);
return new (md_alloc()) Session_component(scr_width, scr_height, scr_mode,
Framebuffer_drv::hw_framebuffer(),
buffered);
}
public:
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc)
: Root_component(session_ep, md_alloc) { }
};
using Genode::size_t;
using Genode::min;
using Genode::max;
using Genode::Dataspace_capability;
using Genode::Attached_rom_dataspace;
using Genode::Attached_ram_dataspace;
}
int main(int argc, char **argv)
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
/* We need to create capabilities for sessions. Therefore, we request the
* CAP service. */
static Cap_connection cap;
private:
/* initialize server entry point */
enum { STACK_SIZE = 4*1024*sizeof(long) };
static Rpc_entrypoint ep(&cap, STACK_SIZE, "vesa_ep");
Genode::Env &_env;
/* init driver back end */
if (Framebuffer_drv::init()) {
Genode::error("H/W driver init failed");
return 3;
unsigned const _scr_width, _scr_height, _scr_depth;
Timer::Connection _timer { _env };
/* dataspace of physical frame buffer */
Dataspace_capability _fb_cap;
void *_fb_addr;
/* dataspace uses a back buffer (if '_buffered' is true) */
Genode::Constructible<Attached_ram_dataspace> _bb;
void _refresh_buffered(int x, int y, int w, int h)
{
/* clip specified coordinates against screen boundaries */
int x2 = min(x + w - 1, (int)_scr_width - 1),
y2 = min(y + h - 1, (int)_scr_height - 1);
int x1 = max(x, 0),
y1 = max(y, 0);
if (x1 > x2 || y1 > y2) return;
/* determine bytes per pixel */
int bypp = 0;
if (_scr_depth == 16) bypp = 2;
if (!bypp) return;
/* copy pixels from back buffer to physical frame buffer */
char *src = _bb->local_addr<char>() + bypp*(_scr_width*y1 + x1),
*dst = (char *)_fb_addr + bypp*(_scr_width*y1 + x1);
blit(src, bypp*_scr_width, dst, bypp*_scr_width,
bypp*(x2 - x1 + 1), y2 - y1 + 1);
}
bool _buffered() const { return _bb.constructed(); }
public:
/**
* Constructor
*/
Session_component(Genode::Env &env,
unsigned scr_width, unsigned scr_height, unsigned scr_depth,
Dataspace_capability fb_cap, bool buffered)
:
_env(env),
_scr_width(scr_width), _scr_height(scr_height), _scr_depth(scr_depth),
_fb_cap(fb_cap)
{
if (!buffered) return;
if (_scr_depth != 16) {
Genode::warning("buffered mode not supported for depth ", _scr_depth);
return;
}
size_t const bb_size = _scr_width*_scr_height*_scr_depth/8;
try { _bb.construct(env.ram(), env.rm(), bb_size); }
catch (...) {
Genode::warning("could not allocate back buffer, disabled buffered output");
return;
}
_fb_addr = env.rm().attach(_fb_cap);
Genode::log("using buffered output");
}
/**
* Destructor
*/
~Session_component()
{
if (_buffered()) {
_bb.destruct();
_env.rm().detach(_fb_addr);
}
}
/***********************************
** Framebuffer session interface **
***********************************/
Dataspace_capability dataspace() override
{
return _buffered() ? Dataspace_capability(_bb->cap())
: Dataspace_capability(_fb_cap);
}
Mode mode() const override
{
return Mode(_scr_width, _scr_height,
_scr_depth == 16 ? Mode::RGB565 : Mode::INVALID);
}
void mode_sigh(Genode::Signal_context_capability) override { }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_timer.sigh(sigh);
_timer.trigger_periodic(10*1000);
}
void refresh(int x, int y, int w, int h) override
{
if (_buffered())
_refresh_buffered(x, y, w, h);
}
};
/**
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Framebuffer::Session_component,
Genode::Single_client> Root_component;
class Framebuffer::Root : public Root_component
{
private:
Genode::Env &_env;
Attached_rom_dataspace const &_config;
unsigned _session_arg(char const *attr_name, char const *args,
char const *arg_name, unsigned default_value)
{
/* try to obtain value from config file */
unsigned result = _config.xml().attribute_value(attr_name,
default_value);
/* check session argument to override value from config file */
return Genode::Arg_string::find_arg(args, arg_name).ulong_value(result);
}
protected:
Session_component *_create_session(char const *args) override
{
unsigned scr_width = _session_arg("width", args, "fb_width", 0);
unsigned scr_height = _session_arg("height", args, "fb_height", 0);
unsigned const scr_depth = _session_arg("depth", args, "fb_mode", 16);
bool const buffered = _config.xml().attribute_value("buffered", false);
if (Framebuffer::set_mode(scr_width, scr_height, scr_depth) != 0) {
Genode::warning("Could not set vesa mode ",
scr_width, "x", scr_height, "@", scr_depth);
throw Root::Invalid_args();
}
Genode::log("using video mode: ",
scr_width, "x", scr_height, "@", scr_depth);
return new (md_alloc()) Session_component(_env,
scr_width, scr_height, scr_depth,
Framebuffer::hw_framebuffer(),
buffered);
}
public:
Root(Genode::Env &env, Genode::Allocator &alloc,
Attached_rom_dataspace const &config)
:
Root_component(&env.ep().rpc_ep(), &alloc),
_env(env), _config(config)
{ }
};
struct Framebuffer::Main
{
Genode::Env &env;
Genode::Heap heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Root root { env, heap, config };
Main(Genode::Env &env) : env(env)
{
try { Framebuffer::init(env, heap); } catch (...) {
Genode::error("H/W driver init failed");
throw;
}
env.parent().announce(env.ep().manage(root));
}
};
/* entry point serving framebuffer root interface */
static Framebuffer::Root fb_root(&ep, env()->heap());
/* tell parent about the service */
env()->parent()->announce(ep.manage(&fb_root));
/* main's done - go to sleep */
sleep_forever();
return 0;
}
void Component::construct(Genode::Env &env) { static Framebuffer::Main inst(env); }

View File

@ -1,5 +1,5 @@
TARGET = fb_drv
REQUIRES = vesa
REQUIRES = x86
SRC_CC = main.cc framebuffer.cc ifx86emu.cc hw_emul.cc
LIBS = base blit x86emu config
LIBS = base blit x86emu
INC_DIR += $(PRG_DIR)/include $(REP_DIR)/include/x86emu