Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 07:59 PM, Anthony Liguori wrote: Just define an interface that returns a struct then. It's no more complicated than that. Ok, so we're debating whether to: 1) add an interface returning a pointer to an internal struct; 2) include in the internal struct a pointer-to-function that does a container_of and returns the outer Device object. Otherwise, we're on the same page. I'm quite relieved. ;) I can see advantages to both approach. The main advantage to (2) is that it scales better when you have multiple interfaces of the same kind exposed by the device. You cannot implement an interface twice. Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 10:01 PM, Anthony Liguori wrote: That's milkymist, not GoldFish. Oh, Goldfish is fake. It's not real hardware. The enumerator device is not a real device. It's weird because it's imaginary and was designed specifically within QEMU. It's not a good example for discussing modelling. There are plenty of PV interfaces implemented by QEMU. Would you say the same of virtio? Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 02:36 AM, Paolo Bonzini wrote: On 07/27/2011 10:01 PM, Anthony Liguori wrote: That's milkymist, not GoldFish. Oh, Goldfish is fake. It's not real hardware. The enumerator device is not a real device. It's weird because it's imaginary and was designed specifically within QEMU. It's not a good example for discussing modelling. There are plenty of PV interfaces implemented by QEMU. Would you say the same of virtio? Virtio was designed to look like real hardware. I would say that trying to fit XenStore into QOM would not be a good exercise. Regards, Anthony Liguori Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 02:46 PM, Anthony Liguori wrote: There are plenty of PV interfaces implemented by QEMU. Would you say the same of virtio? Virtio was designed to look like real hardware. I would say that trying to fit XenStore into QOM would not be a good exercise. No doubt about that. :) I'd put a lot more hope into Goldfish though. Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 08:50 AM, Paolo Bonzini wrote: On 07/28/2011 02:46 PM, Anthony Liguori wrote: There are plenty of PV interfaces implemented by QEMU. Would you say the same of virtio? Virtio was designed to look like real hardware. I would say that trying to fit XenStore into QOM would not be a good exercise. No doubt about that. :) I'd put a lot more hope into Goldfish though. What's unclear to me about the Goldfish enumerator is whether it should be filled out through interaction with hardware devices or via some other mechanism. In many ways, it's similar to ACPI and a Device Tree. In both of those cases, firmware actually is responsible for constructing those tables. Regards, Anthony Liguori Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 04:03 PM, Anthony Liguori wrote: No doubt about that. :) I'd put a lot more hope into Goldfish though. What's unclear to me about the Goldfish enumerator is whether it should be filled out through interaction with hardware devices or via some other mechanism. In many ways, it's similar to ACPI and a Device Tree. In both of those cases, firmware actually is responsible for constructing those tables. Yes, it is a flat device tree. Since it supports hotplug (at least in theory, the Android emulator predates qdev so it doesn't support it), I would say it is more similar to PCI configuration space. The difference is that IRQ numbers and MMIO base addresses are handed out by hardware (by a piece of the SoC) rather than by the firmware. So yes, the hardware would have some kind of bus to talk to the devices and arbitrate hotplug/hotunplug. The only peculiarity being that the bus enumerator hardcodes itself in the list it exposes, in addition to the devices on the bus. But that still means that the devices have two views: 1) the enumerator's view is either this is my name, my MMIO base, my IRQ base or I need 4k of MMIO and 1 IRQ line, please tell me where/which are those, depending on the device; 2) the PIC's view is please bring this IRQ line up/down (the device says which line, since the enumerator can assign those dynamically). The PIC's view is more complicated than a Pin, and more similar to ISA. Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 09:41 AM, Paolo Bonzini wrote: On 07/28/2011 04:03 PM, Anthony Liguori wrote: No doubt about that. :) I'd put a lot more hope into Goldfish though. What's unclear to me about the Goldfish enumerator is whether it should be filled out through interaction with hardware devices or via some other mechanism. In many ways, it's similar to ACPI and a Device Tree. In both of those cases, firmware actually is responsible for constructing those tables. Yes, it is a flat device tree. Since it supports hotplug (at least in theory, the Android emulator predates qdev so it doesn't support it), I would say it is more similar to PCI configuration space. The difference is that IRQ numbers and MMIO base addresses are handed out by hardware (by a piece of the SoC) rather than by the firmware. So yes, the hardware would have some kind of bus to talk to the devices and arbitrate hotplug/hotunplug. The only peculiarity being that the bus enumerator hardcodes itself in the list it exposes, in addition to the devices on the bus. But that still means that the devices have two views: 1) the enumerator's view is either this is my name, my MMIO base, my IRQ base or I need 4k of MMIO and 1 IRQ line, please tell me where/which are those, depending on the device; I think it's important to ask, how would this be implemented in hardware. The only way I can see is to teach each device about this interface and then have a common bus. That implies that you have: class GoldfishEnumerator : public Device { GoldfishDevice *slots[N]; }; interface GoldfishDevice { const char *get_name(); uint64_t get_mmio_base(); ... }; class GoldfishNic : public Device, implements GoldfishDevice { const char *get_name(void) { return nic; } }; With respect to hotplug, that means that you have to hot plug the device to multiple busses. 2) the PIC's view is please bring this IRQ line up/down (the device says which line, since the enumerator can assign those dynamically). The PIC's view is more complicated than a Pin, and more similar to ISA. ISA is just a pin. The ISA bus extender literally has five pins corresponding to the ISA IRQs 7, 6, 5, 4, 3. EISA adds 5 more pins for 10, 11, 12, 14, 15. ISA devices choose their IRQ line by hardwiring their IRQ output pin to a specific IRQ line on the bus. Regards, Anthony Liguori Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 05:04 PM, Anthony Liguori wrote: The only way I can see is to teach each device about this interface and then have a common bus. That implies that you have: class GoldfishEnumerator : public Device { GoldfishDevice *slots[N]; FWIW, there's no hardcoded limit in the interface, and the list of devices is unordered. But that only means you should attach it with plug-set goldfish_tty::enumerator goldfish_enum rather than plug-set goldfish_enum::slots[12] goldfish_tty If you can confirm that, that's fine. }; interface GoldfishDevice { const char *get_name(); uint64_t get_mmio_base(); ... }; class GoldfishNic : public Device, implements GoldfishDevice { const char *get_name(void) { return nic; } uint64_t mmio_base; uint64_t get_mmio_base() { return mmio_base; } uint64_t set_mmio_base(uint64_t addr) { mmio_base = addr; } }; And that's exactly my point. It's a stupid interface full of getters/setters, which is what you get if you use only interface inheritance instead of, where appropriate, data containment. Interfaces should be reserved for what really depends on the _implementation_ of the GoldfishNic, not for accessing a bunch of numbers. There is no implementation-dependent detail of that kind in the GoldfishDevice (unlike other buses, even simple ones like I2C). The PIC's view is more complicated than a Pin, and more similar to ISA. ISA is just a pin. The ISA bus extender literally has five pins corresponding to the ISA IRQs 7, 6, 5, 4, 3. ISA is many pins. :) Goldfish looks similar (32 pins). Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/28/2011 10:47 AM, Paolo Bonzini wrote: On 07/28/2011 05:04 PM, Anthony Liguori wrote: The only way I can see is to teach each device about this interface and then have a common bus. That implies that you have: class GoldfishEnumerator : public Device { GoldfishDevice *slots[N]; FWIW, there's no hardcoded limit in the interface, and the list of devices is unordered. But that only means you should attach it with plug-set goldfish_tty::enumerator goldfish_enum rather than plug-set goldfish_enum::slots[12] goldfish_tty If you can confirm that, that's fine. Yes, you can certainly have an enumerator socket that when set, automatically connects the appropriate properties in the enumerator. That way you don't have to connect things by hand. }; interface GoldfishDevice { const char *get_name(); uint64_t get_mmio_base(); ... }; class GoldfishNic : public Device, implements GoldfishDevice { const char *get_name(void) { return nic; } uint64_t mmio_base; uint64_t get_mmio_base() { return mmio_base; } uint64_t set_mmio_base(uint64_t addr) { mmio_base = addr; } }; And that's exactly my point. It's a stupid interface full of getters/setters, which is what you get if you use only interface inheritance instead of, where appropriate, data containment. You can certainly do: struct GoldfishEnumInfo { const char *name; uint64_t mmio_base; }; interface GoldfishDevice { GoldfishEnumInfo *get_info(); } And then: GoldfishEnumInfo *goldfish_nic_get_info(GoldFishNic *nic) { return nic-enuminfo; } Interfaces should be reserved for what really depends on the _implementation_ of the GoldfishNic, not for accessing a bunch of numbers. Just define an interface that returns a struct then. It's no more complicated than that. What I struggle with is whether you're suggesting that the info isn't part of the device or whether it is part of the device and you just think that we shouldn't need 10 different accessors. There is no implementation-dependent detail of that kind in the GoldfishDevice (unlike other buses, even simple ones like I2C). The PIC's view is more complicated than a Pin, and more similar to ISA. ISA is just a pin. The ISA bus extender literally has five pins corresponding to the ISA IRQs 7, 6, 5, 4, 3. ISA is many pins. :) Goldfish looks similar (32 pins). Sorry, I meant to say ISA IRQs are just exposed as pins. My real point is, doing: class IsaDevice : public Device { Pin irq[16]; }; class MyIsaDevice : public IsaDevice { int irq_index; }; And then doing: my_isa_device-irq_index = 5; Is a very good way to model ISA IRQ selection. You can simplify it by having a single IRQ output for each ISA device instead of any possible IRQ and then route the IRQ as part of the bus connection. Regards, Anthony Liguori Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/26/2011 09:23 PM, Anthony Liguori wrote: On 07/26/2011 01:26 PM, Paolo Bonzini wrote: On 07/26/2011 05:34 PM, Anthony Liguori wrote: 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; }; Hrm, I'm not sure I buy that entirely. I think it would be: class MyWeirdPciView : public PciDevice { PciBus *bus; MyWeirdDevice *dev; }; class MyWeirdIsaView : public IsaDevice { IsaBus *bus; MyWeirdDevice *dev; }; class MyWeirdDevice : public MyBaseDevice { MyWeirdPciView pci; MyWeirdIsaView isa; } The views are basically bridges between PCI/ISA and an internal interface (MyWeirdDevice). That's yet another possibility. There are two difference with what I had written: 1) the back-pointer from MyWeird*View to MyWeirdDevice replaced by container_of. That's cosmetic; 2) I'm not considering the sockets to be separate devices. That's the difference between proxying PCI to another device (wrong, hardware does not do that) and isolating PCI knowledge within a sub-object of the device (just an encapsulation choice, hardware is irrelevant). I don't think the proxy design pattern is the right thing to use. 95% of the time, the device is intrinsically a PCI device. It's not a proxy. It's replacing inheritance with containment to get the flexibility of data MI without the complexity of diamond hierarchies. The other 5% of the time, the device has a well defined interface, and then there is effectively a PCI bridge. But that PCI bridge isn't generic, it's specific to that custom interface. Yes, that can be represented by composition if you wish (an ISASerialState containing an 8250 is the canonical example; the 8139 example below is another). 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. That jumper raises the bit on the wire. Ah ok, I was confusing it with the cable-select wire. My point was that you can choose the jumper representation (low-level) or the cable-select representation (high-level, actually matches modern hardware, even better from the user POV). One is easier to manage and better in all aspects, but both make sense. It's irrelevant to this discussion anyway. 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). Can we be a bit more concrete as I'm having a hard time following your logic. You're assuming a generic PciSocket class, right? I think that's not the right approach, as an example: class Rtl8139PciBridge : public PciDevice { Rtl8139 rtldev; }; class Rtl8139IsaBridge : public IsaDevice { Rtl8139 rtldev; }; With Avi's new memory API, we'd have: class Rtl8139 : public Device { MemoryRegion region[2]; Pin irq; }; And then the construction code for Rtl8139PciBridge would register the regions as bars, and connect the PCI lnk to rtldev.irq. The ISA code would do something similar. Yes, this looks nice (modulo s/Rtl8139/Rtl8139 */). But it is not that much more flexible than qdev 1.0. You're right that for the case of two parents above we were looking at a contrived example. The Goldfish platform provides a more interesting one. There you have an interrupt controller and a bus enumerator device. Most devices are connected to both, but conflating them is wrong for many reasons; 1) the bus enumerator itself uses an interrupt (raised on hotplug); 2) you can enumerate devices that do not have an interrupt line, and you shouldn't need to connect such a device to an interrupt controller; 3) the interrupt controller and bus enumerator use two separate MMIO areas; 4) in principle, other devices could use the interrupt controller (which is the only component connected to the CPU's interrupt line) without being enumerated. 5) A device with two interrupts has two interrupt interfaces and only one enumerator interface. 6) The enumerator interface does not have bus semantics. The enumerator also enumerates itself so it would act as both the bus host and a device on the bus. Composition then lets you use something like this: class
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 03:55 AM, Paolo Bonzini wrote: Yes, this looks nice (modulo s/Rtl8139/Rtl8139 */). But it is not that much more flexible than qdev 1.0. You're right that for the case of two parents above we were looking at a contrived example. The Goldfish platform provides a more interesting one. There you have an interrupt controller and a bus enumerator device. Most devices are connected to both, but conflating them is wrong for many reasons; 1) the bus enumerator itself uses an interrupt (raised on hotplug); 2) you can enumerate devices that do not have an interrupt line, and you shouldn't need to connect such a device to an interrupt controller; 3) the interrupt controller and bus enumerator use two separate MMIO areas; 4) in principle, other devices could use the interrupt controller (which is the only component connected to the CPU's interrupt line) without being enumerated. 5) A device with two interrupts has two interrupt interfaces and only one enumerator interface. 6) The enumerator interface does not have bus semantics. The enumerator also enumerates itself so it would act as both the bus host and a device on the bus. I think I understand what your saying here. But interrupt routing is an interesting problem and I've been thinking about it differently then we do it today. The core is: class Pin : public Device { bool level; }; You can connect a signal to the level to detect edge changes. You can also connect two pins together such that if one raises high, the other raises high. An interrupt controller looks like: struct InterruptController { Pin *irq[256]; }; In the simple case, you have: struct UART : public Device { Pin irq; }; And then you'd set the irq by doing: apic = new InterruptController() uart = new UART() apic-irq[0] = uart-irq; Or at the qmp layer: (qemu) plug_get uart irq uart::irq (qemu) plug_set apic irq[0] uart::irq I mention this because I don't think your example below assumes a model like this. Composition then lets you use something like this: class GoldfishPIC : Device { Pin parent; GoldfishInterruptPin *children[32]; Pin (*init_socket_for_irq_num) (GoldfishInterruptPin *, int); }; So the idea here is that the PIC will multiplex a bunch of interrupts into a single line? I would do this simply as: class GoldfishPIC : Device { Pin out; Pin *in[32]; }; The IRQ number is implicit in the socket index, no? I'm also not sure that there's a strong need to have a typed Pin. class GoldfishInterruptPin { GoldfishPIC *pic; Pin irqnum; }; class GoldfishEnumerator : Device { GoldfishInterruptPin irq; GoldfishBusDeviceInfo info; ListGoldfishBusDeviceInfo allDevices; ... }; class GoldfishBusDeviceInfo { GoldfishEnumerator *parent; char *name; int id; ram_addr_t mmio; int mmio_size; int irq_base; int irq_count; }; Is the enumerator something that has an interface to devices where the devices hold this info? Or is the enumerator just a bank of flash that's preprogrammed with fixed info? If it's the later, I would suggest that we model is in that fashion. No need to teach every single device about the enumerator if they wouldn't normally have information about it. We need lots of new transitions, we need to strive to make things better. But we need to do things in such a way that: (1) we have a good idea of what we're going to end up with at the end of the day (2) there is incremental value being added to QEMU at every step of the way This cannot be done by simply hacking some bits here and there. It requires design, planning, and flag days when appropriate. Agreed. The problem I have with QOM is (2). I am not sure we do get incremental value at every step of the way. We do get incremental value in the char layer, but we also get additional complexity until the transition is over. So roughly speaking, my plan is: 1) Char layer - we get dynamic add of CDS, which enables hot plug of virtio-serial - we get ability to change CDS properties dynamically 2) Block layer - we get -blockdev 3) Display layer - we get dynamic add of VGA devices 4) fsdev - dynamic add of virtio-9p devices 5) network layer - no new features, but better commonality At each phase, we also get significantly better modularity. The block layer is already good here, but the other backends aren't. My only real concern is how to attack the device layer incrementally. I don't think it's impossible but it requires careful thought. I think we can probably retrofit DeviceState as a QOM base class and just systematically convert the types over to QOM. The next step would be to change the property registration to be QOM-like. I think they we could probably push out a lot of what's in DeviceState today into another base class, then introduce a better Device base class. Since a lot of subsystems should just inherit from Device, that gives us a nice way to attack things one subsystem at a time. I think an approach like this
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 02:48 PM, Anthony Liguori wrote: So the idea here is that the PIC will multiplex a bunch of interrupts into a single line? Yes, but the device needs to know the interrupt number so it can expose it through the enumerator interface. So the configuration cannot be simply pic-irq[n] = tty-irq; Logically, it's more similar to the ISA case, but I doubt the PIC distributes all interrupts to everyone in real hardware. Is the enumerator something that has an interface to devices where the devices hold this info? Or is the enumerator just a bank of flash that's preprogrammed with fixed info? The former, at least in theory. Not sure if it also works that way in real hardware, but that's the model it exposes and the way the Android guys implemented it. The device model provides hotplug support, so it is definitely not just flash. Not sure again if this support is used in the hardware. At each phase, we also get significantly better modularity. Fine, but when do we decide it's good enough to merge it? And what if it turns out that it's not suitable for devices? We unified some things, but we also dug ourselves in NIH when we could have used GObject. (GObject definitely does not work for devices, but at least we don't need to write the infrastructure). My only real concern is how to attack the device layer incrementally. I don't think it's impossible but it requires careful thought. No idea here, honestly. :) Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 10:33 AM, Paolo Bonzini wrote: On 07/27/2011 02:48 PM, Anthony Liguori wrote: So the idea here is that the PIC will multiplex a bunch of interrupts into a single line? Yes, but the device needs to know the interrupt number so it can expose it through the enumerator interface. So the configuration cannot be simply pic-irq[n] = tty-irq; Logically, it's more similar to the ISA case, but I doubt the PIC distributes all interrupts to everyone in real hardware. Is the enumerator something that has an interface to devices where the devices hold this info? Or is the enumerator just a bank of flash that's preprogrammed with fixed info? The former, at least in theory. Not sure if it also works that way in real hardware, but that's the model it exposes and the way the Android guys implemented it. The device model provides hotplug support, so it is definitely not just flash. Not sure again if this support is used in the hardware. Sounds like I need to read a little about how this enumerator works. I can't see how this would all operate without the enumerating being some form of a bus. At each phase, we also get significantly better modularity. Fine, but when do we decide it's good enough to merge it? I think we should evaluate the complexity vs. value trade off with the character device layer (when fully converted) and make the decision in a vacuum. If the complexity seems too high, I can try to also convert the block layer and we can reevaluate. I believe that just with the character device layer, it's a net win and I don't think it can be dramatically simplified. The patches are actually not a lot of code. The only complexity is conceptual and that's because it takes into account a lot of different problems. I can even pair things down a bit by removing support for Interfaces and simplifying class initialization of need be for the first merge. And what if it turns out that it's not suitable for devices? We unified some things, but we also dug ourselves in NIH when we could have used GObject. (GObject definitely does not work for devices, but at least we don't need to write the infrastructure). I tried to use GObject btw, I can share the results with you if you'd like. Even with backends, I couldn't make properties work. GObject uses GValues for properties which roughly models immutable values in a variant. But I couldn't find a reasonable way to express Plugs and Sockets in terms of GValues. I expect that at some point in the future, GObject will grow GVariant properties. But I still think GVariant isn't quite what it needs to be since it still assumes immutable variants that can be copied. I thought about just using GType but I thought using GType without using GObject was probably not a great long term plan as I doubt anyone else does this. Regards, Anthony Liguori My only real concern is how to attack the device layer incrementally. I don't think it's impossible but it requires careful thought. No idea here, honestly. :) Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 10:33 AM, Paolo Bonzini wrote: On 07/27/2011 02:48 PM, Anthony Liguori wrote: So the idea here is that the PIC will multiplex a bunch of interrupts into a single line? Yes, but the device needs to know the interrupt number so it can expose it through the enumerator interface. So the configuration cannot be simply pic-irq[n] = tty-irq; Logically, it's more similar to the ISA case, but I doubt the PIC distributes all interrupts to everyone in real hardware. Is the enumerator something that has an interface to devices where the devices hold this info? Or is the enumerator just a bank of flash that's preprogrammed with fixed info? The former, at least in theory. Not sure if it also works that way in real hardware, but that's the model it exposes and the way the Android guys implemented it. I can't really find what you're describing. I think all the specs are on http://www.milkymist.org/mmsoc.html It's seems like there are a couple different kinds of busses, and that there is a CSR bus that is used to access configuration information but I believe only for CSR devices (which are low speed). Can you point me towards the current code for this? Regards, Anthony Liguori
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 06:28 PM, Anthony Liguori wrote: On 07/27/2011 10:33 AM, Paolo Bonzini wrote: On 07/27/2011 02:48 PM, Anthony Liguori wrote: So the idea here is that the PIC will multiplex a bunch of interrupts into a single line? Yes, but the device needs to know the interrupt number so it can expose it through the enumerator interface. So the configuration cannot be simply pic-irq[n] = tty-irq; Logically, it's more similar to the ISA case, but I doubt the PIC distributes all interrupts to everyone in real hardware. Is the enumerator something that has an interface to devices where the devices hold this info? Or is the enumerator just a bank of flash that's preprogrammed with fixed info? The former, at least in theory. Not sure if it also works that way in real hardware, but that's the model it exposes and the way the Android guys implemented it. I can't really find what you're describing. I think all the specs are on http://www.milkymist.org/mmsoc.html That's milkymist, not GoldFish. You can see the code at https://github.com/patricksjackson/qemu/blob/android/hw/goldfish_device.c (see also https://github.com/patricksjackson/qemu/blob/android/hw/goldfish_device.h for the structs composing the list). Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 01:51 PM, Paolo Bonzini wrote: On 07/27/2011 06:28 PM, Anthony Liguori wrote: On 07/27/2011 10:33 AM, Paolo Bonzini wrote: On 07/27/2011 02:48 PM, Anthony Liguori wrote: So the idea here is that the PIC will multiplex a bunch of interrupts into a single line? Yes, but the device needs to know the interrupt number so it can expose it through the enumerator interface. So the configuration cannot be simply pic-irq[n] = tty-irq; Logically, it's more similar to the ISA case, but I doubt the PIC distributes all interrupts to everyone in real hardware. Is the enumerator something that has an interface to devices where the devices hold this info? Or is the enumerator just a bank of flash that's preprogrammed with fixed info? The former, at least in theory. Not sure if it also works that way in real hardware, but that's the model it exposes and the way the Android guys implemented it. I can't really find what you're describing. I think all the specs are on http://www.milkymist.org/mmsoc.html That's milkymist, not GoldFish. Oh, Goldfish is fake. It's not real hardware. The enumerator device is not a real device. It's weird because it's imaginary and was designed specifically within QEMU. It's not a good example for discussing modelling. Regards, Anthony Liguori You can see the code at https://github.com/patricksjackson/qemu/blob/android/hw/goldfish_device.c (see also https://github.com/patricksjackson/qemu/blob/android/hw/goldfish_device.h for the structs composing the list). Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 26 July 2011 15:02, Anthony Liguori anth...@codemonkey.ws wrote: In my attempt at PCI modelling, I had something like: struct I440FX { Device parent; PciDevice slots[32]; }; Which means that to attach to bus 0, slot 3, fn 0, you do: i440fx-slots[3] = mydevice So what I don't really understand about this model is why the PCI connection is privileged in the sense that 'mydevice' is actually an instance of something you can stick directly into one of the PCIBus device's slots. I would expect that 'mydevice' would have a bunch of (effectively) interfaces it exposed, and you'd connect i440fx-slots[3] to mydevice.pciconnector or something. [Which ought to both let the PCIBus call functions implemented by the device, and vice versa.] (What would a model of a two-PCI-slot graphics card look like?) Maybe it would be better to use some other example. After all, the cases like PCI are the ones our device model already handles pretty well, so the interesting cases to look at are where we're not so good at it. What does the implementation of omap2_gpio look like, for instance? (it's not qdev at the moment but there's a set of patches on the list which make it so; the guts of the qdevification are http://patchwork.ozlabs.org/patch/103905/ .) That's a device which exposes: * 4,5, or 6 MMIO regions (depending on how many 'modules' the particular revision you ask for has) * a variably sized array of gpio inputs * ditto, gpio outputs * for each 'module', three specific named outgoing gpio lines mpu_irq, dsp_irq and wakeup * a number of omap_clk connections, where an omap_clk* represents a connection to the OMAP clock tree, and in practice is an interface where the omap_gpio can (a) call a function to ask what rate is this clock running at? and (b) provide a gpio line which will be raised when the clock ticks. [omap_gpio doesn't actually use its clock connections but other omap devices do; they're interesting because we have function calls going in both directions over the interface.] None of these exposed interfaces are particularly obviously more important than any of the others -- they're just all things that might need to be wired up. I'm particularly interested in how much effort is involved in defining ad-hoc platform-specific interface types like omap_clk. -- PMM
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/27/2011 04:33 PM, Peter Maydell wrote: On 26 July 2011 15:02, Anthony Liguorianth...@codemonkey.ws wrote: In my attempt at PCI modelling, I had something like: struct I440FX { Device parent; PciDevice slots[32]; }; Which means that to attach to bus 0, slot 3, fn 0, you do: i440fx-slots[3] = mydevice So what I don't really understand about this model is why the PCI connection is privileged in the sense that 'mydevice' is actually an instance of something you can stick directly into one of the PCIBus device's slots. Oh, it's not privileged at all. It just happens to be that modelling something simple is simple. That's goodness. The example that I used for most of my early testing was meant to be a bit more interesting. I created a Source, Sink, XorGate, AndGate, and OrGate and then used a config file to build a full working 8-bit adder. You can see this at: http://repo.or.cz/w/qemu/aliguori.git/blob/refs/heads/qdev2 Check out devices/gates and vm.cfg. Here's a rough model of how it works: struct XorGate { Device parent; Pin out; Pin *in[2]; }; In XorGate's initfn, it registers three properties, 'in[0]' and 'in[1]' as 'socketPin's and 'out' as 'plugPin'. When XorGate is realized, it makes sure that both in[0] and in[1] have been set (sockets are RW whereas plugs are RO). It then connects to the edge event on the in[0] and in[1] pins and when either event fires, it will compute a value, and set the level of out. XorGate is-a Device, but so is Pin. The following things are valid: (qemu) plug_create xor-gate gate0 (qemu) plug_create xor-gate gate1 (qemu) plug_create xor-gate gate2 (qemu) plug_get gate1 out gate1::out (qemu) plug_set xor-gate in[0] gate1::out (qemu) plug_get gate2 out gate2::out (qemu) plug_set xor-gate in[1] gate2::out Which creates a simple tree of two xor gates who's outputs are tied to another xor gate. Or: XorGate / - XorGate /\ \ XorGate / \ The 'out' property of XorGate is really a child device. All devices (all plugs for that matter) have a global namespace. By convention, uniqueness in name is guaranteed for child devices by reserving the '::' separator and naming children based on 'parentname::propertyname'. But for correctness, the right way to figure out the name of a child is by reading the property. So to answer your above question, a multi PCI slot graphics adapter is simply: struct GraphicsSlot { PciDevice parent; }; struct MultislotGraphicsCard { Device parent; GraphicsSlot slot[2]; }; Then conceptually: mgc = new MultislotGraphicsCard(); i440fx-slot[1] = mgc.slot[0]; i440fx-slot[2] = mgc.slot[1]; You do not need to ever assign a device directly to a socket. This is a fundamental different between QOM and qdev. There is no concept of parent bus. There's no concept of parent--even with composition. Devices can have links to zero or more other Devices. They can also create devices within themselves but those devices don't have any special knowledge of that fact. I would expect that 'mydevice' would have a bunch of (effectively) interfaces it exposed, and you'd connect i440fx-slots[3] to mydevice.pciconnector or something. [Which ought to both let the PCIBus call functions implemented by the device, and vice versa.] (What would a model of a two-PCI-slot graphics card look like?) Maybe it would be better to use some other example. After all, the cases like PCI are the ones our device model already handles pretty well, so the interesting cases to look at are where we're not so good at it. What does the implementation of omap2_gpio look like, for instance? (it's not qdev at the moment but there's a set of patches on the list which make it so; the guts of the qdevification are http://patchwork.ozlabs.org/patch/103905/ .) That's a device which exposes: * 4,5, or 6 MMIO regions (depending on how many 'modules' the particular revision you ask for has) * a variably sized array of gpio inputs * ditto, gpio outputs struct OmapGpio { Device parent; size_t nb_regions; MemoryRegion *regions; size_t nb_out; Pin *out; size_t nb_in; Pin **in; }; void omap_gpio_set_nb_out(OmapGpio *obj, size_t value); void omap_gpio_set_nb_in(OmapGpio *obj, size_t value); void omap_gpio_set_nb_regions(OmapGpio *obj, size_t value); At initfn(), you register three integer properties, 'nb_out', 'nb_in', 'nb_regions'. In the respective setters, you allocate the appropriate array and then unregister the old properties, and then register teh new ones. For instance: void omap_gpio_set_nb_out(OmapGpio *obj, size_t value) { /* remove old properties */ for (i = 0; i obj-nb_out; i++) { plug_del_property_plug(PLUG(obj), out[%d], i); } obj-out = realloc(obj-out, new_size); obj-nb_out = value; /* add new properties */ for (i = 0; i obj-nb_out; i++) {
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/25/2011 03:44 AM, Anthony Liguori wrote: Hi, This series is the rough beginnings of the QEMU Object Model. This is basically qdev generalized on steroids. This series includes the core infrastructure, a strawman Device type, and the beginnings of the conversion of CharDriverState. This is in a rougher state than I would like it to be but I wanted to get the concepts on the list as soon as possible. My plan is to drop the Device parts from future versions of the series and just focus on backends to start with. I am not sure of how the Device and Char/Block/NetworkDriver bits relate to each other. It seems to me that they are two very different families of objects, and we should treat them differently. For host devices (Char/Block/Network) we have a relatively simple interface but we need a richer way to create and destroy the objects at runtime. We have it already for block and network, we don't for char, but it is done ad hoc for each hierarchy. We do not have a deep hierarchy, in fact there is no hierarchy at all (only one abstract class per subsystem). Honestly, it is not too bad. It may not be the cleanest code, but is it worth the kind of ramifications that your patch has? Of course, the answer could be yes if the same model can be applied to devices. Devices do have the same introspection needs more or less, and I like your ideas there. However, the requirements are very different in terms of composition. Also because there is no hierarchy, composition in host devices can be done very easily. A decorator for char/block devices, such as a tee device, can treat the wrapped object(s) the same independent of the actual class. A simple vtable works very well. GObject would also do well, unifying the introspection at the cost of significantly more boilerplate. (Of course, we could rewrite QEMU in Vala). For *guest* devices, however, this is not the case. The PCI host needs to know that the device on the other end is a PCI device. Even the simplest bus, for example I2C, has methods defined on its children. So, the most important point, it seems to me, is to support composition effectively. There need not be any hierarchy at all---not even the two-level hierarchy we have now, everything can inherit from DeviceState---but the combination between devices must be: 1) in a flexible manner, so that it can express complex topologies (as long as plugs and sockets have the same shape of course); 2) in an easily introspectable manner, so that migration and QMP and so on work very well in the presence of said topologies; 3) in a precise manner, so that the two devices being connected can interact effectively; The current qdev fails completely at (1). (2) is very limited if you consider qdev only; qdev+VMState is at least decent, though nowhere near the potential of QOM. However, qdev gets (3) right by making interaction between the parent and the child go through a bus object that knows the details of both. In particular, bus objects and their vtable structures are very effective in qdev because they provide flexibility and avoid impedence mismatch, with a very limited amount of boilerplate. By contrast, the plug/socket model in QOM achieves (1) and (2), but in my opinion it fails at (3). The model for example is not effective in specifying the properties of the socket, which are roughly are the bus properties and the fields added by DeviceState abstract subclasses in the current qdev; it is not clear where they would live in QOM. Perhaps in the parent device or in an intermediate object between the parent and the child; if the latter, it looks like a lot of pointer chasing and a conversion nightmare. Based on my earlier conversations with Peter, I thought a bit on how to do more incremental changes to qdev in order to overcome the inflexibility. Here is a rough overview of the steps: 1) make properties more flexible. In particular, we *absolutely* need array properties, either static or dynamic. The current special casing of GPIO pins is required exactly because we do not have arrays of properties. Also, since arrays occur a lot in the device state, array properties would also be required to be able to introspect on run-time properties (which are now part of VMState only). However, I am not going to consider run-time introspection much more. It is a simple matter of programming if your general introspection design is done right. 2) add more kinds of first-class (user specifiable) properties. GPIO pins, for example, which are already part of qdev but cannot be specified by the user on the command line. Possibly memory regions too. Anything that can be used to configure a device (with respect to the main bus or to its parent) should be a property. 3) at this point, you can get rid of the specialties of SysBus devices. IRQs are an array of GPIO properties, same for memory regions. SysBus
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/26/2011 07:59 AM, Paolo Bonzini wrote: For host devices (Char/Block/Network) we have a relatively simple interface but we need a richer way to create and destroy the objects at runtime. We have it already for block and network, we don't for char, but it is done ad hoc for each hierarchy. We do not have a deep hierarchy, in fact there is no hierarchy at all (only one abstract class per subsystem). Honestly, it is not too bad. It may not be the cleanest code, but is it worth the kind of ramifications that your patch has? Of course, the answer could be yes if the same model can be applied to devices. Devices do have the same introspection needs more or less, and I like your ideas there. However, the requirements are very different in terms of composition. Also because there is no hierarchy, composition in host devices can be done very easily. A decorator for char/block devices, such as a tee device, can treat the wrapped object(s) the same independent of the actual class. A simple vtable works very well. GObject would also do well, unifying the introspection at the cost of significantly more boilerplate. The polymorphism model of QOM is identical to GObject so I'm not sure what you mean here. In the case of tee, it's just an object with two sockets. (Of course, we could rewrite QEMU in Vala). For *guest* devices, however, this is not the case. The PCI host needs to know that the device on the other end is a PCI device. Even the simplest bus, for example I2C, has methods defined on its children. I have PCI patches, but didn't post them in the series. Here's how it works: The PCI host controller, the i440fx, has 32 sockets of PCIDevice. PCIDevice is a base class. The PCI host controller implements a PCIBus interface. The PCIDevices have a socket of a PCIBus Connecting a PCIDevice to the host bus involves setting the socket on the PCI host controller with the PCIDevice and then setting the PCIDevice's bus socket with the host controller. A PCIDevice can also be a PCIBus by implementing the PCIBus interface. This is what enables a PCI bridge to make sense in this model. If you're interested, the tree that has this is http://repo.or.cz/w/qemu/aliguori.git/tree/qdev2:/devices So, the most important point, it seems to me, is to support composition effectively. There need not be any hierarchy at all---not even the two-level hierarchy we have now, everything can inherit from DeviceState---but the combination between devices must be: I think composition is being overloaded here. When I say composition, I mean that one device is created out of multiple other devices. Something like the PIIX3 is composed of an RTC, UART, etc. That's different that connecting up the links in the device tree graph. 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. 2) in an easily introspectable manner, so that migration and QMP and so on work very well in the presence of said topologies; The 'qsh' tree can view the entire device model as a synthetic file system. Plugs are represented as sub directories and sockets as symbolic links. I plan on writing a quick FUSE file system too. There is type information with all of the attributes that's not visible in this view but it's there nonetheless. 3) in a precise manner, so that the two devices being connected can interact effectively; The current qdev fails completely at (1). (2) is very limited if you consider qdev only; qdev+VMState is at least decent, though nowhere near the potential of QOM. However, qdev gets (3) right by making interaction between the parent and the child go through a bus object that knows the details of both. In particular, bus objects and their vtable structures are very effective in qdev because they provide flexibility and avoid impedence mismatch, with a very limited amount of boilerplate. By contrast, the plug/socket model in QOM achieves (1) and (2), but in my opinion it fails at (3). The model for example is not effective in specifying the properties of the socket, which are roughly are the bus properties and the fields added by DeviceState abstract subclasses in the current qdev; There are no properties of the socket. If you look at something like adding a PCI device in qdev, you add a child and set properties of the child to identify how the device sits on the PCI bus. I'd characterize this as awkward, at best. The slot index is not a property of the device, it's a property of how the device is connected to the PCI bus. In my attempt at PCI modelling, I had something like: struct I440FX { Device parent; PciDevice slots[32]; }; Which means that to attach to bus 0, slot 3, fn 0, you do: i440fx-slots[3] = mydevice Likewise, if slot 4 contains a
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/26/2011 04:02 PM, Anthony Liguori wrote: Also because there is no hierarchy, composition in host devices can be done very easily. A decorator for char/block devices, such as a tee device, can treat the wrapped object(s) the same independent of the actual class. A simple vtable works very well. GObject would also do well, unifying the introspection at the cost of significantly more boilerplate. The polymorphism model of QOM is identical to GObject so I'm not sure what you mean here. GObject instead of QOM (just so that we have something that is already written). In the case of tee, it's just an object with two sockets. Yes, understood. I have PCI patches, but didn't post them in the series. Here's how it works: The PCI host controller, the i440fx, has 32 sockets of PCIDevice. PCIDevice is a base class. 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. The PCI host controller implements a PCIBus interface. The PCIDevices have a socket of a PCIBus Connecting a PCIDevice to the host bus involves setting the socket on the PCI host controller with the PCIDevice and then setting the PCIDevice's bus socket with the host controller. A PCIDevice can also be a PCIBus by implementing the PCIBus interface. This is what enables a PCI bridge to make sense in this model. If you're interested, the tree that has this is http://repo.or.cz/w/qemu/aliguori.git/tree/qdev2:/devices 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. 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). There are no properties of the socket. If you look at something like adding a PCI device in qdev, you add a child and set properties of the child to identify how the device sits on the PCI bus. I'd characterize this as awkward, at best. The slot index is not a property of the device, it's a property of how the device is connected to the PCI bus. Yes, for a PCI address I agree. But in a (parallel) SCSI bus, the LUN is logically a property of the device. Same as IDE when you used to set jumpers to choose master/slave. Or ISA interrupt lines. Once you have something like this for a device that bridges two buses, interfaces require a lot of boilerplate for useless getters/setters. i440fx-slots[3] = mydevice Likewise, if slot 4 contains a PCI-to-PCI bridge that ends up being bus 1, and you want to assign to bus 1, slot 2, fn 0: i440fx-slots[4]-slots[2] = myotherdevice; Now you may observe that this is awkward compared to saying bus 1. No, I have no problem with that. :) 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; 5) convert buses to compound properties. Rather than inheriting from PCIDevice, a PCI device would inherit straight from DeviceState and include a PCIDevice struct that defines the backlink from a device to its parent. Note that since we're using C, this is not a big change from what we're doing now! (Inheritance by containment is a special case of containment.) And it allows to define very flexibly a device that would have to sit on two or more buses in the current qdev model. More importantly, it keeps the effectiveness of the qbus ops model, while removing the constraint of a tree topology. 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. 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. Paolo
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/26/2011 09:35 AM, Paolo Bonzini wrote: On 07/26/2011 04:02 PM, Anthony Liguori wrote: Also because there is no hierarchy, composition in host devices can be done very easily. A decorator for char/block devices, such as a tee device, can treat the wrapped object(s) the same independent of the actual class. A simple vtable works very well. GObject would also do well, unifying the introspection at the cost of significantly more boilerplate. The polymorphism model of QOM is identical to GObject so I'm not sure what you mean here. GObject instead of QOM (just so that we have something that is already written). In the case of tee, it's just an object with two sockets. Yes, understood. I have PCI patches, but didn't post them in the series. Here's how it works: The PCI host controller, the i440fx, has 32 sockets of PCIDevice. PCIDevice is a base class. 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. The PCI host controller implements a PCIBus interface. The PCIDevices have a socket of a PCIBus Connecting a PCIDevice to the host bus involves setting the socket on the PCI host controller with the PCIDevice and then setting the PCIDevice's bus socket with the host controller. A PCIDevice can also be a PCIBus by implementing the PCIBus interface. This is what enables a PCI bridge to make sense in this model. If you're interested, the tree that has this is http://repo.or.cz/w/qemu/aliguori.git/tree/qdev2:/devices 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. The common solution is to have the ability to has-a implementation of the interface. 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. There are no properties of the socket. If you look at something like adding a PCI device in qdev, you add a child and set properties of the child to identify how the device sits on the PCI bus. I'd characterize this as awkward, at best. The slot index is not a property of the device, it's a property of how the device is connected to the PCI bus. Yes, for a PCI address I agree. But in a (parallel) SCSI bus, the LUN is logically a property of the device. 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); }; I don't know enough about SCSI to know whether it makes sense to have LUN be a property of the bus or the device. If LUN negotiation is aided by the controller and fixed after startup, then I think it makes sense for there to be a fixed number of sockets in the bus and then for the bus to do LUN assignment at realize (possibly looking at each device to see what the requested LUN is). 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? i440fx-slots[3] = mydevice Likewise, if slot 4 contains a PCI-to-PCI bridge that ends up being bus 1, and you want to assign to bus 1, slot 2, fn 0: i440fx-slots[4]-slots[2] = myotherdevice; Now you may observe that this is awkward compared to saying bus 1. No, I have no problem with that. :) The same applies equally to IDE. ide-primary.master = disk1; ide-secondary.master = cdrom; For IDE, an equally good model would be:
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
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
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/26/2011 01:26 PM, Paolo Bonzini wrote: 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; }; Hrm, I'm not sure I buy that entirely. I think it would be: class MyWeirdPciView : public PciDevice { PciBus *bus; MyWeirdDevice *dev; }; class MyWeirdIsaView : public IsaDevice { IsaBus *bus; MyWeirdDevice *dev; }; class MyWeirdDevice : public MyBaseDevice { MyWeirdPciView pci; MyWeirdIsaView isa; } The views are basically bridges between PCI/ISA and an internal interface (MyWeirdDevice). I don't think having a generic PciSocket class that offloads PCI knowledge to another device is the right model (assuming that's why you're suggesting). It's basically proxying PCI to another device. 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. I don't think the proxy design pattern is the right thing to use. 95% of the time, the device is intrinsically a PCI device. The other 5% of the time, the device has a well defined interface, and then there is effectively a PCI bridge. But that PCI bridge isn't generic, it's specific to that custom interface. 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. That jumper raises the bit on the wire. 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). Can we be a bit more concrete as I'm having a hard time following your logic. You're assuming a generic PciSocket class, right? I think that's not the right approach, as an example: class Rtl8139PciBridge : public PciDevice { Rtl8139 rtldev; }; class Rtl8139IsaBridge : public IsaDevice { Rtl8139 rtldev; }; With Avi's new memory API, we'd have: class Rtl8139 : public Device { MemoryRegion region[2]; Pin irq; }; And then the construction code for Rtl8139PciBridge would register the regions as bars, and connect the PCI lnk to rtldev.irq. The ISA code would do something similar. 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). And that solves the problem yet again for one layer. But what about block, fsdev, and DisplayState? We can keep
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
Am 25.07.2011 03:44, schrieb Anthony Liguori: Hi, This series is the rough beginnings of the QEMU Object Model. This is basically qdev generalized on steroids. This series includes the core infrastructure, a strawman Device type, and the beginnings of the conversion of CharDriverState. This is in a rougher state than I would like it to be but I wanted to get the concepts on the list as soon as possible. My plan is to drop the Device parts from future versions of the series and just focus on backends to start with. Please note that this series has an awful lot of ramifications. Most of our current command line options would become deprecated, the build system will change significantly, and a lot of our QMP functions will become deprecated. It seems like a lot of change, but hopefully this series illustrates how we can do it very incrementally with value being added at each stage of the conversion. I haven't looked in much detail at it yet, but it has still the same problem I was talking about last week: Patches 17-21 don't actually convert existing code, but they add new code. This means that we can't review only the changes, but have to review the whole code. It also makes conflicts with patches modifying the old version hard to even notice. On another note, I'm not so sure if your renaming is really helpful. It doesn't matter that much with qemu-char because someone thought having the function pointers in CharDriverState was a good idea, but if you're consistent, the rename would go like this in the block layer: BlockDriverState - BlockDriver BlockDriver - BlockDriverClass IMHO, that's not very helpful, but just going to create confusion. We could probably discuss other parts of the terminology, too, but let's save the bikeshedding for later. Kevin
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/25/2011 06:21 AM, Kevin Wolf wrote: Am 25.07.2011 03:44, schrieb Anthony Liguori: Hi, This series is the rough beginnings of the QEMU Object Model. This is basically qdev generalized on steroids. This series includes the core infrastructure, a strawman Device type, and the beginnings of the conversion of CharDriverState. This is in a rougher state than I would like it to be but I wanted to get the concepts on the list as soon as possible. My plan is to drop the Device parts from future versions of the series and just focus on backends to start with. Please note that this series has an awful lot of ramifications. Most of our current command line options would become deprecated, the build system will change significantly, and a lot of our QMP functions will become deprecated. It seems like a lot of change, but hopefully this series illustrates how we can do it very incrementally with value being added at each stage of the conversion. I haven't looked in much detail at it yet, but it has still the same problem I was talking about last week: Patches 17-21 don't actually convert existing code, but they add new code. Actually, it's mostly existing code. In terms of incremental conversion, the most straight forward way is to adds the new version side-by-side with the old version and then remove the old version. Converting in device in place requires some gymnastics. If you think it's absolutely critical, I could try to do it but I'm not sure I agree it's the thing to do. This means that we can't review only the changes, but have to review the whole code. It also makes conflicts with patches modifying the old version hard to even notice. On another note, I'm not so sure if your renaming is really helpful. It doesn't matter that much with qemu-char because someone thought having the function pointers in CharDriverState was a good idea, but if you're consistent, the rename would go like this in the block layer: BlockDriverState - BlockDriver BlockDriver - BlockDriverClass I think we do need to introduce consistent naming conventions. If those conventions are FooState and Foo, that could be okay, but the code base today is absolutely not consistent on it. I think Foo and FooClass is better because Foo is the most common usage of the type and it's less characters to type. Regards, Anthony Liguori IMHO, that's not very helpful, but just going to create confusion. We could probably discuss other parts of the terminology, too, but let's save the bikeshedding for later. Kevin
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
Am 25.07.2011 14:45, schrieb Anthony Liguori: On 07/25/2011 06:21 AM, Kevin Wolf wrote: Am 25.07.2011 03:44, schrieb Anthony Liguori: Hi, This series is the rough beginnings of the QEMU Object Model. This is basically qdev generalized on steroids. This series includes the core infrastructure, a strawman Device type, and the beginnings of the conversion of CharDriverState. This is in a rougher state than I would like it to be but I wanted to get the concepts on the list as soon as possible. My plan is to drop the Device parts from future versions of the series and just focus on backends to start with. Please note that this series has an awful lot of ramifications. Most of our current command line options would become deprecated, the build system will change significantly, and a lot of our QMP functions will become deprecated. It seems like a lot of change, but hopefully this series illustrates how we can do it very incrementally with value being added at each stage of the conversion. I haven't looked in much detail at it yet, but it has still the same problem I was talking about last week: Patches 17-21 don't actually convert existing code, but they add new code. Actually, it's mostly existing code. In terms of incremental conversion, the most straight forward way is to adds the new version side-by-side with the old version and then remove the old version. Converting in device in place requires some gymnastics. If you think it's absolutely critical, I could try to do it but I'm not sure I agree it's the thing to do. Okay, if it isn't possible with reasonable effort, I guess we'll have to bite the bullet and give it a very careful manual review immediately before the merge. By the way, I see that you create new directories. You probably have an idea of what the directory structure will look like after the whole conversion is completed. Can you share this idea with us? This means that we can't review only the changes, but have to review the whole code. It also makes conflicts with patches modifying the old version hard to even notice. On another note, I'm not so sure if your renaming is really helpful. It doesn't matter that much with qemu-char because someone thought having the function pointers in CharDriverState was a good idea, but if you're consistent, the rename would go like this in the block layer: BlockDriverState - BlockDriver BlockDriver - BlockDriverClass I think we do need to introduce consistent naming conventions. If those conventions are FooState and Foo, that could be okay, but the code base today is absolutely not consistent on it. I think Foo and FooClass is better because Foo is the most common usage of the type and it's less characters to type. Maybe. But then, CharDriver is a really bad names for an instance. There is only one driver, which made it a good name for the class until now. Maybe CharBackend and CharBackendClass (or CharBackendDriver) would be a more sensible replacement that follows your pattern. Kevin
Re: [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model
On 07/25/2011 08:08 AM, Kevin Wolf wrote: Am 25.07.2011 14:45, schrieb Anthony Liguori: Okay, if it isn't possible with reasonable effort, I guess we'll have to bite the bullet and give it a very careful manual review immediately before the merge. By the way, I see that you create new directories. You probably have an idea of what the directory structure will look like after the whole conversion is completed. Can you share this idea with us? Just the logic extension of what we have already: block/ chrdrv/ net/ qom/ qapi/ devices/ \ pc/ | pci/ | scsi/ | etc. I think Foo and FooClass is better because Foo is the most common usage of the type and it's less characters to type. Maybe. But then, CharDriver is a really bad names for an instance. There is only one driver, which made it a good name for the class until now. Maybe CharBackend and CharBackendClass (or CharBackendDriver) would be a more sensible replacement that follows your pattern. Good suggestion. I've been thinking that there's like to be a need for a generic Backend base class too so that would work well from a naming convention perspective. Regards, Anthony Liguori Kevin