Statistics
| Branch: | Revision:

root / hw / fw_cfg.c @ a1bc20df

History | View | Annotate | Download (16.4 kB)

1 3cce6243 blueswir1
/*
2 3cce6243 blueswir1
 * QEMU Firmware configuration device emulation
3 3cce6243 blueswir1
 *
4 3cce6243 blueswir1
 * Copyright (c) 2008 Gleb Natapov
5 3cce6243 blueswir1
 *
6 3cce6243 blueswir1
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 3cce6243 blueswir1
 * of this software and associated documentation files (the "Software"), to deal
8 3cce6243 blueswir1
 * in the Software without restriction, including without limitation the rights
9 3cce6243 blueswir1
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 3cce6243 blueswir1
 * copies of the Software, and to permit persons to whom the Software is
11 3cce6243 blueswir1
 * furnished to do so, subject to the following conditions:
12 3cce6243 blueswir1
 *
13 3cce6243 blueswir1
 * The above copyright notice and this permission notice shall be included in
14 3cce6243 blueswir1
 * all copies or substantial portions of the Software.
15 3cce6243 blueswir1
 *
16 3cce6243 blueswir1
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 3cce6243 blueswir1
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 3cce6243 blueswir1
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 3cce6243 blueswir1
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 3cce6243 blueswir1
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 3cce6243 blueswir1
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 3cce6243 blueswir1
 * THE SOFTWARE.
23 3cce6243 blueswir1
 */
24 3cce6243 blueswir1
#include "hw.h"
25 084a197a blueswir1
#include "sysemu.h"
26 3cce6243 blueswir1
#include "isa.h"
27 3cce6243 blueswir1
#include "fw_cfg.h"
28 3a5c16fc Blue Swirl
#include "sysbus.h"
29 3d3b8303 wayne
#include "qemu-error.h"
30 3cce6243 blueswir1
31 3cce6243 blueswir1
/* debug firmware config */
32 3cce6243 blueswir1
//#define DEBUG_FW_CFG
33 3cce6243 blueswir1
34 3cce6243 blueswir1
#ifdef DEBUG_FW_CFG
35 001faf32 Blue Swirl
#define FW_CFG_DPRINTF(fmt, ...)                        \
36 001faf32 Blue Swirl
    do { printf("FW_CFG: " fmt , ## __VA_ARGS__); } while (0)
37 3cce6243 blueswir1
#else
38 001faf32 Blue Swirl
#define FW_CFG_DPRINTF(fmt, ...)
39 3cce6243 blueswir1
#endif
40 3cce6243 blueswir1
41 3cce6243 blueswir1
#define FW_CFG_SIZE 2
42 561e1827 Avi Kivity
#define FW_CFG_DATA_SIZE 1
43 3cce6243 blueswir1
44 b96ae2da Blue Swirl
typedef struct FWCfgEntry {
45 ff06108b Juan Quintela
    uint32_t len;
46 3cce6243 blueswir1
    uint8_t *data;
47 3cce6243 blueswir1
    void *callback_opaque;
48 3cce6243 blueswir1
    FWCfgCallback callback;
49 3cce6243 blueswir1
} FWCfgEntry;
50 3cce6243 blueswir1
51 b96ae2da Blue Swirl
struct FWCfgState {
52 3a5c16fc Blue Swirl
    SysBusDevice busdev;
53 561e1827 Avi Kivity
    MemoryRegion ctl_iomem, data_iomem, comb_iomem;
54 3a5c16fc Blue Swirl
    uint32_t ctl_iobase, data_iobase;
55 3cce6243 blueswir1
    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
56 abe147e0 Gerd Hoffmann
    FWCfgFiles *files;
57 3cce6243 blueswir1
    uint16_t cur_entry;
58 ff06108b Juan Quintela
    uint32_t cur_offset;
59 962630f2 Gleb Natapov
    Notifier machine_ready;
60 c2b5bda4 Gerd Hoffmann
};
61 3cce6243 blueswir1
62 3d3b8303 wayne
#define JPG_FILE 0
63 3d3b8303 wayne
#define BMP_FILE 1
64 3d3b8303 wayne
65 9477c87e Pavel Borzenkov
static char *read_splashfile(char *filename, int *file_sizep, int *file_typep)
66 3d3b8303 wayne
{
67 9477c87e Pavel Borzenkov
    GError *err = NULL;
68 9477c87e Pavel Borzenkov
    gboolean res;
69 9477c87e Pavel Borzenkov
    gchar *content;
70 3d3b8303 wayne
    int file_type = -1;
71 9477c87e Pavel Borzenkov
    unsigned int filehead = 0;
72 3d3b8303 wayne
    int bmp_bpp;
73 3d3b8303 wayne
74 9477c87e Pavel Borzenkov
    res = g_file_get_contents(filename, &content, (gsize *)file_sizep, &err);
75 9477c87e Pavel Borzenkov
    if (res == FALSE) {
76 9477c87e Pavel Borzenkov
        error_report("failed to read splash file '%s'", filename);
77 9477c87e Pavel Borzenkov
        g_error_free(err);
78 9477c87e Pavel Borzenkov
        return NULL;
79 3d3b8303 wayne
    }
80 9477c87e Pavel Borzenkov
81 3d3b8303 wayne
    /* check file size */
82 9477c87e Pavel Borzenkov
    if (*file_sizep < 30) {
83 9477c87e Pavel Borzenkov
        goto error;
84 3d3b8303 wayne
    }
85 9477c87e Pavel Borzenkov
86 3d3b8303 wayne
    /* check magic ID */
87 9477c87e Pavel Borzenkov
    filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
88 9477c87e Pavel Borzenkov
    if (filehead == 0xd8ff) {
89 3d3b8303 wayne
        file_type = JPG_FILE;
90 9477c87e Pavel Borzenkov
    } else if (filehead == 0x4d42) {
91 9477c87e Pavel Borzenkov
        file_type = BMP_FILE;
92 3d3b8303 wayne
    } else {
93 9477c87e Pavel Borzenkov
        goto error;
94 3d3b8303 wayne
    }
95 9477c87e Pavel Borzenkov
96 3d3b8303 wayne
    /* check BMP bpp */
97 3d3b8303 wayne
    if (file_type == BMP_FILE) {
98 9477c87e Pavel Borzenkov
        bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
99 3d3b8303 wayne
        if (bmp_bpp != 24) {
100 9477c87e Pavel Borzenkov
            goto error;
101 3d3b8303 wayne
        }
102 3d3b8303 wayne
    }
103 9477c87e Pavel Borzenkov
104 3d3b8303 wayne
    /* return values */
105 3d3b8303 wayne
    *file_typep = file_type;
106 9477c87e Pavel Borzenkov
107 9477c87e Pavel Borzenkov
    return content;
108 9477c87e Pavel Borzenkov
109 9477c87e Pavel Borzenkov
error:
110 9477c87e Pavel Borzenkov
    error_report("splash file '%s' format not recognized; must be JPEG "
111 9477c87e Pavel Borzenkov
                 "or 24 bit BMP", filename);
112 9477c87e Pavel Borzenkov
    g_free(content);
113 9477c87e Pavel Borzenkov
    return NULL;
114 3d3b8303 wayne
}
115 3d3b8303 wayne
116 3d3b8303 wayne
static void fw_cfg_bootsplash(FWCfgState *s)
117 3d3b8303 wayne
{
118 3d3b8303 wayne
    int boot_splash_time = -1;
119 3d3b8303 wayne
    const char *boot_splash_filename = NULL;
120 3d3b8303 wayne
    char *p;
121 9477c87e Pavel Borzenkov
    char *filename, *file_data;
122 3d3b8303 wayne
    int file_size;
123 3d3b8303 wayne
    int file_type = -1;
124 3d3b8303 wayne
    const char *temp;
125 3d3b8303 wayne
126 3d3b8303 wayne
    /* get user configuration */
127 3d3b8303 wayne
    QemuOptsList *plist = qemu_find_opts("boot-opts");
128 3d3b8303 wayne
    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
129 3d3b8303 wayne
    if (opts != NULL) {
130 3d3b8303 wayne
        temp = qemu_opt_get(opts, "splash");
131 3d3b8303 wayne
        if (temp != NULL) {
132 3d3b8303 wayne
            boot_splash_filename = temp;
133 3d3b8303 wayne
        }
134 3d3b8303 wayne
        temp = qemu_opt_get(opts, "splash-time");
135 3d3b8303 wayne
        if (temp != NULL) {
136 3d3b8303 wayne
            p = (char *)temp;
137 3d3b8303 wayne
            boot_splash_time = strtol(p, (char **)&p, 10);
138 3d3b8303 wayne
        }
139 3d3b8303 wayne
    }
140 3d3b8303 wayne
141 3d3b8303 wayne
    /* insert splash time if user configurated */
142 3d3b8303 wayne
    if (boot_splash_time >= 0) {
143 3d3b8303 wayne
        /* validate the input */
144 3d3b8303 wayne
        if (boot_splash_time > 0xffff) {
145 3d3b8303 wayne
            error_report("splash time is big than 65535, force it to 65535.");
146 3d3b8303 wayne
            boot_splash_time = 0xffff;
147 3d3b8303 wayne
        }
148 3d3b8303 wayne
        /* use little endian format */
149 3d3b8303 wayne
        qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
150 3d3b8303 wayne
        qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
151 3d3b8303 wayne
        fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
152 3d3b8303 wayne
    }
153 3d3b8303 wayne
154 3d3b8303 wayne
    /* insert splash file if user configurated */
155 3d3b8303 wayne
    if (boot_splash_filename != NULL) {
156 3d3b8303 wayne
        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
157 3d3b8303 wayne
        if (filename == NULL) {
158 3d3b8303 wayne
            error_report("failed to find file '%s'.", boot_splash_filename);
159 3d3b8303 wayne
            return;
160 3d3b8303 wayne
        }
161 9477c87e Pavel Borzenkov
162 9477c87e Pavel Borzenkov
        /* loading file data */
163 9477c87e Pavel Borzenkov
        file_data = read_splashfile(filename, &file_size, &file_type);
164 9477c87e Pavel Borzenkov
        if (file_data == NULL) {
165 7267c094 Anthony Liguori
            g_free(filename);
166 3d3b8303 wayne
            return;
167 3d3b8303 wayne
        }
168 3d3b8303 wayne
        if (boot_splash_filedata != NULL) {
169 7267c094 Anthony Liguori
            g_free(boot_splash_filedata);
170 3d3b8303 wayne
        }
171 9477c87e Pavel Borzenkov
        boot_splash_filedata = (uint8_t *)file_data;
172 3d3b8303 wayne
        boot_splash_filedata_size = file_size;
173 9477c87e Pavel Borzenkov
174 3d3b8303 wayne
        /* insert data */
175 3d3b8303 wayne
        if (file_type == JPG_FILE) {
176 3d3b8303 wayne
            fw_cfg_add_file(s, "bootsplash.jpg",
177 3d3b8303 wayne
                    boot_splash_filedata, boot_splash_filedata_size);
178 3d3b8303 wayne
        } else {
179 3d3b8303 wayne
            fw_cfg_add_file(s, "bootsplash.bmp",
180 3d3b8303 wayne
                    boot_splash_filedata, boot_splash_filedata_size);
181 3d3b8303 wayne
        }
182 7267c094 Anthony Liguori
        g_free(filename);
183 3d3b8303 wayne
    }
184 3d3b8303 wayne
}
185 3d3b8303 wayne
186 ac05f349 Amos Kong
static void fw_cfg_reboot(FWCfgState *s)
187 ac05f349 Amos Kong
{
188 ac05f349 Amos Kong
    int reboot_timeout = -1;
189 ac05f349 Amos Kong
    char *p;
190 ac05f349 Amos Kong
    const char *temp;
191 ac05f349 Amos Kong
192 ac05f349 Amos Kong
    /* get user configuration */
193 ac05f349 Amos Kong
    QemuOptsList *plist = qemu_find_opts("boot-opts");
194 ac05f349 Amos Kong
    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
195 ac05f349 Amos Kong
    if (opts != NULL) {
196 ac05f349 Amos Kong
        temp = qemu_opt_get(opts, "reboot-timeout");
197 ac05f349 Amos Kong
        if (temp != NULL) {
198 ac05f349 Amos Kong
            p = (char *)temp;
199 ac05f349 Amos Kong
            reboot_timeout = strtol(p, (char **)&p, 10);
200 ac05f349 Amos Kong
        }
201 ac05f349 Amos Kong
    }
202 ac05f349 Amos Kong
    /* validate the input */
203 ac05f349 Amos Kong
    if (reboot_timeout > 0xffff) {
204 ac05f349 Amos Kong
        error_report("reboot timeout is larger than 65535, force it to 65535.");
205 ac05f349 Amos Kong
        reboot_timeout = 0xffff;
206 ac05f349 Amos Kong
    }
207 ac05f349 Amos Kong
    fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4);
208 ac05f349 Amos Kong
}
209 ac05f349 Amos Kong
210 3cce6243 blueswir1
static void fw_cfg_write(FWCfgState *s, uint8_t value)
211 3cce6243 blueswir1
{
212 3cce6243 blueswir1
    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
213 3cce6243 blueswir1
    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
214 3cce6243 blueswir1
215 3cce6243 blueswir1
    FW_CFG_DPRINTF("write %d\n", value);
216 3cce6243 blueswir1
217 962d4b28 Blue Swirl
    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback &&
218 962d4b28 Blue Swirl
        s->cur_offset < e->len) {
219 3cce6243 blueswir1
        e->data[s->cur_offset++] = value;
220 3cce6243 blueswir1
        if (s->cur_offset == e->len) {
221 3cce6243 blueswir1
            e->callback(e->callback_opaque, e->data);
222 3cce6243 blueswir1
            s->cur_offset = 0;
223 3cce6243 blueswir1
        }
224 3cce6243 blueswir1
    }
225 3cce6243 blueswir1
}
226 3cce6243 blueswir1
227 3cce6243 blueswir1
static int fw_cfg_select(FWCfgState *s, uint16_t key)
228 3cce6243 blueswir1
{
229 3cce6243 blueswir1
    int ret;
230 3cce6243 blueswir1
231 3cce6243 blueswir1
    s->cur_offset = 0;
232 3cce6243 blueswir1
    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
233 3cce6243 blueswir1
        s->cur_entry = FW_CFG_INVALID;
234 3cce6243 blueswir1
        ret = 0;
235 3cce6243 blueswir1
    } else {
236 3cce6243 blueswir1
        s->cur_entry = key;
237 3cce6243 blueswir1
        ret = 1;
238 3cce6243 blueswir1
    }
239 3cce6243 blueswir1
240 3cce6243 blueswir1
    FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not ");
241 3cce6243 blueswir1
242 3cce6243 blueswir1
    return ret;
243 3cce6243 blueswir1
}
244 3cce6243 blueswir1
245 3cce6243 blueswir1
static uint8_t fw_cfg_read(FWCfgState *s)
246 3cce6243 blueswir1
{
247 3cce6243 blueswir1
    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
248 3cce6243 blueswir1
    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
249 3cce6243 blueswir1
    uint8_t ret;
250 3cce6243 blueswir1
251 3cce6243 blueswir1
    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
252 3cce6243 blueswir1
        ret = 0;
253 3cce6243 blueswir1
    else
254 3cce6243 blueswir1
        ret = e->data[s->cur_offset++];
255 3cce6243 blueswir1
256 3cce6243 blueswir1
    FW_CFG_DPRINTF("read %d\n", ret);
257 3cce6243 blueswir1
258 3cce6243 blueswir1
    return ret;
259 3cce6243 blueswir1
}
260 3cce6243 blueswir1
261 a8170e5e Avi Kivity
static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
262 561e1827 Avi Kivity
                                     unsigned size)
263 3cce6243 blueswir1
{
264 3cce6243 blueswir1
    return fw_cfg_read(opaque);
265 3cce6243 blueswir1
}
266 3cce6243 blueswir1
267 a8170e5e Avi Kivity
static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
268 561e1827 Avi Kivity
                                  uint64_t value, unsigned size)
269 3cce6243 blueswir1
{
270 7442511c blueswir1
    fw_cfg_write(opaque, (uint8_t)value);
271 3cce6243 blueswir1
}
272 3cce6243 blueswir1
273 a8170e5e Avi Kivity
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
274 561e1827 Avi Kivity
                                 uint64_t value, unsigned size)
275 3cce6243 blueswir1
{
276 3cce6243 blueswir1
    fw_cfg_select(opaque, (uint16_t)value);
277 3cce6243 blueswir1
}
278 3cce6243 blueswir1
279 a8170e5e Avi Kivity
static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
280 561e1827 Avi Kivity
                                 unsigned size, bool is_write)
281 3cce6243 blueswir1
{
282 561e1827 Avi Kivity
    return is_write && size == 2;
283 3cce6243 blueswir1
}
284 3cce6243 blueswir1
285 a8170e5e Avi Kivity
static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr,
286 561e1827 Avi Kivity
                                 unsigned size)
287 3cce6243 blueswir1
{
288 561e1827 Avi Kivity
    return fw_cfg_read(opaque);
289 3cce6243 blueswir1
}
290 3cce6243 blueswir1
291 a8170e5e Avi Kivity
static void fw_cfg_comb_write(void *opaque, hwaddr addr,
292 561e1827 Avi Kivity
                              uint64_t value, unsigned size)
293 3cce6243 blueswir1
{
294 561e1827 Avi Kivity
    switch (size) {
295 561e1827 Avi Kivity
    case 1:
296 561e1827 Avi Kivity
        fw_cfg_write(opaque, (uint8_t)value);
297 561e1827 Avi Kivity
        break;
298 561e1827 Avi Kivity
    case 2:
299 561e1827 Avi Kivity
        fw_cfg_select(opaque, (uint16_t)value);
300 561e1827 Avi Kivity
        break;
301 561e1827 Avi Kivity
    }
302 3cce6243 blueswir1
}
303 3cce6243 blueswir1
304 a8170e5e Avi Kivity
static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
305 561e1827 Avi Kivity
                                  unsigned size, bool is_write)
306 561e1827 Avi Kivity
{
307 561e1827 Avi Kivity
    return (size == 1) || (is_write && size == 2);
308 561e1827 Avi Kivity
}
309 3cce6243 blueswir1
310 561e1827 Avi Kivity
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
311 561e1827 Avi Kivity
    .write = fw_cfg_ctl_mem_write,
312 561e1827 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
313 561e1827 Avi Kivity
    .valid.accepts = fw_cfg_ctl_mem_valid,
314 3cce6243 blueswir1
};
315 3cce6243 blueswir1
316 561e1827 Avi Kivity
static const MemoryRegionOps fw_cfg_data_mem_ops = {
317 561e1827 Avi Kivity
    .read = fw_cfg_data_mem_read,
318 561e1827 Avi Kivity
    .write = fw_cfg_data_mem_write,
319 561e1827 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
320 561e1827 Avi Kivity
    .valid = {
321 561e1827 Avi Kivity
        .min_access_size = 1,
322 561e1827 Avi Kivity
        .max_access_size = 1,
323 561e1827 Avi Kivity
    },
324 3cce6243 blueswir1
};
325 3cce6243 blueswir1
326 561e1827 Avi Kivity
static const MemoryRegionOps fw_cfg_comb_mem_ops = {
327 561e1827 Avi Kivity
    .read = fw_cfg_comb_read,
328 561e1827 Avi Kivity
    .write = fw_cfg_comb_write,
329 561e1827 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
330 561e1827 Avi Kivity
    .valid.accepts = fw_cfg_comb_valid,
331 3cce6243 blueswir1
};
332 3cce6243 blueswir1
333 3a5c16fc Blue Swirl
static void fw_cfg_reset(DeviceState *d)
334 3cce6243 blueswir1
{
335 3a5c16fc Blue Swirl
    FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d);
336 3cce6243 blueswir1
337 3cce6243 blueswir1
    fw_cfg_select(s, 0);
338 3cce6243 blueswir1
}
339 3cce6243 blueswir1
340 ff06108b Juan Quintela
/* Save restore 32 bit int as uint16_t
341 ff06108b Juan Quintela
   This is a Big hack, but it is how the old state did it.
342 ff06108b Juan Quintela
   Or we broke compatibility in the state, or we can't use struct tm
343 ff06108b Juan Quintela
 */
344 ff06108b Juan Quintela
345 ff06108b Juan Quintela
static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
346 ff06108b Juan Quintela
{
347 ff06108b Juan Quintela
    uint32_t *v = pv;
348 ff06108b Juan Quintela
    *v = qemu_get_be16(f);
349 ff06108b Juan Quintela
    return 0;
350 ff06108b Juan Quintela
}
351 ff06108b Juan Quintela
352 ff06108b Juan Quintela
static void put_unused(QEMUFile *f, void *pv, size_t size)
353 ff06108b Juan Quintela
{
354 66c80e75 Vagrant Cascadian
    fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
355 ff06108b Juan Quintela
    fprintf(stderr, "This functions shouldn't be called.\n");
356 ff06108b Juan Quintela
}
357 ff06108b Juan Quintela
358 d05ac8fa Blue Swirl
static const VMStateInfo vmstate_hack_uint32_as_uint16 = {
359 ff06108b Juan Quintela
    .name = "int32_as_uint16",
360 ff06108b Juan Quintela
    .get  = get_uint32_as_uint16,
361 ff06108b Juan Quintela
    .put  = put_unused,
362 ff06108b Juan Quintela
};
363 ff06108b Juan Quintela
364 ff06108b Juan Quintela
#define VMSTATE_UINT16_HACK(_f, _s, _t)                                    \
365 ff06108b Juan Quintela
    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)
366 ff06108b Juan Quintela
367 ff06108b Juan Quintela
368 ff06108b Juan Quintela
static bool is_version_1(void *opaque, int version_id)
369 ff06108b Juan Quintela
{
370 ff06108b Juan Quintela
    return version_id == 1;
371 ff06108b Juan Quintela
}
372 ff06108b Juan Quintela
373 7d2edd40 Juan Quintela
static const VMStateDescription vmstate_fw_cfg = {
374 7d2edd40 Juan Quintela
    .name = "fw_cfg",
375 ff06108b Juan Quintela
    .version_id = 2,
376 7d2edd40 Juan Quintela
    .minimum_version_id = 1,
377 7d2edd40 Juan Quintela
    .minimum_version_id_old = 1,
378 7d2edd40 Juan Quintela
    .fields      = (VMStateField []) {
379 7d2edd40 Juan Quintela
        VMSTATE_UINT16(cur_entry, FWCfgState),
380 ff06108b Juan Quintela
        VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
381 ff06108b Juan Quintela
        VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
382 7d2edd40 Juan Quintela
        VMSTATE_END_OF_LIST()
383 7d2edd40 Juan Quintela
    }
384 7d2edd40 Juan Quintela
};
385 3cce6243 blueswir1
386 c2b5bda4 Gerd Hoffmann
int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len)
387 3cce6243 blueswir1
{
388 3cce6243 blueswir1
    int arch = !!(key & FW_CFG_ARCH_LOCAL);
389 3cce6243 blueswir1
390 3cce6243 blueswir1
    key &= FW_CFG_ENTRY_MASK;
391 3cce6243 blueswir1
392 3cce6243 blueswir1
    if (key >= FW_CFG_MAX_ENTRY)
393 3cce6243 blueswir1
        return 0;
394 3cce6243 blueswir1
395 3cce6243 blueswir1
    s->entries[arch][key].data = data;
396 3cce6243 blueswir1
    s->entries[arch][key].len = len;
397 3cce6243 blueswir1
398 3cce6243 blueswir1
    return 1;
399 3cce6243 blueswir1
}
400 3cce6243 blueswir1
401 c2b5bda4 Gerd Hoffmann
int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
402 3cce6243 blueswir1
{
403 3cce6243 blueswir1
    uint16_t *copy;
404 3cce6243 blueswir1
405 7267c094 Anthony Liguori
    copy = g_malloc(sizeof(value));
406 3cce6243 blueswir1
    *copy = cpu_to_le16(value);
407 c2b5bda4 Gerd Hoffmann
    return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
408 3cce6243 blueswir1
}
409 3cce6243 blueswir1
410 c2b5bda4 Gerd Hoffmann
int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
411 3cce6243 blueswir1
{
412 3cce6243 blueswir1
    uint32_t *copy;
413 3cce6243 blueswir1
414 7267c094 Anthony Liguori
    copy = g_malloc(sizeof(value));
415 3cce6243 blueswir1
    *copy = cpu_to_le32(value);
416 c2b5bda4 Gerd Hoffmann
    return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
417 3cce6243 blueswir1
}
418 3cce6243 blueswir1
419 c2b5bda4 Gerd Hoffmann
int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
420 3cce6243 blueswir1
{
421 3cce6243 blueswir1
    uint64_t *copy;
422 3cce6243 blueswir1
423 7267c094 Anthony Liguori
    copy = g_malloc(sizeof(value));
424 3cce6243 blueswir1
    *copy = cpu_to_le64(value);
425 c2b5bda4 Gerd Hoffmann
    return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
426 3cce6243 blueswir1
}
427 3cce6243 blueswir1
428 c2b5bda4 Gerd Hoffmann
int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
429 3cce6243 blueswir1
                        void *callback_opaque, uint8_t *data, size_t len)
430 3cce6243 blueswir1
{
431 3cce6243 blueswir1
    int arch = !!(key & FW_CFG_ARCH_LOCAL);
432 3cce6243 blueswir1
433 85df0de4 blueswir1
    if (!(key & FW_CFG_WRITE_CHANNEL))
434 85df0de4 blueswir1
        return 0;
435 85df0de4 blueswir1
436 3cce6243 blueswir1
    key &= FW_CFG_ENTRY_MASK;
437 3cce6243 blueswir1
438 85df0de4 blueswir1
    if (key >= FW_CFG_MAX_ENTRY || len > 65535)
439 3cce6243 blueswir1
        return 0;
440 3cce6243 blueswir1
441 3cce6243 blueswir1
    s->entries[arch][key].data = data;
442 3cce6243 blueswir1
    s->entries[arch][key].len = len;
443 3cce6243 blueswir1
    s->entries[arch][key].callback_opaque = callback_opaque;
444 3cce6243 blueswir1
    s->entries[arch][key].callback = callback;
445 3cce6243 blueswir1
446 3cce6243 blueswir1
    return 1;
447 3cce6243 blueswir1
}
448 3cce6243 blueswir1
449 de1f34cb Gleb Natapov
int fw_cfg_add_file(FWCfgState *s,  const char *filename, uint8_t *data,
450 de1f34cb Gleb Natapov
                    uint32_t len)
451 abe147e0 Gerd Hoffmann
{
452 de9352bc Gerd Hoffmann
    int i, index;
453 abe147e0 Gerd Hoffmann
454 abe147e0 Gerd Hoffmann
    if (!s->files) {
455 abe147e0 Gerd Hoffmann
        int dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
456 7267c094 Anthony Liguori
        s->files = g_malloc0(dsize);
457 abe147e0 Gerd Hoffmann
        fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, (uint8_t*)s->files, dsize);
458 abe147e0 Gerd Hoffmann
    }
459 abe147e0 Gerd Hoffmann
460 abe147e0 Gerd Hoffmann
    index = be32_to_cpu(s->files->count);
461 abe147e0 Gerd Hoffmann
    if (index == FW_CFG_FILE_SLOTS) {
462 abe147e0 Gerd Hoffmann
        fprintf(stderr, "fw_cfg: out of file slots\n");
463 abe147e0 Gerd Hoffmann
        return 0;
464 abe147e0 Gerd Hoffmann
    }
465 abe147e0 Gerd Hoffmann
466 abe147e0 Gerd Hoffmann
    fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len);
467 abe147e0 Gerd Hoffmann
468 de1f34cb Gleb Natapov
    pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
469 de1f34cb Gleb Natapov
            filename);
470 de9352bc Gerd Hoffmann
    for (i = 0; i < index; i++) {
471 de9352bc Gerd Hoffmann
        if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
472 de9352bc Gerd Hoffmann
            FW_CFG_DPRINTF("%s: skip duplicate: %s\n", __FUNCTION__,
473 de9352bc Gerd Hoffmann
                           s->files->f[index].name);
474 de9352bc Gerd Hoffmann
            return 1;
475 de9352bc Gerd Hoffmann
        }
476 abe147e0 Gerd Hoffmann
    }
477 de9352bc Gerd Hoffmann
478 abe147e0 Gerd Hoffmann
    s->files->f[index].size   = cpu_to_be32(len);
479 abe147e0 Gerd Hoffmann
    s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
480 abe147e0 Gerd Hoffmann
    FW_CFG_DPRINTF("%s: #%d: %s (%d bytes)\n", __FUNCTION__,
481 abe147e0 Gerd Hoffmann
                   index, s->files->f[index].name, len);
482 abe147e0 Gerd Hoffmann
483 abe147e0 Gerd Hoffmann
    s->files->count = cpu_to_be32(index+1);
484 abe147e0 Gerd Hoffmann
    return 1;
485 abe147e0 Gerd Hoffmann
}
486 abe147e0 Gerd Hoffmann
487 9e8dd451 Jan Kiszka
static void fw_cfg_machine_ready(struct Notifier *n, void *data)
488 962630f2 Gleb Natapov
{
489 962630f2 Gleb Natapov
    uint32_t len;
490 962630f2 Gleb Natapov
    FWCfgState *s = container_of(n, FWCfgState, machine_ready);
491 962630f2 Gleb Natapov
    char *bootindex = get_boot_devices_list(&len);
492 962630f2 Gleb Natapov
493 962630f2 Gleb Natapov
    fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
494 962630f2 Gleb Natapov
}
495 962630f2 Gleb Natapov
496 c2b5bda4 Gerd Hoffmann
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
497 a8170e5e Avi Kivity
                        hwaddr ctl_addr, hwaddr data_addr)
498 3cce6243 blueswir1
{
499 3a5c16fc Blue Swirl
    DeviceState *dev;
500 3a5c16fc Blue Swirl
    SysBusDevice *d;
501 3cce6243 blueswir1
    FWCfgState *s;
502 3cce6243 blueswir1
503 3a5c16fc Blue Swirl
    dev = qdev_create(NULL, "fw_cfg");
504 3a5c16fc Blue Swirl
    qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
505 3a5c16fc Blue Swirl
    qdev_prop_set_uint32(dev, "data_iobase", data_port);
506 3a5c16fc Blue Swirl
    qdev_init_nofail(dev);
507 3a5c16fc Blue Swirl
    d = sysbus_from_qdev(dev);
508 3a5c16fc Blue Swirl
509 3a5c16fc Blue Swirl
    s = DO_UPCAST(FWCfgState, busdev.qdev, dev);
510 3cce6243 blueswir1
511 3cce6243 blueswir1
    if (ctl_addr) {
512 3a5c16fc Blue Swirl
        sysbus_mmio_map(d, 0, ctl_addr);
513 3cce6243 blueswir1
    }
514 3cce6243 blueswir1
    if (data_addr) {
515 3a5c16fc Blue Swirl
        sysbus_mmio_map(d, 1, data_addr);
516 3cce6243 blueswir1
    }
517 3cce6243 blueswir1
    fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4);
518 084a197a blueswir1
    fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
519 993fbfdb Anthony Liguori
    fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
520 905fdcb5 blueswir1
    fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
521 6be68d7e Jes Sorensen
    fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
522 95387491 Jan Kiszka
    fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
523 3d3b8303 wayne
    fw_cfg_bootsplash(s);
524 ac05f349 Amos Kong
    fw_cfg_reboot(s);
525 962630f2 Gleb Natapov
526 962630f2 Gleb Natapov
    s->machine_ready.notify = fw_cfg_machine_ready;
527 962630f2 Gleb Natapov
    qemu_add_machine_init_done_notifier(&s->machine_ready);
528 962630f2 Gleb Natapov
529 3cce6243 blueswir1
    return s;
530 3cce6243 blueswir1
}
531 3a5c16fc Blue Swirl
532 3a5c16fc Blue Swirl
static int fw_cfg_init1(SysBusDevice *dev)
533 3a5c16fc Blue Swirl
{
534 3a5c16fc Blue Swirl
    FWCfgState *s = FROM_SYSBUS(FWCfgState, dev);
535 3a5c16fc Blue Swirl
536 561e1827 Avi Kivity
    memory_region_init_io(&s->ctl_iomem, &fw_cfg_ctl_mem_ops, s,
537 561e1827 Avi Kivity
                          "fwcfg.ctl", FW_CFG_SIZE);
538 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->ctl_iomem);
539 561e1827 Avi Kivity
    memory_region_init_io(&s->data_iomem, &fw_cfg_data_mem_ops, s,
540 561e1827 Avi Kivity
                          "fwcfg.data", FW_CFG_DATA_SIZE);
541 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->data_iomem);
542 561e1827 Avi Kivity
    /* In case ctl and data overlap: */
543 561e1827 Avi Kivity
    memory_region_init_io(&s->comb_iomem, &fw_cfg_comb_mem_ops, s,
544 561e1827 Avi Kivity
                          "fwcfg", FW_CFG_SIZE);
545 561e1827 Avi Kivity
546 561e1827 Avi Kivity
    if (s->ctl_iobase + 1 == s->data_iobase) {
547 561e1827 Avi Kivity
        sysbus_add_io(dev, s->ctl_iobase, &s->comb_iomem);
548 561e1827 Avi Kivity
    } else {
549 561e1827 Avi Kivity
        if (s->ctl_iobase) {
550 561e1827 Avi Kivity
            sysbus_add_io(dev, s->ctl_iobase, &s->ctl_iomem);
551 561e1827 Avi Kivity
        }
552 561e1827 Avi Kivity
        if (s->data_iobase) {
553 561e1827 Avi Kivity
            sysbus_add_io(dev, s->data_iobase, &s->data_iomem);
554 561e1827 Avi Kivity
        }
555 3a5c16fc Blue Swirl
    }
556 3a5c16fc Blue Swirl
    return 0;
557 3a5c16fc Blue Swirl
}
558 3a5c16fc Blue Swirl
559 999e12bb Anthony Liguori
static Property fw_cfg_properties[] = {
560 999e12bb Anthony Liguori
    DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
561 999e12bb Anthony Liguori
    DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
562 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
563 999e12bb Anthony Liguori
};
564 999e12bb Anthony Liguori
565 999e12bb Anthony Liguori
static void fw_cfg_class_init(ObjectClass *klass, void *data)
566 999e12bb Anthony Liguori
{
567 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
568 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
569 999e12bb Anthony Liguori
570 999e12bb Anthony Liguori
    k->init = fw_cfg_init1;
571 39bffca2 Anthony Liguori
    dc->no_user = 1;
572 39bffca2 Anthony Liguori
    dc->reset = fw_cfg_reset;
573 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_fw_cfg;
574 39bffca2 Anthony Liguori
    dc->props = fw_cfg_properties;
575 999e12bb Anthony Liguori
}
576 999e12bb Anthony Liguori
577 39bffca2 Anthony Liguori
static TypeInfo fw_cfg_info = {
578 39bffca2 Anthony Liguori
    .name          = "fw_cfg",
579 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
580 39bffca2 Anthony Liguori
    .instance_size = sizeof(FWCfgState),
581 39bffca2 Anthony Liguori
    .class_init    = fw_cfg_class_init,
582 3a5c16fc Blue Swirl
};
583 3a5c16fc Blue Swirl
584 83f7d43a Andreas Färber
static void fw_cfg_register_types(void)
585 3a5c16fc Blue Swirl
{
586 39bffca2 Anthony Liguori
    type_register_static(&fw_cfg_info);
587 3a5c16fc Blue Swirl
}
588 3a5c16fc Blue Swirl
589 83f7d43a Andreas Färber
type_init(fw_cfg_register_types)