ram_fb_drv: RAM framebuffer driver for Qemu

Enable "-device ramfb" to use in Qemu. Also add drivers interactive
using this framebuffer for the "virt_qemu" platform.

issue #4254
This commit is contained in:
Sebastian Sumpf 2021-04-15 10:15:50 +02:00 committed by Christian Helmuth
parent 38d731bd79
commit e4ae817e82
13 changed files with 339 additions and 0 deletions

View File

@ -0,0 +1,3 @@
Device drivers needed to run interactive
scenarios on the Virt platform as emulated by Qemu

View File

@ -0,0 +1,4 @@
_/src/virt_qemu_drivers
_/src/platform_drv
_/src/event_filter
_/raw/drivers_interactive-virt_qemu

View File

@ -0,0 +1 @@
2021-04-16-n dfdb663efd7c1a6b2e9bb399f03ac7bb42657ba5

View File

@ -0,0 +1,7 @@
content: drivers.config event_filter.config en_us.chargen special.chargen
drivers.config event_filter.config:
cp $(REP_DIR)/recipes/raw/drivers_interactive-virt_qemu/$@ $@
en_us.chargen special.chargen:
cp $(REP_DIR)/src/server/event_filter/$@ $@

View File

@ -0,0 +1,66 @@
<config>
<parent-provides>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="ROM"/>
<service name="PD"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Capture"/>
<service name="Event"/>
</parent-provides>
<default caps="100"/>
<start name="platform_drv">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Platform"/> </provides>
<route> <any-service> <parent/> </any-service> </route>
<config>
<!-- device resource declarations -->
<device name="fw-cfg" type="qemu,fw-cfg-mmio">
<io_mem address="0x9020000" size="0x1000"/>
</device>
<!-- policy part, who owns which devices -->
<policy label="fb_drv -> " info="yes">
<device name="fw-cfg"/>
</policy>
</config>
</start>
<start name="fb_drv">
<binary name="ram_fb_drv"/>
<resource name="RAM" quantum="8M"/>
<route>
<service name="Platform">
<child name="platform_drv"/>
</service>
<service name="ROM"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="Timer"> <parent/> </service>
<service name="Capture"> <parent/> </service>
</route>
</start>
<start name="event_filter" caps="90">
<resource name="RAM" quantum="1280K"/>
<provides> <service name="Event"/> </provides>
<route>
<service name="ROM" label="config">
<parent label="event_filter.config"/>
</service>
<service name="ROM"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="Timer"> <parent/> </service>
<service name="Event"> <parent/> </service>
</route>
</start>
</config>

View File

@ -0,0 +1,26 @@
<config>
<output>
<chargen>
<accelerate max="50" sensitivity_percent="1000" curve="127">
<button-scroll>
<input name="ps2"/>
<vertical button="BTN_MIDDLE" speed_percent="-10"/>
<horizontal button="BTN_MIDDLE" speed_percent="-10"/>
</button-scroll>
</accelerate>
<mod1>
<key name="KEY_LEFTSHIFT"/> <key name="KEY_RIGHTSHIFT"/>
</mod1>
<mod2>
<key name="KEY_LEFTCTRL"/> <key name="KEY_RIGHTCTRL"/>
</mod2>
<mod3>
<key name="KEY_RIGHTALT"/> <!-- AltGr -->
</mod3>
<repeat delay_ms="230" rate_ms="90"/>
<include rom="en_us.chargen"/>
<include rom="special.chargen"/>
</chargen>
</output>
<policy label="ps2" input="ps2"/>
</config>

View File

@ -0,0 +1 @@
2021-04-16-b 1ac1f670f6c96ac6098145f15924265616f99c6a

View File

@ -0,0 +1,7 @@
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
content: src/drivers
src/drivers:
mkdir -p $@/framebuffer
cp -r $(REP_DIR)/src/drivers/framebuffer/ram/* $@/framebuffer

View File

@ -0,0 +1 @@
2021-04-16-m ba0d520e8e92df0c87e0406d31115966a0301fb1

View File

@ -0,0 +1,7 @@
base
os
capture_session
event_session
platform_session
timer_session
blit

View File

@ -0,0 +1,2 @@
Framebuffer driver for Qemu's 'ramfb' device. In order to enablethe RAM
framebuffer add the '-device ramfb' option to Qemu's command line.

View File

@ -0,0 +1,209 @@
/*
* \brief RAM framebuffer driver for Qemu
* \author Sebastian Sumpf
* \date 2021-04-15
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/attached_ram_dataspace.h>
#include <base/component.h>
#include <base/log.h>
#include <capture_session/connection.h>
#include <platform_session/device.h>
#include <timer_session/connection.h>
#include <util/endian.h>
#include <util/mmio.h>
using namespace Genode;
class Main
{
private:
enum {
SCR_WIDTH = 1024u,
SCR_HEIGHT = 768u,
SCR_STRIDE = SCR_WIDTH * 4,
};
/*****************************
** Qemu firmware interface **
*****************************/
struct Fw : Mmio
{
template <typename T>
struct Data : Register<0x0, sizeof(T) * 8> { };
struct Selector : Register<0x8, 16> { };
struct Dma : Register<0x10, 64> { };
Fw(addr_t const base)
:
Mmio(base) { }
};
Env &_env;
/************************
** Genode integration **
************************/
using Type = Platform::Device::Type;
Platform::Connection _platform { _env };
Platform::Device _fw_dev { _platform, Type { "qemu,fw-cfg-mmio" } };
Platform::Device::Mmio _fw_mem { _fw_dev };
Fw _fw { (addr_t)_fw_mem.local_addr<addr_t>() };
Ram_dataspace_capability _fb_ds_cap {
_platform.alloc_dma_buffer(SCR_HEIGHT * SCR_STRIDE, UNCACHED) };
Attached_dataspace _fb_ds { _env.rm(), _fb_ds_cap };
Ram_dataspace_capability _config_ds_cap {
_platform.alloc_dma_buffer(0x1000, UNCACHED) };
Attached_dataspace _config_ds { _env.rm(), _config_ds_cap };
Capture::Area const _size { SCR_WIDTH, SCR_HEIGHT };
Capture::Connection _capture { _env };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size };
Timer::Connection _timer { _env };
Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer };
void _handle_timer()
{
using Pixel = Capture::Pixel;
Surface<Pixel> surface(_fb_ds.local_addr<Pixel>(), _size);
_captured_screen.apply_to_surface(surface);
}
/* device selector */
void _fw_selector(uint16_t key) {
_fw.write<Fw::Selector>(host_to_big_endian(key)); }
/* read data for selected key */
template <typename T> T _fw_data() {
return host_to_big_endian(_fw.read<Fw::Data<T>>()); }
/* DMA control structure */
struct Fw_dma_config : Genode::Mmio
{
struct Control : Register<0x0, 32> { };
struct Length : Register<0x4, 32> { };
struct Address : Register<0x8, 64> { };
Fw_dma_config(addr_t const base)
:
Mmio(base)
{
/* set write bit */
write<Control>(host_to_big_endian(1u << 4));
}
};
/* file structure for directory traversal (key=0x19) */
struct Fw_config_file
{
uint32_t size;
uint16_t key;
uint16_t reserved;
char name[56];
};
/* ramfb configuration */
struct Ram_fb_config : Genode::Mmio
{
struct Address : Register<0x0, 64> { };
struct Drm_format : Register<0x8, 32> { };
struct Width : Register<0x10, 32> { };
struct Height : Register<0x14, 32> { };
struct Stride : Register<0x18, 32> { };
Ram_fb_config(addr_t const base)
:
Mmio(base)
{
enum {
DRM_FORMAT_ARGB8888 = 0x34325241,
};
/* RGBA32 */
write<Drm_format>(host_to_big_endian(DRM_FORMAT_ARGB8888));
write<Stride>(host_to_big_endian(SCR_STRIDE));
}
};
Fw_config_file _find_ramfb()
{
/* file directory */
_fw_selector(0x19);
uint32_t count = _fw_data<uint32_t>();
Fw_config_file file { };
for (unsigned i = 0; i < count; i++) {
file.size = _fw_data<uint32_t>();
file.key = _fw_data<uint16_t>();
file.reserved = _fw_data<uint16_t>();
for (unsigned j = 0; j < 56; j++)
file.name[j] = _fw_data<char>();
if (Genode::strcmp(file.name, "etc/ramfb") == 0) {
log("RAM FB found with key ", file.key);
return file;
}
}
error("'etc/ramfb' not found, try the '-device ramfb' option with Qemu");
throw -1;
}
void _setup_framebuffer(Fw_config_file const &file)
{
enum { FW_OFFSET = 28 };
_fw_selector(file.key);
addr_t config_addr = (addr_t)_config_ds.local_addr<addr_t>();
addr_t config_phys = (addr_t)_platform.dma_addr(_config_ds_cap);
addr_t fb_phys = (addr_t)_platform.dma_addr(_fb_ds_cap);
Ram_fb_config config { config_addr };
config.write<Ram_fb_config::Address>(host_to_big_endian(fb_phys));
config.write<Ram_fb_config::Width>(host_to_big_endian(SCR_WIDTH));
config.write<Ram_fb_config::Height>(host_to_big_endian(SCR_HEIGHT));
Fw_dma_config fw_dma { config_addr + FW_OFFSET};
fw_dma.write<Fw_dma_config::Length>(host_to_big_endian(file.size));
fw_dma.write<Fw_dma_config::Address>(host_to_big_endian(config_phys));
_fw.write<Fw::Dma>(host_to_big_endian(config_phys + FW_OFFSET));
}
public:
Main(Env &env)
:
_env(env)
{
_setup_framebuffer(_find_ramfb());
_timer.sigh(_timer_handler);
_timer.trigger_periodic(20*1000);
}
};
void Component::construct(Genode::Env &env)
{
log ("--- Qemu Ramfb driver --");
static Main main(env);
};

View File

@ -0,0 +1,5 @@
TARGET = ram_fb_drv
SRC_CC = main.cc
LIBS = base blit
REQUIRES = arm_v8