qemu-usb: xHCI model as library

NEC USB3 controller ported from Qemu 2.4.1. See README for more
details.

Issue #1863.
This commit is contained in:
Sebastian Sumpf 2015-12-10 17:24:22 +01:00 committed by Christian Helmuth
parent e233fe0b71
commit a640be9a24
17 changed files with 2825 additions and 0 deletions

View File

@ -0,0 +1,129 @@
/*
* \brief Qemu USB controller interface
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2015-12-14
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__QEMU__USB_H_
#define _INCLUDE__QEMU__USB_H_
#include <base/stdint.h>
#include <base/signal.h>
namespace Qemu {
typedef Genode::size_t size_t;
typedef Genode::off_t off_t;
typedef Genode::int64_t int64_t;
typedef Genode::addr_t addr_t;
/************************************
** Qemu library backend interface **
************************************/
/*
* The backend interface needs to be provided the user of the library.
*/
/**
* Timer_queue class
*
* The library uses the Timer_queue internally to schedule timeouts.
*/
struct Timer_queue
{
virtual int64_t get_ns() = 0;
virtual void register_timer(void *qtimer, void (*cb)(void *data), void *data) = 0;
virtual void delete_timer(void *qtimer) = 0;
virtual void activate_timer(void *qtimer, long long int expires_abs) = 0;
virtual void deactivate_timer(void *qtimer) = 0;
};
/**
* Pci_device class
*
* The library uses the Pci_device to access physical DMA memory and to
* raise interrupts.
*/
struct Pci_device
{
/**
* Raise interrupt
*
* \param assert 1 == raise, 0 == deassert interrupt
*/
virtual void raise_interrupt(int assert) = 0;
virtual int read_dma(addr_t addr, void *buf, size_t size) = 0;
virtual int write_dma(addr_t addr, void const *buf, size_t size) = 0;
virtual void *map_dma(addr_t base, size_t size) = 0;
virtual void unmap_dma(void *addr, size_t size) = 0;
};
/*************************************
** Qemu library frontend functions **
*************************************/
/**
* Controller class to access MMIO register of the xHCI device model
*
* This class is implemented by the library.
*/
struct Controller
{
/**
* Size of the MMIO region of the controller
*/
virtual size_t mmio_size() const = 0;
/**
* Read/write MMIO offset in the MMIO region of the controller
*/
virtual int mmio_read(off_t offset, void *buf, size_t size) = 0;
virtual int mmio_write(off_t offset, void const *buf, size_t size) = 0;
};
/**
* Initialize USB library
*
* \param tq Timer_queue instance provided by the user of the library
* \param pd Pci_device instance provided by the user of the library
* \param sr Signal_receiver used by the library to install signals
*
* \return Pointer to Controller object that is used to access the xHCI device state
*/
Controller *usb_init(Timer_queue &tq, Pci_device &pd, Genode::Signal_receiver &sr);
/**
* Reset USB libray
*/
void usb_reset();
/**
* Update USB devices list
*
* Needs to be called after a library reset.
*/
void usb_update_devices();
/**
* Library timer callback
*
* Needs to be called when a timer triggers (see Timer_queue interface).
*
* \param cb Callback installed by Timer_queue::register_timer()
* \param data Data pointer given in Timer_queue::register_timer()
*/
void usb_timer_callback(void (*cb)(void *data), void *data);
}
#endif /* _INCLUDE__QEMU__USB_H_ */

View File

@ -0,0 +1,11 @@
QEMU_CONTRIB_DIR := $(call select_from_ports,qemu-usb)/src/lib/qemu
LIB_DIR := $(REP_DIR)/src/lib/qemu-usb
LIB_INC_DIR := $(LIB_DIR)/include
#
# The order of include-search directories is important, we need to look into
# 'contrib' before falling back to our custom 'qemu_emul.h' header.
INC_DIR += $(LIB_INC_DIR)
INC_DIR += $(QEMU_CONTRIB_DIR)/include
INC_DIR += $(LIB_CACHE_DIR)/qemu-usb_include/include

View File

@ -0,0 +1,19 @@
LIB_DIR = $(REP_DIR)/src/lib/qemu-usb
QEMU_USB_DIR = $(call select_from_ports,qemu-usb)/src/lib/qemu/hw/usb
CC_WARN=
INC_DIR += $(LIB_DIR) $(QEMU_USB_DIR)
LIBS = qemu-usb_include
SRC_CC = dummies.cc qemu_emul.cc host.cc
SRC_C = hcd-xhci.c core.c bus.c
SHARED_LIB = yes
LD_OPT += --version-script=$(LIB_DIR)/symbol.map
vpath %.c $(QEMU_USB_DIR)
vpath %.cc $(LIB_DIR)

View File

@ -0,0 +1,24 @@
ifeq ($(called_from_lib_mk),yes)
QEMU_CONTRIB_DIR := $(call select_from_ports,qemu-usb)/src/lib/qemu
QEMU_EMUL_H := $(REP_DIR)/src/lib/qemu-usb/include/qemu_emul.h
#
# Determine the header files included by the contrib code. For each
# of these header files we create a symlink to 'qemu_emul.h'.
#
GEN_INCLUDES := $(shell grep -rh "^\#include .*" $(QEMU_CONTRIB_DIR) |\
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" | sort | uniq)
#
# Put Qemu headers in 'GEN_INC' dir
#
GEN_INC := $(shell pwd)/include
GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
all: $(GEN_INCLUDES)
$(GEN_INCLUDES):
$(VERBOSE)mkdir -p $(dir $@)
$(VERBOSE)ln -s $(QEMU_EMUL_H) $@
endif

View File

@ -0,0 +1 @@
cf9157628466843e495e600f15a40e64993dd87f

View File

@ -0,0 +1,13 @@
LICENSE := GPLv2
VERSION := 2.4.1
DOWNLOADS := qemu.archive
URL(qemu) := http://wiki.qemu-project.org/download/qemu-$(VERSION).tar.bz2
SHA(qemu) := 629fb77fc03713b1267c1d51a8df6c0d9c7fd39b
DIR(qemu) := src/lib/qemu
TAR_OPT(qemu) := --strip-components=1 --files-from $(REP_DIR)/src/lib/qemu-usb/files.list
HASH_INPUT += $(REP_DIR)/src/lib/qemu-usb/files.list
PATCHES := src/lib/qemu-usb/patches/xhci_state.patch \
src/lib/qemu-usb/patches/usb_bus_nfree.patch
PATCH_OPT:= -p1

View File

@ -0,0 +1,30 @@
This library makes the xHCI device model of Qemu available on Genode
and is used as a back end for such for device models in existing VMMs.
Usage
~~~~~
The user of this library is required to provide certain back end
functionality, namely a Timer_queue to handle timer events and a Pci_device
that handles access to the PCI bus (raise interrupts, (un)map DMA memory)
within the VMM device model.
To use this library the user calls 'Qemu::usb_init' and passes
pointers to the back end objects. In addition, a Signal_receiver
reference has also to be handed over. It will receive all signals
required by this library.
'Qemu::usb_init' returns a pointer to a Controller object. MMIO
access must be forwarded to this object when the device model in the VMM
wants to access the MMIO regions of the xHCI device.
Whenever the VMM requests a device reset the 'Qemu::usb_reset'
function has to be called. It will remove and free all attached
USB devices and will reset the state of the xHCI device model.
After the xHCI device model has been reset 'Qemu::usb_update_devices'
needs to be called to reattach USB devices.
Timer callbacks that have been registered using the Timer_queue
interface have to be executed by calling 'Qemu::usb_timer_callback'
when the timer triggers.

View File

@ -0,0 +1,202 @@
/*
* \brief Qemu USB controller interface
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2015-12-14
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
/* local includes */
#include <extern_c_begin.h>
#include <qemu_emul.h>
#include <extern_c_end.h>
extern "C" {
enum {
SHOW_TRACE = 0,
};
#define TRACE_AND_STOP \
do { \
PWRN("%s not implemented called from: %p", __func__, __builtin_return_address(0)); \
Genode::sleep_forever(); \
} while (0)
#define TRACE \
do { \
if (SHOW_TRACE) \
PWRN("%s not implemented", __func__); \
} while (0)
/****************
** hcd-xhci.c **
****************/
void memory_region_del_subregion(MemoryRegion*, MemoryRegion*)
{
TRACE_AND_STOP;
}
void msix_vector_unuse(PCIDevice*, unsigned int)
{
TRACE;
}
int msix_vector_use(PCIDevice*, unsigned int)
{
TRACE;
return 0;
}
ObjectClass* object_class_dynamic_cast_assert(ObjectClass*, const char*, const char*, int,
const char*)
{
TRACE_AND_STOP;
return nullptr;
}
Object* object_dynamic_cast_assert(Object*, const char*, const char*, int, const char*)
{
TRACE_AND_STOP;
return nullptr;
}
bool pci_bus_is_express(PCIBus*)
{
TRACE;
return false;
}
void pci_register_bar(PCIDevice*, int, uint8_t, MemoryRegion*)
{
TRACE;
}
int pcie_endpoint_cap_init(PCIDevice*, uint8_t)
{
TRACE_AND_STOP;
return -1;
}
/***********
** bus.c **
***********/
static Error _error;
Error *error_abort = &_error;
ObjectClass* object_get_class(Object*)
{
TRACE_AND_STOP;
return nullptr;
}
const char* object_get_typename(Object*)
{
TRACE;
return nullptr;
}
void qbus_set_bus_hotplug_handler(BusState *state, Error **error)
{
TRACE;
}
gchar* g_strdup_printf(const gchar*, ...)
{
TRACE;
return 0;
}
void pstrcpy(char*, int, const char*)
{
TRACE;
}
long int strtol(const char*, char**, int)
{
TRACE;
return -1;
}
DeviceState* qdev_try_create(BusState*, const char*)
{
TRACE_AND_STOP;
return nullptr;
}
void monitor_printf(Monitor*, const char*, ...)
{
TRACE;
}
void qdev_simple_device_unplug_cb(HotplugHandler*, DeviceState*, Error**)
{
TRACE_AND_STOP;
}
char* qdev_get_dev_path(DeviceState*)
{
TRACE_AND_STOP;
return 0;
}
const char* qdev_fw_name(DeviceState*)
{
TRACE;
return 0;
}
gchar* g_strdup(const gchar*)
{
TRACE;
return 0;
}
size_t strlen(const char*)
{
TRACE_AND_STOP;
return 0;
}
/**********
** libc **
**********/
void abort() { TRACE_AND_STOP; }
} /* extern "C" */

View File

@ -0,0 +1,6 @@
qemu-2.4.1/include/hw/usb.h
qemu-2.4.1/include/qemu/queue.h
qemu-2.4.1/include/qom/object.h
qemu-2.4.1/hw/usb/bus.c
qemu-2.4.1/hw/usb/core.c
qemu-2.4.1/hw/usb/hcd-xhci.c

View File

@ -0,0 +1,658 @@
/**
* \brief USB session back end
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2015-12-18
*/
#include <base/allocator_avl.h>
#include <base/sleep.h>
#include <base/printf.h>
#include <os/attached_rom_dataspace.h>
#include <os/server.h>
#include <os/signal_rpc_dispatcher.h>
#include <usb_session/connection.h>
#include <usb/usb.h>
#include <util/xml_node.h>
#include <extern_c_begin.h>
#include <qemu_emul.h>
#include <hw/usb.h>
#include <extern_c_end.h>
using namespace Genode;
static bool const verbose_devices = false;
static bool const verbose_host = false;
Lock _lock;
static void update_ep(USBDevice *);
static bool claim_interfaces(USBDevice *dev);
struct Completion : Usb::Completion
{
USBPacket *p = nullptr;
USBDevice *dev = nullptr;
uint8_t *data = nullptr;
enum State { VALID, FREE, CANCELED };
State state = FREE;
void complete(Usb::Packet_descriptor &p) override { }
void complete(Usb::Packet_descriptor &packet, char *content)
{
if (state != VALID)
return;
int actual_size = 0;
switch (packet.type) {
case Usb::Packet_descriptor::CTRL:
actual_size = packet.control.actual_size;
break;
case Usb::Packet_descriptor::BULK:
case Usb::Packet_descriptor::IRQ:
actual_size = packet.transfer.actual_size;
default:
break;
}
if (actual_size < 0) actual_size = 0;
if (verbose_host)
PDBG("packet.type: %u actual_size: 0x%x", packet.type, actual_size);
p->actual_length = 0;
if (p->pid == USB_TOKEN_IN && actual_size > 0) {
if (data) Genode::memcpy(data, content, actual_size);
else usb_packet_copy(p, content, actual_size);
}
p->actual_length = actual_size;
if (packet.succeded)
p->status = USB_RET_SUCCESS;
else
p->status = USB_RET_IOERROR;
switch (packet.type) {
case Usb::Packet_descriptor::CONFIG:
if (!claim_interfaces(dev))
p->status = USB_RET_IOERROR;
case Usb::Packet_descriptor::ALT_SETTING:
update_ep(dev);
case Usb::Packet_descriptor::CTRL:
usb_generic_async_ctrl_complete(dev, p);
break;
case Usb::Packet_descriptor::BULK:
case Usb::Packet_descriptor::IRQ:
usb_packet_complete(dev, p);
break;
default:
break;
}
}
};
struct Usb_host_device : List<Usb_host_device>::Element
{
struct Could_not_create_device : Genode::Exception { };
bool deleted = false;
char const *label = nullptr;
unsigned bus = 0;
unsigned dev = 0;
USBHostDevice *qemu_dev;
Completion completion[Usb::Session::TX_QUEUE_SIZE];
Signal_receiver &sig_rec;
Signal_dispatcher<Usb_host_device> state_dispatcher { sig_rec, *this, &Usb_host_device::state_change };
Allocator_avl alloc { env()->heap() };
Usb::Connection usb_raw { &alloc, label, 1024*1024, state_dispatcher };
Signal_dispatcher<Usb_host_device> ack_avail_dispatcher { sig_rec, *this, &Usb_host_device::ack_avail };
void _release_interfaces()
{
Usb::Config_descriptor cdescr;
Usb::Device_descriptor ddescr;
usb_raw.config_descriptor(&ddescr, &cdescr);
for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
usb_raw.release_interface(i);
}
}
bool _claim_interfaces()
{
Usb::Config_descriptor cdescr;
Usb::Device_descriptor ddescr;
usb_raw.config_descriptor(&ddescr, &cdescr);
bool result = true;
for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
try {
usb_raw.claim_interface(i);
} catch (Usb::Session::Interface_already_claimed) {
result = false;
}
}
if (!result) PERR("Device already claimed");
return result;
}
Usb_host_device(Signal_receiver &sig_rec, char const *label,
unsigned bus, unsigned dev)
: label(label), bus(bus), dev(dev), sig_rec(sig_rec)
{
usb_raw.tx_channel()->sigh_ack_avail(ack_avail_dispatcher);
if (!_claim_interfaces())
throw Could_not_create_device();
qemu_dev = create_usbdevice(this);
if (!qemu_dev)
throw Could_not_create_device();
}
static int to_qemu_speed(unsigned speed)
{
switch (speed) {
case Usb::Device::SPEED_LOW: return USB_SPEED_LOW;
case Usb::Device::SPEED_FULL: return USB_SPEED_FULL;
case Usb::Device::SPEED_HIGH: return USB_SPEED_HIGH;
case Usb::Device::SPEED_SUPER: return USB_SPEED_SUPER;
default: return 0;
}
}
void ack_avail(unsigned)
{
Lock::Guard g(_lock);
/* we are already dead, do nothing */
if (deleted == true) return;
while (usb_raw.source()->ack_avail()) {
Usb::Packet_descriptor packet = usb_raw.source()->get_acked_packet();
char *packet_content = usb_raw.source()->packet_content(packet);
dynamic_cast<Completion *>(packet.completion)->complete(packet, packet_content);
free_packet(packet);
}
}
void _destroy()
{
/* mark delete before removing */
deleted = true;
/* remove from USB bus */
remove_usbdevice(qemu_dev);
qemu_dev = nullptr;
}
void state_change(unsigned)
{
Lock::Guard g(_lock);
if (usb_raw.plugged())
return;
_destroy();
}
void destroy()
{
Lock::Guard g(_lock);
_release_interfaces();
_destroy();
}
Usb::Packet_descriptor alloc_packet(int length)
{
if (!usb_raw.source()->ready_to_submit())
throw -1;
Usb::Packet_descriptor packet = usb_raw.source()->alloc_packet(length);
packet.completion = alloc_completion();
return packet;
}
void free_packet(Usb::Packet_descriptor &packet)
{
dynamic_cast<Completion *>(packet.completion)->state = Completion::FREE;
usb_raw.source()->release_packet(packet);
}
Completion *alloc_completion()
{
for (unsigned i = 0; i < Usb::Session::TX_QUEUE_SIZE; i++)
if (completion[i].state == Completion::FREE) {
completion[i]. state = Completion::VALID;
return &completion[i];
}
return nullptr;
}
Completion *find_completion(USBPacket *p)
{
for (unsigned i = 0; i < Usb::Session::TX_QUEUE_SIZE; i++)
if (completion[i].p == p)
return &completion[i];
return nullptr;
}
void submit(Usb::Packet_descriptor p) {
usb_raw.source()->submit_packet(p); }
bool claim_interfaces() { return _claim_interfaces(); }
void set_configuration(uint8_t value, USBPacket *p)
{
_release_interfaces();
Usb::Packet_descriptor packet = alloc_packet(0);
packet.type = Usb::Packet_descriptor::CONFIG;
packet.number = value;
Completion *c = dynamic_cast<Completion *>(packet.completion);
c->p = p;
c->dev = cast_USBDevice(qemu_dev);
submit(packet);
p->status = USB_RET_ASYNC;
}
void set_interface(int index, uint8_t value, USBPacket *p)
{
Usb::Packet_descriptor packet = alloc_packet(0);
packet.type = Usb::Packet_descriptor::ALT_SETTING;
packet.interface.number = index;
packet.interface.alt_setting = value;
Completion *c = dynamic_cast<Completion *>(packet.completion);
c->p = p;
c->dev = cast_USBDevice(qemu_dev);
submit(packet);
p->status = USB_RET_ASYNC;
}
void update_ep(USBDevice *udev)
{
usb_ep_reset(udev);
/* retrieve device speed */
Usb::Config_descriptor cdescr;
Usb::Device_descriptor ddescr;
usb_raw.config_descriptor(&ddescr, &cdescr);
for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
udev->altsetting[i] = usb_raw.alt_settings(i);
}
for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
for (int j = 0; j < udev->altsetting[i]; j++) {
Usb::Interface_descriptor iface;
usb_raw.interface_descriptor(i, j, &iface);
for (unsigned k = 0; k < iface.num_endpoints; k++) {
Usb::Endpoint_descriptor endp;
usb_raw.endpoint_descriptor(i, j, k, &endp);
int const pid = (endp.address & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
int const ep = (endp.address & 0xf);
uint8_t const type = (endp.attributes & 0x3);
usb_ep_set_max_packet_size(udev, pid, ep, endp.max_packet_size);
usb_ep_set_type(udev, pid, ep, type);
usb_ep_set_ifnum(udev, pid, ep, i);
usb_ep_set_halted(udev, pid, ep, 0);
}
}
}
}
};
/********************
** Qemu interface **
********************/
#define TRACE_AND_STOP do { PDBG("not implemented"); } while(false)
#define USB_HOST_DEVICE(obj) \
OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)
static void update_ep(USBDevice *udev)
{
USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data;
dev->update_ep(udev);
}
static bool claim_interfaces(USBDevice *udev)
{
USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data;
return dev->claim_interfaces();
}
static void usb_host_realize(USBDevice *udev, Error **errp)
{
USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data;
/* retrieve device speed */
Usb::Config_descriptor cdescr;
Usb::Device_descriptor ddescr;
dev->usb_raw.config_descriptor(&ddescr, &cdescr);
if (verbose_host)
PDBG("set udev->speed to %d", Usb_host_device::to_qemu_speed(ddescr.speed));
udev->speed = Usb_host_device::to_qemu_speed(ddescr.speed);
udev->speedmask = (1 << udev->speed);
udev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
dev->update_ep(udev);
}
static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p)
{
USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data;
Completion *c = dev->find_completion(p);
c->state = Completion::CANCELED;
}
static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
{
USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data;
size_t size = 0;
unsigned timeout = 0;
Usb::Packet_descriptor::Type type = Usb::Packet_descriptor::BULK;
switch (usb_ep_get_type(udev, p->pid, p->ep->nr)) {
case USB_ENDPOINT_XFER_BULK:
type = Usb::Packet_descriptor::BULK;
size = usb_packet_size(p);
break;
case USB_ENDPOINT_XFER_INT:
type = Usb::Packet_descriptor::IRQ;
size = p->iov.size;
/* values match usb_drv */
switch (udev->speed) {
case USB_SPEED_SUPER:
timeout = 1<<15;
break;
case USB_SPEED_HIGH:
timeout = 1<<13;
break;
case USB_SPEED_FULL:
case USB_SPEED_LOW:
timeout = 1<<7;
break;
default: break;
}
break;
default:
PERR("not supported data request");
break;
}
bool const in = p->pid == USB_TOKEN_IN;
Usb::Packet_descriptor packet = dev->alloc_packet(size);
packet.type = type;
packet.transfer.ep = p->ep->nr | (in ? USB_DIR_IN : 0);
packet.transfer.timeout = timeout;
if (!in) {
char * const content = dev->usb_raw.source()->packet_content(packet);
usb_packet_copy(p, content, size);
}
Completion *c = dynamic_cast<Completion *>(packet.completion);
c->p = p;
c->dev = udev;
c->data = nullptr;
dev->submit(packet);
p->status = USB_RET_ASYNC;
}
static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
int request, int value, int index,
int length, uint8_t *data)
{
USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data;
if (verbose_host)
PDBG("r: %x v: %x i: %x length: %d", request, value, index, length);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
udev->addr = value;
return;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
dev->set_configuration(value & 0xff, p);
return;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
dev->set_interface(index, value, p);
return;
}
if (udev->speed == USB_SPEED_SUPER &&
!(udev->port->speedmask & USB_SPEED_MASK_SUPER) &&
request == 0x8006 && value == 0x100 && index == 0) {
PERR("r->usb3ep0quirk = true");
}
Usb::Packet_descriptor packet;
try {
packet = dev->alloc_packet(length);
} catch (...) { PERR("Packet allocation failed"); return; }
packet.type = Usb::Packet_descriptor::CTRL;
packet.control.request_type = request >> 8;
packet.control.request = request & 0xff;
packet.control.index = index;
packet.control.value = value;
Completion *c = dynamic_cast<Completion *>(packet.completion);
c->p = p;
c->dev = udev;
c->data = data;
if (!(packet.control.request_type & USB_DIR_IN) && length) {
char *packet_content = dev->usb_raw.source()->packet_content(packet);
Genode::memcpy(packet_content, data, length);
}
dev->submit(packet);
p->status = USB_RET_ASYNC;
}
static Property usb_host_dev_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
static void usb_host_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = usb_host_realize;
uc->product_desc = "USB Host Device";
uc->cancel_packet = usb_host_cancel_packet;
uc->handle_data = usb_host_handle_data;
uc->handle_control = usb_host_handle_control;
dc->props = usb_host_dev_properties;
}
static TypeInfo usb_host_dev_info;
static void usb_host_register_types(void)
{
usb_host_dev_info.name = TYPE_USB_HOST_DEVICE;
usb_host_dev_info.parent = TYPE_USB_DEVICE;
usb_host_dev_info.instance_size = sizeof(USBHostDevice);
usb_host_dev_info.class_init = usb_host_class_initfn;
type_register_static(&usb_host_dev_info);
}
struct Usb_devices : List<Usb_host_device>
{
Signal_receiver &_sig_rec;
Signal_dispatcher<Usb_devices> _device_dispatcher { _sig_rec, *this, &Usb_devices::_devices_update };
Attached_rom_dataspace _devices_rom { "usb_devices" };
void _garbage_collect()
{
for (Usb_host_device *d = first(); d; d = d->next()) {
if (d->deleted == false)
continue;
remove(d);
Genode::destroy(env()->heap(), d);
}
}
Usb_host_device *_find_usb_device(unsigned bus, unsigned dev)
{
for (Usb_host_device *d = first(); d; d = d->next())
if (d->bus == bus && d->dev == dev)
return d;
return nullptr;
}
void _devices_update(unsigned)
{
Lock::Guard g(_lock);
_garbage_collect();
_devices_rom.update();
if (!_devices_rom.is_valid())
return;
if (verbose_devices)
PINF("%s", _devices_rom.local_addr<char>());
Xml_node devices_node(_devices_rom.local_addr<char>(), _devices_rom.size());
devices_node.for_each_sub_node("device", [&] (Xml_node const &node) {
unsigned product = node.attribute_value<unsigned>("product_id", 0);
unsigned vendor = node.attribute_value<unsigned>("vendor_id", 0);
unsigned bus = node.attribute_value<unsigned>("bus", 0);
unsigned dev = node.attribute_value<unsigned>("dev", 0);
Genode::String<128> label;
try {
node.attribute("label").value(&label);
} catch (Genode::Xml_attribute::Nonexistent_attribute) {
PERR("No label found for device %03x:%03x", bus, dev);
return;
}
/* ignore if already created */
if (_find_usb_device(bus, dev)) return;
try {
Usb_host_device *new_device = new (env()->heap())
Usb_host_device(_sig_rec, label.string(), bus, dev);
insert(new_device);
PINF("Attach USB device %03x:%03x (%x:%x)",
bus, dev, vendor, product);
} catch (...) {
PERR("Could not attach USB device %03x:%03x (%x:%x)",
bus, dev, vendor, product);
}
});
}
Usb_devices(Signal_receiver *sig_rec)
: _sig_rec(*sig_rec)
{
_devices_rom.sigh(_device_dispatcher);
}
void destroy()
{
for (Usb_host_device *d = first(); d; d = d->next())
d->destroy();
_garbage_collect();
}
};
static Usb_devices *_devices;
extern "C" void usb_host_destroy()
{
if (_devices == nullptr) return;
_devices->destroy();
}
extern "C" void usb_host_update_devices()
{
if (_devices == nullptr) return;
_devices->_devices_update(0);
}
/*
* Do not use type_init macro because of name mangling
*/
extern "C" void _type_init_usb_host_register_types(Genode::Signal_receiver *sig_rec)
{
usb_host_register_types();
static Usb_devices devices(sig_rec);
_devices = &devices;
}

View File

@ -0,0 +1,27 @@
/*
* \brief Include before including Linux headers in C++
* \author Christian Helmuth
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#define extern_c_begin
extern "C" {
/* some warnings should only be switched of for Linux headers */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-arith"
#pragma GCC diagnostic ignored "-Wsign-compare"
/* deal with C++ keywords used for identifiers etc. */
#define private private_
#define class class_
#define new new_
#define typename typename_

View File

@ -0,0 +1,21 @@
/*
* \brief Include after including Linux headers in C++
* \author Christian Helmuth
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#undef typename
#undef new
#undef class
#undef private
#pragma GCC diagnostic pop
} /* extern "C" */

View File

@ -0,0 +1,728 @@
/*
* \brief Qemu emulation environment
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2015-12-14
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__QEMU_EMUL_H_
#define _INCLUDE__QEMU_EMUL_H_
#include <stdarg.h>
#include <base/fixed_stdint.h>
void q_printf(char const *, ...) __attribute__((format(printf, 1, 2)));
void q_vprintf(char const *, va_list);
typedef genode_uint8_t uint8_t;
typedef genode_uint16_t uint16_t;
typedef genode_uint32_t uint32_t;
typedef genode_uint64_t uint64_t;
typedef genode_int32_t int32_t;
typedef genode_int64_t int64_t;
typedef signed long ssize_t;
#ifndef __cplusplus
typedef _Bool bool;
enum { false = 0, true = 1 };
#endif
typedef __SIZE_TYPE__ size_t;
typedef unsigned long dma_addr_t;
typedef uint64_t hwaddr;
typedef struct uint16List
{
union {
uint16_t value;
uint64_t padding;
};
struct uint16List *next;
} uint16List;
/**********
** libc **
**********/
enum {
EINVAL = 22,
};
void *malloc(size_t size);
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void free(void *p);
void abort();
#define fprintf(fd, fmt, ...) q_printf(fmt, ##__VA_ARGS__)
int snprintf(char *buf, size_t size, const char *fmt, ...);
int strcmp(const char *s1, const char *s2);
size_t strlen(char const *s);
long int strtol(const char *nptr, char **endptr, int base);
char *strchr(const char *s, int c);
/*************
** defines **
*************/
#define NULL (void *)0
#define QEMU_SENTINEL
#define le32_to_cpu(x) (x)
#define cpu_to_le32(x) (x)
#define cpu_to_le64(x) (x)
#define le32_to_cpus(x)
#define le64_to_cpus(x)
/**
* Forward declarations
*/
typedef struct Monitor Monitor;
typedef struct QDict QDict;
typedef struct CPUReadMemoryFunc CPUReadMemoryFunc;
typedef struct CPUWriteMemoryFunc CPUWriteMemoryFunc;
typedef struct MemoryRegion { unsigned dummy; } MemoryRegion;
struct tm;
/******************
** qapi/error.h **
******************/
typedef struct Error { char string[256]; } Error;
void error_setg(Error **errp, const char *fmt, ...);
const char *error_get_pretty(Error *err);
void error_report(const char *fmt, ...);
void error_free(Error *err);
void error_propagate(Error **dst_errp, Error *local_err);
extern Error *error_abort;
/*******************
** qemu/bitops.h **
*******************/
#define BITS_PER_BYTE 8
#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE)
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
static inline void set_bit(long nr, unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = addr + BIT_WORD(nr);
*p |= mask;
}
/*******************
** qemu-common.h **
*******************/
struct iovec
{
void *iov_base;
size_t iov_len;
};
typedef struct QEMUIOVector
{
struct iovec *iov;
int niov;
size_t size;
int alloc_hint;
} QEMUIOVector;
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
void qemu_iovec_reset(QEMUIOVector *qiov);
void qemu_iovec_destroy(QEMUIOVector *qiov);
void pstrcpy(char *buf, int buf_size, const char *str);
/****************
** qemu/iov.h **
****************/
size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
size_t offset, const void *buf, size_t bytes);
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, void *buf, size_t bytes);
size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, int fillc, size_t bytes);
/******************
** qom/object.h **
******************/
typedef struct Object { unsigned dummy; } Object;
typedef struct ObjectClass { unsigned dummy; } ObjectClass;
struct DeviceState;
struct PCIDevice;
struct XHCIState;
struct PCIDevice *cast_PCIDevice(void *);
struct XHCIState *cast_XHCIState(void *);
struct DeviceState *cast_DeviceState(void *);
struct BusState *cast_BusState(void *);
struct Object *cast_object(void *);
struct USBDevice *cast_USBDevice(void *);
struct USBHostDevice *cast_USBHostDevice(void *);
struct PCIDeviceClass *cast_PCIDeviceClass(void *);
struct DeviceClass *cast_DeviceClass(void *);
struct BusClass *cast_BusClass(void *);
struct HotplugHandlerClass *cast_HotplugHandlerClass(void *);
struct USBDeviceClass *cast_USBDeviceClass(void *);
#define OBJECT_CHECK(type, obj, str) \
cast_##type((void *)obj)
#define OBJECT_CLASS_CHECK(type, klass, str) \
OBJECT_CHECK(type, (klass), str)
#define OBJECT(obj) \
cast_object(obj)
#define OBJECT_GET_CLASS(klass, obj, str) \
OBJECT_CHECK(klass, obj, str)
typedef struct InterfaceInfo {
const char *type;
} InterfaceInfo;
typedef struct TypeInfo
{
char const *name;
char const *parent;
size_t instance_size;
bool abstract;
size_t class_size;
void (*class_init)(ObjectClass *klass, void *data);
InterfaceInfo *interfaces;
} TypeInfo;
struct Type_impl { unsigned dummy; };
typedef struct Type_impl *Type;
Type type_register_static(const TypeInfo *info);
#define object_property_set_bool(...)
#define object_unparent(...)
const char *object_get_typename(Object *obj);
/********************
** glib emulation **
********************/
#define g_new0(type, count)({ \
typeof(type) *t = (typeof(type)*)malloc(sizeof(type) * count); \
memset(t, 0, sizeof(type) * count); \
t; \
})
#define g_free(p) free(p)
#define g_malloc malloc
#define g_malloc0(size) ({ \
void *t = malloc((size)); \
memset(t, 0, (size)); \
t; \
})
typedef void* gpointer;
typedef struct GSList GSList;
struct GSList
{
gpointer data;
GSList *next;
};
GSList *g_slist_append(GSList *list, gpointer data);
typedef char gchar;
gchar *g_strdup(gchar const *str);
gchar *g_strdup_printf(gchar const *fmt, ...);
/********************
** hw/qdev-core.h **
********************/
typedef enum DeviceCategory {
DEVICE_CATEGORY_USB = 1,
DEVICE_CATEGORY_MAX
} DeviceCategory;
typedef struct BusState BusState;
typedef struct DeviceState
{
BusState *parent_bus;
} DeviceState;
struct VMStateDescription;
struct Property;
typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);
typedef struct DeviceClass
{
DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
struct Property *props;
void (*reset)(DeviceState *dev);
DeviceRealize realize;
DeviceUnrealize unrealize;
const struct VMStateDescription *vmsd;
const char *bus_type;
} DeviceClass;
#define DEVICE_CLASS(klass) OBJECT_CHECK(DeviceClass, (klass), "device")
typedef struct BusState
{
DeviceState *parent;
char *name;
} BusState;
typedef struct BusClass
{
void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
char *(*get_dev_path)(DeviceState *dev);
char *(*get_fw_dev_path)(DeviceState *dev);
} BusClass;
#define TYPE_BUS "bus"
#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
#define TYPE_DEVICE "device"
#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
enum Prop_type
{
BIT, UINT32, END
};
typedef struct Property
{
enum Prop_type type;
unsigned offset;
unsigned long value;
} Property;
#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _bool) \
{ .type = BIT, .offset = offsetof(_state, _field), .value = (_bool << _bit) }
#define DEFINE_PROP_UINT32(_name, _state, _field, _value) \
{ .type = UINT32, .offset = offsetof(_state, _field), .value = _value }
#define DEFINE_PROP_END_OF_LIST() { .type = END }
#define DEFINE_PROP_STRING(...) {}
/* forward */
typedef struct DeviceState DeviceState;
typedef struct HotplugHandler HotplugHandler;
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void qbus_create_inplace(void *bus, size_t size, const char *typename,
DeviceState *parent, const char *name);
void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp);
DeviceState *qdev_create(BusState *bus, const char *name);
DeviceState *qdev_try_create(BusState *bus, const char *name);
char *qdev_get_dev_path(DeviceState *dev);
const char *qdev_fw_name(DeviceState *dev);
/******************
** hw/hotplug.h **
******************/
typedef struct HotplugHandler { unsigned dummy; } HotplugHandler;
typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp);
typedef struct HotplugHandlerClass
{
hotplug_fn unplug;
} HotplugHandlerClass;
#define TYPE_HOTPLUG_HANDLER "hotplug-handler"
#define HOTPLUG_HANDLER_CLASS(klass) \
OBJECT_CLASS_CHECK(HotplugHandlerClass, (klass), TYPE_HOTPLUG_HANDLER)
/****************
** hw/osdep.h **
****************/
#define offsetof(type, member) ((size_t) &((type *)0)->member)
#define container_of(ptr, type, member) ({ \
const typeof(((type *) 0)->member) *__mptr = (ptr); \
(type *) ((char *) __mptr - offsetof(type, member));})
#define DO_UPCAST(type, field, dev) cast_DeviceStateToUSBBus()
struct USBBus *cast_DeviceStateToUSBBus(void);
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/******************
** qemu/timer.h **
******************/
enum QEMUClockType
{
QEMU_CLOCK_VIRTUAL = 1,
};
typedef enum QEMUClockType QEMUClockType;
typedef struct QEMUTimer { unsigned dummy; } QEMUTimer;
typedef void QEMUTimerCB(void *opaque);
QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb, void *opaque);
void timer_mod(QEMUTimer *ts, int64_t expire_timer);
void timer_del(QEMUTimer *ts);
void timer_free(QEMUTimer *ts);
int64_t qemu_clock_get_ns(QEMUClockType type);
/***********************
** exec/cpu-common.h **
***********************/
enum device_endian { DEVICE_LITTLE_ENDIAN = 2 };
/*******************
** exec/memory.h **
*******************/
typedef struct AddressSpace { unsigned dummy; } AddressSpace;
typedef struct MemoryRegionOps {
uint64_t (*read)(void *opaque, hwaddr addr, unsigned size);
void (*write)(void *opaque, hwaddr addr, uint64_t data, unsigned size);
enum device_endian endianness;
struct {
unsigned min_access_size;
unsigned max_access_size;
} valid;
struct {
unsigned min_access_size;
unsigned max_access_size;
} impl;
} MemoryRegionOps;
void memory_region_init(MemoryRegion *mr,
struct Object *owner,
const char *name,
uint64_t size);
void memory_region_init_io(MemoryRegion *mr,
struct Object *owner,
const MemoryRegionOps *ops,
void *opaque,
const char *name,
uint64_t size);
void memory_region_add_subregion(MemoryRegion *mr,
hwaddr offset,
MemoryRegion *subregion);
void memory_region_del_subregion(MemoryRegion *mr,
MemoryRegion *subregion);
/******************
** sysemu/dma.h **
******************/
typedef struct QEMUIOVector QEMUSGList;
void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
void qemu_sglist_destroy(QEMUSGList *qsg);
int dma_memory_read(AddressSpace *as, dma_addr_t addr, void *buf, dma_addr_t len);
static inline uint64_t ldq_le_dma(AddressSpace *as, dma_addr_t addr)
{
uint64_t val;
dma_memory_read(as, addr, &val, 8);
return val;
}
static inline uint64_t ldq_le_pci_dma(void *dev, dma_addr_t addr)
{
return ldq_le_dma(0, addr);
}
/**************
** hw/pci.h **
**************/
enum Pci_regs {
PCI_BASE_ADDRESS_SPACE_MEMORY = 0,
PCI_BASE_ADDRESS_MEM_TYPE_64 = 0x04,
PCI_CLASS_PROG = 0x09,
PCI_CACHE_LINE_SIZE = 0x0c,
PCI_INTERRUPT_PIN = 0x3d,
};
enum Pci_ids {
PCI_CLASS_SERIAL_USB = 0x0c03,
PCI_VENDOR_ID_NEC = 0x1033,
PCI_DEVICE_ID_NEC_UPD720200 = 0x0194,
};
typedef struct PCIBus { unsigned dummy; } PCIBus;
typedef struct PCIDevice
{
uint8_t config[0x1000]; /* PCIe config space */
PCIBus *bus;
uint8_t *msix_table;
uint8_t *msix_pba;
MemoryRegion msix_table_mmio;
MemoryRegion msix_pba_mmio;
unsigned *msix_entry_used;
} PCIDevice;
typedef void PCIUnregisterFunc(PCIDevice *pci_dev);
typedef struct PCIDeviceClass
{
void (*realize)(PCIDevice *dev, Error **errp);
PCIUnregisterFunc *exit;
uint16_t vendor_id;
uint16_t device_id;
uint8_t revision;
uint16_t class_id;
int is_express;
} PCIDeviceClass;
#define TYPE_PCI_DEVICE "pci-device"
#define PCI_DEVICE(obj) \
OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
#define PCI_DEVICE_CLASS(klass) \
OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
void *buf, dma_addr_t len);
int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
const void *buf, dma_addr_t len);
void pci_set_irq(PCIDevice *pci_dev, int level);
void pci_irq_assert(PCIDevice *pci_dev);
void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
int alloc_hint);
AddressSpace *pci_get_address_space(PCIDevice *dev);
void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory);
bool pci_bus_is_express(PCIBus *bus);
int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
/*********************
** hw/pci/msi(x).h **
*********************/
int msi_init(struct PCIDevice *dev, uint8_t offset,
unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
int msix_init(PCIDevice *dev, unsigned short nentries,
MemoryRegion *table_bar, uint8_t table_bar_nr,
unsigned table_offset, MemoryRegion *pba_bar,
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
bool msi_enabled(const PCIDevice *dev);
int msix_enabled(PCIDevice *dev);
int msix_vector_use(PCIDevice *dev, unsigned vector);
void msix_vector_unuse(PCIDevice *dev, unsigned vector);
void msi_notify(PCIDevice *dev, unsigned int vector);
void msix_notify(PCIDevice *dev, unsigned vector);
/*************************
** migration/vmstate.h **
*************************/
#define VMSTATE_BOOL(...) {}
#define VMSTATE_UINT8(...) {}
#define VMSTATE_UINT32(...) {}
#define VMSTATE_UINT32_TEST(...) {}
#define VMSTATE_UINT64(...) {}
#define VMSTATE_INT32(...) {}
#define VMSTATE_INT64(...) {}
#define VMSTATE_STRUCT_ARRAY_TEST(...) {}
#define VMSTATE_UINT8_ARRAY(...) {}
#define VMSTATE_STRUCT_VARRAY_UINT32(...) {}
#define VMSTATE_PCIE_DEVICE(...) {}
#define VMSTATE_MSIX(...) {}
#define VMSTATE_TIMER_PTR(...) {}
#define VMSTATE_STRUCT(...) {}
#define VMSTATE_END_OF_LIST() {}
typedef struct VMStateField { unsigned dummy; } VMStateField;
typedef struct VMStateDescription
{
char const *name;
int version_id;
int minimum_version_id;
int (*post_load)(void *opaque, int version_id);
VMStateField *fields;
} VMStateDescription;
/**************
** assert.h **
**************/
#define assert(cond) do { \
if (!(cond)) { \
q_printf("assertion faied: %s:%d\n", __FILE__, __LINE__); \
int *d = (int *)0x0; \
*d = 1; \
}} while (0)
/************
** traces **
************/
#define trace_usb_xhci_irq_msix_use(v)
#define trace_usb_xhci_irq_msix_unuse(v)
#define trace_usb_xhci_irq_msix(v)
#define trace_usb_xhci_irq_msi(v)
#define trace_usb_xhci_queue_event(...)
#define trace_usb_xhci_fetch_trb(...)
#define trace_usb_xhci_run(...)
#define trace_usb_xhci_stop(...)
#define trace_usb_xhci_ep_state(...)
#define trace_usb_xhci_ep_enable(...)
#define trace_usb_xhci_ep_disable(...)
#define trace_usb_xhci_ep_stop(...)
#define trace_usb_xhci_ep_reset(...)
#define trace_usb_xhci_ep_set_dequeue(...)
#define trace_usb_xhci_xfer_async(...)
#define trace_usb_xhci_xfer_nak(...)
#define trace_usb_xhci_xfer_success(...)
#define trace_usb_xhci_xfer_error(...)
#define trace_usb_xhci_xfer_start(...)
#define trace_usb_xhci_unimplemented(...)
#define trace_usb_xhci_ep_kick(...)
#define trace_usb_xhci_xfer_retry(...)
#define trace_usb_xhci_slot_enable(...)
#define trace_usb_xhci_slot_disable(...)
#define trace_usb_xhci_slot_address(...)
#define trace_usb_xhci_slot_configure(...)
#define trace_usb_xhci_irq_intx(...)
#define trace_usb_xhci_slot_reset(...)
#define trace_usb_xhci_slot_evaluate(...)
#define trace_usb_xhci_port_notify(...)
#define trace_usb_xhci_port_link(...)
#define trace_usb_xhci_port_reset(...)
#define trace_usb_xhci_reset(...)
#define trace_usb_xhci_cap_read(...)
#define trace_usb_xhci_port_read(...)
#define trace_usb_xhci_port_write(...)
#define trace_usb_xhci_oper_read(...)
#define trace_usb_xhci_oper_write(...)
#define trace_usb_xhci_runtime_read(...)
#define trace_usb_xhci_runtime_write(...)
#define trace_usb_xhci_doorbell_read(...)
#define trace_usb_xhci_doorbell_write(...)
#define trace_usb_xhci_exit(...)
#define trace_usb_port_claim(...)
#define trace_usb_port_release(...)
#define trace_usb_port_attach(...)
#define trace_usb_port_detach(...)
#define trace_usb_packet_state_fault(...)
#define trace_usb_packet_state_change(...)
/***********************
** library interface **
***********************/
#define type_init(func) void _type_init_##func(void) { func(); }
#define TYPE_USB_HOST_DEVICE "usb-host"
typedef struct USBHostDevice
{
void *data;
} USBHostDevice;
USBHostDevice *create_usbdevice(void *data);
void remove_usbdevice(USBHostDevice *device);
void usb_host_destroy();
void usb_host_update_devices();
/***********************
** monitor/monitor.h **
***********************/
void monitor_printf(Monitor *mon, const char *fmt, ...);
#endif /* _INCLUDE__QEMU_EMUL_H_ */

View File

@ -0,0 +1,19 @@
diff --git a/src/lib/qemu/hw/usb/bus.c b/src/lib/qemu/hw/usb/bus.c
index 5f39e1e..b94f3af 100644
--- a/src/lib/qemu/hw/usb/bus.c
+++ b/src/lib/qemu/hw/usb/bus.c
@@ -433,10 +433,10 @@ void usb_claim_port(USBDevice *dev, Error **errp)
return;
}
} else {
- if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
- /* Create a new hub and chain it on */
- usb_try_create_simple(bus, "usb-hub", NULL);
- }
+ // if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
+ // /* Create a new hub and chain it on */
+ // usb_try_create_simple(bus, "usb-hub", NULL);
+ // }
if (bus->nfree == 0) {
error_setg(errp, "tried to attach usb device %s to a bus "
"with no free ports", dev->product_desc);

View File

@ -0,0 +1,27 @@
diff --git a/src/lib/qemu/hw/usb/hcd-xhci.c b/src/lib/qemu/hw/usb/hcd-xhci.c
index c673bed..b2a8939 100644
--- a/src/lib/qemu/hw/usb/hcd-xhci.c
+++ b/src/lib/qemu/hw/usb/hcd-xhci.c
@@ -486,6 +486,8 @@ struct XHCIState {
#define TYPE_XHCI "nec-usb-xhci"
+#ifndef __cplusplus
+
#define XHCI(obj) \
OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
@@ -2361,6 +2363,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
if (bsr) {
slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
+ usb_device_reset(dev);
} else {
USBPacket p;
uint8_t buf[1];
@@ -3914,3 +3917,5 @@ static void xhci_register_types(void)
}
type_init(xhci_register_types)
+
+#endif /* __cplusplus */

View File

@ -0,0 +1,896 @@
/*
* \brief Qemu USB controller interface
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2015-12-14
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <util/misc_math.h>
/* local includes */
#include <extern_c_begin.h>
#include <qemu_emul.h>
/* XHCIState is defined in this file */
#include <hcd-xhci.c>
#include <extern_c_end.h>
#include <qemu/usb.h>
/*******************
** USB interface **
*******************/
static bool const verbose_irq = false;
static bool const verbose_iov = false;
static bool const verbose_mmio = false;
extern "C" void _type_init_usb_register_types();
extern "C" void _type_init_usb_host_register_types(Genode::Signal_receiver*);
extern "C" void _type_init_xhci_register_types();
extern Genode::Lock _lock;
Qemu::Controller *qemu_controller();
static Qemu::Timer_queue* _timer_queue;
static Qemu::Pci_device* _pci_device;
Qemu::Controller *Qemu::usb_init(Timer_queue &tq, Pci_device &pci, Genode::Signal_receiver &sig_rec)
{
_timer_queue = &tq;
_pci_device = &pci;
_type_init_usb_register_types();
_type_init_xhci_register_types();
_type_init_usb_host_register_types(&sig_rec);
return qemu_controller();
}
void reset_controller();
void Qemu::usb_reset()
{
usb_host_destroy();
reset_controller();
}
void Qemu::usb_update_devices() {
usb_host_update_devices(); }
void Qemu::usb_timer_callback(void (*cb)(void*), void *data)
{
Genode::Lock::Guard g(_lock);
cb(data);
}
/**********
** libc **
**********/
void *malloc(size_t size) {
return Genode::env()->heap()->alloc(size); }
void *memset(void *s, int c, size_t n) {
return Genode::memset(s, c, n); }
void free(void *p) {
Genode::env()->heap()->free(p, 0); }
void q_printf(char const *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
Genode::String_console sc(buf, size);
sc.vprintf(fmt, args);
va_end(args);
return sc.len();
}
int strcmp(const char *s1, const char *s2)
{
return Genode::strcmp(s1, s2);
}
/********************
** Qemu emulation **
********************/
/**
* Set properties of objects
*/
template <typename T>
void properties_apply(T *state, DeviceClass *klass)
{
Property *p = klass->props;
if (!p)
return;
while (p->type != END) {
char *s = (char *)state;
s += p->offset;
uint32_t *member = (uint32_t *)s;
if (p->type == BIT)
*member |= p->value;
if (p->type == UINT32)
*member = p->value;
p++;
}
}
/**
* Class and objects wrapper
*/
struct Wrapper
{
unsigned long _start;
Object _object;
DeviceState _device_state;
PCIDevice _pci_device;
USBDevice _usb_device;
BusState _bus_state;
XHCIState *_xhci_state = nullptr;
USBHostDevice _usb_host_device;
ObjectClass _object_class;
DeviceClass _device_class;
PCIDeviceClass _pci_device_class;
BusClass _bus_class;
USBDeviceClass _usb_device_class;
HotplugHandlerClass _hotplug_handler_class;
unsigned long _end;
Wrapper() { }
bool in_object(void * ptr)
{
/*
* XHCIState is roughly 3 MiB large so we only create on instance
* (see below) and have to do this pointer check shenanigans.
*/
if (_xhci_state != nullptr
&& ptr >= _xhci_state
&& ptr < ((char*)_xhci_state + sizeof(XHCIState)))
return true;
using addr_t = Genode::addr_t;
addr_t p = (addr_t)ptr;
if (p > (addr_t)&_start && p < (addr_t)&_end)
return true;
return false;
}
};
struct Object_pool
{
enum {
XHCI, /* XHCI controller */
USB_BUS, /* bus driver */
USB_DEVICE, /* USB device driver */
USB_HOST_DEVICE, /* USB host device driver */
MAX = 8 /* host devices (USB_HOST_DEVICE - MAX) */
};
bool used[MAX];
Wrapper obj[MAX];
Wrapper *create_object()
{
for (unsigned i = USB_HOST_DEVICE + 1; i < MAX; i++) {
if (used[i] == false) {
used[i] = true;
return &obj[i];
}
}
return nullptr;
}
void free_object(Wrapper *w)
{
for (unsigned i = USB_HOST_DEVICE + 1; i < MAX; i++)
if (w == &obj[i]) {
used[i] = false;
break;
}
}
Wrapper * find_object(void *ptr)
{
for (Wrapper &w : obj) {
if(w.in_object(ptr))
return &w;
}
PERR("object for pointer not found called from: %p", __builtin_return_address(0));
throw -1;
}
XHCIState *xhci_state() {
return obj[XHCI]._xhci_state; }
BusState *bus() {
return &obj[USB_BUS]._bus_state; }
static Object_pool *p()
{
static Object_pool _p;
return &_p;
}
};
/***********
** casts **
***********/
struct PCIDevice *cast_PCIDevice(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_pci_device; }
struct XHCIState *cast_XHCIState(void *ptr) {
return Object_pool::p()->find_object(ptr)->_xhci_state; }
struct DeviceState *cast_DeviceState(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_device_state; }
struct BusState *cast_BusState(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_bus_state; }
struct USBDevice *cast_USBDevice(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_usb_device; }
struct Object *cast_object(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_object; }
struct PCIDeviceClass *cast_PCIDeviceClass(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_pci_device_class; }
struct DeviceClass *cast_DeviceClass(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_device_class; }
struct USBDeviceClass *cast_USBDeviceClass(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_usb_device_class; }
struct BusClass *cast_BusClass(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_bus_class; }
struct HotplugHandlerClass *cast_HotplugHandlerClass(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_hotplug_handler_class; }
struct USBHostDevice *cast_USBHostDevice(void *ptr) {
return &Object_pool::p()->find_object(ptr)->_usb_host_device; }
struct USBBus *cast_DeviceStateToUSBBus(void) {
return &Object_pool::p()->xhci_state()->bus; }
USBHostDevice *create_usbdevice(void *data)
{
Wrapper *obj = Object_pool::p()->create_object();
if (!obj) {
PERR("could not create new object");
return nullptr;
}
obj->_usb_device_class = Object_pool::p()->obj[Object_pool::USB_HOST_DEVICE]._usb_device_class;
/*
* Set parent bus object
*/
DeviceState *dev_state = &obj->_device_state;
dev_state->parent_bus = Object_pool::p()->bus();
/* set data pointer */
obj->_usb_host_device.data = data;
/*
* Attach new USB host device to USB device driver
*/
Error *e = nullptr;
DeviceClass *usb_device_class = &Object_pool::p()->obj[Object_pool::USB_DEVICE]._device_class;
usb_device_class->realize(dev_state, &e);
if (e) {
error_free(e);
e = nullptr;
usb_device_class->unrealize(dev_state, &e);
Object_pool::p()->free_object(obj);
return nullptr;
}
return &obj->_usb_host_device;
}
void remove_usbdevice(USBHostDevice *device)
{
DeviceClass *usb_device_class = &Object_pool::p()->obj[Object_pool::USB_DEVICE]._device_class;
DeviceState *usb_device_state = cast_DeviceState(device);
if (usb_device_class == nullptr)
PERR("usb_device_class null");
if (usb_device_state == nullptr)
PERR("usb_device_class null");
Error *e = nullptr;
usb_device_class->unrealize(usb_device_state, &e);
Wrapper *obj = Object_pool::p()->find_object(device);
Object_pool::p()->free_object(obj);
}
void reset_controller()
{
Wrapper *w = &Object_pool::p()->obj[Object_pool::XHCI];
DeviceClass *dc = &w->_device_class;
dc->reset(&w->_device_state);
}
/***********************************
** Qemu interface implementation **
***********************************/
Type type_register_static(TypeInfo const *t)
{
if (!Genode::strcmp(t->name, TYPE_XHCI)) {
Wrapper *w = &Object_pool::p()->obj[Object_pool::XHCI];
w->_xhci_state = (XHCIState*) malloc(sizeof(XHCIState));
Genode::memset(w->_xhci_state, 0, sizeof(XHCIState));
t->class_init(&w->_object_class, 0);
properties_apply(w->_xhci_state, &w->_device_class);
PCIDevice *pci = &w->_pci_device;
PCIDeviceClass *pci_class = &w->_pci_device_class;
Error *e;
pci_class->realize(pci, &e);
}
if (!Genode::strcmp(t->name, TYPE_USB_DEVICE)) {
Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_DEVICE];
t->class_init(&w->_object_class, 0);
}
if (!Genode::strcmp(t->name, TYPE_USB_HOST_DEVICE)) {
Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_HOST_DEVICE];
t->class_init(&w->_object_class, 0);
}
if (!Genode::strcmp(t->name, TYPE_USB_BUS)) {
Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_BUS];
ObjectClass *c = &w->_object_class;
t->class_init(c, 0);
}
return nullptr;
}
void qbus_create_inplace(void* bus, size_t size , const char* type,
DeviceState *parent, const char *name)
{
Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_BUS];
BusState *b = &w->_bus_state;
char const *n = "xhci.0";
b->name = (char *)malloc(Genode::strlen(n) + 1);
Genode::strncpy(b->name, n, Genode::strlen(n) + 1);
}
void timer_del(QEMUTimer *t)
{
_timer_queue->deactivate_timer(t);
}
void timer_free(QEMUTimer *t)
{
_timer_queue->delete_timer(t);
free(t);
}
void timer_mod(QEMUTimer *t, int64_t expire)
{
_timer_queue->activate_timer(t, expire);
}
QEMUTimer* timer_new_ns(QEMUClockType, void (*cb)(void*), void *opaque)
{
QEMUTimer *t = (QEMUTimer*)malloc(sizeof(QEMUTimer));
if (t == nullptr) {
PERR("could not create QEMUTimer");
return nullptr;
}
_timer_queue->register_timer(t, cb, opaque);
return t;
}
int64_t qemu_clock_get_ns(QEMUClockType) {
return _timer_queue->get_ns(); }
struct Controller : public Qemu::Controller
{
struct Mmio
{
Genode::addr_t id;
Genode::size_t size;
Genode::off_t offset;
MemoryRegionOps const *ops;
} mmio_regions [16];
uint64_t _mmio_size;
Controller()
{
Genode::memset(mmio_regions, 0, sizeof(mmio_regions));
}
void mmio_add_region(uint64_t size) { _mmio_size = size; }
void mmio_add_region_io(Genode::addr_t id, uint64_t size, MemoryRegionOps const *ops)
{
for (Mmio &mmio : mmio_regions) {
if (mmio.id != 0) continue;
mmio.id = id;
mmio.size = size;
mmio.ops = ops;
return;
}
}
Mmio &find_region(Genode::off_t offset)
{
for (Mmio &mmio : mmio_regions) {
if (offset >= mmio.offset
&& (offset < mmio.offset + (Genode::off_t)mmio.size))
return mmio;
}
PERR("could not find MMIO region for offset: %lx", offset);
throw -1;
}
void mmio_add_sub_region(Genode::addr_t id, Genode::off_t offset)
{
for (Mmio &mmio : mmio_regions) {
if (mmio.id != id) continue;
mmio.offset = offset;
return;
}
}
size_t mmio_size() const { return _mmio_size; }
int mmio_read(Genode::off_t offset, void *buf, size_t size)
{
Genode::Lock::Guard g(_lock);
Mmio &mmio = find_region(offset);
Genode::off_t reg = offset - mmio.offset;
void *ptr = Object_pool::p()->xhci_state();
/*
* Handle port access
*/
if (offset >= (OFF_OPER + 0x400) && offset < OFF_RUNTIME) {
uint32_t port = (offset - 0x440) / 0x10;
ptr = (void*)&Object_pool::p()->xhci_state()->ports[port];
}
uint64_t v = mmio.ops->read(ptr, reg, size);
*((uint32_t*)buf) = v;
if (verbose_mmio)
PDBG("mmio: %lx offset: %lx reg: %lx v: %llx", mmio.id, offset, reg, v);
return 0;
}
int mmio_write(Genode::off_t offset, void const *buf, size_t size)
{
Genode::Lock::Guard g(_lock);
Mmio &mmio = find_region(offset);
Genode::off_t reg = offset - mmio.offset;
uint64_t v = *((uint64_t*)buf);
void *ptr = Object_pool::p()->xhci_state();
/*
* Handle port access
*/
if (offset >= (OFF_OPER + 0x400) && offset < OFF_RUNTIME) {
uint32_t port = (offset - 0x440) / 0x10;
ptr = (void*)&Object_pool::p()->xhci_state()->ports[port];
}
mmio.ops->write(ptr, reg, v, size);
if (verbose_mmio)
PDBG("mmio: %lx offset: %lx reg: %lx v: %llx", mmio.id, offset, reg, v);
return 0;
}
};
static Controller *controller()
{
static Controller _inst;
return &_inst;
}
Qemu::Controller *qemu_controller()
{
return controller();
}
/**********
** MMIO **
**********/
void memory_region_init(MemoryRegion *mr, Object *obj, const char *name, uint64_t size) {
controller()->mmio_add_region(size); }
void memory_region_init_io(MemoryRegion* mr, Object* obj, const MemoryRegionOps* ops,
void *, const char * name, uint64_t size) {
controller()->mmio_add_region_io((Genode::addr_t)mr, size, ops); }
void memory_region_add_subregion(MemoryRegion *mr, hwaddr offset, MemoryRegion *sr) {
controller()->mmio_add_sub_region((Genode::addr_t)sr, offset); }
/*********
** DMA **
*********/
int pci_dma_read(PCIDevice*, dma_addr_t addr, void *buf, dma_addr_t size)
{
return _pci_device->read_dma(addr, buf, size);
}
int pci_dma_write(PCIDevice*, dma_addr_t addr, const void *buf, dma_addr_t size)
{
return _pci_device->write_dma(addr, buf, size);
}
int dma_memory_read(AddressSpace*, dma_addr_t addr, void *buf, dma_addr_t size)
{
return _pci_device->read_dma(addr, buf, size);
}
/****************
** Interrupts **
****************/
void pci_set_irq(PCIDevice*, int level)
{
if (verbose_irq)
PDBG("IRQ level: %d", level);
_pci_device->raise_interrupt(level);
}
void pci_irq_assert(PCIDevice*)
{
pci_set_irq(nullptr, 1);
}
int msi_init(PCIDevice *pdev, uint8_t offset, unsigned int nr_vectors, bool msi64bit,
bool msi_per_vector_mask)
{
return 0;
}
int msix_init(PCIDevice*, short unsigned int, MemoryRegion*, uint8_t, unsigned int, MemoryRegion*,
uint8_t, unsigned int, uint8_t)
{
return 0;
}
bool msi_enabled(const PCIDevice *pdev)
{
return false;
}
int msix_enabled(PCIDevice *pdev)
{
return 0;
}
void msi_notify(PCIDevice *pdev, unsigned int level) { }
void msix_notify(PCIDevice *pdev , unsigned int level) { }
/*************************************
** IO vector / scatter-gatter list **
*************************************/
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
{
int niov = qiov->niov;
if (qiov->alloc_hint <= niov) {
if (verbose_iov)
PDBG("alloc_hint %d <= niov: %d", qiov->alloc_hint, niov);
qiov->alloc_hint += 64;
iovec *new_iov = (iovec*) malloc(sizeof(iovec) * qiov->alloc_hint);
if (new_iov == nullptr) {
PERR("Could not reallocate iov");
throw -1;
}
for (int i = 0; i < niov; i++) {
new_iov[i].iov_base = qiov->iov[i].iov_base;
new_iov[i].iov_len = qiov->iov[i].iov_len;
}
free(qiov->iov);
qiov->iov = new_iov;
}
if (verbose_iov)
PDBG("niov: %u iov_base: %p base: %p len: %zu",
niov, &qiov->iov[niov].iov_base, base, len);
qiov->iov[niov].iov_base = base;
qiov->iov[niov].iov_len = len;
qiov->size += len;
qiov->niov++;
}
void qemu_iovec_destroy(QEMUIOVector *qiov)
{
qemu_iovec_reset(qiov);
free(qiov->iov);
qiov->iov = nullptr;
}
void qemu_iovec_reset(QEMUIOVector *qiov)
{
qiov->size = 0;
qiov->niov = 0;
}
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
{
if (verbose_iov)
PDBG("iov: %p alloc_hint: %d", qiov->iov, alloc_hint);
iovec *iov = qiov->iov;
if (iov != nullptr) {
if (alloc_hint > qiov->alloc_hint)
PERR("iov already initialized: %p and alloc_hint smaller", iov);
qemu_iovec_reset(qiov);
return;
}
if (alloc_hint <= 0) alloc_hint = 1;
qiov->alloc_hint = alloc_hint;
qiov->iov = (iovec*) malloc(sizeof(iovec) * alloc_hint);
if (qiov->iov == nullptr) {
PERR("Could not allocate iov");
throw -1;
}
Genode::memset(qiov->iov, 0, sizeof(iovec) * alloc_hint);
qemu_iovec_reset(qiov);
}
/* taken from util/iov.c */
size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
size_t offset, const void *buf, size_t bytes)
{
size_t done;
unsigned int i;
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
if (offset < iov[i].iov_len) {
size_t len = Genode::min(iov[i].iov_len - offset, bytes - done);
memcpy((char*)iov[i].iov_base + offset, (char*)buf + done, len);
done += len;
offset = 0;
} else {
offset -= iov[i].iov_len;
}
}
assert(offset == 0);
return done;
}
/* taken from util/iov.c */
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, void *buf, size_t bytes)
{
size_t done;
unsigned int i;
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
if (offset < iov[i].iov_len) {
size_t len = Genode::min(iov[i].iov_len - offset, bytes - done);
memcpy((char*)buf + done, (char*)iov[i].iov_base + offset, len);
done += len;
offset = 0;
} else {
offset -= iov[i].iov_len;
}
}
assert(offset == 0);
return done;
}
void pci_dma_sglist_init(QEMUSGList *sgl, PCIDevice*, int alloc_hint) {
qemu_iovec_init(sgl, alloc_hint); }
void qemu_sglist_add(QEMUSGList *sgl, dma_addr_t base, dma_addr_t len) {
qemu_iovec_add(sgl, (void*)base, len); }
void qemu_sglist_destroy(QEMUSGList *sgl) {
qemu_iovec_destroy(sgl); }
int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
{
void *mem;
for (int i = 0; i < sgl->niov; i++) {
dma_addr_t base = (dma_addr_t) sgl->iov[i].iov_base;
dma_addr_t len = sgl->iov[i].iov_len;
while (len) {
dma_addr_t xlen = len;
mem = _pci_device->map_dma(base, xlen);
if (verbose_iov)
PDBG("mem: 0x%p base: 0x%p len: 0x%lx", mem, (void*)base, len);
if (!mem) {
goto err;
}
if (xlen > len) {
xlen = len;
}
qemu_iovec_add(&p->iov, mem, xlen);
len -= xlen;
base += xlen;
}
}
return 0;
err:
PERR("could not map dma");
usb_packet_unmap(p, sgl);
return -1;
}
void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl)
{
for (int i = 0; i < p->iov.niov; i++) {
_pci_device->unmap_dma(p->iov.iov[i].iov_base,
p->iov.iov[i].iov_len);
}
}
/******************
** qapi/error.h **
******************/
void error_setg(Error **errp, const char *fmt, ...)
{
assert(*errp == nullptr);
*errp = (Error*) malloc(sizeof(Error));
if (*errp == nullptr) {
PERR("Could not allocate Error");
return;
}
Error *e = *errp;
va_list args;
va_start(args, fmt);
Genode::String_console sc(e->string, sizeof(e->string));
sc.vprintf(fmt, args);
va_end(args);
}
void error_propagate(Error **dst_errp, Error *local_err) {
*dst_errp = local_err; }
void error_free(Error *err) { free(err); }

View File

@ -0,0 +1,14 @@
/*
*
*/
{
global:
extern "C++" {
Qemu::*;
};
local:
*;
};