mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-22 12:06:00 +00:00
os: Add VirtIO framebuffer driver.
This implements the necessary bits to provide 2D framebuffer support on top of VirtIO GPU device as implemented in Qemu. I don't know if any other implementation of this specific device exists. Compared to the ramfb driver which already exists in Genode Virtio FB driver has one major benefit. It allows Qemu window to be dynamically resized at runtime. The driver will treat this as resolution change and act accordingly. Ramfb driver can currently only use the hardcoded 1024x768 screen size. Changing screen resolution might not sound like a big deal, but it is rather useful to run Genode on Qemu in full screen mode.
This commit is contained in:
parent
2ec9e69fd4
commit
7c1888644a
2
repos/os/recipes/src/virtio_fb_drv/content.mk
Normal file
2
repos/os/recipes/src/virtio_fb_drv/content.mk
Normal file
@ -0,0 +1,2 @@
|
||||
SRC_DIR = src/drivers/framebuffer/virtio
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
1
repos/os/recipes/src/virtio_fb_drv/hash
Normal file
1
repos/os/recipes/src/virtio_fb_drv/hash
Normal file
@ -0,0 +1 @@
|
||||
2021-09-21 505752c4facfcd13ceb75f90b7c9f43209586513
|
7
repos/os/recipes/src/virtio_fb_drv/used_apis
Normal file
7
repos/os/recipes/src/virtio_fb_drv/used_apis
Normal file
@ -0,0 +1,7 @@
|
||||
base
|
||||
blit
|
||||
capture_session
|
||||
event_session
|
||||
os
|
||||
platform_session
|
||||
virtio
|
563
repos/os/src/drivers/framebuffer/virtio/component.h
Normal file
563
repos/os/src/drivers/framebuffer/virtio/component.h
Normal file
@ -0,0 +1,563 @@
|
||||
/*
|
||||
* \brief VirtIO MMIO Framebuffer component
|
||||
* \author Piotr Tworek
|
||||
* \date 2020-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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/component.h>
|
||||
#include <base/signal.h>
|
||||
#include <capture_session/connection.h>
|
||||
#include <irq_session/client.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <util/register.h>
|
||||
#include <virtio/queue.h>
|
||||
|
||||
namespace Virtio_fb {
|
||||
using namespace Genode;
|
||||
class Driver;
|
||||
}
|
||||
|
||||
/*
|
||||
* This driver is based on Virtual I/O Device specification, Version 1.1, chapter 5.7
|
||||
* "GPU Device". This document can be found at:
|
||||
* https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html
|
||||
*/
|
||||
class Virtio_fb::Driver
|
||||
{
|
||||
private:
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Driver(Root const &) = delete;
|
||||
Driver &operator = (Driver const &) = delete;
|
||||
|
||||
struct Device_init_failed : Exception { };
|
||||
struct Unsupported_version : Exception { };
|
||||
struct Features_init_failed : Exception { };
|
||||
struct Queue_init_failed : Exception { };
|
||||
struct Display_init_failed : Exception { };
|
||||
struct Display_deinit_failed : Exception { };
|
||||
|
||||
enum : uint16_t { CONTROL_VQ = 0, CURSOR_VQ = 1 };
|
||||
|
||||
struct Features : Register<64>
|
||||
{
|
||||
struct VIRGL : Bitfield<0, 1> { };
|
||||
struct EDID : Bitfield<1, 1> { };
|
||||
struct VERSION_1 : Bitfield<32, 1> { };
|
||||
};
|
||||
|
||||
struct Control_header
|
||||
{
|
||||
enum Type : uint32_t
|
||||
{
|
||||
/* 2D commands */
|
||||
CMD_GET_DISPLAY_INFO = 0x0100,
|
||||
CMD_RESOURCE_CREATE_2D,
|
||||
CMD_RESOURCE_UNREF,
|
||||
CMD_RESOURCE_SET_SCANOUT,
|
||||
CMD_RESOURCE_FLUSH,
|
||||
CMD_RESOURCE_TRANSFER_TO_HOST,
|
||||
CMD_RESOURCE_ATTACH_BACKING,
|
||||
CMD_RESOURCE_DETACH_BACKING,
|
||||
|
||||
/* Success responses */
|
||||
RESP_OK_NODATA = 0x1100,
|
||||
RESP_OK_DISPLAY_INFO,
|
||||
RESP_OK_CAPSET_INFO,
|
||||
RESP_OK_CAPSET,
|
||||
RESP_OK_EDID,
|
||||
|
||||
/* Error responses */
|
||||
RESP_ERROR_UNSPECIFIED = 0x1200,
|
||||
RESP_ERROR_OUT_OF_MEMORY,
|
||||
RESP_ERROR_INVALID_SCANOUT_ID,
|
||||
RESP_ERROR_INVALID_RESOURCE_ID,
|
||||
RESP_ERROR_INVALID_CONTEXT_ID,
|
||||
RESP_ERROR_INVALID_PARAMETER_ID,
|
||||
};
|
||||
|
||||
Type type;
|
||||
uint32_t flags = 0;
|
||||
uint64_t fence_id = 0;
|
||||
uint32_t ctx_id = 0;
|
||||
uint32_t const padding = 0;
|
||||
};
|
||||
|
||||
enum { MAX_SCANOUTS = 16 };
|
||||
enum : uint32_t { EVENT_DISPLAY = (1 << 0) };
|
||||
|
||||
enum Config : uint8_t
|
||||
{
|
||||
EVENTS_READ = 0,
|
||||
EVENTS_CLEAR = 4,
|
||||
NUM_SCANOUTS = 8,
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct Display_info
|
||||
{
|
||||
Control_header hdr;
|
||||
struct
|
||||
{
|
||||
Rect rect;
|
||||
uint32_t enabled;
|
||||
uint32_t flags;
|
||||
} modes[MAX_SCANOUTS];
|
||||
};
|
||||
|
||||
enum class Resource_Id : uint32_t { FRAMEBUFFER = 1 };
|
||||
|
||||
enum class Format : uint32_t { B8G8R8X8 = 2 };
|
||||
|
||||
struct Resource_create_2d
|
||||
{
|
||||
Resource_Id const resource_id = Resource_Id::FRAMEBUFFER;
|
||||
Format const format = Format::B8G8R8X8;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct Resource_destroy_2d
|
||||
{
|
||||
Resource_Id const resource_id = Resource_Id::FRAMEBUFFER;
|
||||
uint32_t const padding = 0;
|
||||
};
|
||||
|
||||
struct Attach_backing
|
||||
{
|
||||
Resource_Id const resource_id = Resource_Id::FRAMEBUFFER;
|
||||
uint32_t const nr_entries = 1;
|
||||
uint64_t addr;
|
||||
uint32_t length;
|
||||
uint32_t const padding = 0;
|
||||
};
|
||||
|
||||
using Detach_backing = Resource_destroy_2d;
|
||||
|
||||
struct Set_scanout
|
||||
{
|
||||
Rect rect;
|
||||
uint32_t scanout_id;
|
||||
Resource_Id const resource_id = Resource_Id::FRAMEBUFFER;
|
||||
};
|
||||
|
||||
struct Transfer_to_host_2d
|
||||
{
|
||||
Rect rect;
|
||||
uint64_t offset;
|
||||
Resource_Id const resource_id = Resource_Id::FRAMEBUFFER;
|
||||
uint32_t const paddiing = 0;
|
||||
};
|
||||
|
||||
struct Resource_flush
|
||||
{
|
||||
Rect rect;
|
||||
Resource_Id const resource_id = Resource_Id::FRAMEBUFFER;
|
||||
uint32_t const padding = 0;
|
||||
};
|
||||
|
||||
struct Control_queue_traits
|
||||
{
|
||||
static const bool device_write_only = false;
|
||||
static const bool has_data_payload = true;
|
||||
};
|
||||
|
||||
typedef Virtio::Queue<Control_header, Control_queue_traits> Control_queue;
|
||||
|
||||
class Fb_memory_resource
|
||||
{
|
||||
private:
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Fb_memory_resource(Fb_memory_resource const &) = delete;
|
||||
Fb_memory_resource &operator = (Fb_memory_resource const &) = delete;
|
||||
|
||||
Platform::Connection &_platform;
|
||||
Attached_dataspace _attachement;
|
||||
|
||||
static size_t _fb_size(Capture::Area const &area) {
|
||||
return area.w() * area.h() * 4; }
|
||||
|
||||
public:
|
||||
|
||||
addr_t phys_addr()
|
||||
{
|
||||
Dataspace_client client(_attachement.cap());
|
||||
return client.phys_addr();
|
||||
}
|
||||
|
||||
Capture::Pixel *local_addr() { return _attachement.local_addr<Capture::Pixel>(); }
|
||||
size_t size() const { return _attachement.size(); };
|
||||
|
||||
Fb_memory_resource(Region_map &rm,
|
||||
Platform::Connection &platform,
|
||||
Capture::Area const &area)
|
||||
: _platform(platform)
|
||||
, _attachement(rm, _platform.alloc_dma_buffer(_fb_size(area), UNCACHED)) { }
|
||||
|
||||
~Fb_memory_resource()
|
||||
{
|
||||
_platform.free_dma_buffer(static_cap_cast<Ram_dataspace>(_attachement.cap()));
|
||||
_attachement.invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
Env &_env;
|
||||
Platform::Connection &_platform;
|
||||
Virtio::Device &_device;
|
||||
Control_queue _ctrl_vq { _env.ram(), _env.rm(), 4, 512 };
|
||||
uint32_t const _num_scanouts;
|
||||
Signal_handler<Driver> _irq_handler { _env.ep(), *this, &Driver::_handle_irq };
|
||||
|
||||
/*
|
||||
* Capture
|
||||
*/
|
||||
uint32_t _selected_scanout_id { 0 };
|
||||
Capture::Area _display_area { 0, 0 };
|
||||
Capture::Connection _capture { _env };
|
||||
Constructible<Capture::Connection::Screen> _captured_screen { };
|
||||
Timer::Connection _capture_timer { _env };
|
||||
Constructible<Fb_memory_resource> _fb_res { };
|
||||
|
||||
Signal_handler<Driver> _capture_timer_handler {
|
||||
_env.ep(), *this, &Driver::_handle_capture_timer };
|
||||
|
||||
|
||||
static uint32_t _read_num_scanouts(Virtio::Device &device)
|
||||
{
|
||||
uint32_t num_scanouts;
|
||||
uint32_t before = 0, after = 0;
|
||||
do {
|
||||
num_scanouts = device.read_config(
|
||||
Config::NUM_SCANOUTS, Virtio::Device::ACCESS_32BIT);
|
||||
} while (after != before);
|
||||
return num_scanouts;
|
||||
}
|
||||
|
||||
uint32_t _read_pending_events()
|
||||
{
|
||||
uint32_t events;
|
||||
uint32_t before = 0, after = 0;
|
||||
do {
|
||||
events = _device.read_config(
|
||||
Config::EVENTS_READ, Virtio::Device::ACCESS_32BIT);
|
||||
} while (after != before);
|
||||
do {
|
||||
_device.write_config(
|
||||
Config::EVENTS_CLEAR, Virtio::Device::ACCESS_32BIT, events);
|
||||
} while (after != before);
|
||||
return events;
|
||||
}
|
||||
|
||||
static uint32_t _init_device(Virtio::Device &device,
|
||||
Virtio::Queue_description const &ctrl_vq_desc)
|
||||
{
|
||||
using Status = Virtio::Device::Status;
|
||||
|
||||
if (!device.set_status(Status::RESET)) {
|
||||
error("Failed to reset the device!");
|
||||
throw Device_init_failed();
|
||||
}
|
||||
|
||||
if (!device.set_status(Status::ACKNOWLEDGE)) {
|
||||
error("Failed to acknowledge the device!");
|
||||
throw Device_init_failed();
|
||||
}
|
||||
|
||||
if (!device.set_status(Status::DRIVER)) {
|
||||
device.set_status(Status::FAILED);
|
||||
error("Device initialization failed!");
|
||||
throw Device_init_failed();
|
||||
}
|
||||
|
||||
const uint32_t low = device.get_features(0);
|
||||
const uint32_t high = device.get_features(1);
|
||||
const Features::access_t device_features = ((uint64_t)high << 32) | low;
|
||||
Features::access_t driver_features = 0;
|
||||
|
||||
/* This driver does not support legacy VirtIO versions. */
|
||||
if (!Features::VERSION_1::get(device_features)) {
|
||||
error("Unsupprted VirtIO device version!");
|
||||
throw Unsupported_version();
|
||||
}
|
||||
Features::VERSION_1::set(driver_features);
|
||||
|
||||
device.set_features(0, (uint32_t)driver_features);
|
||||
device.set_features(1, (uint32_t)(driver_features >> 32));
|
||||
|
||||
if (!device.set_status(Status::FEATURES_OK)) {
|
||||
device.set_status(Status::FAILED);
|
||||
error("Device feature negotiation failed!");
|
||||
throw Features_init_failed();
|
||||
}
|
||||
|
||||
if (!device.configure_queue(CONTROL_VQ, ctrl_vq_desc)) {
|
||||
error("Failed to initialize \"control\" VirtIO queue!");
|
||||
throw Queue_init_failed();
|
||||
}
|
||||
|
||||
using Status = Virtio::Device::Status;
|
||||
if (!device.set_status(Status::DRIVER_OK)) {
|
||||
device.set_status(Status::FAILED);
|
||||
error("Failed to initialize VirtIO queues!");
|
||||
throw Queue_init_failed();
|
||||
}
|
||||
|
||||
auto num_scanouts = _read_num_scanouts(device);
|
||||
if (num_scanouts > MAX_SCANOUTS) {
|
||||
error("Invalid scanout number!");
|
||||
throw Device_init_failed();
|
||||
}
|
||||
|
||||
return num_scanouts;
|
||||
}
|
||||
|
||||
void _configure_display() {
|
||||
Control_header res2d_cmd { Control_header::CMD_RESOURCE_CREATE_2D };
|
||||
Resource_create_2d res2d_data {
|
||||
.width = _display_area.w(),
|
||||
.height = _display_area.h(),
|
||||
};
|
||||
|
||||
if (!_exec_cmd(res2d_cmd, res2d_data)) {
|
||||
error("Failed to create 2D resource!");
|
||||
throw Display_init_failed();
|
||||
}
|
||||
|
||||
try {
|
||||
_fb_res.construct(_env.rm(), _platform, _display_area);
|
||||
} catch (...) {
|
||||
error("Failed to allocate framebuffer!");
|
||||
throw;
|
||||
}
|
||||
|
||||
{
|
||||
Control_header attach_cmd { Control_header::CMD_RESOURCE_ATTACH_BACKING };
|
||||
Attach_backing attach_data {
|
||||
.addr = _fb_res->phys_addr(),
|
||||
.length = static_cast<uint32_t>(_fb_res->size())
|
||||
};
|
||||
|
||||
if (!_exec_cmd(attach_cmd, attach_data)) {
|
||||
error("Failed to attach framebuffer backing!");
|
||||
throw Display_init_failed();
|
||||
}
|
||||
}
|
||||
|
||||
Control_header scanout_cmd { Control_header::CMD_RESOURCE_SET_SCANOUT };
|
||||
Set_scanout scanout_data {
|
||||
.rect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = _display_area.w(),
|
||||
.height = _display_area.h(),
|
||||
},
|
||||
.scanout_id = _selected_scanout_id,
|
||||
};
|
||||
|
||||
if (!_exec_cmd(scanout_cmd, scanout_data)) {
|
||||
error("Failed to assign framebuffer to a scanout!");
|
||||
throw Display_init_failed();
|
||||
}
|
||||
|
||||
_captured_screen.construct(_capture, _env.rm(), _display_area);
|
||||
}
|
||||
|
||||
void _shutdown_display()
|
||||
{
|
||||
Control_header detach_cmd { Control_header::CMD_RESOURCE_DETACH_BACKING };
|
||||
Detach_backing detach_data;
|
||||
|
||||
if (!_exec_cmd(detach_cmd, detach_data)) {
|
||||
error("Failed to detatch framebuffer backing!");
|
||||
throw Display_deinit_failed();
|
||||
}
|
||||
|
||||
Control_header unref_cmd { Control_header::CMD_RESOURCE_UNREF };
|
||||
Resource_destroy_2d unref_data;
|
||||
|
||||
if (!_exec_cmd(unref_cmd, unref_data)) {
|
||||
error("Failed to unref framebuffer resource!");
|
||||
throw Display_deinit_failed();
|
||||
}
|
||||
|
||||
_captured_screen.destruct();
|
||||
_fb_res.destruct();
|
||||
}
|
||||
|
||||
void _reconfigure_display()
|
||||
{
|
||||
if (!_update_display_info(true)) {
|
||||
error("Failed to update display info!");
|
||||
throw Display_deinit_failed();
|
||||
}
|
||||
|
||||
_shutdown_display();
|
||||
_configure_display();
|
||||
}
|
||||
|
||||
void _handle_irq()
|
||||
{
|
||||
const uint32_t reasons = _device.read_isr();
|
||||
|
||||
enum { IRQ_USED_RING_UPDATE = 1, IRQ_CONFIG_CHANGE = 2 };
|
||||
|
||||
/*
|
||||
* This driver does not request interrupts when dealing with control
|
||||
* queue. Some older pre 6.x Qemu versions do signal ctrl ring update
|
||||
* when display size is changed. Just ACK and otherwise ignore such
|
||||
* bogus updates.
|
||||
*/
|
||||
if ((reasons & IRQ_USED_RING_UPDATE) && _ctrl_vq.has_used_buffers())
|
||||
_ctrl_vq.ack_all_transfers();
|
||||
|
||||
if (reasons & IRQ_CONFIG_CHANGE) {
|
||||
auto const events = _read_pending_events();
|
||||
if (events & EVENT_DISPLAY)
|
||||
_reconfigure_display();
|
||||
}
|
||||
|
||||
_device.irq_ack();
|
||||
}
|
||||
|
||||
void _handle_capture_timer()
|
||||
{
|
||||
using Pixel = Capture::Pixel;
|
||||
|
||||
if (!_captured_screen.constructed())
|
||||
return;
|
||||
|
||||
Capture::Surface<Pixel> surface(_fb_res->local_addr(), _display_area);
|
||||
_captured_screen->apply_to_surface(surface);
|
||||
|
||||
_update_fb();
|
||||
}
|
||||
|
||||
void _flush_ctrl_vq()
|
||||
{
|
||||
_device.notify_buffers_available(CONTROL_VQ);
|
||||
while (!_ctrl_vq.has_used_buffers());
|
||||
}
|
||||
|
||||
template <typename CMD_DATA_TYPE>
|
||||
bool _exec_cmd(Control_header const &cmd,
|
||||
CMD_DATA_TYPE const &cmd_data)
|
||||
{
|
||||
return _ctrl_vq.write_data_read_reply<Control_header>(
|
||||
cmd, (char const *)&cmd_data, sizeof(CMD_DATA_TYPE),
|
||||
[this]() { _flush_ctrl_vq(); },
|
||||
[](Control_header const &response) {
|
||||
return response.type == Control_header::RESP_OK_NODATA; });
|
||||
}
|
||||
|
||||
bool _update_display_info(bool use_current_scanout)
|
||||
{
|
||||
Control_header cmd { Control_header::CMD_GET_DISPLAY_INFO };
|
||||
|
||||
auto display_info_cb = [&](Display_info const &info) {
|
||||
for (size_t i = 0; i < _num_scanouts; ++i) {
|
||||
if (info.modes[i].enabled) {
|
||||
if (use_current_scanout && (_selected_scanout_id != i))
|
||||
continue;
|
||||
auto const &r = info.modes[i].rect;
|
||||
_display_area = Capture::Area{ r.width, r.height };
|
||||
_selected_scanout_id = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!_ctrl_vq.write_data_read_reply<Display_info>(
|
||||
cmd, [this] { _flush_ctrl_vq(); }, display_info_cb)) {
|
||||
error("Failed to request display info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _init_display() {
|
||||
if (!_update_display_info(false))
|
||||
throw Display_init_failed();
|
||||
_configure_display();
|
||||
}
|
||||
|
||||
void _update_fb()
|
||||
{
|
||||
Control_header transfer_cmd { Control_header::CMD_RESOURCE_TRANSFER_TO_HOST };
|
||||
Transfer_to_host_2d transfer_data {
|
||||
.rect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = _display_area.w(),
|
||||
.height = _display_area.h(),
|
||||
},
|
||||
.offset = 0,
|
||||
};
|
||||
if (!_exec_cmd(transfer_cmd, transfer_data)) {
|
||||
error("Failed to send transfer 2D resource to host command!");
|
||||
return;
|
||||
}
|
||||
|
||||
Control_header flush_cmd { Control_header::CMD_RESOURCE_FLUSH };
|
||||
Resource_flush flush_data {
|
||||
.rect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = _display_area.w(),
|
||||
.height = _display_area.h(),
|
||||
},
|
||||
};
|
||||
if (!_exec_cmd(flush_cmd, flush_data)) {
|
||||
error("Failed to send flush resource command!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Driver(Env &env,
|
||||
Platform::Connection &platform,
|
||||
Virtio::Device &device)
|
||||
: _env(env),
|
||||
_platform(platform),
|
||||
_device(device),
|
||||
_num_scanouts(_init_device(_device, _ctrl_vq.description()))
|
||||
{
|
||||
try {
|
||||
_init_display();
|
||||
} catch (...) {
|
||||
device.set_status(Virtio::Device::Status::RESET);
|
||||
throw;
|
||||
}
|
||||
|
||||
_device.irq_sigh(_irq_handler);
|
||||
_device.irq_ack();
|
||||
_capture_timer.sigh(_capture_timer_handler);
|
||||
_capture_timer.trigger_periodic(10*1000);
|
||||
}
|
||||
|
||||
~Driver()
|
||||
{
|
||||
_device.set_status(Virtio::Device::Status::RESET);
|
||||
}
|
||||
};
|
42
repos/os/src/drivers/framebuffer/virtio/mmio_device.cc
Normal file
42
repos/os/src/drivers/framebuffer/virtio/mmio_device.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* \brief VirtIO MMIO Framebuffer driver
|
||||
* \author Piotr Tworek
|
||||
* \date 2020-02-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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/component.h>
|
||||
#include <platform_session/connection.h>
|
||||
#include <virtio/mmio_device.h>
|
||||
|
||||
#include "component.h"
|
||||
|
||||
namespace Virtio_mmio_fb {
|
||||
using namespace Genode;
|
||||
struct Main;
|
||||
}
|
||||
|
||||
struct Virtio_mmio_fb::Main
|
||||
{
|
||||
Genode::Env &env;
|
||||
Platform::Connection platform { env };
|
||||
Platform::Device platform_device { platform,
|
||||
Platform::Device::Type { "gpu" } };
|
||||
Virtio::Device virtio_device { platform_device };
|
||||
Virtio_fb::Driver driver { env, platform, virtio_device };
|
||||
|
||||
Main(Env &env)
|
||||
try : env(env) { log("--- VirtIO MMIO Framebuffer driver started ---"); }
|
||||
catch (...) { env.parent().exit(-1); }
|
||||
};
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
static Virtio_mmio_fb::Main main(env);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
REQUIRES = arm
|
||||
|
||||
include $(REP_DIR)/src/drivers/framebuffer/virtio/target_mmio.inc
|
@ -0,0 +1,3 @@
|
||||
REQUIRES = arm_64
|
||||
|
||||
include $(REP_DIR)/src/drivers/framebuffer/virtio/target_mmio.inc
|
6
repos/os/src/drivers/framebuffer/virtio/target_mmio.inc
Normal file
6
repos/os/src/drivers/framebuffer/virtio/target_mmio.inc
Normal file
@ -0,0 +1,6 @@
|
||||
TARGET = virtio_mmio_fb_drv
|
||||
SRC_CC = mmio_device.cc
|
||||
LIBS = base blit
|
||||
INC_DIR = $(REP_DIR)/src/drivers/framebuffer/virtio
|
||||
|
||||
vpath % $(REP_DIR)/src/drivers/framebuffer/virtio
|
Loading…
x
Reference in New Issue
Block a user