29 #include <l4/re/util/meta> 31 #include <l4/cxx/bitfield> 32 #include <l4/cxx/utils> 33 #include <l4/cxx/unique_ptr> 35 #include <l4/sys/cxx/ipc_legacy> 37 #include "../l4virtio" 62 typedef L4Re::Rm::Auto_region< l4virtio_config_hdr_t*> Cfg_region;
66 l4_uint32_t _host_features[
sizeof(l4virtio_config_hdr_t::dev_features_map)
74 {
return (x + 0xfU) & ~0xfU; }
77 void volatile *get_priv_config()
const 97 : _vendor(vendor), _device(device),
98 _qoffset(0x100 + align(cfg_size)),
121 _config->generation = 0;
122 memset(_config->driver_features_map, 0, sizeof (_config->driver_features_map));
123 memset(_host_features, 0,
sizeof(_host_features));
124 _host_features[1] = 1;
128 void set_host_feature(
unsigned feature)
131 void clear_host_feature(
unsigned feature)
134 bool get_host_feature(
unsigned feature)
138 {
return _host_features[idx]; }
141 {
return _host_features[idx]; }
150 Status
status()
const {
return _status; }
209 _nqueues = num_queues;
229 (
reinterpret_cast<char *
>(_config.get()) + _qoffset) + index;
237 _config->magic = L4VIRTIO_MAGIC;
238 _config->version = 2;
239 _config->device = _device;
240 _config->vendor = _vendor;
242 _config->irq_status = 0;
243 _config->num_queues = _nqueues;
244 _config->queues_offset = _qoffset;
246 memcpy(_config->dev_features_map, _host_features,
247 sizeof(_config->dev_features_map));
250 ++_config->generation;
263 bool inc_generation =
false)
const 276 ++_config->generation;
286 {
return _config.get(); }
296 template<
typename PRIV_CONFIG>
301 typedef PRIV_CONFIG Priv_config;
315 :
Dev_config(vendor, device,
sizeof(PRIV_CONFIG), num_queues)
327 Priv_config
volatile *priv_config()
const 329 return static_cast<Priv_config
volatile *
>(get_priv_config());
334 struct No_custom_data {};
341 template <
typename DATA>
348 CXX_BITFIELD_MEMBER(0, 0, rw, raw);
364 L4Re::Rm::Auto_region<l4_addr_t> _local_base;
369 return (T)(addr - _trans_offset);
403 if (_ds_offset >= ds_size)
410 if (_ds_offset > ds_size - size)
414 if ((ULLONG_MAX - size) < _drv_base)
419 chksys(Env::env()->rm()->attach(&_local_base, size,
427 _trans_offset = _drv_base - _local_base.get();
434 Flags
flags()
const {
return _flags; }
438 {
return _size == 0; }
444 void *
local_base()
const {
return (
void*)_local_base.get(); }
464 if (base < _drv_base)
467 if (base > _drv_base + _size - 1)
473 if (base - _drv_base > _size - size)
487 {
return _local<T*>(p.
get()); }
498 template <
typename DATA>
505 cxx::unique_ptr<Mem_region[]> _l;
522 _l = cxx::make_unique<Driver_mem_region_t<DATA>[]>(
max);
529 {
return _free == _max; }
545 _l[_free++] = Mem_region(drv_base, size, offset, cxx::move(
ds));
546 return &_l[_free - 1];
553 void remove(Mem_region
const *r)
555 if (r < &_l[0] || r >= &_l[_free])
558 unsigned idx = r - &_l[0];
560 for (
unsigned i = idx + 1; i < _free - 1; ++i)
561 _l[i] = cxx::move(_l[i + 1]);
563 _l[--_free] = Mem_region();
575 return _find(base, size);
587 Mem_region
const *r = find(desc.
addr.
get(), desc.
len);
602 Mem_region
const **data)
const 604 Mem_region
const *r = find(desc.
addr.
get(), desc.
len);
623 template<
typename ARG>
627 Mem_region *r = find(desc.
addr.
get(), desc.
len);
631 *data = ARG(r, desc, p);
637 for (
unsigned i = 0; i < _free; ++i)
638 if (_l[i].contains(base, size))
651 template<
typename DATA>
664 L4_RPC_LEGACY_DISPATCH(L4virtio::Device);
665 template<
typename IOS>
int virtio_dispatch(
unsigned r, IOS &ios)
666 {
return dispatch(r, ios); }
669 virtual void reset() = 0;
672 virtual bool check_queues() = 0;
675 virtual int reconfig_queue(
unsigned idx) = 0;
678 virtual void register_single_driver_irq() = 0;
689 : _device_config(dev_config)
696 {
return &_mem_info; };
698 long op_set_status(L4virtio::Device::Rights,
unsigned status)
699 {
return _set_status(status); }
701 long op_config_queue(L4virtio::Device::Rights,
unsigned queue)
710 return reconfig_queue(queue);
713 long op_register_ds(L4virtio::Device::Rights,
717 printf(
"Registering dataspace from 0x%llx with %lu KiB, offset 0x%lx\n",
718 ds_base, sz >> 10, offset);
720 _check_n_init_shm(ds_cap_fp, ds_base, sz, offset);
725 long op_register_iface(L4virtio::Device::Rights,
733 register_single_driver_irq();
735 printf(
"register client: host IRQ: %lx config DS: %lx\n",
736 device_notify_irq().cap(), _device_config->
ds().
cap());
755 bool inc_generation =
false)
757 _device_config->
reset_queue(idx, num_max, inc_generation);
799 qc = _device_config->
qconfig(qn);
814 printf(
"%p: setup queue: num=0x%x max_num=0x%x desc=0x%llx avail=0x%llx used=0x%llx\n",
815 this, num, num_max, desc, avail, used);
817 if (!num || num > num_max)
842 if (
L4_UNLIKELY(!used_info || !used_info->is_writable()))
845 printf(
"shm=[%llx-%llx] local=[%lx-%lx] desc=[%llx-%llx] (%p-%p)\n",
846 desc_info->drv_base(), desc_info->drv_base() + desc_info->size() - 1,
847 (
unsigned long)desc_info->local_base(),
848 (
unsigned long)desc_info->local_base() + desc_info->size() - 1,
853 printf(
"shm=[%llx-%llx] local=[%lx-%lx] avail=[%llx-%llx] (%p-%p)\n",
854 avail_info->drv_base(), avail_info->drv_base() + avail_info->size() - 1,
855 (
unsigned long)avail_info->local_base(),
856 (
unsigned long)avail_info->local_base() + avail_info->size() - 1,
861 printf(
"shm=[%llx-%llx] local=[%lx-%lx] used=[%llx-%llx] (%p-%p)\n",
862 used_info->drv_base(), used_info->drv_base() + used_info->size() - 1,
863 (
unsigned long)used_info->local_base(),
864 (
unsigned long)used_info->local_base() + used_info->size() - 1,
878 if (_mem_info.
full())
881 auto const *i = _mem_info.
add(base, size, offset, cxx::move(shm));
882 printf(
"PORT[%p]: DMA guest [%llx-%llx] local [%lx-%lx] offset %lx\n",
883 this, i->drv_base(), i->drv_base() + i->size() - 1,
884 (
unsigned long)i->local_base(),
885 (
unsigned long)i->local_base() + i->size() - 1,
903 switch (cmd & L4VIRTIO_CMD_MASK)
906 _set_status(cmd & ~L4VIRTIO_CMD_MASK);
910 reconfig_queue(cmd & ~L4VIRTIO_CMD_MASK);
931 ds =
L4Re::chkcap(server_iface()->
template rcv_cap<L4Re::Dataspace>(0));
934 check_n_init_shm(cxx::move(ds), base, size, offset);
937 int _set_status(
unsigned _status)
943 printf(
"Resetting device\n");
951 if (status.
running() && !check_queues())
l4_uint32_t get_cmd() const
Get the value from the cmd register.
Request writable mapping.
Capability type for RPC interfaces (see L4::Cap<T>).
Descriptor in the descriptor table.
Pointer used in virtio descriptors.
Read and interface specific 'W' right for capability flex-pages.
l4_uint32_t status
Device status register (read-only).
Virtqueue implementation for the device.
Abstraction for L4-Virtio device config memory.
Status status() const
Get current device status (trusted).
Server-side L4-VIRTIO device stub.
void l4virtio_set_feature(l4_uint32_t *feature_map, unsigned feat)
Set the given feature bit in a feature map.
bool handle_mem_cmd_write()
Check for a value in the cmd register and handle a write.
Dev_config(l4_uint32_t vendor, l4_uint32_t device, unsigned cfg_size, l4_uint32_t num_queues=0)
Setup/Create a L4-Virtio config data space.
bool change_queue_config(l4_uint32_t num_queues)
Setup new queue configuration.
Interface for server-loop related functions.
bool cap_received() const
Check if the capability has been mapped.
l4virtio_config_queue_t volatile const * qconfig(unsigned index) const
Get queue read-only config data for queue with the given index.
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
void reset_hdr(bool inc_generation=false) const
Reset the config header to the initial contents.
void load_desc(Virtqueue::Desc const &desc, Request_processor const *p, Mem_region const **data) const
Default implementation returning the Driver_mem_region.
Common L4 ABI Data Types.
Driver_mem_list_t()
Make an empty, zero capacity list.
l4_uint32_t cmd
L4 specific command register polled by the driver iff supported.
Address cannot be translated.
Information about the dataspace.
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false)
Trigger reset for the configuration space for queue idx.
Cap< T > make_cap(L4::Cap< T > cap, unsigned rights)
Make an L4::Ipc::Cap<T> for the given capability and rights.
L4::Cap< L4Re::Dataspace > ds() const
Get data-space capability for the shared config data space.
C++ interface of the initial environment that is provided to an L4 task.
Exception used by Queue to indicate descriptor errors.
l4_addr_t l4_trunc_page(l4_addr_t address) L4_NOTHROW
Round an address down to the next lower page boundary.
Driver_mem_region_t(l4_uint64_t drv_base, l4_umword_t size, l4_addr_t offset, Ds_cap &&ds)
Make a local memory region for the given driver values.
Type of the device status register.
l4_uint64_t used_addr
W: address of used ring.
void disable()
Completely disable the queue.
l4_uint64_t drv_base() const
Search for a suitable address range.
Mem_region * find(l4_uint64_t base, l4_umword_t size) const
Find memory region containing the given driver address region.
void device_error()
Transition device into failed state.
Mem_list _mem_info
Memory region list.
Encapsulate the state for processing a VIRTIO request.
l4_uint16_t num
RW: number of descriptors configured for this queue.
Read right for capability flex-pages.
Interface for memory-like objects.
T1 max(T1 a, T1 b)
Get the maximum of a and b.
l4virtio_config_hdr_t const volatile * hdr() const
Get a read-only pointer to the config header.
long info(Stats *stats)
Get information on the dataspace.
#define L4_PAGESIZE
Minimal page size (in bytes).
driver_bfm_t::Val driver() const
Get the driver bits ( 1 to 1 ) of raw .
void * l4virtio_device_config(l4virtio_config_hdr_t const *cfg)
Get the pointer to the device configuration.
bool contains(l4_uint64_t base, l4_umword_t size) const
Test if the given driver address range is within this region.
bool running() const
Check if the device is in running state.
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
static Env const * env()
Returns the initial environment for the current task.
L4-VIRTIO config header, provided in shared data space.
unsigned l4virtio_get_feature(l4_uint32_t *feature_map, unsigned feat)
Check if the given bit in a feature map is set.
l4_cap_idx_t cap() const
Return capability selector.
_Cap_alloc & cap_alloc
Capability allocator.
Cap< T > make_cap_rw(L4::Cap< T > cap)
Make an L4::Ipc::Cap<T> for the given capability with L4_CAP_FPAGE_RW rights.
unsigned long l4_umword_t
Unsigned machine word.
l4_uint16_t num_max
R: maximum number of descriptors supported by this queue.
Ptr< void > addr
Address stored in descriptor.
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
List of driver memory regions assigned to a single L4-VIRTIO transport instance.
void init(unsigned max)
Make a fresh list with capacity max.
L4::Cap< L4Re::Dataspace > ds() const
#define L4_LIKELY(x)
Expression is likely to execute.
unsigned char raw
Raw value of the VIRTIO device status register.
l4_uint16_t ready
RW: queue ready flag (read-write)
void set_status(Status status)
Set device status register.
void setup(unsigned num, void *desc, void *avail, void *used)
Enable this queue.
T * local(Ptr< T > p) const
Get the local address for driver address p.
void set_failed()
Set device status failed bit.
Mem_list const * mem_info() const
Get the memory region list used for this device.
failed_bfm_t::Val failed() const
Get the failed bits ( 7 to 7 ) of raw .
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Type for device feature bitmap.
static unsigned long avail_size(unsigned num)
Calculate the size of the available ring for num entries.
Queue configuration entry.
Region of driver memory, that shall be managed locally.
void init_mem_info(unsigned num)
Initialize the memory region list to the given maximum.
void reset_cmd()
Reset the cmd register after execution of a command.
void load_desc(Virtqueue::Desc const &desc, Request_processor const *p, ARG *data) const
Default implementation returning generic information.
bool reset_queue(unsigned index, unsigned num_max, bool inc_generation=false) const
Reset queue config for the given queue.
void load_desc(Virtqueue::Desc const &desc, Request_processor const *p, Virtqueue::Desc const **table) const
Default implementation for loading an indirect descriptor.
Device_t(Dev_config *dev_config)
Make a device for the given config.
static unsigned long desc_size(unsigned num)
Calculate the size of the descriptor table for num entries.
unsigned long long l4_uint64_t
Unsigned 64bit value.
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
Enable/disable the specified queue.
L4-VIRTIO Transport C++ API.
void * local_base() const
Mem_region const * add(l4_uint64_t drv_base, l4_umword_t size, l4_addr_t offset, Ds_cap &&ds)
Add a new region to the list.
l4_uint32_t len
Length of described buffer.
L4Re::Util::Auto_cap< L4Re::Dataspace >::Cap Ds_cap
type for storing a data-space capability internally
Mask to get command bits.
unsigned long l4_addr_t
Address type.
l4_uint64_t desc_addr
W: address of descriptor table.
acked_bfm_t::Val acked() const
Get the acked bits ( 0 to 0 ) of raw .
void l4virtio_clear_feature(l4_uint32_t *feature_map, unsigned feat)
Clear the given feature bit in a feature map.
l4_uint64_t avail_addr
W: address of available ring.
unsigned int l4_uint32_t
Unsigned 32bit value.
Driver_mem_region_t()
Make default empty memroy region.
Generic RPC wrapper for L4 flex-pages.
static unsigned long used_size(unsigned num)
Calculate the size of the used ring for num entries.
l4_addr_t ds_offset() const