Commit 3cce62435ccdab61336c6b0ec709252c79f553ba
1 parent
b03d0971
Key/value based qemu<->guest firmware communication mechanism (Gleb Natapov)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5256 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
344 additions
and
0 deletions
Makefile.target
@@ -474,6 +474,7 @@ endif #CONFIG_DARWIN_USER | @@ -474,6 +474,7 @@ endif #CONFIG_DARWIN_USER | ||
474 | ifndef CONFIG_USER_ONLY | 474 | ifndef CONFIG_USER_ONLY |
475 | 475 | ||
476 | OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o | 476 | OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o |
477 | +OBJS+=fw_cfg.o | ||
477 | ifdef CONFIG_WIN32 | 478 | ifdef CONFIG_WIN32 |
478 | OBJS+=block-raw-win32.o | 479 | OBJS+=block-raw-win32.o |
479 | else | 480 | else |
hw/fw_cfg.c
0 → 100644
1 | +/* | ||
2 | + * QEMU Firmware configuration device emulation | ||
3 | + * | ||
4 | + * Copyright (c) 2008 Gleb Natapov | ||
5 | + * | ||
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | + * of this software and associated documentation files (the "Software"), to deal | ||
8 | + * in the Software without restriction, including without limitation the rights | ||
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | + * copies of the Software, and to permit persons to whom the Software is | ||
11 | + * furnished to do so, subject to the following conditions: | ||
12 | + * | ||
13 | + * The above copyright notice and this permission notice shall be included in | ||
14 | + * all copies or substantial portions of the Software. | ||
15 | + * | ||
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | + * THE SOFTWARE. | ||
23 | + */ | ||
24 | +#include "hw.h" | ||
25 | +#include "isa.h" | ||
26 | +#include "fw_cfg.h" | ||
27 | + | ||
28 | +/* debug firmware config */ | ||
29 | +//#define DEBUG_FW_CFG | ||
30 | + | ||
31 | +#ifdef DEBUG_FW_CFG | ||
32 | +#define FW_CFG_DPRINTF(fmt, args...) \ | ||
33 | + do { printf("FW_CFG: " fmt , ##args); } while (0) | ||
34 | +#else | ||
35 | +#define FW_CFG_DPRINTF(fmt, args...) | ||
36 | +#endif | ||
37 | + | ||
38 | +#define FW_CFG_SIZE 2 | ||
39 | + | ||
40 | +typedef struct _FWCfgEntry { | ||
41 | + uint16_t len; | ||
42 | + uint8_t *data; | ||
43 | + void *callback_opaque; | ||
44 | + FWCfgCallback callback; | ||
45 | +} FWCfgEntry; | ||
46 | + | ||
47 | +typedef struct _FWCfgState { | ||
48 | + FWCfgEntry entries[2][FW_CFG_MAX_ENTRY]; | ||
49 | + uint16_t cur_entry; | ||
50 | + uint16_t cur_offset; | ||
51 | +} FWCfgState; | ||
52 | + | ||
53 | +static void fw_cfg_write(FWCfgState *s, uint8_t value) | ||
54 | +{ | ||
55 | + int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); | ||
56 | + FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; | ||
57 | + | ||
58 | + FW_CFG_DPRINTF("write %d\n", value); | ||
59 | + | ||
60 | + if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) { | ||
61 | + e->data[s->cur_offset++] = value; | ||
62 | + if (s->cur_offset == e->len) { | ||
63 | + e->callback(e->callback_opaque, e->data); | ||
64 | + s->cur_offset = 0; | ||
65 | + } | ||
66 | + } | ||
67 | +} | ||
68 | + | ||
69 | +static int fw_cfg_select(FWCfgState *s, uint16_t key) | ||
70 | +{ | ||
71 | + int ret; | ||
72 | + | ||
73 | + s->cur_offset = 0; | ||
74 | + if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) { | ||
75 | + s->cur_entry = FW_CFG_INVALID; | ||
76 | + ret = 0; | ||
77 | + } else { | ||
78 | + s->cur_entry = key; | ||
79 | + ret = 1; | ||
80 | + } | ||
81 | + | ||
82 | + FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not "); | ||
83 | + | ||
84 | + return ret; | ||
85 | +} | ||
86 | + | ||
87 | +static uint8_t fw_cfg_read(FWCfgState *s) | ||
88 | +{ | ||
89 | + int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); | ||
90 | + FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; | ||
91 | + uint8_t ret; | ||
92 | + | ||
93 | + if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len) | ||
94 | + ret = 0; | ||
95 | + else | ||
96 | + ret = e->data[s->cur_offset++]; | ||
97 | + | ||
98 | + FW_CFG_DPRINTF("read %d\n", ret); | ||
99 | + | ||
100 | + return ret; | ||
101 | +} | ||
102 | + | ||
103 | +static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr) | ||
104 | +{ | ||
105 | + return fw_cfg_read(opaque); | ||
106 | +} | ||
107 | + | ||
108 | +static void fw_cfg_io_writeb(void *opaque, uint32_t addr, uint32_t value) | ||
109 | +{ | ||
110 | + return fw_cfg_write(opaque, (uint8_t)value); | ||
111 | +} | ||
112 | + | ||
113 | +static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value) | ||
114 | +{ | ||
115 | + fw_cfg_select(opaque, (uint16_t)value); | ||
116 | +} | ||
117 | + | ||
118 | +static uint32_t fw_cfg_mem_readb(void *opaque, target_phys_addr_t addr) | ||
119 | +{ | ||
120 | + return fw_cfg_read(opaque); | ||
121 | +} | ||
122 | + | ||
123 | +static void fw_cfg_mem_writeb(void *opaque, target_phys_addr_t addr, | ||
124 | + uint32_t value) | ||
125 | +{ | ||
126 | + return fw_cfg_write(opaque, (uint8_t)value); | ||
127 | +} | ||
128 | + | ||
129 | +static void fw_cfg_mem_writew(void *opaque, target_phys_addr_t addr, | ||
130 | + uint32_t value) | ||
131 | +{ | ||
132 | + fw_cfg_select(opaque, (uint16_t)value); | ||
133 | +} | ||
134 | + | ||
135 | +static CPUReadMemoryFunc *fw_cfg_ctl_mem_read[3] = { | ||
136 | + NULL, | ||
137 | + NULL, | ||
138 | + NULL, | ||
139 | +}; | ||
140 | + | ||
141 | +static CPUWriteMemoryFunc *fw_cfg_ctl_mem_write[3] = { | ||
142 | + NULL, | ||
143 | + fw_cfg_mem_writew, | ||
144 | + NULL, | ||
145 | +}; | ||
146 | + | ||
147 | +static CPUReadMemoryFunc *fw_cfg_data_mem_read[3] = { | ||
148 | + fw_cfg_mem_readb, | ||
149 | + NULL, | ||
150 | + NULL, | ||
151 | +}; | ||
152 | + | ||
153 | +static CPUWriteMemoryFunc *fw_cfg_data_mem_write[3] = { | ||
154 | + fw_cfg_mem_writeb, | ||
155 | + NULL, | ||
156 | + NULL, | ||
157 | +}; | ||
158 | + | ||
159 | +static void fw_cfg_reset(void *opaque) | ||
160 | +{ | ||
161 | + FWCfgState *s = opaque; | ||
162 | + | ||
163 | + fw_cfg_select(s, 0); | ||
164 | +} | ||
165 | + | ||
166 | +static void fw_cfg_save(QEMUFile *f, void *opaque) | ||
167 | +{ | ||
168 | + FWCfgState *s = opaque; | ||
169 | + | ||
170 | + qemu_put_be16s(f, &s->cur_entry); | ||
171 | + qemu_put_be16s(f, &s->cur_offset); | ||
172 | +} | ||
173 | + | ||
174 | +static int fw_cfg_load(QEMUFile *f, void *opaque, int version_id) | ||
175 | +{ | ||
176 | + FWCfgState *s = opaque; | ||
177 | + | ||
178 | + if (version_id > 1) | ||
179 | + return -EINVAL; | ||
180 | + | ||
181 | + qemu_get_be16s(f, &s->cur_entry); | ||
182 | + qemu_get_be16s(f, &s->cur_offset); | ||
183 | + | ||
184 | + return 0; | ||
185 | +} | ||
186 | + | ||
187 | +int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint16_t len) | ||
188 | +{ | ||
189 | + FWCfgState *s = opaque; | ||
190 | + int arch = !!(key & FW_CFG_ARCH_LOCAL); | ||
191 | + | ||
192 | + key &= FW_CFG_ENTRY_MASK; | ||
193 | + | ||
194 | + if (key >= FW_CFG_MAX_ENTRY) | ||
195 | + return 0; | ||
196 | + | ||
197 | + s->entries[arch][key].data = data; | ||
198 | + s->entries[arch][key].len = len; | ||
199 | + | ||
200 | + return 1; | ||
201 | +} | ||
202 | + | ||
203 | +int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value) | ||
204 | +{ | ||
205 | + uint16_t *copy; | ||
206 | + | ||
207 | + copy = qemu_malloc(sizeof(value)); | ||
208 | + if (!copy) | ||
209 | + return 0; | ||
210 | + *copy = cpu_to_le16(value); | ||
211 | + return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value)); | ||
212 | +} | ||
213 | + | ||
214 | +int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value) | ||
215 | +{ | ||
216 | + uint32_t *copy; | ||
217 | + | ||
218 | + copy = qemu_malloc(sizeof(value)); | ||
219 | + if (!copy) | ||
220 | + return 0; | ||
221 | + *copy = cpu_to_le32(value); | ||
222 | + return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value)); | ||
223 | +} | ||
224 | + | ||
225 | +int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value) | ||
226 | +{ | ||
227 | + uint64_t *copy; | ||
228 | + | ||
229 | + copy = qemu_malloc(sizeof(value)); | ||
230 | + if (!copy) | ||
231 | + return 0; | ||
232 | + *copy = cpu_to_le64(value); | ||
233 | + return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value)); | ||
234 | +} | ||
235 | + | ||
236 | +int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback, | ||
237 | + void *callback_opaque, uint8_t *data, size_t len) | ||
238 | +{ | ||
239 | + FWCfgState *s = opaque; | ||
240 | + int arch = !!(key & FW_CFG_ARCH_LOCAL); | ||
241 | + | ||
242 | + key &= FW_CFG_ENTRY_MASK; | ||
243 | + | ||
244 | + if (key >= FW_CFG_MAX_ENTRY || !(key & FW_CFG_WRITE_CHANNEL) | ||
245 | + || len > 65535) | ||
246 | + return 0; | ||
247 | + | ||
248 | + s->entries[arch][key].data = data; | ||
249 | + s->entries[arch][key].len = len; | ||
250 | + s->entries[arch][key].callback_opaque = callback_opaque; | ||
251 | + s->entries[arch][key].callback = callback; | ||
252 | + | ||
253 | + return 1; | ||
254 | +} | ||
255 | + | ||
256 | +void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, | ||
257 | + target_phys_addr_t ctl_addr, target_phys_addr_t data_addr) | ||
258 | +{ | ||
259 | + FWCfgState *s; | ||
260 | + int io_ctl_memory, io_data_memory; | ||
261 | + | ||
262 | + s = qemu_mallocz(sizeof(FWCfgState)); | ||
263 | + if (!s) | ||
264 | + return NULL; | ||
265 | + | ||
266 | + if (ctl_port) { | ||
267 | + register_ioport_write(ctl_port, 2, 2, fw_cfg_io_writew, s); | ||
268 | + } | ||
269 | + if (data_port) { | ||
270 | + register_ioport_read(data_port, 1, 1, fw_cfg_io_readb, s); | ||
271 | + register_ioport_write(data_port, 1, 1, fw_cfg_io_writeb, s); | ||
272 | + } | ||
273 | + if (ctl_addr) { | ||
274 | + io_ctl_memory = cpu_register_io_memory(0, fw_cfg_ctl_mem_read, | ||
275 | + fw_cfg_ctl_mem_write, s); | ||
276 | + cpu_register_physical_memory(ctl_addr, FW_CFG_SIZE, io_ctl_memory); | ||
277 | + } | ||
278 | + if (data_addr) { | ||
279 | + io_data_memory = cpu_register_io_memory(0, fw_cfg_data_mem_read, | ||
280 | + fw_cfg_data_mem_write, s); | ||
281 | + cpu_register_physical_memory(data_addr, FW_CFG_SIZE, io_data_memory); | ||
282 | + } | ||
283 | + fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4); | ||
284 | + register_savevm("fw_cfg", -1, 1, fw_cfg_save, fw_cfg_load, s); | ||
285 | + qemu_register_reset(fw_cfg_reset, s); | ||
286 | + fw_cfg_reset(s); | ||
287 | + | ||
288 | + return s; | ||
289 | +} |
hw/fw_cfg.h
0 → 100644
1 | +#ifndef FW_CFG_H | ||
2 | +#define FW_CFG_H | ||
3 | + | ||
4 | +#define FW_CFG_SIGNATURE 0x00 | ||
5 | +#define FW_CFG_ID 0x01 | ||
6 | +#define FW_CFG_MAX_ENTRY 0x10 | ||
7 | + | ||
8 | +#define FW_CFG_WRITE_CHANNEL 0x4000 | ||
9 | +#define FW_CFG_ARCH_LOCAL 0x8000 | ||
10 | +#define FW_CFG_ENTRY_MASK ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL) | ||
11 | + | ||
12 | +#define FW_CFG_INVALID 0xffff | ||
13 | + | ||
14 | +#ifndef NO_QEMU_PROTOS | ||
15 | +typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); | ||
16 | + | ||
17 | +int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint16_t len); | ||
18 | +int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value); | ||
19 | +int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value); | ||
20 | +int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value); | ||
21 | +int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback, | ||
22 | + void *callback_opaque, uint8_t *data, size_t len); | ||
23 | +void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, | ||
24 | + target_phys_addr_t crl_addr, target_phys_addr_t data_addr); | ||
25 | + | ||
26 | +#endif /* NO_QEMU_PROTOS */ | ||
27 | + | ||
28 | +#endif |
hw/pc.c
@@ -32,6 +32,7 @@ | @@ -32,6 +32,7 @@ | ||
32 | #include "smbus.h" | 32 | #include "smbus.h" |
33 | #include "boards.h" | 33 | #include "boards.h" |
34 | #include "console.h" | 34 | #include "console.h" |
35 | +#include "fw_cfg.h" | ||
35 | 36 | ||
36 | /* output Bochs bios info messages */ | 37 | /* output Bochs bios info messages */ |
37 | //#define DEBUG_BIOS | 38 | //#define DEBUG_BIOS |
@@ -44,6 +45,7 @@ | @@ -44,6 +45,7 @@ | ||
44 | 45 | ||
45 | /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ | 46 | /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ |
46 | #define ACPI_DATA_SIZE 0x10000 | 47 | #define ACPI_DATA_SIZE 0x10000 |
48 | +#define BIOS_CFG_IOPORT 0x510 | ||
47 | 49 | ||
48 | #define MAX_IDE_BUS 2 | 50 | #define MAX_IDE_BUS 2 |
49 | 51 | ||
@@ -416,6 +418,8 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) | @@ -416,6 +418,8 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) | ||
416 | 418 | ||
417 | static void bochs_bios_init(void) | 419 | static void bochs_bios_init(void) |
418 | { | 420 | { |
421 | + void *fw_cfg; | ||
422 | + | ||
419 | register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); | 423 | register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); |
420 | register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); | 424 | register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); |
421 | register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); | 425 | register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); |
@@ -426,6 +430,9 @@ static void bochs_bios_init(void) | @@ -426,6 +430,9 @@ static void bochs_bios_init(void) | ||
426 | register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); | 430 | register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); |
427 | register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); | 431 | register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); |
428 | register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); | 432 | register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); |
433 | + | ||
434 | + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); | ||
435 | + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); | ||
429 | } | 436 | } |
430 | 437 | ||
431 | /* Generate an initial boot sector which sets state and jump to | 438 | /* Generate an initial boot sector which sets state and jump to |
hw/sun4m.c
@@ -34,6 +34,7 @@ | @@ -34,6 +34,7 @@ | ||
34 | #include "scsi.h" | 34 | #include "scsi.h" |
35 | #include "pc.h" | 35 | #include "pc.h" |
36 | #include "isa.h" | 36 | #include "isa.h" |
37 | +#include "fw_cfg.h" | ||
37 | 38 | ||
38 | //#define DEBUG_IRQ | 39 | //#define DEBUG_IRQ |
39 | 40 | ||
@@ -78,6 +79,7 @@ | @@ -78,6 +79,7 @@ | ||
78 | #define PROM_SIZE_MAX (512 * 1024) | 79 | #define PROM_SIZE_MAX (512 * 1024) |
79 | #define PROM_VADDR 0xffd00000 | 80 | #define PROM_VADDR 0xffd00000 |
80 | #define PROM_FILENAME "openbios-sparc32" | 81 | #define PROM_FILENAME "openbios-sparc32" |
82 | +#define CFG_ADDR 0xd00000510ULL | ||
81 | 83 | ||
82 | // Control plane, 8-bit and 24-bit planes | 84 | // Control plane, 8-bit and 24-bit planes |
83 | #define TCX_SIZE (9 * 1024 * 1024) | 85 | #define TCX_SIZE (9 * 1024 * 1024) |
@@ -410,6 +412,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | @@ -410,6 +412,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | ||
410 | char buf[1024]; | 412 | char buf[1024]; |
411 | BlockDriverState *fd[MAX_FD]; | 413 | BlockDriverState *fd[MAX_FD]; |
412 | int drive_index; | 414 | int drive_index; |
415 | + void *fw_cfg; | ||
413 | 416 | ||
414 | /* init CPUs */ | 417 | /* init CPUs */ |
415 | if (!cpu_model) | 418 | if (!cpu_model) |
@@ -570,6 +573,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | @@ -570,6 +573,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | ||
570 | if (hwdef->ecc_base != (target_phys_addr_t)-1) | 573 | if (hwdef->ecc_base != (target_phys_addr_t)-1) |
571 | ecc_init(hwdef->ecc_base, slavio_irq[hwdef->ecc_irq], | 574 | ecc_init(hwdef->ecc_base, slavio_irq[hwdef->ecc_irq], |
572 | hwdef->ecc_version); | 575 | hwdef->ecc_version); |
576 | + | ||
577 | + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); | ||
578 | + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); | ||
573 | } | 579 | } |
574 | 580 | ||
575 | static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | 581 | static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, |
@@ -589,6 +595,7 @@ static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | @@ -589,6 +595,7 @@ static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | ||
589 | char buf[1024]; | 595 | char buf[1024]; |
590 | BlockDriverState *fd[MAX_FD]; | 596 | BlockDriverState *fd[MAX_FD]; |
591 | int drive_index; | 597 | int drive_index; |
598 | + void *fw_cfg; | ||
592 | 599 | ||
593 | /* init CPU */ | 600 | /* init CPU */ |
594 | if (!cpu_model) | 601 | if (!cpu_model) |
@@ -715,6 +722,9 @@ static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | @@ -715,6 +722,9 @@ static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size, | ||
715 | nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, | 722 | nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, |
716 | boot_device, RAM_size, kernel_size, graphic_width, | 723 | boot_device, RAM_size, kernel_size, graphic_width, |
717 | graphic_height, graphic_depth, hwdef->machine_id, "Sun4c"); | 724 | graphic_height, graphic_depth, hwdef->machine_id, "Sun4c"); |
725 | + | ||
726 | + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); | ||
727 | + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); | ||
718 | } | 728 | } |
719 | 729 | ||
720 | static const struct hwdef hwdefs[] = { | 730 | static const struct hwdef hwdefs[] = { |
@@ -1405,6 +1415,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, | @@ -1405,6 +1415,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, | ||
1405 | int ret; | 1415 | int ret; |
1406 | char buf[1024]; | 1416 | char buf[1024]; |
1407 | int drive_index; | 1417 | int drive_index; |
1418 | + void *fw_cfg; | ||
1408 | 1419 | ||
1409 | /* init CPUs */ | 1420 | /* init CPUs */ |
1410 | if (!cpu_model) | 1421 | if (!cpu_model) |
@@ -1528,6 +1539,9 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, | @@ -1528,6 +1539,9 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, | ||
1528 | nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, | 1539 | nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, |
1529 | boot_device, RAM_size, kernel_size, graphic_width, | 1540 | boot_device, RAM_size, kernel_size, graphic_width, |
1530 | graphic_height, graphic_depth, hwdef->machine_id, "Sun4d"); | 1541 | graphic_height, graphic_depth, hwdef->machine_id, "Sun4d"); |
1542 | + | ||
1543 | + fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); | ||
1544 | + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); | ||
1531 | } | 1545 | } |
1532 | 1546 | ||
1533 | /* SPARCserver 1000 hardware initialisation */ | 1547 | /* SPARCserver 1000 hardware initialisation */ |
hw/sun4u.c
@@ -31,6 +31,7 @@ | @@ -31,6 +31,7 @@ | ||
31 | #include "sysemu.h" | 31 | #include "sysemu.h" |
32 | #include "boards.h" | 32 | #include "boards.h" |
33 | #include "firmware_abi.h" | 33 | #include "firmware_abi.h" |
34 | +#include "fw_cfg.h" | ||
34 | 35 | ||
35 | #define KERNEL_LOAD_ADDR 0x00404000 | 36 | #define KERNEL_LOAD_ADDR 0x00404000 |
36 | #define CMDLINE_ADDR 0x003ff000 | 37 | #define CMDLINE_ADDR 0x003ff000 |
@@ -44,6 +45,7 @@ | @@ -44,6 +45,7 @@ | ||
44 | #define PROM_FILENAME "openbios-sparc64" | 45 | #define PROM_FILENAME "openbios-sparc64" |
45 | #define NVRAM_SIZE 0x2000 | 46 | #define NVRAM_SIZE 0x2000 |
46 | #define MAX_IDE_BUS 2 | 47 | #define MAX_IDE_BUS 2 |
48 | +#define BIOS_CFG_IOPORT 0x510 | ||
47 | 49 | ||
48 | struct hwdef { | 50 | struct hwdef { |
49 | const char * const default_cpu_model; | 51 | const char * const default_cpu_model; |
@@ -270,6 +272,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, | @@ -270,6 +272,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, | ||
270 | int drive_index; | 272 | int drive_index; |
271 | BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; | 273 | BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; |
272 | BlockDriverState *fd[MAX_FD]; | 274 | BlockDriverState *fd[MAX_FD]; |
275 | + void *fw_cfg; | ||
273 | 276 | ||
274 | linux_boot = (kernel_filename != NULL); | 277 | linux_boot = (kernel_filename != NULL); |
275 | 278 | ||
@@ -415,6 +418,8 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, | @@ -415,6 +418,8 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, | ||
415 | graphic_width, graphic_height, graphic_depth, | 418 | graphic_width, graphic_height, graphic_depth, |
416 | (uint8_t *)&nd_table[0].macaddr); | 419 | (uint8_t *)&nd_table[0].macaddr); |
417 | 420 | ||
421 | + fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); | ||
422 | + fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); | ||
418 | } | 423 | } |
419 | 424 | ||
420 | static const struct hwdef hwdefs[] = { | 425 | static const struct hwdef hwdefs[] = { |