Statistics
| Branch: | Revision:

root / hw / fw_cfg.c @ 1de7afc9

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