genode_c_api: unify shared dataspace callbacks

* Unifies the declaration of callbacks which manage driver/client
  shared dataspaces
* Move the Linux driver-specific callback implementation to the
  lx_emul library from the PC's USB host driver

Fix genodelabs/genode#4439
This commit is contained in:
Stefan Kalkowski 2022-03-03 16:11:32 +01:00
parent b1e2e654a9
commit b80146a6f7
11 changed files with 221 additions and 167 deletions

View File

@ -0,0 +1,32 @@
/*
* \brief Lx_emul support to allocate shared DMA buffer for Genode's C API
* \author Stefan Kalkowski
* \date 2022-03-02
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_EMUL__SHARED_DMA_BUFFER_H_
#define _LX_EMUL__SHARED_DMA_BUFFER_H_
#include <genode_c_api/base.h>
#ifdef __cplusplus
extern "C" {
#endif
struct genode_shared_dataspace *
lx_emul_shared_dma_buffer_allocate(unsigned long size);
void lx_emul_shared_dma_buffer_free(struct genode_shared_dataspace * ds);
#ifdef __cplusplus
}
#endif
#endif /* _LX_EMUL__SHARED_DMA_BUFFER_H_ */

View File

@ -0,0 +1,58 @@
/*
* \brief Lx_emul backend for shared dma buffers
* \author Stefan Kalkowski
* \date 2022-03-02
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/attached_dataspace.h>
#include <lx_kit/env.h>
#include <lx_kit/memory.h>
#include <lx_emul/page_virt.h>
#include <lx_emul/shared_dma_buffer.h>
struct genode_shared_dataspace : Genode::Attached_dataspace {};
extern "C" struct genode_shared_dataspace *
lx_emul_shared_dma_buffer_allocate(unsigned long size)
{
Genode::Attached_dataspace & ds =
Lx_kit::env().memory.alloc_dataspace(size);
/*
* We have to call virt_to_pages eagerly here,
* to get contingous page objects registered
*/
lx_emul_virt_to_pages(ds.local_addr<void>(), size >> 12);
return static_cast<genode_shared_dataspace*>(&ds);
}
extern "C" void
lx_emul_shared_dma_buffer_free(struct genode_shared_dataspace * ds)
{
lx_emul_forget_pages(ds->local_addr<void>(), ds->size());
Lx_kit::env().memory.free_dataspace(ds->local_addr<void>());
}
Genode::addr_t
genode_shared_dataspace_local_address(struct genode_shared_dataspace * ds)
{
return (Genode::addr_t)ds->local_addr<void>();
}
Genode::Dataspace_capability
genode_shared_dataspace_capability(struct genode_shared_dataspace * ds)
{
return ds->cap();
}

View File

@ -26,7 +26,7 @@ extern "C" {
struct genode_env;
struct genode_allocator;
struct genode_signal_handler;
struct genode_attached_dataspace;
struct genode_shared_dataspace;
#ifdef __cplusplus
} /* extern "C" */
@ -43,10 +43,9 @@ struct genode_attached_dataspace;
#include <base/allocator.h>
#include <base/attached_dataspace.h>
struct genode_env : Genode::Env { };
struct genode_allocator : Genode::Allocator { };
struct genode_signal_handler : Genode::Signal_dispatcher_base { };
struct genode_attached_dataspace : Genode::Attached_dataspace { };
struct genode_env : Genode::Env { };
struct genode_allocator : Genode::Allocator { };
struct genode_signal_handler : Genode::Signal_dispatcher_base { };
static inline auto genode_env_ptr(Genode::Env &env)
{
@ -69,11 +68,30 @@ static inline Genode::Signal_context_capability cap(genode_signal_handler *sigh_
return *static_cast<Genode::Signal_handler<Genode::Meta::Empty> *>(dispatcher_ptr);
}
static inline auto genode_attached_dataspace_ptr(Genode::Attached_dataspace &ds)
{
return static_cast<genode_attached_dataspace *>(&ds);
}
/**
* Returns local address of attached shared dataspace
*/
Genode::addr_t
genode_shared_dataspace_local_address(struct genode_shared_dataspace * ds);
/**
* Returns capability of shared dataspace
*/
Genode::Dataspace_capability
genode_shared_dataspace_capability(struct genode_shared_dataspace * ds);
#endif
/**
* Callback definition to allocate and attach a dataspace to share
*/
typedef struct genode_shared_dataspace *
(*genode_shared_dataspace_alloc_attach_t) (unsigned long size);
/**
* Callback definition to detach and free dataspace
*/
typedef void
(*genode_shared_dataspace_free_t) (struct genode_shared_dataspace * ds);
#endif /* _INCLUDE__GENODE_C_API__BASE_H_ */

View File

@ -29,18 +29,6 @@ extern "C" {
** Initialization **
********************/
/**
* Callback called during peer session request to allocate dma-capable shared buffer
*/
typedef struct genode_attached_dataspace * (*genode_block_alloc_peer_buffer_t)
(unsigned long size);
/**
* Callback called when closing peer session to free shared buffer
*/
typedef void (*genode_block_free_peer_buffer_t)
(struct genode_attached_dataspace * ds);
/**
* Initialize block root component
*
@ -49,8 +37,8 @@ typedef void (*genode_block_free_peer_buffer_t)
void genode_block_init(struct genode_env *env,
struct genode_allocator *alloc,
struct genode_signal_handler *handler,
genode_block_alloc_peer_buffer_t,
genode_block_free_peer_buffer_t);
genode_shared_dataspace_alloc_attach_t,
genode_shared_dataspace_free_t);
/**************************************

View File

@ -34,18 +34,6 @@ extern "C" {
** Initialization **
********************/
/**
* Callback called during peer session request to allocate dma-capable shared buffer
*/
typedef struct genode_attached_dataspace * (*genode_usb_alloc_peer_buffer_t)
(unsigned long size);
/**
* Callback called when closing peer session to free shared buffer
*/
typedef void (*genode_usb_free_peer_buffer_t)
(struct genode_attached_dataspace * ds);
/**
* Callback to copy over config descriptor for given device
*/
@ -81,13 +69,13 @@ typedef int (*genode_usb_rpc_endp_desc_t)
unsigned alt, unsigned endp, void * buf, unsigned long buf_size);
struct genode_usb_rpc_callbacks {
genode_usb_alloc_peer_buffer_t alloc_fn;
genode_usb_free_peer_buffer_t free_fn;
genode_usb_rpc_config_desc_t cfg_desc_fn;
genode_usb_rpc_alt_settings_t alt_settings_fn;
genode_usb_rpc_iface_desc_t iface_desc_fn;
genode_usb_rpc_iface_extra_t iface_extra_fn;
genode_usb_rpc_endp_desc_t endp_desc_fn;
genode_shared_dataspace_alloc_attach_t alloc_fn;
genode_shared_dataspace_free_t free_fn;
genode_usb_rpc_config_desc_t cfg_desc_fn;
genode_usb_rpc_alt_settings_t alt_settings_fn;
genode_usb_rpc_iface_desc_t iface_desc_fn;
genode_usb_rpc_iface_extra_t iface_extra_fn;
genode_usb_rpc_endp_desc_t endp_desc_fn;
};
/**

View File

@ -24,55 +24,68 @@
using namespace Genode;
struct genode_block_session : Rpc_object<Block::Session>
class genode_block_session : public Rpc_object<Block::Session>
{
enum { MAX_REQUESTS = 32 };
private:
struct Request {
enum State { FREE, IN_FLY, DONE };
friend class Root;
State state { FREE };
genode_block_request dev_req { GENODE_BLOCK_UNAVAIL, 0, 0, nullptr };
Block::Request peer_req {};
};
enum { MAX_REQUESTS = 32 };
Attached_dataspace & ds;
Block::Request_stream rs;
Request requests[MAX_REQUESTS];
struct Request {
enum State { FREE, IN_FLY, DONE };
template <typename FUNC>
void first_request(Request::State state, FUNC const & fn)
{
for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) {
if (requests[idx].state == state) {
fn(requests[idx]);
return;
State state { FREE };
genode_block_request dev_req { GENODE_BLOCK_UNAVAIL,
0, 0, nullptr };
Block::Request peer_req {};
};
genode_shared_dataspace * _ds;
Block::Request_stream _rs;
Request _requests[MAX_REQUESTS];
template <typename FUNC>
void _first_request(Request::State state, FUNC const & fn)
{
for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) {
if (_requests[idx].state == state) {
fn(_requests[idx]);
return;
}
}
}
}
template <typename FUNC>
void for_each_request(Request::State state, FUNC const & fn)
{
for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) {
if (requests[idx].state == state)
fn(requests[idx]);
template <typename FUNC>
void _for_each_request(Request::State state, FUNC const & fn)
{
for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) {
if (_requests[idx].state == state)
fn(_requests[idx]);
}
}
}
genode_block_session(Env & env,
Block::Session::Info info,
Signal_context_capability cap,
size_t buffer_size);
/*
* Non_copyable
*/
genode_block_session(const genode_block_session&);
genode_block_session & operator=(const genode_block_session&);
Info info() const override { return rs.info(); }
public:
Capability<Tx> tx_cap() override { return rs.tx_cap(); }
genode_block_session(Env & env,
Block::Session::Info info,
Signal_context_capability cap,
size_t buffer_size);
genode_block_request * request();
void ack(genode_block_request * req, bool success);
Info info() const override { return _rs.info(); }
void notify_peers() { rs.wakeup_client_if_needed(); }
Capability<Tx> tx_cap() override { return _rs.tx_cap(); }
genode_block_request * request();
void ack(genode_block_request * req, bool success);
void notify_peers() { _rs.wakeup_client_if_needed(); }
};
@ -131,9 +144,9 @@ class Root : public Root_component<genode_block_session>
};
static ::Root * _block_root = nullptr;
static genode_block_alloc_peer_buffer_t _alloc_peer_buffer = nullptr;
static genode_block_free_peer_buffer_t _free_peer_buffer = nullptr;
static ::Root * _block_root = nullptr;
static genode_shared_dataspace_alloc_attach_t _alloc_peer_buffer = nullptr;
static genode_shared_dataspace_free_t _free_peer_buffer = nullptr;
genode_block_request * genode_block_session::request()
@ -142,7 +155,7 @@ genode_block_request * genode_block_session::request()
genode_block_request * ret = nullptr;
rs.with_requests([&] (Block::Request request) {
_rs.with_requests([&] (Block::Request request) {
if (ret)
return Response::RETRY;
@ -156,7 +169,7 @@ genode_block_request * genode_block_session::request()
Response response = Response::RETRY;
first_request(Request::FREE, [&] (Request & r) {
_first_request(Request::FREE, [&] (Request & r) {
r.state = Request::IN_FLY;
r.peer_req = request;
@ -178,8 +191,8 @@ genode_block_request * genode_block_session::request()
r.dev_req.blk_nr = op.block_number;
r.dev_req.blk_cnt = op.count;
r.dev_req.addr = (void*)((addr_t)ds.local_addr<void>()
+ request.offset);
r.dev_req.addr = (void*)
(genode_shared_dataspace_local_address(_ds) + request.offset);
ret = &r.dev_req;
response = Response::ACCEPTED;
@ -194,14 +207,14 @@ genode_block_request * genode_block_session::request()
void genode_block_session::ack(genode_block_request * req, bool success)
{
for_each_request(Request::IN_FLY, [&] (Request & r) {
_for_each_request(Request::IN_FLY, [&] (Request & r) {
if (&r.dev_req == req)
r.state = Request::DONE;
});
/* Acknowledge any pending packets */
rs.try_acknowledge([&](Block::Request_stream::Ack & ack) {
first_request(Request::DONE, [&] (Request & r) {
_rs.try_acknowledge([&](Block::Request_stream::Ack & ack) {
_first_request(Request::DONE, [&] (Request & r) {
r.state = Request::FREE;
r.peer_req.success = success;
ack.submit(r.peer_req);
@ -215,8 +228,8 @@ genode_block_session::genode_block_session(Env & env,
Signal_context_capability cap,
size_t buffer_size)
:
ds(*static_cast<Attached_dataspace*>(_alloc_peer_buffer(buffer_size))),
rs(env.rm(), ds.cap(), env.ep(), cap, info) { }
_ds(_alloc_peer_buffer(buffer_size)),
_rs(env.rm(), genode_shared_dataspace_capability(_ds), env.ep(), cap, info) { }
genode_block_session * ::Root::_create_session(const char * args,
@ -262,9 +275,9 @@ void ::Root::_destroy_session(genode_block_session * session)
si.block_session = nullptr;
});
Attached_dataspace & ds = session->ds;
genode_shared_dataspace * ds = session->_ds;
Genode::destroy(md_alloc(), session);
_free_peer_buffer(genode_attached_dataspace_ptr(ds));
_free_peer_buffer(ds);
}
@ -344,11 +357,12 @@ void ::Root::notify_peers()
_env(env), _sigh_cap(cap) { }
extern "C" void genode_block_init(genode_env *env_ptr,
genode_allocator *alloc_ptr,
genode_signal_handler *sigh_ptr,
genode_block_alloc_peer_buffer_t alloc_func,
genode_block_free_peer_buffer_t free_func)
extern "C" void
genode_block_init(genode_env * env_ptr,
genode_allocator * alloc_ptr,
genode_signal_handler * sigh_ptr,
genode_shared_dataspace_alloc_attach_t alloc_func,
genode_shared_dataspace_free_t free_func)
{
static ::Root root(*static_cast<Env*>(env_ptr),
*static_cast<Allocator*>(alloc_ptr),

View File

@ -60,7 +60,7 @@ class genode_usb_session : public Usb::Session_rpc_object
Constructible<Usb::Packet_descriptor> packets[MAX_PACKETS_IN_FLY] { };
::Root & _root;
Attached_dataspace & _ds;
genode_shared_dataspace * _ds;
Signal_context_capability _sigh_state_cap {};
genode_usb_session_handle_t _id;
Session_label const _label;
@ -68,12 +68,16 @@ class genode_usb_session : public Usb::Session_rpc_object
void _ack(int err, Usb::Packet_descriptor p);
/*
* Non_copyable
*/
genode_usb_session(const genode_usb_session&);
genode_usb_session & operator=(const genode_usb_session&);
public:
genode_usb_session(::Root & root,
Attached_dataspace & ds,
genode_shared_dataspace * ds,
Env & env,
Signal_context_capability cap,
genode_usb_session_handle_t id,
@ -425,7 +429,8 @@ bool genode_usb_session::request(genode_usb_request_callbacks & req, void * data
addr_t offset = (addr_t)sink()->packet_content(p) -
(addr_t)sink()->ds_local_base();
void * addr = (void*)((addr_t)_ds.local_addr<void>() + offset);
void * addr = (void*)(genode_shared_dataspace_local_address(_ds)
+ offset);
switch (p.type) {
case Packet_descriptor::STRING:
@ -482,13 +487,14 @@ void genode_usb_session::handle_response(genode_usb_request_handle_t id,
genode_usb_session::genode_usb_session(::Root & root,
Attached_dataspace & ds,
genode_shared_dataspace * ds,
Env & env,
Signal_context_capability cap,
genode_usb_session_handle_t id,
Session_label const label)
:
Usb::Session_rpc_object(ds.cap(), env.ep().rpc_ep(), env.rm()),
Usb::Session_rpc_object(genode_shared_dataspace_capability(ds),
env.ep().rpc_ep(), env.rm()),
_root(root),
_ds(ds),
_id(id),
@ -548,9 +554,8 @@ genode_usb_session * ::Root::_create_session(const char * args,
throw Insufficient_ram_quota();
}
Attached_dataspace & ds =
*static_cast<Attached_dataspace*>(_callbacks->alloc_fn(tx_buf_size));
genode_usb_session * ret = new (md_alloc())
genode_shared_dataspace * ds = _callbacks->alloc_fn(tx_buf_size);
genode_usb_session * ret = new (md_alloc())
genode_usb_session(*this, ds, _env, _sigh_cap, _id_alloc.alloc(), label);
_sessions.insert(&ret->_le);
@ -576,11 +581,11 @@ void ::Root::_destroy_session(genode_usb_session * session)
});
genode_usb_session_handle_t id = session->_id;
Attached_dataspace & ds = session->_ds;
genode_shared_dataspace * ds = session->_ds;
_sessions.remove(&session->_le);
Genode::destroy(md_alloc(), session);
_id_alloc.free((addr_t)id);
_callbacks->free_fn(genode_attached_dataspace_ptr(ds));
_callbacks->free_fn(ds);
}

View File

@ -16,41 +16,19 @@
#include <base/env.h>
#include <lx_emul/init.h>
#include <lx_emul/page_virt.h>
#include <lx_kit/env.h>
#include <lx_kit/init.h>
#include <lx_user/io.h>
#include <usb.h>
#include <genode_c_api/usb.h>
using namespace Genode;
extern "C" struct genode_attached_dataspace *
genode_usb_allocate_peer_buffer(unsigned long size)
{
Attached_dataspace & ds = Lx_kit::env().memory.alloc_dataspace(size);
/*
* We have to call virt_to_pages eagerly here,
* to get contingous page objects registered
*/
lx_emul_virt_to_pages(ds.local_addr<void>(), size >> 12);
return genode_attached_dataspace_ptr(ds);
}
extern "C" void genode_usb_free_peer_buffer(struct genode_attached_dataspace * ptr)
{
Attached_dataspace *ds = static_cast<Attached_dataspace*>(ptr);
lx_emul_forget_pages(ds->local_addr<void>(), ds->size());
Lx_kit::env().memory.free_dataspace(ds->local_addr<void>());
}
static bool _bios_handoff;
extern struct genode_usb_rpc_callbacks genode_usb_rpc_callbacks_obj;
extern "C" int inhibit_pci_fixup(char const *name)
{

View File

@ -4,10 +4,12 @@ REL_PRG_DIR := $(PRG_DIR)/../..
TARGET := pc_usb_host_drv
LIBS := base pc_lx_emul
INC_DIR := $(REL_PRG_DIR)
INC_DIR += $(REL_PRG_DIR)
SRC_CC += main.cc
SRC_CC += misc.cc
SRC_CC += time.cc
SRC_CC += lx_emul/shared_dma_buffer.cc
SRC_C += dummies.c
SRC_C += lx_emul.c
SRC_C += usb.c

View File

@ -15,11 +15,14 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <lx_emul/shared_dma_buffer.h>
#include <lx_emul/task.h>
#include <lx_user/init.h>
#include <lx_user/io.h>
#include <usb.h>
#include <genode_c_api/usb.h>
struct usb_interface;
struct usb_find_request {
genode_usb_bus_num_t bus;
@ -153,8 +156,8 @@ static int endpoint_descriptor(genode_usb_bus_num_t bus,
struct genode_usb_rpc_callbacks genode_usb_rpc_callbacks_obj = {
.alloc_fn = genode_usb_allocate_peer_buffer,
.free_fn = genode_usb_free_peer_buffer,
.alloc_fn = lx_emul_shared_dma_buffer_allocate,
.free_fn = lx_emul_shared_dma_buffer_free,
.cfg_desc_fn = config_descriptor,
.alt_settings_fn = alt_settings,
.iface_desc_fn = interface_descriptor,

View File

@ -1,32 +0,0 @@
/**
* \brief USB related definitions for kernel/genode c-api
* \author Stefan Kalkowski
* \date 2021-09-17
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <genode_c_api/usb.h>
struct usb_interface;
#ifdef __cplusplus
extern "C" {
#endif
struct genode_attached_dataspace *
genode_usb_allocate_peer_buffer(unsigned long size);
void genode_usb_free_peer_buffer(struct genode_attached_dataspace * ptr);
extern struct genode_usb_rpc_callbacks genode_usb_rpc_callbacks_obj;
#ifdef __cplusplus
}
#endif