From e4ae817e82dac0a3dc781ac71dd442c0cdeddf01 Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Thu, 15 Apr 2021 10:15:50 +0200 Subject: [PATCH] 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 --- .../pkg/drivers_interactive-virt_qemu/README | 3 + .../drivers_interactive-virt_qemu/archives | 4 + .../pkg/drivers_interactive-virt_qemu/hash | 1 + .../drivers_interactive-virt_qemu/content.mk | 7 + .../drivers.config | 66 ++++++ .../event_filter.config | 26 +++ .../raw/drivers_interactive-virt_qemu/hash | 1 + .../recipes/src/virt_qemu_drivers/content.mk | 7 + repos/os/recipes/src/virt_qemu_drivers/hash | 1 + .../recipes/src/virt_qemu_drivers/used_apis | 7 + repos/os/src/drivers/framebuffer/ram/README | 2 + repos/os/src/drivers/framebuffer/ram/main.cc | 209 ++++++++++++++++++ .../os/src/drivers/framebuffer/ram/target.mk | 5 + 13 files changed, 339 insertions(+) create mode 100644 repos/os/recipes/pkg/drivers_interactive-virt_qemu/README create mode 100644 repos/os/recipes/pkg/drivers_interactive-virt_qemu/archives create mode 100644 repos/os/recipes/pkg/drivers_interactive-virt_qemu/hash create mode 100644 repos/os/recipes/raw/drivers_interactive-virt_qemu/content.mk create mode 100644 repos/os/recipes/raw/drivers_interactive-virt_qemu/drivers.config create mode 100644 repos/os/recipes/raw/drivers_interactive-virt_qemu/event_filter.config create mode 100644 repos/os/recipes/raw/drivers_interactive-virt_qemu/hash create mode 100644 repos/os/recipes/src/virt_qemu_drivers/content.mk create mode 100644 repos/os/recipes/src/virt_qemu_drivers/hash create mode 100644 repos/os/recipes/src/virt_qemu_drivers/used_apis create mode 100644 repos/os/src/drivers/framebuffer/ram/README create mode 100644 repos/os/src/drivers/framebuffer/ram/main.cc create mode 100644 repos/os/src/drivers/framebuffer/ram/target.mk diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu/README b/repos/os/recipes/pkg/drivers_interactive-virt_qemu/README new file mode 100644 index 0000000000..3273ce23de --- /dev/null +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu/README @@ -0,0 +1,3 @@ + + Device drivers needed to run interactive + scenarios on the Virt platform as emulated by Qemu diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu/archives b/repos/os/recipes/pkg/drivers_interactive-virt_qemu/archives new file mode 100644 index 0000000000..455264e522 --- /dev/null +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu/archives @@ -0,0 +1,4 @@ +_/src/virt_qemu_drivers +_/src/platform_drv +_/src/event_filter +_/raw/drivers_interactive-virt_qemu diff --git a/repos/os/recipes/pkg/drivers_interactive-virt_qemu/hash b/repos/os/recipes/pkg/drivers_interactive-virt_qemu/hash new file mode 100644 index 0000000000..18dfb2eb5e --- /dev/null +++ b/repos/os/recipes/pkg/drivers_interactive-virt_qemu/hash @@ -0,0 +1 @@ +2021-04-16-n dfdb663efd7c1a6b2e9bb399f03ac7bb42657ba5 diff --git a/repos/os/recipes/raw/drivers_interactive-virt_qemu/content.mk b/repos/os/recipes/raw/drivers_interactive-virt_qemu/content.mk new file mode 100644 index 0000000000..54b94f2896 --- /dev/null +++ b/repos/os/recipes/raw/drivers_interactive-virt_qemu/content.mk @@ -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/$@ $@ diff --git a/repos/os/recipes/raw/drivers_interactive-virt_qemu/drivers.config b/repos/os/recipes/raw/drivers_interactive-virt_qemu/drivers.config new file mode 100644 index 0000000000..8464a17e5b --- /dev/null +++ b/repos/os/recipes/raw/drivers_interactive-virt_qemu/drivers.config @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/recipes/raw/drivers_interactive-virt_qemu/event_filter.config b/repos/os/recipes/raw/drivers_interactive-virt_qemu/event_filter.config new file mode 100644 index 0000000000..55cdbc6167 --- /dev/null +++ b/repos/os/recipes/raw/drivers_interactive-virt_qemu/event_filter.config @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/recipes/raw/drivers_interactive-virt_qemu/hash b/repos/os/recipes/raw/drivers_interactive-virt_qemu/hash new file mode 100644 index 0000000000..3ce371e3be --- /dev/null +++ b/repos/os/recipes/raw/drivers_interactive-virt_qemu/hash @@ -0,0 +1 @@ +2021-04-16-b 1ac1f670f6c96ac6098145f15924265616f99c6a diff --git a/repos/os/recipes/src/virt_qemu_drivers/content.mk b/repos/os/recipes/src/virt_qemu_drivers/content.mk new file mode 100644 index 0000000000..bce2ccada9 --- /dev/null +++ b/repos/os/recipes/src/virt_qemu_drivers/content.mk @@ -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 diff --git a/repos/os/recipes/src/virt_qemu_drivers/hash b/repos/os/recipes/src/virt_qemu_drivers/hash new file mode 100644 index 0000000000..d7c654a4ec --- /dev/null +++ b/repos/os/recipes/src/virt_qemu_drivers/hash @@ -0,0 +1 @@ +2021-04-16-m ba0d520e8e92df0c87e0406d31115966a0301fb1 diff --git a/repos/os/recipes/src/virt_qemu_drivers/used_apis b/repos/os/recipes/src/virt_qemu_drivers/used_apis new file mode 100644 index 0000000000..2d46ac2a1b --- /dev/null +++ b/repos/os/recipes/src/virt_qemu_drivers/used_apis @@ -0,0 +1,7 @@ +base +os +capture_session +event_session +platform_session +timer_session +blit diff --git a/repos/os/src/drivers/framebuffer/ram/README b/repos/os/src/drivers/framebuffer/ram/README new file mode 100644 index 0000000000..ac088a5b67 --- /dev/null +++ b/repos/os/src/drivers/framebuffer/ram/README @@ -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. diff --git a/repos/os/src/drivers/framebuffer/ram/main.cc b/repos/os/src/drivers/framebuffer/ram/main.cc new file mode 100644 index 0000000000..208d095435 --- /dev/null +++ b/repos/os/src/drivers/framebuffer/ram/main.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 + 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() }; + + 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
_timer_handler { _env.ep(), *this, &Main::_handle_timer }; + + void _handle_timer() + { + using Pixel = Capture::Pixel; + + Surface surface(_fb_ds.local_addr(), _size); + + _captured_screen.apply_to_surface(surface); + } + + /* device selector */ + void _fw_selector(uint16_t key) { + _fw.write(host_to_big_endian(key)); } + + /* read data for selected key */ + template T _fw_data() { + return host_to_big_endian(_fw.read>()); } + + /* 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(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(host_to_big_endian(DRM_FORMAT_ARGB8888)); + write(host_to_big_endian(SCR_STRIDE)); + } + }; + + Fw_config_file _find_ramfb() + { + /* file directory */ + _fw_selector(0x19); + uint32_t count = _fw_data(); + + Fw_config_file file { }; + for (unsigned i = 0; i < count; i++) { + + file.size = _fw_data(); + file.key = _fw_data(); + file.reserved = _fw_data(); + + for (unsigned j = 0; j < 56; j++) + file.name[j] = _fw_data(); + + 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 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(host_to_big_endian(fb_phys)); + config.write(host_to_big_endian(SCR_WIDTH)); + config.write(host_to_big_endian(SCR_HEIGHT)); + + Fw_dma_config fw_dma { config_addr + FW_OFFSET}; + fw_dma.write(host_to_big_endian(file.size)); + fw_dma.write(host_to_big_endian(config_phys)); + + _fw.write(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); +}; diff --git a/repos/os/src/drivers/framebuffer/ram/target.mk b/repos/os/src/drivers/framebuffer/ram/target.mk new file mode 100644 index 0000000000..6544c8b9e8 --- /dev/null +++ b/repos/os/src/drivers/framebuffer/ram/target.mk @@ -0,0 +1,5 @@ +TARGET = ram_fb_drv +SRC_CC = main.cc +LIBS = base blit + +REQUIRES = arm_v8