Statistics
| Branch: | Revision:

root / hw / fw_cfg.c @ cc9f28bc

History | View | Annotate | Download (8.5 kB)

1 3cce6243 blueswir1
/*
2 3cce6243 blueswir1
 * QEMU Firmware configuration device emulation
3 3cce6243 blueswir1
 *
4 3cce6243 blueswir1
 * Copyright (c) 2008 Gleb Natapov
5 3cce6243 blueswir1
 *
6 3cce6243 blueswir1
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 3cce6243 blueswir1
 * of this software and associated documentation files (the "Software"), to deal
8 3cce6243 blueswir1
 * in the Software without restriction, including without limitation the rights
9 3cce6243 blueswir1
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 3cce6243 blueswir1
 * copies of the Software, and to permit persons to whom the Software is
11 3cce6243 blueswir1
 * furnished to do so, subject to the following conditions:
12 3cce6243 blueswir1
 *
13 3cce6243 blueswir1
 * The above copyright notice and this permission notice shall be included in
14 3cce6243 blueswir1
 * all copies or substantial portions of the Software.
15 3cce6243 blueswir1
 *
16 3cce6243 blueswir1
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 3cce6243 blueswir1
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 3cce6243 blueswir1
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 3cce6243 blueswir1
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 3cce6243 blueswir1
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 3cce6243 blueswir1
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 3cce6243 blueswir1
 * THE SOFTWARE.
23 3cce6243 blueswir1
 */
24 3cce6243 blueswir1
#include "hw.h"
25 084a197a blueswir1
#include "sysemu.h"
26 3cce6243 blueswir1
#include "isa.h"
27 3cce6243 blueswir1
#include "fw_cfg.h"
28 3cce6243 blueswir1
29 3cce6243 blueswir1
/* debug firmware config */
30 3cce6243 blueswir1
//#define DEBUG_FW_CFG
31 3cce6243 blueswir1
32 3cce6243 blueswir1
#ifdef DEBUG_FW_CFG
33 001faf32 Blue Swirl
#define FW_CFG_DPRINTF(fmt, ...)                        \
34 001faf32 Blue Swirl
    do { printf("FW_CFG: " fmt , ## __VA_ARGS__); } while (0)
35 3cce6243 blueswir1
#else
36 001faf32 Blue Swirl
#define FW_CFG_DPRINTF(fmt, ...)
37 3cce6243 blueswir1
#endif
38 3cce6243 blueswir1
39 3cce6243 blueswir1
#define FW_CFG_SIZE 2
40 3cce6243 blueswir1
41 3cce6243 blueswir1
typedef struct _FWCfgEntry {
42 ff06108b Juan Quintela
    uint32_t len;
43 3cce6243 blueswir1
    uint8_t *data;
44 3cce6243 blueswir1
    void *callback_opaque;
45 3cce6243 blueswir1
    FWCfgCallback callback;
46 3cce6243 blueswir1
} FWCfgEntry;
47 3cce6243 blueswir1
48 3cce6243 blueswir1
typedef struct _FWCfgState {
49 3cce6243 blueswir1
    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
50 3cce6243 blueswir1
    uint16_t cur_entry;
51 ff06108b Juan Quintela
    uint32_t cur_offset;
52 3cce6243 blueswir1
} FWCfgState;
53 3cce6243 blueswir1
54 3cce6243 blueswir1
static void fw_cfg_write(FWCfgState *s, uint8_t value)
55 3cce6243 blueswir1
{
56 3cce6243 blueswir1
    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
57 3cce6243 blueswir1
    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
58 3cce6243 blueswir1
59 3cce6243 blueswir1
    FW_CFG_DPRINTF("write %d\n", value);
60 3cce6243 blueswir1
61 3cce6243 blueswir1
    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
62 3cce6243 blueswir1
        e->data[s->cur_offset++] = value;
63 3cce6243 blueswir1
        if (s->cur_offset == e->len) {
64 3cce6243 blueswir1
            e->callback(e->callback_opaque, e->data);
65 3cce6243 blueswir1
            s->cur_offset = 0;
66 3cce6243 blueswir1
        }
67 3cce6243 blueswir1
    }
68 3cce6243 blueswir1
}
69 3cce6243 blueswir1
70 3cce6243 blueswir1
static int fw_cfg_select(FWCfgState *s, uint16_t key)
71 3cce6243 blueswir1
{
72 3cce6243 blueswir1
    int ret;
73 3cce6243 blueswir1
74 3cce6243 blueswir1
    s->cur_offset = 0;
75 3cce6243 blueswir1
    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
76 3cce6243 blueswir1
        s->cur_entry = FW_CFG_INVALID;
77 3cce6243 blueswir1
        ret = 0;
78 3cce6243 blueswir1
    } else {
79 3cce6243 blueswir1
        s->cur_entry = key;
80 3cce6243 blueswir1
        ret = 1;
81 3cce6243 blueswir1
    }
82 3cce6243 blueswir1
83 3cce6243 blueswir1
    FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not ");
84 3cce6243 blueswir1
85 3cce6243 blueswir1
    return ret;
86 3cce6243 blueswir1
}
87 3cce6243 blueswir1
88 3cce6243 blueswir1
static uint8_t fw_cfg_read(FWCfgState *s)
89 3cce6243 blueswir1
{
90 3cce6243 blueswir1
    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
91 3cce6243 blueswir1
    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
92 3cce6243 blueswir1
    uint8_t ret;
93 3cce6243 blueswir1
94 3cce6243 blueswir1
    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
95 3cce6243 blueswir1
        ret = 0;
96 3cce6243 blueswir1
    else
97 3cce6243 blueswir1
        ret = e->data[s->cur_offset++];
98 3cce6243 blueswir1
99 3cce6243 blueswir1
    FW_CFG_DPRINTF("read %d\n", ret);
100 3cce6243 blueswir1
101 3cce6243 blueswir1
    return ret;
102 3cce6243 blueswir1
}
103 3cce6243 blueswir1
104 3cce6243 blueswir1
static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr)
105 3cce6243 blueswir1
{
106 3cce6243 blueswir1
    return fw_cfg_read(opaque);
107 3cce6243 blueswir1
}
108 3cce6243 blueswir1
109 3cce6243 blueswir1
static void fw_cfg_io_writeb(void *opaque, uint32_t addr, uint32_t value)
110 3cce6243 blueswir1
{
111 7442511c blueswir1
    fw_cfg_write(opaque, (uint8_t)value);
112 3cce6243 blueswir1
}
113 3cce6243 blueswir1
114 3cce6243 blueswir1
static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value)
115 3cce6243 blueswir1
{
116 3cce6243 blueswir1
    fw_cfg_select(opaque, (uint16_t)value);
117 3cce6243 blueswir1
}
118 3cce6243 blueswir1
119 c227f099 Anthony Liguori
static uint32_t fw_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
120 3cce6243 blueswir1
{
121 3cce6243 blueswir1
    return fw_cfg_read(opaque);
122 3cce6243 blueswir1
}
123 3cce6243 blueswir1
124 c227f099 Anthony Liguori
static void fw_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
125 3cce6243 blueswir1
                              uint32_t value)
126 3cce6243 blueswir1
{
127 7442511c blueswir1
    fw_cfg_write(opaque, (uint8_t)value);
128 3cce6243 blueswir1
}
129 3cce6243 blueswir1
130 c227f099 Anthony Liguori
static void fw_cfg_mem_writew(void *opaque, target_phys_addr_t addr,
131 3cce6243 blueswir1
                              uint32_t value)
132 3cce6243 blueswir1
{
133 3cce6243 blueswir1
    fw_cfg_select(opaque, (uint16_t)value);
134 3cce6243 blueswir1
}
135 3cce6243 blueswir1
136 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const fw_cfg_ctl_mem_read[3] = {
137 3cce6243 blueswir1
    NULL,
138 3cce6243 blueswir1
    NULL,
139 3cce6243 blueswir1
    NULL,
140 3cce6243 blueswir1
};
141 3cce6243 blueswir1
142 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const fw_cfg_ctl_mem_write[3] = {
143 3cce6243 blueswir1
    NULL,
144 3cce6243 blueswir1
    fw_cfg_mem_writew,
145 3cce6243 blueswir1
    NULL,
146 3cce6243 blueswir1
};
147 3cce6243 blueswir1
148 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const fw_cfg_data_mem_read[3] = {
149 3cce6243 blueswir1
    fw_cfg_mem_readb,
150 3cce6243 blueswir1
    NULL,
151 3cce6243 blueswir1
    NULL,
152 3cce6243 blueswir1
};
153 3cce6243 blueswir1
154 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const fw_cfg_data_mem_write[3] = {
155 3cce6243 blueswir1
    fw_cfg_mem_writeb,
156 3cce6243 blueswir1
    NULL,
157 3cce6243 blueswir1
    NULL,
158 3cce6243 blueswir1
};
159 3cce6243 blueswir1
160 3cce6243 blueswir1
static void fw_cfg_reset(void *opaque)
161 3cce6243 blueswir1
{
162 3cce6243 blueswir1
    FWCfgState *s = opaque;
163 3cce6243 blueswir1
164 3cce6243 blueswir1
    fw_cfg_select(s, 0);
165 3cce6243 blueswir1
}
166 3cce6243 blueswir1
167 ff06108b Juan Quintela
/* Save restore 32 bit int as uint16_t
168 ff06108b Juan Quintela
   This is a Big hack, but it is how the old state did it.
169 ff06108b Juan Quintela
   Or we broke compatibility in the state, or we can't use struct tm
170 ff06108b Juan Quintela
 */
171 ff06108b Juan Quintela
172 ff06108b Juan Quintela
static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
173 ff06108b Juan Quintela
{
174 ff06108b Juan Quintela
    uint32_t *v = pv;
175 ff06108b Juan Quintela
    *v = qemu_get_be16(f);
176 ff06108b Juan Quintela
    return 0;
177 ff06108b Juan Quintela
}
178 ff06108b Juan Quintela
179 ff06108b Juan Quintela
static void put_unused(QEMUFile *f, void *pv, size_t size)
180 ff06108b Juan Quintela
{
181 ff06108b Juan Quintela
    fprintf(stderr, "uint32_as_uint16 is only used for backward compatibilty.\n");
182 ff06108b Juan Quintela
    fprintf(stderr, "This functions shouldn't be called.\n");
183 ff06108b Juan Quintela
}
184 ff06108b Juan Quintela
185 ff06108b Juan Quintela
const VMStateInfo vmstate_hack_uint32_as_uint16 = {
186 ff06108b Juan Quintela
    .name = "int32_as_uint16",
187 ff06108b Juan Quintela
    .get  = get_uint32_as_uint16,
188 ff06108b Juan Quintela
    .put  = put_unused,
189 ff06108b Juan Quintela
};
190 ff06108b Juan Quintela
191 ff06108b Juan Quintela
#define VMSTATE_UINT16_HACK(_f, _s, _t)                                    \
192 ff06108b Juan Quintela
    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)
193 ff06108b Juan Quintela
194 ff06108b Juan Quintela
195 ff06108b Juan Quintela
static bool is_version_1(void *opaque, int version_id)
196 ff06108b Juan Quintela
{
197 ff06108b Juan Quintela
    return version_id == 1;
198 ff06108b Juan Quintela
}
199 ff06108b Juan Quintela
200 7d2edd40 Juan Quintela
static const VMStateDescription vmstate_fw_cfg = {
201 7d2edd40 Juan Quintela
    .name = "fw_cfg",
202 ff06108b Juan Quintela
    .version_id = 2,
203 7d2edd40 Juan Quintela
    .minimum_version_id = 1,
204 7d2edd40 Juan Quintela
    .minimum_version_id_old = 1,
205 7d2edd40 Juan Quintela
    .fields      = (VMStateField []) {
206 7d2edd40 Juan Quintela
        VMSTATE_UINT16(cur_entry, FWCfgState),
207 ff06108b Juan Quintela
        VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
208 ff06108b Juan Quintela
        VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
209 7d2edd40 Juan Quintela
        VMSTATE_END_OF_LIST()
210 7d2edd40 Juan Quintela
    }
211 7d2edd40 Juan Quintela
};
212 3cce6243 blueswir1
213 ff06108b Juan Quintela
int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint32_t len)
214 3cce6243 blueswir1
{
215 3cce6243 blueswir1
    FWCfgState *s = opaque;
216 3cce6243 blueswir1
    int arch = !!(key & FW_CFG_ARCH_LOCAL);
217 3cce6243 blueswir1
218 3cce6243 blueswir1
    key &= FW_CFG_ENTRY_MASK;
219 3cce6243 blueswir1
220 3cce6243 blueswir1
    if (key >= FW_CFG_MAX_ENTRY)
221 3cce6243 blueswir1
        return 0;
222 3cce6243 blueswir1
223 3cce6243 blueswir1
    s->entries[arch][key].data = data;
224 3cce6243 blueswir1
    s->entries[arch][key].len = len;
225 3cce6243 blueswir1
226 3cce6243 blueswir1
    return 1;
227 3cce6243 blueswir1
}
228 3cce6243 blueswir1
229 3cce6243 blueswir1
int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value)
230 3cce6243 blueswir1
{
231 3cce6243 blueswir1
    uint16_t *copy;
232 3cce6243 blueswir1
233 3cce6243 blueswir1
    copy = qemu_malloc(sizeof(value));
234 3cce6243 blueswir1
    *copy = cpu_to_le16(value);
235 3cce6243 blueswir1
    return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
236 3cce6243 blueswir1
}
237 3cce6243 blueswir1
238 3cce6243 blueswir1
int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value)
239 3cce6243 blueswir1
{
240 3cce6243 blueswir1
    uint32_t *copy;
241 3cce6243 blueswir1
242 3cce6243 blueswir1
    copy = qemu_malloc(sizeof(value));
243 3cce6243 blueswir1
    *copy = cpu_to_le32(value);
244 3cce6243 blueswir1
    return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
245 3cce6243 blueswir1
}
246 3cce6243 blueswir1
247 3cce6243 blueswir1
int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value)
248 3cce6243 blueswir1
{
249 3cce6243 blueswir1
    uint64_t *copy;
250 3cce6243 blueswir1
251 3cce6243 blueswir1
    copy = qemu_malloc(sizeof(value));
252 3cce6243 blueswir1
    *copy = cpu_to_le64(value);
253 3cce6243 blueswir1
    return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
254 3cce6243 blueswir1
}
255 3cce6243 blueswir1
256 3cce6243 blueswir1
int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
257 3cce6243 blueswir1
                        void *callback_opaque, uint8_t *data, size_t len)
258 3cce6243 blueswir1
{
259 3cce6243 blueswir1
    FWCfgState *s = opaque;
260 3cce6243 blueswir1
    int arch = !!(key & FW_CFG_ARCH_LOCAL);
261 3cce6243 blueswir1
262 85df0de4 blueswir1
    if (!(key & FW_CFG_WRITE_CHANNEL))
263 85df0de4 blueswir1
        return 0;
264 85df0de4 blueswir1
265 3cce6243 blueswir1
    key &= FW_CFG_ENTRY_MASK;
266 3cce6243 blueswir1
267 85df0de4 blueswir1
    if (key >= FW_CFG_MAX_ENTRY || len > 65535)
268 3cce6243 blueswir1
        return 0;
269 3cce6243 blueswir1
270 3cce6243 blueswir1
    s->entries[arch][key].data = data;
271 3cce6243 blueswir1
    s->entries[arch][key].len = len;
272 3cce6243 blueswir1
    s->entries[arch][key].callback_opaque = callback_opaque;
273 3cce6243 blueswir1
    s->entries[arch][key].callback = callback;
274 3cce6243 blueswir1
275 3cce6243 blueswir1
    return 1;
276 3cce6243 blueswir1
}
277 3cce6243 blueswir1
278 3cce6243 blueswir1
void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
279 c227f099 Anthony Liguori
                target_phys_addr_t ctl_addr, target_phys_addr_t data_addr)
280 3cce6243 blueswir1
{
281 3cce6243 blueswir1
    FWCfgState *s;
282 3cce6243 blueswir1
    int io_ctl_memory, io_data_memory;
283 3cce6243 blueswir1
284 3cce6243 blueswir1
    s = qemu_mallocz(sizeof(FWCfgState));
285 3cce6243 blueswir1
286 3cce6243 blueswir1
    if (ctl_port) {
287 3cce6243 blueswir1
        register_ioport_write(ctl_port, 2, 2, fw_cfg_io_writew, s);
288 3cce6243 blueswir1
    }
289 3cce6243 blueswir1
    if (data_port) {
290 3cce6243 blueswir1
        register_ioport_read(data_port, 1, 1, fw_cfg_io_readb, s);
291 3cce6243 blueswir1
        register_ioport_write(data_port, 1, 1, fw_cfg_io_writeb, s);
292 3cce6243 blueswir1
    }
293 3cce6243 blueswir1
    if (ctl_addr) {
294 1eed09cb Avi Kivity
        io_ctl_memory = cpu_register_io_memory(fw_cfg_ctl_mem_read,
295 3cce6243 blueswir1
                                           fw_cfg_ctl_mem_write, s);
296 3cce6243 blueswir1
        cpu_register_physical_memory(ctl_addr, FW_CFG_SIZE, io_ctl_memory);
297 3cce6243 blueswir1
    }
298 3cce6243 blueswir1
    if (data_addr) {
299 1eed09cb Avi Kivity
        io_data_memory = cpu_register_io_memory(fw_cfg_data_mem_read,
300 3cce6243 blueswir1
                                           fw_cfg_data_mem_write, s);
301 3cce6243 blueswir1
        cpu_register_physical_memory(data_addr, FW_CFG_SIZE, io_data_memory);
302 3cce6243 blueswir1
    }
303 3cce6243 blueswir1
    fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4);
304 084a197a blueswir1
    fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
305 993fbfdb Anthony Liguori
    fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
306 905fdcb5 blueswir1
    fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
307 6be68d7e Jes Sorensen
    fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
308 95387491 Jan Kiszka
    fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
309 905fdcb5 blueswir1
310 7d2edd40 Juan Quintela
    vmstate_register(-1, &vmstate_fw_cfg, s);
311 a08d4367 Jan Kiszka
    qemu_register_reset(fw_cfg_reset, s);
312 3cce6243 blueswir1
313 3cce6243 blueswir1
    return s;
314 3cce6243 blueswir1
}