mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
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:
parent
38d731bd79
commit
e4ae817e82
@ -0,0 +1,3 @@
|
||||
|
||||
Device drivers needed to run interactive
|
||||
scenarios on the Virt platform as emulated by Qemu
|
@ -0,0 +1,4 @@
|
||||
_/src/virt_qemu_drivers
|
||||
_/src/platform_drv
|
||||
_/src/event_filter
|
||||
_/raw/drivers_interactive-virt_qemu
|
1
repos/os/recipes/pkg/drivers_interactive-virt_qemu/hash
Normal file
1
repos/os/recipes/pkg/drivers_interactive-virt_qemu/hash
Normal file
@ -0,0 +1 @@
|
||||
2021-04-16-n dfdb663efd7c1a6b2e9bb399f03ac7bb42657ba5
|
@ -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/$@ $@
|
@ -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>
|
@ -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>
|
1
repos/os/recipes/raw/drivers_interactive-virt_qemu/hash
Normal file
1
repos/os/recipes/raw/drivers_interactive-virt_qemu/hash
Normal file
@ -0,0 +1 @@
|
||||
2021-04-16-b 1ac1f670f6c96ac6098145f15924265616f99c6a
|
7
repos/os/recipes/src/virt_qemu_drivers/content.mk
Normal file
7
repos/os/recipes/src/virt_qemu_drivers/content.mk
Normal 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
|
1
repos/os/recipes/src/virt_qemu_drivers/hash
Normal file
1
repos/os/recipes/src/virt_qemu_drivers/hash
Normal file
@ -0,0 +1 @@
|
||||
2021-04-16-m ba0d520e8e92df0c87e0406d31115966a0301fb1
|
7
repos/os/recipes/src/virt_qemu_drivers/used_apis
Normal file
7
repos/os/recipes/src/virt_qemu_drivers/used_apis
Normal file
@ -0,0 +1,7 @@
|
||||
base
|
||||
os
|
||||
capture_session
|
||||
event_session
|
||||
platform_session
|
||||
timer_session
|
||||
blit
|
2
repos/os/src/drivers/framebuffer/ram/README
Normal file
2
repos/os/src/drivers/framebuffer/ram/README
Normal 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.
|
209
repos/os/src/drivers/framebuffer/ram/main.cc
Normal file
209
repos/os/src/drivers/framebuffer/ram/main.cc
Normal 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);
|
||||
};
|
5
repos/os/src/drivers/framebuffer/ram/target.mk
Normal file
5
repos/os/src/drivers/framebuffer/ram/target.mk
Normal file
@ -0,0 +1,5 @@
|
||||
TARGET = ram_fb_drv
|
||||
SRC_CC = main.cc
|
||||
LIBS = base blit
|
||||
|
||||
REQUIRES = arm_v8
|
Loading…
x
Reference in New Issue
Block a user