Statistics
| Branch: | Revision:

root / hw / nvram / fw_cfg.c @ 600c60b7

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