+
+typedef struct {
+ int32_t *bootindex;
+ const char *suffix;
+ DeviceState *dev;
+} BootIndexProperty;
+
+static void device_get_bootindex(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ BootIndexProperty *prop = opaque;
+ visit_type_int32(v, name, prop->bootindex, errp);
+}
+
+static void device_set_bootindex(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ BootIndexProperty *prop = opaque;
+ int32_t boot_index;
+ Error *local_err = NULL;
+
+ visit_type_int32(v, name, &boot_index, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ /* check whether bootindex is present in fw_boot_order list */
+ check_boot_index(boot_index, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ /* change bootindex to a new one */
+ *prop->bootindex = boot_index;
+
+ add_boot_device_path(*prop->bootindex, prop->dev, prop->suffix);
+
+out:
+ error_propagate(errp, local_err);
+}
+
+static void property_release_bootindex(Object *obj, const char *name,
+ void *opaque)
+
+{
+ BootIndexProperty *prop = opaque;
+
+ del_boot_device_path(prop->dev, prop->suffix);
+ g_free(prop);
+}
+
+void device_add_bootindex_property(Object *obj, int32_t *bootindex,
+ const char *name, const char *suffix,
+ DeviceState *dev, Error **errp)
+{
+ Error *local_err = NULL;
+ BootIndexProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->bootindex = bootindex;
+ prop->suffix = suffix;
+ prop->dev = dev;
+
+ object_property_add(obj, name, "int32",
+ device_get_bootindex,
+ device_set_bootindex,
+ property_release_bootindex,
+ prop, &local_err);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ g_free(prop);
+ return;
+ }
+ /* initialize devices' bootindex property to -1 */
+ object_property_set_int(obj, -1, name, NULL);
+}
+
+typedef struct FWLCHSEntry FWLCHSEntry;
+
+struct FWLCHSEntry {
+ QTAILQ_ENTRY(FWLCHSEntry) link;
+ DeviceState *dev;
+ char *suffix;
+ uint32_t lcyls;
+ uint32_t lheads;
+ uint32_t lsecs;
+};
+
+static QTAILQ_HEAD(, FWLCHSEntry) fw_lchs =
+ QTAILQ_HEAD_INITIALIZER(fw_lchs);
+
+void add_boot_device_lchs(DeviceState *dev, const char *suffix,
+ uint32_t lcyls, uint32_t lheads, uint32_t lsecs)
+{
+ FWLCHSEntry *node;
+
+ if (!lcyls && !lheads && !lsecs) {
+ return;
+ }
+
+ assert(dev != NULL || suffix != NULL);
+
+ node = g_malloc0(sizeof(FWLCHSEntry));
+ node->suffix = g_strdup(suffix);
+ node->dev = dev;
+ node->lcyls = lcyls;
+ node->lheads = lheads;
+ node->lsecs = lsecs;
+
+ QTAILQ_INSERT_TAIL(&fw_lchs, node, link);
+}
+
+void del_boot_device_lchs(DeviceState *dev, const char *suffix)
+{
+ FWLCHSEntry *i;
+
+ if (dev == NULL) {
+ return;
+ }
+
+ QTAILQ_FOREACH(i, &fw_lchs, link) {
+ if ((!suffix || !g_strcmp0(i->suffix, suffix)) &&
+ i->dev == dev) {
+ QTAILQ_REMOVE(&fw_lchs, i, link);
+ g_free(i->suffix);
+ g_free(i);
+
+ break;
+ }
+ }
+}
+
+char *get_boot_devices_lchs_list(size_t *size)
+{
+ FWLCHSEntry *i;
+ size_t total = 0;
+ char *list = NULL;
+
+ QTAILQ_FOREACH(i, &fw_lchs, link) {
+ char *bootpath;
+ char *chs_string;
+ size_t len;
+
+ bootpath = get_boot_device_path(i->dev, false, i->suffix);
+ chs_string = g_strdup_printf("%s %" PRIu32 " %" PRIu32 " %" PRIu32,
+ bootpath, i->lcyls, i->lheads, i->lsecs);
+
+ if (total) {
+ list[total - 1] = '\n';
+ }
+ len = strlen(chs_string) + 1;
+ list = g_realloc(list, total + len);
+ memcpy(&list[total], chs_string, len);
+ total += len;
+ g_free(chs_string);
+ g_free(bootpath);
+ }
+
+ *size = total;
+
+ return list;
+}