qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
Date: Tue, 26 Jul 2011 20:26:16 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20110707 Thunderbird/5.0

On 07/26/2011 05:34 PM, Anthony Liguori wrote:
And as such it can add data members. But when a device is on two buses,
you cannot have both of them adding data members. I know MI is hard to
get right, and in fact I'm not proposing to do MI---not even interface
inheritance. I don't want to have any base class but DeviceState.

I could use a concrete example here, but here's how this would be
expressed:

class MyWeirdDevice : public MyBaseDevice, implements PciDevice, IsaDevice
{
PciBus *pci_bus;
IsaDevice *isa_bus;
};

Which actually models hw pretty well. A device that exists on two busses
has to have two sockets that can accept the plugs from the busses
they're joining.

It's pretty much exactly how it works in real life.

You could just as well say that real life works like this:

class PciSocket {
    PciBus *pci_bus;
    uint8_t *config;
    uint8_t *cmask;
    uint8_t *wmask;
    uint8_t *w1cmask;
    uint8_t *used;
    uint32_t devfn;
    char name[64];
    PCIIORegion io_regions[PCI_NUM_REGIONS];
    ...

};

class IsaSocket {
    IsaBus *isa_bus;
    uint32_t isairq[2];  // not sure this is a good idea, just
    int nirqs;           // mimicking qdev
    uint16_t ioports[32];// statically assigned unlike PCI bars
    int nioports;
}

class MyWeirdDevice : public MyBaseDevice {
    PciSocket pci;
    IsaSocket isa;
};


Yes, this is pretty much what I had imagined. But it does not scale to a
topology where you have two parents, both of which want to add data
members.

Which would be true MI. The problem with true MI is that you'll end up
with a diamond if you try to have anything useful (like properties) in
the base.

See above for how you would avoid that.

1) in a flexible manner, so that it can express complex topologies (as
long as "plugs" and "sockets" have the same shape of course);

Right, this is what we do today in QOM. Plugs and Sockets are typed.
Those types can be interfaces or base classes so there's a lot of
flexibility.

Interfaces (is-a) are less flexible than embedded objects (has-a).

It depends on what you're trying to model I guess. In some cases where
the interface is more or less stateless or that state isn't common among
implementations, interfaces are quite nice.

Yes, I'm not sure this is the case here. :)

 > Same as IDE when you used to set
jumpers to choose master/slave. Or ISA interrupt lines.

The ISA dip switches literally select which line of the bus gets routed
to the device. All devices have access to all interrupt lines through
the bus.

So when modelling, it makes sense to have the irq be a property of the
device and then to have the bus interface expose the irqs. For instance:

struct IsaBusClass
{
void (*set_irq_level)(IsaBus *bus, int irq, bool level);
};

Agreed. Though I'm not sure that the same is true for all fields in qemu's current PCIDevice.

Once you have something like this for a device that bridges two buses,
interfaces require a lot of boilerplate for useless getters/setters.

Can you elaborate?

If you store data (configuration space etc.) in the device, and the bus has to access it, you need getters/setters in the interface. Letting the bus hold an interior reference to the PciSocket (perhaps adding a single get_device_for_socket function to the PciSocketOps) solves the problem.

The same applies equally to IDE.

ide->primary.master = disk1;
ide->secondary.master = cdrom;

For IDE, an equally good model would be:

ide->primary.add(disk1);
disk1.masterSlave = MASTER;
ide->secondary.add(cdrom);
cdrom.masterSlave = MASTER;

There's a pin in the IDE cable that determines master or slave depending
on whether it's raised high.

Yes, that's the "newer" way. There used to be jumpers to choose between master, slave and cable-select.

I think modelling it that way makes more sense from an end user
perspective since it prevents the possibility of have two master devices
(which is incorrect).

... but you could do that, if for some reason you wanted to model the jumper-based world. But this is a mostly irrelevant digression.

Interfaces are the right way to do this. Getting MI right is fairly hard

But we don't need is-a, we need has-a. Multiple is-a is harder than
single is-a. Multiple has-a does not add any complication.

Yeah, that's what plug properties are for :-)

I agree, but at the cost of pointer chasing and making it harder to implement get_device_for_socket for buses that need it (in the above sketch it can be a simple container_of).

I think all of the requirements you've outlined are currently handled in
QOM.

They more than likely are. The question is whether they're handled in
the most programmer-efficient manner, and whether the advantages of a
single grand unified object model for host and guest devices is worth
the effort.

Indeed. I think that it's a no brainer for the backends and that's why
I'm starting there.

I don't think it's a no brainer. It's simply much easier, but right now it is also a solution in search of a problem (if all you want is dynamic creation of character devices, you could do that without a generic object model).

If starting from a blank slate, I would be much more enthusiastic. But all that QEMU does _not_ need is yet another incomplete transition.

Paolo



reply via email to

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