fw_cfg.c 18.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * QEMU Firmware configuration device emulation
 *
 * Copyright (c) 2008 Gleb Natapov
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
24
#include "hw/hw.h"
25
#include "sysemu/sysemu.h"
P
Paolo Bonzini 已提交
26 27
#include "hw/isa/isa.h"
#include "hw/nvram/fw_cfg.h"
28
#include "hw/sysbus.h"
29
#include "trace.h"
30 31
#include "qemu/error-report.h"
#include "qemu/config-file.h"
32 33

#define FW_CFG_SIZE 2
A
Avi Kivity 已提交
34
#define FW_CFG_DATA_SIZE 1
35 36 37
#define TYPE_FW_CFG "fw_cfg"
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
H
Hu Tao 已提交
38
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
39

B
Blue Swirl 已提交
40
typedef struct FWCfgEntry {
41
    uint32_t len;
42 43 44
    uint8_t *data;
    void *callback_opaque;
    FWCfgCallback callback;
45
    FWCfgReadCallback read_callback;
46 47
} FWCfgEntry;

B
Blue Swirl 已提交
48
struct FWCfgState {
H
Hu Tao 已提交
49 50 51 52
    /*< private >*/
    SysBusDevice parent_obj;
    /*< public >*/

A
Avi Kivity 已提交
53
    MemoryRegion ctl_iomem, data_iomem, comb_iomem;
B
Blue Swirl 已提交
54
    uint32_t ctl_iobase, data_iobase;
55
    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
G
Gerd Hoffmann 已提交
56
    FWCfgFiles *files;
57
    uint16_t cur_entry;
58
    uint32_t cur_offset;
G
Gleb Natapov 已提交
59
    Notifier machine_ready;
G
Gerd Hoffmann 已提交
60
};
61

W
wayne 已提交
62 63 64
#define JPG_FILE 0
#define BMP_FILE 1

65
static char *read_splashfile(char *filename, gsize *file_sizep,
66
                             int *file_typep)
W
wayne 已提交
67
{
68 69 70
    GError *err = NULL;
    gboolean res;
    gchar *content;
71 72
    int file_type;
    unsigned int filehead;
W
wayne 已提交
73 74
    int bmp_bpp;

75
    res = g_file_get_contents(filename, &content, file_sizep, &err);
76 77 78 79
    if (res == FALSE) {
        error_report("failed to read splash file '%s'", filename);
        g_error_free(err);
        return NULL;
W
wayne 已提交
80
    }
81

W
wayne 已提交
82
    /* check file size */
83 84
    if (*file_sizep < 30) {
        goto error;
W
wayne 已提交
85
    }
86

W
wayne 已提交
87
    /* check magic ID */
88 89
    filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
    if (filehead == 0xd8ff) {
W
wayne 已提交
90
        file_type = JPG_FILE;
91 92
    } else if (filehead == 0x4d42) {
        file_type = BMP_FILE;
W
wayne 已提交
93
    } else {
94
        goto error;
W
wayne 已提交
95
    }
96

W
wayne 已提交
97 98
    /* check BMP bpp */
    if (file_type == BMP_FILE) {
99
        bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
W
wayne 已提交
100
        if (bmp_bpp != 24) {
101
            goto error;
W
wayne 已提交
102 103
        }
    }
104

W
wayne 已提交
105 106
    /* return values */
    *file_typep = file_type;
107 108 109 110 111 112 113 114

    return content;

error:
    error_report("splash file '%s' format not recognized; must be JPEG "
                 "or 24 bit BMP", filename);
    g_free(content);
    return NULL;
W
wayne 已提交
115 116 117 118 119 120 121
}

static void fw_cfg_bootsplash(FWCfgState *s)
{
    int boot_splash_time = -1;
    const char *boot_splash_filename = NULL;
    char *p;
122
    char *filename, *file_data;
123
    gsize file_size;
124
    int file_type;
W
wayne 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
    const char *temp;

    /* get user configuration */
    QemuOptsList *plist = qemu_find_opts("boot-opts");
    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
    if (opts != NULL) {
        temp = qemu_opt_get(opts, "splash");
        if (temp != NULL) {
            boot_splash_filename = temp;
        }
        temp = qemu_opt_get(opts, "splash-time");
        if (temp != NULL) {
            p = (char *)temp;
            boot_splash_time = strtol(p, (char **)&p, 10);
        }
    }

    /* insert splash time if user configurated */
    if (boot_splash_time >= 0) {
        /* validate the input */
        if (boot_splash_time > 0xffff) {
            error_report("splash time is big than 65535, force it to 65535.");
            boot_splash_time = 0xffff;
        }
        /* use little endian format */
        qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
        qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
        fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
    }

    /* insert splash file if user configurated */
    if (boot_splash_filename != NULL) {
        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
        if (filename == NULL) {
            error_report("failed to find file '%s'.", boot_splash_filename);
            return;
        }
162 163 164 165

        /* loading file data */
        file_data = read_splashfile(filename, &file_size, &file_type);
        if (file_data == NULL) {
166
            g_free(filename);
W
wayne 已提交
167 168 169
            return;
        }
        if (boot_splash_filedata != NULL) {
170
            g_free(boot_splash_filedata);
W
wayne 已提交
171
        }
172
        boot_splash_filedata = (uint8_t *)file_data;
W
wayne 已提交
173
        boot_splash_filedata_size = file_size;
174

W
wayne 已提交
175 176 177 178 179 180 181 182
        /* insert data */
        if (file_type == JPG_FILE) {
            fw_cfg_add_file(s, "bootsplash.jpg",
                    boot_splash_filedata, boot_splash_filedata_size);
        } else {
            fw_cfg_add_file(s, "bootsplash.bmp",
                    boot_splash_filedata, boot_splash_filedata_size);
        }
183
        g_free(filename);
W
wayne 已提交
184 185 186
    }
}

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
static void fw_cfg_reboot(FWCfgState *s)
{
    int reboot_timeout = -1;
    char *p;
    const char *temp;

    /* get user configuration */
    QemuOptsList *plist = qemu_find_opts("boot-opts");
    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
    if (opts != NULL) {
        temp = qemu_opt_get(opts, "reboot-timeout");
        if (temp != NULL) {
            p = (char *)temp;
            reboot_timeout = strtol(p, (char **)&p, 10);
        }
    }
    /* validate the input */
    if (reboot_timeout > 0xffff) {
        error_report("reboot timeout is larger than 65535, force it to 65535.");
        reboot_timeout = 0xffff;
    }
    fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4);
}

211 212 213 214 215
static void fw_cfg_write(FWCfgState *s, uint8_t value)
{
    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];

216
    trace_fw_cfg_write(s, value);
217

218 219
    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback &&
        s->cur_offset < e->len) {
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
        e->data[s->cur_offset++] = value;
        if (s->cur_offset == e->len) {
            e->callback(e->callback_opaque, e->data);
            s->cur_offset = 0;
        }
    }
}

static int fw_cfg_select(FWCfgState *s, uint16_t key)
{
    int ret;

    s->cur_offset = 0;
    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
        s->cur_entry = FW_CFG_INVALID;
        ret = 0;
    } else {
        s->cur_entry = key;
        ret = 1;
    }

241
    trace_fw_cfg_select(s, key, ret);
242 243 244 245 246 247 248 249 250 251 252
    return ret;
}

static uint8_t fw_cfg_read(FWCfgState *s)
{
    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
    uint8_t ret;

    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
        ret = 0;
253 254 255 256
    else {
        if (e->read_callback) {
            e->read_callback(e->callback_opaque, s->cur_offset);
        }
257
        ret = e->data[s->cur_offset++];
258
    }
259

260
    trace_fw_cfg_read(s, ret);
261 262 263
    return ret;
}

A
Avi Kivity 已提交
264
static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
265
                                     unsigned size)
266 267 268 269
{
    return fw_cfg_read(opaque);
}

A
Avi Kivity 已提交
270
static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
271
                                  uint64_t value, unsigned size)
272
{
273
    fw_cfg_write(opaque, (uint8_t)value);
274 275
}

A
Avi Kivity 已提交
276
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
277
                                 uint64_t value, unsigned size)
278 279 280 281
{
    fw_cfg_select(opaque, (uint16_t)value);
}

A
Avi Kivity 已提交
282
static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
283
                                 unsigned size, bool is_write)
284
{
A
Avi Kivity 已提交
285
    return is_write && size == 2;
286 287
}

A
Avi Kivity 已提交
288
static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
289
                                 unsigned size)
290
{
A
Avi Kivity 已提交
291
    return fw_cfg_read(opaque);
292 293
}

A
Avi Kivity 已提交
294
static void fw_cfg_comb_write(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
295
                              uint64_t value, unsigned size)
296
{
A
Avi Kivity 已提交
297 298 299 300 301 302 303 304
    switch (size) {
    case 1:
        fw_cfg_write(opaque, (uint8_t)value);
        break;
    case 2:
        fw_cfg_select(opaque, (uint16_t)value);
        break;
    }
305 306
}

A
Avi Kivity 已提交
307
static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
308 309 310 311
                                  unsigned size, bool is_write)
{
    return (size == 1) || (is_write && size == 2);
}
312

A
Avi Kivity 已提交
313 314 315 316
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
    .write = fw_cfg_ctl_mem_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid.accepts = fw_cfg_ctl_mem_valid,
317 318
};

A
Avi Kivity 已提交
319 320 321 322 323 324 325 326
static const MemoryRegionOps fw_cfg_data_mem_ops = {
    .read = fw_cfg_data_mem_read,
    .write = fw_cfg_data_mem_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid = {
        .min_access_size = 1,
        .max_access_size = 1,
    },
327 328
};

A
Avi Kivity 已提交
329 330 331
static const MemoryRegionOps fw_cfg_comb_mem_ops = {
    .read = fw_cfg_comb_read,
    .write = fw_cfg_comb_write,
332
    .endianness = DEVICE_LITTLE_ENDIAN,
A
Avi Kivity 已提交
333
    .valid.accepts = fw_cfg_comb_valid,
334 335
};

B
Blue Swirl 已提交
336
static void fw_cfg_reset(DeviceState *d)
337
{
H
Hu Tao 已提交
338
    FWCfgState *s = FW_CFG(d);
339 340 341 342

    fw_cfg_select(s, 0);
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356
/* Save restore 32 bit int as uint16_t
   This is a Big hack, but it is how the old state did it.
   Or we broke compatibility in the state, or we can't use struct tm
 */

static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
{
    uint32_t *v = pv;
    *v = qemu_get_be16(f);
    return 0;
}

static void put_unused(QEMUFile *f, void *pv, size_t size)
{
357
    fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
358 359 360
    fprintf(stderr, "This functions shouldn't be called.\n");
}

B
Blue Swirl 已提交
361
static const VMStateInfo vmstate_hack_uint32_as_uint16 = {
362 363 364 365 366 367 368 369 370 371 372 373 374 375
    .name = "int32_as_uint16",
    .get  = get_uint32_as_uint16,
    .put  = put_unused,
};

#define VMSTATE_UINT16_HACK(_f, _s, _t)                                    \
    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)


static bool is_version_1(void *opaque, int version_id)
{
    return version_id == 1;
}

J
Juan Quintela 已提交
376 377
static const VMStateDescription vmstate_fw_cfg = {
    .name = "fw_cfg",
378
    .version_id = 2,
J
Juan Quintela 已提交
379
    .minimum_version_id = 1,
380
    .fields = (VMStateField[]) {
J
Juan Quintela 已提交
381
        VMSTATE_UINT16(cur_entry, FWCfgState),
382 383
        VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
        VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
J
Juan Quintela 已提交
384 385 386
        VMSTATE_END_OF_LIST()
    }
};
387

388 389 390 391
static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
                                           FWCfgReadCallback callback,
                                           void *callback_opaque,
                                           void *data, size_t len)
392 393 394 395 396
{
    int arch = !!(key & FW_CFG_ARCH_LOCAL);

    key &= FW_CFG_ENTRY_MASK;

397
    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
398 399

    s->entries[arch][key].data = data;
400
    s->entries[arch][key].len = (uint32_t)len;
401 402 403 404
    s->entries[arch][key].read_callback = callback;
    s->entries[arch][key].callback_opaque = callback_opaque;
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
                                              void *data, size_t len)
{
    void *ptr;
    int arch = !!(key & FW_CFG_ARCH_LOCAL);

    key &= FW_CFG_ENTRY_MASK;

    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);

    /* return the old data to the function caller, avoid memory leak */
    ptr = s->entries[arch][key].data;
    s->entries[arch][key].data = data;
    s->entries[arch][key].len = len;
    s->entries[arch][key].callback_opaque = NULL;
    s->entries[arch][key].callback = NULL;

    return ptr;
}

425 426 427
void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
{
    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len);
428 429
}

430 431 432 433
void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
{
    size_t sz = strlen(value) + 1;

434
    return fw_cfg_add_bytes(s, key, g_memdup(value, sz), sz);
435 436
}

437
void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
438 439 440
{
    uint16_t *copy;

441
    copy = g_malloc(sizeof(value));
442
    *copy = cpu_to_le16(value);
443
    fw_cfg_add_bytes(s, key, copy, sizeof(value));
444 445
}

446
void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
447 448 449
{
    uint32_t *copy;

450
    copy = g_malloc(sizeof(value));
451
    *copy = cpu_to_le32(value);
452
    fw_cfg_add_bytes(s, key, copy, sizeof(value));
453 454
}

455
void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
456 457 458
{
    uint64_t *copy;

459
    copy = g_malloc(sizeof(value));
460
    *copy = cpu_to_le64(value);
461
    fw_cfg_add_bytes(s, key, copy, sizeof(value));
462 463
}

464
void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
465
                         void *callback_opaque, void *data, size_t len)
466 467 468
{
    int arch = !!(key & FW_CFG_ARCH_LOCAL);

469
    assert(key & FW_CFG_WRITE_CHANNEL);
470

471 472
    key &= FW_CFG_ENTRY_MASK;

473
    assert(key < FW_CFG_MAX_ENTRY && len <= UINT32_MAX);
474 475

    s->entries[arch][key].data = data;
476
    s->entries[arch][key].len = (uint32_t)len;
477 478 479 480
    s->entries[arch][key].callback_opaque = callback_opaque;
    s->entries[arch][key].callback = callback;
}

481 482 483
void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
                              FWCfgReadCallback callback, void *callback_opaque,
                              void *data, size_t len)
G
Gerd Hoffmann 已提交
484
{
G
Gerd Hoffmann 已提交
485
    int i, index;
486
    size_t dsize;
G
Gerd Hoffmann 已提交
487 488

    if (!s->files) {
489
        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
490
        s->files = g_malloc0(dsize);
491
        fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
G
Gerd Hoffmann 已提交
492 493 494
    }

    index = be32_to_cpu(s->files->count);
495
    assert(index < FW_CFG_FILE_SLOTS);
G
Gerd Hoffmann 已提交
496

497 498
    fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
                                   callback, callback_opaque, data, len);
G
Gerd Hoffmann 已提交
499

500 501
    pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
            filename);
G
Gerd Hoffmann 已提交
502 503
    for (i = 0; i < index; i++) {
        if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
504
            trace_fw_cfg_add_file_dupe(s, s->files->f[index].name);
505
            return;
G
Gerd Hoffmann 已提交
506
        }
G
Gerd Hoffmann 已提交
507
    }
G
Gerd Hoffmann 已提交
508

G
Gerd Hoffmann 已提交
509 510
    s->files->f[index].size   = cpu_to_be32(len);
    s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
511
    trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
G
Gerd Hoffmann 已提交
512 513 514 515

    s->files->count = cpu_to_be32(index+1);
}

516 517 518 519 520 521
void fw_cfg_add_file(FWCfgState *s,  const char *filename,
                     void *data, size_t len)
{
    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
}

522 523 524 525
void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
                        void *data, size_t len)
{
    int i, index;
526
    void *ptr = NULL;
527 528 529 530 531 532 533 534

    assert(s->files);

    index = be32_to_cpu(s->files->count);
    assert(index < FW_CFG_FILE_SLOTS);

    for (i = 0; i < index; i++) {
        if (strcmp(filename, s->files->f[i].name) == 0) {
535 536 537 538
            ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
                                           data, len);
            s->files->f[i].size   = cpu_to_be32(len);
            return ptr;
539 540 541 542 543 544 545 546
        }
    }
    /* add new one */
    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
    return NULL;
}

static void fw_cfg_machine_reset(void *opaque)
G
Gleb Natapov 已提交
547
{
548
    void *ptr;
549
    size_t len;
550
    FWCfgState *s = opaque;
551
    char *bootindex = get_boot_devices_list(&len, false);
G
Gleb Natapov 已提交
552

553 554 555 556 557 558 559 560
    ptr = fw_cfg_modify_file(s, "bootorder", (uint8_t *)bootindex, len);
    g_free(ptr);
}

static void fw_cfg_machine_ready(struct Notifier *n, void *data)
{
    FWCfgState *s = container_of(n, FWCfgState, machine_ready);
    qemu_register_reset(fw_cfg_machine_reset, s);
G
Gleb Natapov 已提交
561 562
}

G
Gerd Hoffmann 已提交
563
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
A
Avi Kivity 已提交
564
                        hwaddr ctl_addr, hwaddr data_addr)
565
{
B
Blue Swirl 已提交
566 567
    DeviceState *dev;
    SysBusDevice *d;
568 569
    FWCfgState *s;

H
Hu Tao 已提交
570
    dev = qdev_create(NULL, TYPE_FW_CFG);
B
Blue Swirl 已提交
571 572
    qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
    qdev_prop_set_uint32(dev, "data_iobase", data_port);
573
    d = SYS_BUS_DEVICE(dev);
B
Blue Swirl 已提交
574

H
Hu Tao 已提交
575
    s = FW_CFG(dev);
576

577 578 579
    assert(!object_resolve_path(FW_CFG_PATH, NULL));

    object_property_add_child(qdev_get_machine(), FW_CFG_NAME, OBJECT(s), NULL);
580 581 582

    qdev_init_nofail(dev);

583
    if (ctl_addr) {
B
Blue Swirl 已提交
584
        sysbus_mmio_map(d, 0, ctl_addr);
585 586
    }
    if (data_addr) {
B
Blue Swirl 已提交
587
        sysbus_mmio_map(d, 1, data_addr);
588
    }
589
    fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
590
    fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
591
    fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
592
    fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
593
    fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
W
wayne 已提交
594
    fw_cfg_bootsplash(s);
595
    fw_cfg_reboot(s);
G
Gleb Natapov 已提交
596 597 598 599

    s->machine_ready.notify = fw_cfg_machine_ready;
    qemu_add_machine_init_done_notifier(&s->machine_ready);

600 601
    return s;
}
B
Blue Swirl 已提交
602

H
Hu Tao 已提交
603
static void fw_cfg_initfn(Object *obj)
B
Blue Swirl 已提交
604
{
H
Hu Tao 已提交
605 606
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    FWCfgState *s = FW_CFG(obj);
B
Blue Swirl 已提交
607

608
    memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, s,
A
Avi Kivity 已提交
609
                          "fwcfg.ctl", FW_CFG_SIZE);
H
Hu Tao 已提交
610
    sysbus_init_mmio(sbd, &s->ctl_iomem);
611
    memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops, s,
A
Avi Kivity 已提交
612
                          "fwcfg.data", FW_CFG_DATA_SIZE);
H
Hu Tao 已提交
613
    sysbus_init_mmio(sbd, &s->data_iomem);
A
Avi Kivity 已提交
614
    /* In case ctl and data overlap: */
615
    memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, s,
A
Avi Kivity 已提交
616
                          "fwcfg", FW_CFG_SIZE);
H
Hu Tao 已提交
617 618 619 620 621 622 623
}

static void fw_cfg_realize(DeviceState *dev, Error **errp)
{
    FWCfgState *s = FW_CFG(dev);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);

A
Avi Kivity 已提交
624 625

    if (s->ctl_iobase + 1 == s->data_iobase) {
H
Hu Tao 已提交
626
        sysbus_add_io(sbd, s->ctl_iobase, &s->comb_iomem);
A
Avi Kivity 已提交
627 628
    } else {
        if (s->ctl_iobase) {
H
Hu Tao 已提交
629
            sysbus_add_io(sbd, s->ctl_iobase, &s->ctl_iomem);
A
Avi Kivity 已提交
630 631
        }
        if (s->data_iobase) {
H
Hu Tao 已提交
632
            sysbus_add_io(sbd, s->data_iobase, &s->data_iomem);
A
Avi Kivity 已提交
633
        }
B
Blue Swirl 已提交
634 635 636
    }
}

637
static Property fw_cfg_properties[] = {
638 639
    DEFINE_PROP_UINT32("ctl_iobase", FWCfgState, ctl_iobase, -1),
    DEFINE_PROP_UINT32("data_iobase", FWCfgState, data_iobase, -1),
640 641 642
    DEFINE_PROP_END_OF_LIST(),
};

643 644
FWCfgState *fw_cfg_find(void)
{
H
Hu Tao 已提交
645
    return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
646 647
}

648 649
static void fw_cfg_class_init(ObjectClass *klass, void *data)
{
650
    DeviceClass *dc = DEVICE_CLASS(klass);
651

H
Hu Tao 已提交
652
    dc->realize = fw_cfg_realize;
653 654 655
    dc->reset = fw_cfg_reset;
    dc->vmsd = &vmstate_fw_cfg;
    dc->props = fw_cfg_properties;
656 657
}

658
static const TypeInfo fw_cfg_info = {
659
    .name          = TYPE_FW_CFG,
660 661
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(FWCfgState),
H
Hu Tao 已提交
662
    .instance_init = fw_cfg_initfn,
663
    .class_init    = fw_cfg_class_init,
B
Blue Swirl 已提交
664 665
};

A
Andreas Färber 已提交
666
static void fw_cfg_register_types(void)
B
Blue Swirl 已提交
667
{
668
    type_register_static(&fw_cfg_info);
B
Blue Swirl 已提交
669 670
}

A
Andreas Färber 已提交
671
type_init(fw_cfg_register_types)