shortcut: added back and controller shortcut info
[sdk/emulator/qemu.git] / bootdevice.c
1 /*
2  * QEMU Boot Device Implement
3  *
4  * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO.,LTD.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "sysemu/sysemu.h"
26 #include "qapi/visitor.h"
27 #include "qemu/error-report.h"
28
29 typedef struct FWBootEntry FWBootEntry;
30
31 struct FWBootEntry {
32     QTAILQ_ENTRY(FWBootEntry) link;
33     int32_t bootindex;
34     DeviceState *dev;
35     char *suffix;
36 };
37
38 static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
39     QTAILQ_HEAD_INITIALIZER(fw_boot_order);
40
41 void check_boot_index(int32_t bootindex, Error **errp)
42 {
43     FWBootEntry *i;
44
45     if (bootindex >= 0) {
46         QTAILQ_FOREACH(i, &fw_boot_order, link) {
47             if (i->bootindex == bootindex) {
48                 error_setg(errp, "The bootindex %d has already been used",
49                            bootindex);
50                 return;
51             }
52         }
53     }
54 }
55
56 void del_boot_device_path(DeviceState *dev, const char *suffix)
57 {
58     FWBootEntry *i;
59
60     if (dev == NULL) {
61         return;
62     }
63
64     QTAILQ_FOREACH(i, &fw_boot_order, link) {
65         if ((!suffix || !g_strcmp0(i->suffix, suffix)) &&
66              i->dev == dev) {
67             QTAILQ_REMOVE(&fw_boot_order, i, link);
68             g_free(i->suffix);
69             g_free(i);
70
71             break;
72         }
73     }
74 }
75
76 void add_boot_device_path(int32_t bootindex, DeviceState *dev,
77                           const char *suffix)
78 {
79     FWBootEntry *node, *i;
80
81     if (bootindex < 0) {
82         del_boot_device_path(dev, suffix);
83         return;
84     }
85
86     assert(dev != NULL || suffix != NULL);
87
88     del_boot_device_path(dev, suffix);
89
90     node = g_malloc0(sizeof(FWBootEntry));
91     node->bootindex = bootindex;
92     node->suffix = g_strdup(suffix);
93     node->dev = dev;
94
95     QTAILQ_FOREACH(i, &fw_boot_order, link) {
96         if (i->bootindex == bootindex) {
97             error_report("Two devices with same boot index %d", bootindex);
98             exit(1);
99         } else if (i->bootindex < bootindex) {
100             continue;
101         }
102         QTAILQ_INSERT_BEFORE(i, node, link);
103         return;
104     }
105     QTAILQ_INSERT_TAIL(&fw_boot_order, node, link);
106 }
107
108 DeviceState *get_boot_device(uint32_t position)
109 {
110     uint32_t counter = 0;
111     FWBootEntry *i = NULL;
112     DeviceState *res = NULL;
113
114     if (!QTAILQ_EMPTY(&fw_boot_order)) {
115         QTAILQ_FOREACH(i, &fw_boot_order, link) {
116             if (counter == position) {
117                 res = i->dev;
118                 break;
119             }
120             counter++;
121         }
122     }
123     return res;
124 }
125
126 /*
127  * This function returns null terminated string that consist of new line
128  * separated device paths.
129  *
130  * memory pointed by "size" is assigned total length of the array in bytes
131  *
132  */
133 char *get_boot_devices_list(size_t *size, bool ignore_suffixes)
134 {
135     FWBootEntry *i;
136     size_t total = 0;
137     char *list = NULL;
138
139     QTAILQ_FOREACH(i, &fw_boot_order, link) {
140         char *devpath = NULL, *bootpath;
141         size_t len;
142
143         if (i->dev) {
144             devpath = qdev_get_fw_dev_path(i->dev);
145             assert(devpath);
146         }
147
148         if (i->suffix && !ignore_suffixes && devpath) {
149             size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
150
151             bootpath = g_malloc(bootpathlen);
152             snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
153             g_free(devpath);
154         } else if (devpath) {
155             bootpath = devpath;
156         } else if (!ignore_suffixes) {
157             assert(i->suffix);
158             bootpath = g_strdup(i->suffix);
159         } else {
160             bootpath = g_strdup("");
161         }
162
163         if (total) {
164             list[total-1] = '\n';
165         }
166         len = strlen(bootpath) + 1;
167         list = g_realloc(list, total + len);
168         memcpy(&list[total], bootpath, len);
169         total += len;
170         g_free(bootpath);
171     }
172
173     *size = total;
174
175     if (boot_strict && *size > 0) {
176         list[total-1] = '\n';
177         list = g_realloc(list, total + 5);
178         memcpy(&list[total], "HALT", 5);
179         *size = total + 5;
180     }
181     return list;
182 }
183
184 typedef struct {
185     int32_t *bootindex;
186     const char *suffix;
187     DeviceState *dev;
188 } BootIndexProperty;
189
190 static void device_get_bootindex(Object *obj, Visitor *v, void *opaque,
191                                  const char *name, Error **errp)
192 {
193     BootIndexProperty *prop = opaque;
194     visit_type_int32(v, prop->bootindex, name, errp);
195 }
196
197 static void device_set_bootindex(Object *obj, Visitor *v, void *opaque,
198                                  const char *name, Error **errp)
199 {
200     BootIndexProperty *prop = opaque;
201     int32_t boot_index;
202     Error *local_err = NULL;
203
204     visit_type_int32(v, &boot_index, name, &local_err);
205     if (local_err) {
206         goto out;
207     }
208     /* check whether bootindex is present in fw_boot_order list  */
209     check_boot_index(boot_index, &local_err);
210     if (local_err) {
211         goto out;
212     }
213     /* change bootindex to a new one */
214     *prop->bootindex = boot_index;
215
216     add_boot_device_path(*prop->bootindex, prop->dev, prop->suffix);
217
218 out:
219     if (local_err) {
220         error_propagate(errp, local_err);
221     }
222 }
223
224 static void property_release_bootindex(Object *obj, const char *name,
225                                        void *opaque)
226
227 {
228     BootIndexProperty *prop = opaque;
229
230     del_boot_device_path(prop->dev, prop->suffix);
231     g_free(prop);
232 }
233
234 void device_add_bootindex_property(Object *obj, int32_t *bootindex,
235                                    const char *name, const char *suffix,
236                                    DeviceState *dev, Error **errp)
237 {
238     Error *local_err = NULL;
239     BootIndexProperty *prop = g_malloc0(sizeof(*prop));
240
241     prop->bootindex = bootindex;
242     prop->suffix = suffix;
243     prop->dev = dev;
244
245     object_property_add(obj, name, "int32",
246                         device_get_bootindex,
247                         device_set_bootindex,
248                         property_release_bootindex,
249                         prop, &local_err);
250
251     if (local_err) {
252         error_propagate(errp, local_err);
253         g_free(prop);
254         return;
255     }
256     /* initialize devices' bootindex property to -1 */
257     object_property_set_int(obj, -1, name, NULL);
258 }