Statistics
| Branch: | Revision:

root / hw / fw_cfg.c @ 3204db98

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