Statistics
| Branch: | Revision:

root / hw / fw_cfg.c @ be40edcd

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