Diff for /qemu/hw/qdev.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2018/04/24 17:37:39 version 1.1.1.3, 2018/04/24 18:28:31
Line 29 Line 29
 #include "qdev.h"  #include "qdev.h"
 #include "sysemu.h"  #include "sysemu.h"
 #include "monitor.h"  #include "monitor.h"
 #include "qerror.h"  
   
 static int qdev_hotplug = 0;  static int qdev_hotplug = 0;
   
Line 78  static DeviceInfo *qdev_find_info(BusInf Line 77  static DeviceInfo *qdev_find_info(BusInf
     return NULL;      return NULL;
 }  }
   
   static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
   {
       DeviceState *dev;
   
       assert(bus->info == info->bus_info);
       dev = qemu_mallocz(info->size);
       dev->info = info;
       dev->parent_bus = bus;
       qdev_prop_set_defaults(dev, dev->info->props);
       qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
       qdev_prop_set_globals(dev);
       QLIST_INSERT_HEAD(&bus->children, dev, sibling);
       if (qdev_hotplug) {
           assert(bus->allow_hotplug);
           dev->hotplugged = 1;
       }
       dev->instance_id_alias = -1;
       dev->state = DEV_STATE_CREATED;
       return dev;
   }
   
 /* Create a new device.  This only initializes the device state structure  /* Create a new device.  This only initializes the device state structure
    and allows properties to be set.  qdev_init should be called to     and allows properties to be set.  qdev_init should be called to
    initialize the actual device emulation.  */     initialize the actual device emulation.  */
 DeviceState *qdev_create(BusState *bus, const char *name)  DeviceState *qdev_create(BusState *bus, const char *name)
 {  {
     DeviceInfo *info;      DeviceInfo *info;
     DeviceState *dev;  
   
     if (!bus) {      if (!bus) {
         if (!main_system_bus) {          if (!main_system_bus) {
Line 98  DeviceState *qdev_create(BusState *bus,  Line 117  DeviceState *qdev_create(BusState *bus, 
         hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);          hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
     }      }
   
     dev = qemu_mallocz(info->size);      return qdev_create_from_info(bus, info);
     dev->info = info;  
     dev->parent_bus = bus;  
     qdev_prop_set_defaults(dev, dev->info->props);  
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);  
     qdev_prop_set_globals(dev);  
     QLIST_INSERT_HEAD(&bus->children, dev, sibling);  
     if (qdev_hotplug) {  
         assert(bus->allow_hotplug);  
         dev->hotplugged = 1;  
     }  
     dev->state = DEV_STATE_CREATED;  
     return dev;  
 }  }
   
 static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)  static void qdev_print_devinfo(DeviceInfo *info)
 {  {
     int pos = 0;      error_printf("name \"%s\", bus %s",
     int ret;                   info->name, info->bus_info->name);
   
     ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",  
                    info->name, info->bus_info->name);  
     pos += MIN(len-pos,ret);  
     if (info->alias) {      if (info->alias) {
         ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);          error_printf(", alias \"%s\"", info->alias);
         pos += MIN(len-pos,ret);  
     }      }
     if (info->desc) {      if (info->desc) {
         ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);          error_printf(", desc \"%s\"", info->desc);
         pos += MIN(len-pos,ret);  
     }      }
     if (info->no_user) {      if (info->no_user) {
         ret = snprintf(dest+pos, len-pos, ", no-user");          error_printf(", no-user");
         pos += MIN(len-pos,ret);  
     }      }
     return pos;      error_printf("\n");
 }  }
   
 static int set_property(const char *name, const char *value, void *opaque)  static int set_property(const char *name, const char *value, void *opaque)
Line 146  static int set_property(const char *name Line 146  static int set_property(const char *name
         return 0;          return 0;
   
     if (qdev_prop_parse(dev, name, value) == -1) {      if (qdev_prop_parse(dev, name, value) == -1) {
         qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",  
                    name, value, dev->info->name);  
         return -1;          return -1;
     }      }
     return 0;      return 0;
 }  }
   
   int qdev_device_help(QemuOpts *opts)
   {
       const char *driver;
       DeviceInfo *info;
       Property *prop;
   
       driver = qemu_opt_get(opts, "driver");
       if (driver && !strcmp(driver, "?")) {
           for (info = device_info_list; info != NULL; info = info->next) {
               if (info->no_user) {
                   continue;       /* not available, don't show */
               }
               qdev_print_devinfo(info);
           }
           return 1;
       }
   
       if (!qemu_opt_get(opts, "?")) {
           return 0;
       }
   
       info = qdev_find_info(NULL, driver);
       if (!info) {
           return 0;
       }
   
       for (prop = info->props; prop && prop->name; prop++) {
           /*
            * TODO Properties without a parser are just for dirty hacks.
            * qdev_prop_ptr is the only such PropertyInfo.  It's marked
            * for removal.  This conditional should be removed along with
            * it.
            */
           if (!prop->info->parse) {
               continue;           /* no way to set it, don't show */
           }
           error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
       }
       return 1;
   }
   
 DeviceState *qdev_device_add(QemuOpts *opts)  DeviceState *qdev_device_add(QemuOpts *opts)
 {  {
     const char *driver, *path, *id;      const char *driver, *path, *id;
Line 162  DeviceState *qdev_device_add(QemuOpts *o Line 201  DeviceState *qdev_device_add(QemuOpts *o
   
     driver = qemu_opt_get(opts, "driver");      driver = qemu_opt_get(opts, "driver");
     if (!driver) {      if (!driver) {
         qemu_error("-device: no driver specified\n");          qerror_report(QERR_MISSING_PARAMETER, "driver");
         return NULL;  
     }  
     if (strcmp(driver, "?") == 0) {  
         char msg[256];  
         for (info = device_info_list; info != NULL; info = info->next) {  
             qdev_print_devinfo(info, msg, sizeof(msg));  
             qemu_error("%s\n", msg);  
         }  
         return NULL;          return NULL;
     }      }
   
     /* find driver */      /* find driver */
     info = qdev_find_info(NULL, driver);      info = qdev_find_info(NULL, driver);
     if (!info) {      if (!info || info->no_user) {
         qemu_error_new(QERR_DEVICE_NOT_FOUND, driver);          qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
         return NULL;          error_printf_unless_qmp("Try with argument '?' for a list.\n");
     }  
     if (info->no_user) {  
         qemu_error("device \"%s\" can't be added via command line\n",  
                    info->name);  
         return NULL;          return NULL;
     }      }
   
Line 190  DeviceState *qdev_device_add(QemuOpts *o Line 217  DeviceState *qdev_device_add(QemuOpts *o
     path = qemu_opt_get(opts, "bus");      path = qemu_opt_get(opts, "bus");
     if (path != NULL) {      if (path != NULL) {
         bus = qbus_find(path);          bus = qbus_find(path);
           if (!bus) {
               return NULL;
           }
           if (bus->info != info->bus_info) {
               qerror_report(QERR_BAD_BUS_FOR_DEVICE,
                              driver, bus->info->name);
               return NULL;
           }
     } else {      } else {
         bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);          bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
     }          if (!bus) {
     if (!bus) {              qerror_report(QERR_NO_BUS_FOR_DEVICE,
         qemu_error("Did not find %s bus for %s\n",                             info->name, info->bus_info->name);
                    path ? path : info->bus_info->name, info->name);              return NULL;
         return NULL;          }
     }      }
     if (qdev_hotplug && !bus->allow_hotplug) {      if (qdev_hotplug && !bus->allow_hotplug) {
         qemu_error("Bus %s does not support hotplugging\n",          qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
                    bus->name);  
         return NULL;          return NULL;
     }      }
   
     /* create device, set properties */      /* create device, set properties */
     qdev = qdev_create(bus, driver);      qdev = qdev_create_from_info(bus, info);
     id = qemu_opts_id(opts);      id = qemu_opts_id(opts);
     if (id) {      if (id) {
         qdev->id = id;          qdev->id = id;
Line 215  DeviceState *qdev_device_add(QemuOpts *o Line 249  DeviceState *qdev_device_add(QemuOpts *o
         return NULL;          return NULL;
     }      }
     if (qdev_init(qdev) < 0) {      if (qdev_init(qdev) < 0) {
         qemu_error("Error initializing device %s\n", driver);          qerror_report(QERR_DEVICE_INIT_FAILED, driver);
         return NULL;          return NULL;
     }      }
     qdev->opts = opts;      qdev->opts = opts;
Line 245  int qdev_init(DeviceState *dev) Line 279  int qdev_init(DeviceState *dev)
         return rc;          return rc;
     }      }
     qemu_register_reset(qdev_reset, dev);      qemu_register_reset(qdev_reset, dev);
     if (dev->info->vmsd)      if (dev->info->vmsd) {
         vmstate_register(-1, dev->info->vmsd, dev);          vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
                                          dev->instance_id_alias,
                                          dev->alias_required_for_version);
       }
     dev->state = DEV_STATE_INITIALIZED;      dev->state = DEV_STATE_INITIALIZED;
     return 0;      return 0;
 }  }
   
   void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
                                    int required_for_version)
   {
       assert(dev->state == DEV_STATE_CREATED);
       dev->instance_id_alias = alias_id;
       dev->alias_required_for_version = required_for_version;
   }
   
 int qdev_unplug(DeviceState *dev)  int qdev_unplug(DeviceState *dev)
 {  {
     if (!dev->parent_bus->allow_hotplug) {      if (!dev->parent_bus->allow_hotplug) {
         qemu_error("Bus %s does not support hotplugging\n",          qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
                    dev->parent_bus->name);  
         return -1;          return -1;
     }      }
     assert(dev->info->unplug != NULL);      assert(dev->info->unplug != NULL);
Line 282  void qdev_init_nofail(DeviceState *dev) Line 326  void qdev_init_nofail(DeviceState *dev)
 {  {
     DeviceInfo *info = dev->info;      DeviceInfo *info = dev->info;
   
     if (qdev_init(dev) < 0)      if (qdev_init(dev) < 0) {
         hw_error("Initialization of device %s failed\n", info->name);          error_report("Initialization of device %s failed\n", info->name);
           exit(1);
       }
 }  }
   
 /* Unlink device from bus and free the structure.  */  /* Unlink device from bus and free the structure.  */
 void qdev_free(DeviceState *dev)  void qdev_free(DeviceState *dev)
 {  {
     BusState *bus;      BusState *bus;
       Property *prop;
   
     if (dev->state == DEV_STATE_INITIALIZED) {      if (dev->state == DEV_STATE_INITIALIZED) {
         while (dev->num_child_bus) {          while (dev->num_child_bus) {
Line 297  void qdev_free(DeviceState *dev) Line 344  void qdev_free(DeviceState *dev)
             qbus_free(bus);              qbus_free(bus);
         }          }
         if (dev->info->vmsd)          if (dev->info->vmsd)
             vmstate_unregister(dev->info->vmsd, dev);              vmstate_unregister(dev, dev->info->vmsd, dev);
         if (dev->info->exit)          if (dev->info->exit)
             dev->info->exit(dev);              dev->info->exit(dev);
         if (dev->opts)          if (dev->opts)
Line 305  void qdev_free(DeviceState *dev) Line 352  void qdev_free(DeviceState *dev)
     }      }
     qemu_unregister_reset(qdev_reset, dev);      qemu_unregister_reset(qdev_reset, dev);
     QLIST_REMOVE(dev, sibling);      QLIST_REMOVE(dev, sibling);
       for (prop = dev->info->props; prop && prop->name; prop++) {
           if (prop->info->free) {
               prop->info->free(dev, prop);
           }
       }
     qemu_free(dev);      qemu_free(dev);
 }  }
   
Line 321  void qdev_machine_creation_done(void) Line 373  void qdev_machine_creation_done(void)
 CharDriverState *qdev_init_chardev(DeviceState *dev)  CharDriverState *qdev_init_chardev(DeviceState *dev)
 {  {
     static int next_serial;      static int next_serial;
     static int next_virtconsole;  
     /* FIXME: This is a nasty hack that needs to go away.  */      /* FIXME: This function needs to go away: use chardev properties!  */
     if (strncmp(dev->info->name, "virtio", 6) == 0) {      return serial_hds[next_serial++];
         return virtcon_hds[next_virtconsole++];  
     } else {  
         return serial_hds[next_serial++];  
     }  
 }  }
   
 BusState *qdev_get_parent_bus(DeviceState *dev)  BusState *qdev_get_parent_bus(DeviceState *dev)
Line 368  void qdev_set_nic_properties(DeviceState Line 416  void qdev_set_nic_properties(DeviceState
         qdev_prop_set_vlan(dev, "vlan", nd->vlan);          qdev_prop_set_vlan(dev, "vlan", nd->vlan);
     if (nd->netdev)      if (nd->netdev)
         qdev_prop_set_netdev(dev, "netdev", nd->netdev);          qdev_prop_set_netdev(dev, "netdev", nd->netdev);
     if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED &&      if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
         qdev_prop_exists(dev, "vectors")) {          qdev_prop_exists(dev, "vectors")) {
         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);          qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
     }      }
Line 446  static DeviceState *qdev_find_recursive( Line 494  static DeviceState *qdev_find_recursive(
     return NULL;      return NULL;
 }  }
   
 static void qbus_list_bus(DeviceState *dev, char *dest, int len)  static void qbus_list_bus(DeviceState *dev)
 {  {
     BusState *child;      BusState *child;
     const char *sep = " ";      const char *sep = " ";
     int pos = 0;  
   
     pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",      error_printf("child busses at \"%s\":",
                     dev->id ? dev->id : dev->info->name);                   dev->id ? dev->id : dev->info->name);
     QLIST_FOREACH(child, &dev->child_bus, sibling) {      QLIST_FOREACH(child, &dev->child_bus, sibling) {
         pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);          error_printf("%s\"%s\"", sep, child->name);
         sep = ", ";          sep = ", ";
     }      }
       error_printf("\n");
 }  }
   
 static void qbus_list_dev(BusState *bus, char *dest, int len)  static void qbus_list_dev(BusState *bus)
 {  {
     DeviceState *dev;      DeviceState *dev;
     const char *sep = " ";      const char *sep = " ";
     int pos = 0;  
   
     pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",      error_printf("devices at \"%s\":", bus->name);
                     bus->name);  
     QLIST_FOREACH(dev, &bus->children, sibling) {      QLIST_FOREACH(dev, &bus->children, sibling) {
         pos += snprintf(dest+pos, len-pos, "%s\"%s\"",          error_printf("%s\"%s\"", sep, dev->info->name);
                         sep, dev->info->name);  
         if (dev->id)          if (dev->id)
             pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);              error_printf("/\"%s\"", dev->id);
         sep = ", ";          sep = ", ";
     }      }
       error_printf("\n");
 }  }
   
 static BusState *qbus_find_bus(DeviceState *dev, char *elem)  static BusState *qbus_find_bus(DeviceState *dev, char *elem)
Line 521  static BusState *qbus_find(const char *p Line 567  static BusState *qbus_find(const char *p
 {  {
     DeviceState *dev;      DeviceState *dev;
     BusState *bus;      BusState *bus;
     char elem[128], msg[256];      char elem[128];
     int pos, len;      int pos, len;
   
     /* find start element */      /* find start element */
Line 530  static BusState *qbus_find(const char *p Line 576  static BusState *qbus_find(const char *p
         pos = 0;          pos = 0;
     } else {      } else {
         if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {          if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
             qemu_error("path parse error (\"%s\")\n", path);              assert(!path[0]);
             return NULL;              elem[0] = len = 0;
         }          }
         bus = qbus_find_recursive(main_system_bus, elem, NULL);          bus = qbus_find_recursive(main_system_bus, elem, NULL);
         if (!bus) {          if (!bus) {
             qemu_error("bus \"%s\" not found\n", elem);              qerror_report(QERR_BUS_NOT_FOUND, elem);
             return NULL;              return NULL;
         }          }
         pos = len;          pos = len;
     }      }
   
     for (;;) {      for (;;) {
           assert(path[pos] == '/' || !path[pos]);
           while (path[pos] == '/') {
               pos++;
           }
         if (path[pos] == '\0') {          if (path[pos] == '\0') {
             /* we are done */  
             return bus;              return bus;
         }          }
   
         /* find device */          /* find device */
         if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {          if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
             qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);              assert(0);
             return NULL;              elem[0] = len = 0;
         }          }
         pos += len;          pos += len;
         dev = qbus_find_dev(bus, elem);          dev = qbus_find_dev(bus, elem);
         if (!dev) {          if (!dev) {
             qbus_list_dev(bus, msg, sizeof(msg));              qerror_report(QERR_DEVICE_NOT_FOUND, elem);
             qemu_error("device \"%s\" not found\n%s\n", elem, msg);              if (!monitor_cur_is_qmp()) {
                   qbus_list_dev(bus);
               }
             return NULL;              return NULL;
         }          }
   
           assert(path[pos] == '/' || !path[pos]);
           while (path[pos] == '/') {
               pos++;
           }
         if (path[pos] == '\0') {          if (path[pos] == '\0') {
             /* last specified element is a device.  If it has exactly              /* last specified element is a device.  If it has exactly
              * one child bus accept it nevertheless */               * one child bus accept it nevertheless */
             switch (dev->num_child_bus) {              switch (dev->num_child_bus) {
             case 0:              case 0:
                 qemu_error("device has no child bus (%s)\n", path);                  qerror_report(QERR_DEVICE_NO_BUS, elem);
                 return NULL;                  return NULL;
             case 1:              case 1:
                 return QLIST_FIRST(&dev->child_bus);                  return QLIST_FIRST(&dev->child_bus);
             default:              default:
                 qbus_list_bus(dev, msg, sizeof(msg));                  qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
                 qemu_error("device has multiple child busses (%s)\n%s\n",                  if (!monitor_cur_is_qmp()) {
                            path, msg);                      qbus_list_bus(dev);
                   }
                 return NULL;                  return NULL;
             }              }
         }          }
   
         /* find bus */          /* find bus */
         if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {          if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
             qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);              assert(0);
             return NULL;              elem[0] = len = 0;
         }          }
         pos += len;          pos += len;
         bus = qbus_find_bus(dev, elem);          bus = qbus_find_bus(dev, elem);
         if (!bus) {          if (!bus) {
             qbus_list_bus(dev, msg, sizeof(msg));              qerror_report(QERR_BUS_NOT_FOUND, elem);
             qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);              if (!monitor_cur_is_qmp()) {
                   qbus_list_bus(dev);
               }
             return NULL;              return NULL;
         }          }
     }      }
Line 649  void qbus_free(BusState *bus) Line 708  void qbus_free(BusState *bus)
         QLIST_REMOVE(bus, sibling);          QLIST_REMOVE(bus, sibling);
         bus->parent->num_child_bus--;          bus->parent->num_child_bus--;
     }      }
       qemu_free((void*)bus->name);
     if (bus->qdev_allocated) {      if (bus->qdev_allocated) {
         qemu_free(bus);          qemu_free(bus);
     }      }
Line 665  static void qdev_print_props(Monitor *mo Line 725  static void qdev_print_props(Monitor *mo
     if (!props)      if (!props)
         return;          return;
     while (props->name) {      while (props->name) {
           /*
            * TODO Properties without a print method are just for dirty
            * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's
            * marked for removal.  The test props->info->print should be
            * removed along with it.
            */
         if (props->info->print) {          if (props->info->print) {
             props->info->print(dev, props, buf, sizeof(buf));              props->info->print(dev, props, buf, sizeof(buf));
             qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);              qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
Line 716  void do_info_qtree(Monitor *mon) Line 782  void do_info_qtree(Monitor *mon)
 void do_info_qdm(Monitor *mon)  void do_info_qdm(Monitor *mon)
 {  {
     DeviceInfo *info;      DeviceInfo *info;
     char msg[256];  
   
     for (info = device_info_list; info != NULL; info = info->next) {      for (info = device_info_list; info != NULL; info = info->next) {
         qdev_print_devinfo(info, msg, sizeof(msg));          qdev_print_devinfo(info);
         monitor_printf(mon, "%s\n", msg);  
     }      }
 }  }
   
 void do_device_add(Monitor *mon, const QDict *qdict)  int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {  {
     QemuOpts *opts;      QemuOpts *opts;
   
     opts = qemu_opts_parse(&qemu_device_opts,      opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);
                            qdict_get_str(qdict, "config"), "driver");      if (!opts) {
     if (opts)          return -1;
         qdev_device_add(opts);      }
       if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
           qemu_opts_del(opts);
           return 0;
       }
       if (!qdev_device_add(opts)) {
           qemu_opts_del(opts);
           return -1;
       }
       return 0;
 }  }
   
 void do_device_del(Monitor *mon, const QDict *qdict)  int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {  {
     const char *id = qdict_get_str(qdict, "id");      const char *id = qdict_get_str(qdict, "id");
     DeviceState *dev;      DeviceState *dev;
   
     dev = qdev_find_recursive(main_system_bus, id);      dev = qdev_find_recursive(main_system_bus, id);
     if (NULL == dev) {      if (NULL == dev) {
         qemu_error("Device '%s' not found\n", id);          qerror_report(QERR_DEVICE_NOT_FOUND, id);
         return;          return -1;
     }      }
     qdev_unplug(dev);      return qdev_unplug(dev);
 }  }

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


unix.superglobalmegacorp.com