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_env;
struct genode_allocator; struct genode_allocator;
struct genode_signal_handler; struct genode_signal_handler;
struct genode_attached_dataspace; struct genode_shared_dataspace;
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
@ -46,7 +46,6 @@ struct genode_attached_dataspace;
struct genode_env : Genode::Env { }; struct genode_env : Genode::Env { };
struct genode_allocator : Genode::Allocator { }; struct genode_allocator : Genode::Allocator { };
struct genode_signal_handler : Genode::Signal_dispatcher_base { }; struct genode_signal_handler : Genode::Signal_dispatcher_base { };
struct genode_attached_dataspace : Genode::Attached_dataspace { };
static inline auto genode_env_ptr(Genode::Env &env) 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); return *static_cast<Genode::Signal_handler<Genode::Meta::Empty> *>(dispatcher_ptr);
} }
static inline auto genode_attached_dataspace_ptr(Genode::Attached_dataspace &ds) /**
{ * Returns local address of attached shared dataspace
return static_cast<genode_attached_dataspace *>(&ds); */
} 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 #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_ */ #endif /* _INCLUDE__GENODE_C_API__BASE_H_ */

View File

@ -29,18 +29,6 @@ extern "C" {
** Initialization ** ** 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 * Initialize block root component
* *
@ -49,8 +37,8 @@ typedef void (*genode_block_free_peer_buffer_t)
void genode_block_init(struct genode_env *env, void genode_block_init(struct genode_env *env,
struct genode_allocator *alloc, struct genode_allocator *alloc,
struct genode_signal_handler *handler, struct genode_signal_handler *handler,
genode_block_alloc_peer_buffer_t, genode_shared_dataspace_alloc_attach_t,
genode_block_free_peer_buffer_t); genode_shared_dataspace_free_t);
/************************************** /**************************************

View File

@ -34,18 +34,6 @@ extern "C" {
** Initialization ** ** 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 * Callback to copy over config descriptor for given device
*/ */
@ -81,8 +69,8 @@ typedef int (*genode_usb_rpc_endp_desc_t)
unsigned alt, unsigned endp, void * buf, unsigned long buf_size); unsigned alt, unsigned endp, void * buf, unsigned long buf_size);
struct genode_usb_rpc_callbacks { struct genode_usb_rpc_callbacks {
genode_usb_alloc_peer_buffer_t alloc_fn; genode_shared_dataspace_alloc_attach_t alloc_fn;
genode_usb_free_peer_buffer_t free_fn; genode_shared_dataspace_free_t free_fn;
genode_usb_rpc_config_desc_t cfg_desc_fn; genode_usb_rpc_config_desc_t cfg_desc_fn;
genode_usb_rpc_alt_settings_t alt_settings_fn; genode_usb_rpc_alt_settings_t alt_settings_fn;
genode_usb_rpc_iface_desc_t iface_desc_fn; genode_usb_rpc_iface_desc_t iface_desc_fn;

View File

@ -24,55 +24,68 @@
using namespace Genode; using namespace Genode;
struct genode_block_session : Rpc_object<Block::Session> class genode_block_session : public Rpc_object<Block::Session>
{ {
private:
friend class Root;
enum { MAX_REQUESTS = 32 }; enum { MAX_REQUESTS = 32 };
struct Request { struct Request {
enum State { FREE, IN_FLY, DONE }; enum State { FREE, IN_FLY, DONE };
State state { FREE }; State state { FREE };
genode_block_request dev_req { GENODE_BLOCK_UNAVAIL, 0, 0, nullptr }; genode_block_request dev_req { GENODE_BLOCK_UNAVAIL,
0, 0, nullptr };
Block::Request peer_req {}; Block::Request peer_req {};
}; };
Attached_dataspace & ds; genode_shared_dataspace * _ds;
Block::Request_stream rs; Block::Request_stream _rs;
Request requests[MAX_REQUESTS]; Request _requests[MAX_REQUESTS];
template <typename FUNC> template <typename FUNC>
void first_request(Request::State state, FUNC const & fn) void _first_request(Request::State state, FUNC const & fn)
{ {
for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) { for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) {
if (requests[idx].state == state) { if (_requests[idx].state == state) {
fn(requests[idx]); fn(_requests[idx]);
return; return;
} }
} }
} }
template <typename FUNC> template <typename FUNC>
void for_each_request(Request::State state, FUNC const & fn) void _for_each_request(Request::State state, FUNC const & fn)
{ {
for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) { for (unsigned idx = 0; idx < MAX_REQUESTS; idx++) {
if (requests[idx].state == state) if (_requests[idx].state == state)
fn(requests[idx]); fn(_requests[idx]);
} }
} }
/*
* Non_copyable
*/
genode_block_session(const genode_block_session&);
genode_block_session & operator=(const genode_block_session&);
public:
genode_block_session(Env & env, genode_block_session(Env & env,
Block::Session::Info info, Block::Session::Info info,
Signal_context_capability cap, Signal_context_capability cap,
size_t buffer_size); size_t buffer_size);
Info info() const override { return rs.info(); } Info info() const override { return _rs.info(); }
Capability<Tx> tx_cap() override { return rs.tx_cap(); } Capability<Tx> tx_cap() override { return _rs.tx_cap(); }
genode_block_request * request(); genode_block_request * request();
void ack(genode_block_request * req, bool success); void ack(genode_block_request * req, bool success);
void notify_peers() { rs.wakeup_client_if_needed(); } void notify_peers() { _rs.wakeup_client_if_needed(); }
}; };
@ -132,8 +145,8 @@ class Root : public Root_component<genode_block_session>
static ::Root * _block_root = nullptr; static ::Root * _block_root = nullptr;
static genode_block_alloc_peer_buffer_t _alloc_peer_buffer = nullptr; static genode_shared_dataspace_alloc_attach_t _alloc_peer_buffer = nullptr;
static genode_block_free_peer_buffer_t _free_peer_buffer = nullptr; static genode_shared_dataspace_free_t _free_peer_buffer = nullptr;
genode_block_request * genode_block_session::request() genode_block_request * genode_block_session::request()
@ -142,7 +155,7 @@ genode_block_request * genode_block_session::request()
genode_block_request * ret = nullptr; genode_block_request * ret = nullptr;
rs.with_requests([&] (Block::Request request) { _rs.with_requests([&] (Block::Request request) {
if (ret) if (ret)
return Response::RETRY; return Response::RETRY;
@ -156,7 +169,7 @@ genode_block_request * genode_block_session::request()
Response response = Response::RETRY; Response response = Response::RETRY;
first_request(Request::FREE, [&] (Request & r) { _first_request(Request::FREE, [&] (Request & r) {
r.state = Request::IN_FLY; r.state = Request::IN_FLY;
r.peer_req = request; 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_nr = op.block_number;
r.dev_req.blk_cnt = op.count; r.dev_req.blk_cnt = op.count;
r.dev_req.addr = (void*)((addr_t)ds.local_addr<void>() r.dev_req.addr = (void*)
+ request.offset); (genode_shared_dataspace_local_address(_ds) + request.offset);
ret = &r.dev_req; ret = &r.dev_req;
response = Response::ACCEPTED; 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) 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) if (&r.dev_req == req)
r.state = Request::DONE; r.state = Request::DONE;
}); });
/* Acknowledge any pending packets */ /* Acknowledge any pending packets */
rs.try_acknowledge([&](Block::Request_stream::Ack & ack) { _rs.try_acknowledge([&](Block::Request_stream::Ack & ack) {
first_request(Request::DONE, [&] (Request & r) { _first_request(Request::DONE, [&] (Request & r) {
r.state = Request::FREE; r.state = Request::FREE;
r.peer_req.success = success; r.peer_req.success = success;
ack.submit(r.peer_req); ack.submit(r.peer_req);
@ -215,8 +228,8 @@ genode_block_session::genode_block_session(Env & env,
Signal_context_capability cap, Signal_context_capability cap,
size_t buffer_size) size_t buffer_size)
: :
ds(*static_cast<Attached_dataspace*>(_alloc_peer_buffer(buffer_size))), _ds(_alloc_peer_buffer(buffer_size)),
rs(env.rm(), ds.cap(), env.ep(), cap, info) { } _rs(env.rm(), genode_shared_dataspace_capability(_ds), env.ep(), cap, info) { }
genode_block_session * ::Root::_create_session(const char * args, 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; si.block_session = nullptr;
}); });
Attached_dataspace & ds = session->ds; genode_shared_dataspace * ds = session->_ds;
Genode::destroy(md_alloc(), session); 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) { } _env(env), _sigh_cap(cap) { }
extern "C" void genode_block_init(genode_env *env_ptr, extern "C" void
genode_block_init(genode_env * env_ptr,
genode_allocator * alloc_ptr, genode_allocator * alloc_ptr,
genode_signal_handler * sigh_ptr, genode_signal_handler * sigh_ptr,
genode_block_alloc_peer_buffer_t alloc_func, genode_shared_dataspace_alloc_attach_t alloc_func,
genode_block_free_peer_buffer_t free_func) genode_shared_dataspace_free_t free_func)
{ {
static ::Root root(*static_cast<Env*>(env_ptr), static ::Root root(*static_cast<Env*>(env_ptr),
*static_cast<Allocator*>(alloc_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] { }; Constructible<Usb::Packet_descriptor> packets[MAX_PACKETS_IN_FLY] { };
::Root & _root; ::Root & _root;
Attached_dataspace & _ds; genode_shared_dataspace * _ds;
Signal_context_capability _sigh_state_cap {}; Signal_context_capability _sigh_state_cap {};
genode_usb_session_handle_t _id; genode_usb_session_handle_t _id;
Session_label const _label; 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); void _ack(int err, Usb::Packet_descriptor p);
/*
* Non_copyable
*/
genode_usb_session(const genode_usb_session&); genode_usb_session(const genode_usb_session&);
genode_usb_session & operator=(const genode_usb_session&);
public: public:
genode_usb_session(::Root & root, genode_usb_session(::Root & root,
Attached_dataspace & ds, genode_shared_dataspace * ds,
Env & env, Env & env,
Signal_context_capability cap, Signal_context_capability cap,
genode_usb_session_handle_t id, 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 offset = (addr_t)sink()->packet_content(p) -
(addr_t)sink()->ds_local_base(); (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) { switch (p.type) {
case Packet_descriptor::STRING: 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, genode_usb_session::genode_usb_session(::Root & root,
Attached_dataspace & ds, genode_shared_dataspace * ds,
Env & env, Env & env,
Signal_context_capability cap, Signal_context_capability cap,
genode_usb_session_handle_t id, genode_usb_session_handle_t id,
Session_label const label) 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), _root(root),
_ds(ds), _ds(ds),
_id(id), _id(id),
@ -548,8 +554,7 @@ genode_usb_session * ::Root::_create_session(const char * args,
throw Insufficient_ram_quota(); throw Insufficient_ram_quota();
} }
Attached_dataspace & ds = genode_shared_dataspace * ds = _callbacks->alloc_fn(tx_buf_size);
*static_cast<Attached_dataspace*>(_callbacks->alloc_fn(tx_buf_size));
genode_usb_session * ret = new (md_alloc()) genode_usb_session * ret = new (md_alloc())
genode_usb_session(*this, ds, _env, _sigh_cap, _id_alloc.alloc(), label); genode_usb_session(*this, ds, _env, _sigh_cap, _id_alloc.alloc(), label);
_sessions.insert(&ret->_le); _sessions.insert(&ret->_le);
@ -576,11 +581,11 @@ void ::Root::_destroy_session(genode_usb_session * session)
}); });
genode_usb_session_handle_t id = session->_id; genode_usb_session_handle_t id = session->_id;
Attached_dataspace & ds = session->_ds; genode_shared_dataspace * ds = session->_ds;
_sessions.remove(&session->_le); _sessions.remove(&session->_le);
Genode::destroy(md_alloc(), session); Genode::destroy(md_alloc(), session);
_id_alloc.free((addr_t)id); _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 <base/env.h>
#include <lx_emul/init.h> #include <lx_emul/init.h>
#include <lx_emul/page_virt.h>
#include <lx_kit/env.h> #include <lx_kit/env.h>
#include <lx_kit/init.h> #include <lx_kit/init.h>
#include <lx_user/io.h> #include <lx_user/io.h>
#include <usb.h> #include <genode_c_api/usb.h>
using namespace Genode; 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; static bool _bios_handoff;
extern struct genode_usb_rpc_callbacks genode_usb_rpc_callbacks_obj;
extern "C" int inhibit_pci_fixup(char const *name) 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 TARGET := pc_usb_host_drv
LIBS := base pc_lx_emul LIBS := base pc_lx_emul
INC_DIR := $(REL_PRG_DIR)
INC_DIR += $(REL_PRG_DIR)
SRC_CC += main.cc SRC_CC += main.cc
SRC_CC += misc.cc SRC_CC += misc.cc
SRC_CC += time.cc SRC_CC += time.cc
SRC_CC += lx_emul/shared_dma_buffer.cc
SRC_C += dummies.c SRC_C += dummies.c
SRC_C += lx_emul.c SRC_C += lx_emul.c
SRC_C += usb.c SRC_C += usb.c

View File

@ -15,11 +15,14 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/hcd.h> #include <linux/usb/hcd.h>
#include <lx_emul/shared_dma_buffer.h>
#include <lx_emul/task.h> #include <lx_emul/task.h>
#include <lx_user/init.h> #include <lx_user/init.h>
#include <lx_user/io.h> #include <lx_user/io.h>
#include <usb.h> #include <genode_c_api/usb.h>
struct usb_interface;
struct usb_find_request { struct usb_find_request {
genode_usb_bus_num_t bus; 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 = { struct genode_usb_rpc_callbacks genode_usb_rpc_callbacks_obj = {
.alloc_fn = genode_usb_allocate_peer_buffer, .alloc_fn = lx_emul_shared_dma_buffer_allocate,
.free_fn = genode_usb_free_peer_buffer, .free_fn = lx_emul_shared_dma_buffer_free,
.cfg_desc_fn = config_descriptor, .cfg_desc_fn = config_descriptor,
.alt_settings_fn = alt_settings, .alt_settings_fn = alt_settings,
.iface_desc_fn = interface_descriptor, .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