qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC] Plan for moving forward with QOM


From: Anthony Liguori
Subject: Re: [Qemu-devel] [RFC] Plan for moving forward with QOM
Date: Thu, 15 Sep 2011 08:26:49 -0500
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110516 Lightning/1.0b2 Thunderbird/3.1.10

On 09/15/2011 01:47 AM, Paolo Bonzini wrote:
On 09/14/2011 08:04 PM, Anthony Liguori wrote:
The concept of busses are implemented as an
interface that a device implements.

I noticed that you haven't written in the document how to make devices reside on
a particular bus (PCI, ISA, I2C, ...).

The three possibilities for this are:

* a device implements an interface. I would rule this out because for most buses
the devices will need to store some data (PCI: configuration data, pointer to
the parent bus; ISA: pointer to the parent bus). Interfaces are
implementation-only, so you have to place the data in each device and cause
massive code duplication.

I agree.


* a device inherits from an abstract class, e.g. PCIDevice. It is useful to see
how the inheritance tree would look like for two devices with a common chipset
and multiple interfaces:

Device
NE2000
PCIDevice
PCI_NE2000 ------> includes a NE2000
ISA_NE2000 ------> includes a NE2000

I think this model is the closest to what we have today and is the most obvious. For something like ne2k, I would expect:

class NE2000 : public Device
{
  // ne2k public functions
};

class PCI_NE2000 : public PciDevice
{
  // implement PCI functions by calling ne2k public functions
  NE2000 ne2k;
};

class ISA_NE2000 : public IsaDevice
{
  // implement ISA functions by calling ne2k public functions
  NE2000 ne2k;
};

* a device is composed with a connector object. There is no PCIDevice class
anymore, so the bus has an array of socket<PCIConnector> instead. The case above
would look like this

Device
NE2000 (abstract)
PCI_NE2000 ------> includes a PCIConnector
ISA_NE2000 ------> includes an ISAConnector

Or, if you insist on a closer mapping of real hardware, where there are no
abstract classes, it would look like this:

Device
NE2000
PCI_NE2000 ------> includes an NE2000 and a PCIConnector
ISA_NE2000 ------> includes an NE2000 and an ISAConnector

I think there are two ways to view this:

class PciDevice : public Device
{
   PciConnector connector;
   // init function registers closures with connector that dispatch
   // to abstract functions
};

Or:

class PciConnector : public PciDevice
{
   // provides interfaces to register closures which implement
   // PCI abstract functions
};

I personally lean toward the later as I don't think the PciConnector model really does map all that well to hardware (normally, at least). I think this is much closer to how real hardware actually works.


Advantages of abstract classes are pretty obvious, so I will just list them: it
is more similar to what is done in QDev, and perhaps it is more intuitive.


Advantages of connectors include:

* it is more flexible: it lets you choose between a more abstract and a more
low-level representation (the two hierarchies above);

* you have the option of showing a simpler device tree to the user, without the
internal composition. This is important because, unlike QDev, composition in QOM
is explicit. So QOM would place NIC properties in NE2000, not in *_NE2000 
(right?).

* related to this, it keeps property names more stable. If I understand
correctly, if the device starts as ISA-only or PCI-only, i.e.:

Device
PCIDevice
PCI_NE2000

and later you change it to support multiple buses, suddenly properties would
have to be addressed differently to account for the composition of NE2000 inside
PCI_NE2000. You could I guess implement "forwarder properties", but that would
also lead to more boilerplate code.

Any other opinions?

The properties thing is definitely an interesting point, but I'm not sure how far you can push it. If you start out with a NE2000 device that is ISA and you decide to abstract it to a shared model, all you need to do is keep the ISA NE2000 device named NE2000 and call the common chip and PCI bridge something else.

I really think it's important to keep the simple cases simple. I think any model where you don't do:

class E1000 : public PciDevice
{
};

Is unnecessarily complicated. If it's too complicated, conversions will be much slower to do and will be more likely to be done wrong.

Regards,

Anthony Liguori

Paolo





reply via email to

[Prev in Thread] Current Thread [Next in Thread]