]> Git Repo - qemu.git/blame - hw/sun4m.c
Add SparcStation-10 machine
[qemu.git] / hw / sun4m.c
CommitLineData
420557e8
FB
1/*
2 * QEMU Sun4m System Emulator
3 *
b81b3b10 4 * Copyright (c) 2003-2005 Fabrice Bellard
420557e8
FB
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 "vl.h"
420557e8 25
36cd9210
BS
26/*
27 * Sun4m architecture was used in the following machines:
28 *
29 * SPARCserver 6xxMP/xx
30 * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), SPARCclassic X (4/10)
31 * SPARCstation LX/ZX (4/30)
32 * SPARCstation Voyager
33 * SPARCstation 10/xx, SPARCserver 10/xx
34 * SPARCstation 5, SPARCserver 5
35 * SPARCstation 20/xx, SPARCserver 20
36 * SPARCstation 4
37 *
38 * See for example: http://www.sunhelp.org/faq/sunref1.html
39 */
40
420557e8 41#define KERNEL_LOAD_ADDR 0x00004000
b6f479d3 42#define CMDLINE_ADDR 0x007ff000
713c45fa 43#define INITRD_LOAD_ADDR 0x00800000
b3783731 44#define PROM_SIZE_MAX (256 * 1024)
e80cfcfc 45#define PROM_ADDR 0xffd00000
0986ac3b 46#define PROM_FILENAME "openbios-sparc32"
b8174937 47
ba3c64fb 48#define MAX_CPUS 16
420557e8 49
36cd9210
BS
50struct hwdef {
51 target_ulong iommu_base, slavio_base;
52 target_ulong intctl_base, counter_base, nvram_base, ms_kb_base, serial_base;
53 target_ulong fd_base;
54 target_ulong dma_base, esp_base, le_base;
55 target_ulong tcx_base, cs_base;
56 long vram_size, nvram_size;
57 // IRQ numbers are not PIL ones, but master interrupt controller register
58 // bit numbers
59 int intctl_g_intr, esp_irq, le_irq, cpu_irq, clock_irq, clock1_irq;
60 int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq;
61 int machine_id; // For NVRAM
e0353fe2 62 uint32_t intbit_to_level[32];
36cd9210
BS
63};
64
420557e8
FB
65/* TSC handling */
66
67uint64_t cpu_get_tsc()
68{
69 return qemu_get_clock(vm_clock);
70}
71
6f7e9aec
FB
72int DMA_get_channel_mode (int nchan)
73{
74 return 0;
75}
76int DMA_read_memory (int nchan, void *buf, int pos, int size)
77{
78 return 0;
79}
80int DMA_write_memory (int nchan, void *buf, int pos, int size)
81{
82 return 0;
83}
84void DMA_hold_DREQ (int nchan) {}
85void DMA_release_DREQ (int nchan) {}
86void DMA_schedule(int nchan) {}
87void DMA_run (void) {}
88void DMA_init (int high_page_enable) {}
89void DMA_register_channel (int nchan,
90 DMA_transfer_handler transfer_handler,
91 void *opaque)
92{
93}
94
819385c5 95static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
6f7e9aec 96{
819385c5
FB
97 m48t59_write(nvram, addr++, (value >> 8) & 0xff);
98 m48t59_write(nvram, addr++, value & 0xff);
6f7e9aec
FB
99}
100
819385c5 101static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
6f7e9aec 102{
819385c5
FB
103 m48t59_write(nvram, addr++, value >> 24);
104 m48t59_write(nvram, addr++, (value >> 16) & 0xff);
105 m48t59_write(nvram, addr++, (value >> 8) & 0xff);
106 m48t59_write(nvram, addr++, value & 0xff);
6f7e9aec
FB
107}
108
819385c5 109static void nvram_set_string (m48t59_t *nvram, uint32_t addr,
6f7e9aec
FB
110 const unsigned char *str, uint32_t max)
111{
112 unsigned int i;
113
114 for (i = 0; i < max && str[i] != '\0'; i++) {
819385c5 115 m48t59_write(nvram, addr + i, str[i]);
6f7e9aec 116 }
819385c5 117 m48t59_write(nvram, addr + max - 1, '\0');
6f7e9aec 118}
420557e8 119
819385c5 120static m48t59_t *nvram;
420557e8 121
6f7e9aec
FB
122extern int nographic;
123
819385c5 124static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline,
6f7e9aec
FB
125 int boot_device, uint32_t RAM_size,
126 uint32_t kernel_size,
36cd9210
BS
127 int width, int height, int depth,
128 int machine_id)
e80cfcfc
FB
129{
130 unsigned char tmp = 0;
131 int i, j;
132
6f7e9aec
FB
133 // Try to match PPC NVRAM
134 nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
135 nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */
136 // NVRAM_size, arch not applicable
ba3c64fb
FB
137 m48t59_write(nvram, 0x2D, smp_cpus & 0xff);
138 m48t59_write(nvram, 0x2E, 0);
819385c5 139 m48t59_write(nvram, 0x2F, nographic & 0xff);
6f7e9aec 140 nvram_set_lword(nvram, 0x30, RAM_size);
819385c5 141 m48t59_write(nvram, 0x34, boot_device & 0xff);
6f7e9aec
FB
142 nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR);
143 nvram_set_lword(nvram, 0x3C, kernel_size);
b6f479d3 144 if (cmdline) {
b6f479d3 145 strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
6f7e9aec
FB
146 nvram_set_lword(nvram, 0x40, CMDLINE_ADDR);
147 nvram_set_lword(nvram, 0x44, strlen(cmdline));
b6f479d3 148 }
6f7e9aec
FB
149 // initrd_image, initrd_size passed differently
150 nvram_set_word(nvram, 0x54, width);
151 nvram_set_word(nvram, 0x56, height);
152 nvram_set_word(nvram, 0x58, depth);
b6f479d3 153
6f7e9aec 154 // Sun4m specific use
e80cfcfc 155 i = 0x1fd8;
819385c5 156 m48t59_write(nvram, i++, 0x01);
36cd9210 157 m48t59_write(nvram, i++, machine_id);
e80cfcfc 158 j = 0;
819385c5
FB
159 m48t59_write(nvram, i++, macaddr[j++]);
160 m48t59_write(nvram, i++, macaddr[j++]);
161 m48t59_write(nvram, i++, macaddr[j++]);
162 m48t59_write(nvram, i++, macaddr[j++]);
163 m48t59_write(nvram, i++, macaddr[j++]);
164 m48t59_write(nvram, i, macaddr[j]);
e80cfcfc
FB
165
166 /* Calculate checksum */
167 for (i = 0x1fd8; i < 0x1fe7; i++) {
819385c5 168 tmp ^= m48t59_read(nvram, i);
e80cfcfc 169 }
819385c5 170 m48t59_write(nvram, 0x1fe7, tmp);
e80cfcfc
FB
171}
172
173static void *slavio_intctl;
174
175void pic_info()
176{
177 slavio_pic_info(slavio_intctl);
178}
179
180void irq_info()
181{
182 slavio_irq_info(slavio_intctl);
183}
184
185void pic_set_irq(int irq, int level)
186{
187 slavio_pic_set_irq(slavio_intctl, irq, level);
188}
189
502a5395
PB
190void pic_set_irq_new(void *opaque, int irq, int level)
191{
192 pic_set_irq(irq, level);
193}
194
ba3c64fb
FB
195void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
196{
197 slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
198}
199
3475187d
FB
200static void *slavio_misc;
201
202void qemu_system_powerdown(void)
203{
204 slavio_set_power_fail(slavio_misc, 1);
205}
206
c68ea704
FB
207static void main_cpu_reset(void *opaque)
208{
209 CPUState *env = opaque;
210 cpu_reset(env);
211}
212
36cd9210
BS
213static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size,
214 DisplayState *ds, const char *cpu_model)
215
420557e8 216{
ba3c64fb 217 CPUState *env, *envs[MAX_CPUS];
713c45fa 218 unsigned int i;
67e999be 219 void *iommu, *dma, *main_esp, *main_lance = NULL;
62724a37 220 const sparc_def_t *def;
420557e8 221
ba3c64fb 222 /* init CPUs */
62724a37
BS
223 sparc_find_by_name(cpu_model, &def);
224 if (def == NULL) {
225 fprintf(stderr, "Unable to find Sparc CPU definition\n");
226 exit(1);
227 }
ba3c64fb
FB
228 for(i = 0; i < smp_cpus; i++) {
229 env = cpu_init();
62724a37 230 cpu_sparc_register(env, def);
ba3c64fb
FB
231 envs[i] = env;
232 if (i != 0)
233 env->halted = 1;
234 register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
235 qemu_register_reset(main_cpu_reset, env);
236 }
420557e8
FB
237 /* allocate RAM */
238 cpu_register_physical_memory(0, ram_size, 0);
420557e8 239
36cd9210
BS
240 iommu = iommu_init(hwdef->iommu_base);
241 slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
e0353fe2
BS
242 hwdef->intctl_base + 0x10000,
243 &hwdef->intbit_to_level[0]);
ba3c64fb
FB
244 for(i = 0; i < smp_cpus; i++) {
245 slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
246 }
36cd9210
BS
247 dma = sparc32_dma_init(hwdef->dma_base, hwdef->esp_irq,
248 hwdef->le_irq, iommu, slavio_intctl);
ba3c64fb 249
36cd9210
BS
250 tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size,
251 hwdef->vram_size, graphic_width, graphic_height);
a41b2ff2
PB
252 if (nd_table[0].vlan) {
253 if (nd_table[0].model == NULL
254 || strcmp(nd_table[0].model, "lance") == 0) {
36cd9210 255 main_lance = lance_init(&nd_table[0], hwdef->le_base, dma);
a41b2ff2
PB
256 } else {
257 fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
258 exit (1);
259 }
260 }
36cd9210 261 nvram = m48t59_init(0, hwdef->nvram_base, 0, hwdef->nvram_size, 8);
ba3c64fb 262 for (i = 0; i < MAX_CPUS; i++) {
36cd9210
BS
263 slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE,
264 hwdef->clock_irq, 0, i);
ba3c64fb 265 }
36cd9210
BS
266 slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2,
267 (unsigned int)-1);
268 slavio_serial_ms_kbd_init(hwdef->ms_kb_base, hwdef->ms_kb_irq);
b81b3b10
FB
269 // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
270 // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
36cd9210
BS
271 slavio_serial_init(hwdef->serial_base, hwdef->ser_irq,
272 serial_hds[1], serial_hds[0]);
273 fdctrl_init(hwdef->fd_irq, 0, 1, hwdef->fd_base, fd_table);
274 main_esp = esp_init(bs_table, hwdef->esp_base, dma);
f1587550
TS
275
276 for (i = 0; i < MAX_DISKS; i++) {
277 if (bs_table[i]) {
278 esp_scsi_attach(main_esp, bs_table[i], i);
279 }
280 }
281
36cd9210
BS
282 slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq);
283 cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
67e999be 284 sparc32_dma_set_reset_data(dma, main_esp, main_lance);
36cd9210
BS
285}
286
287static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device,
288 const char *kernel_filename,
289 const char *kernel_cmdline,
290 const char *initrd_filename,
291 int machine_id)
292{
293 int ret, linux_boot;
294 char buf[1024];
295 unsigned int i;
296 long prom_offset, initrd_size, kernel_size;
297
298 linux_boot = (kernel_filename != NULL);
420557e8 299
e80cfcfc 300 prom_offset = ram_size + vram_size;
b3783731
FB
301 cpu_register_physical_memory(PROM_ADDR,
302 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK,
303 prom_offset | IO_MEM_ROM);
e80cfcfc 304
0986ac3b 305 snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
9ee3c029 306 ret = load_elf(buf, 0, NULL);
e80cfcfc
FB
307 if (ret < 0) {
308 fprintf(stderr, "qemu: could not load prom '%s'\n",
309 buf);
310 exit(1);
311 }
e80cfcfc 312
6f7e9aec 313 kernel_size = 0;
e80cfcfc 314 if (linux_boot) {
9ee3c029 315 kernel_size = load_elf(kernel_filename, -0xf0000000, NULL);
6f7e9aec
FB
316 if (kernel_size < 0)
317 kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
318 if (kernel_size < 0)
319 kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
320 if (kernel_size < 0) {
420557e8 321 fprintf(stderr, "qemu: could not load kernel '%s'\n",
e80cfcfc
FB
322 kernel_filename);
323 exit(1);
420557e8 324 }
713c45fa
FB
325
326 /* load initrd */
327 initrd_size = 0;
328 if (initrd_filename) {
329 initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
330 if (initrd_size < 0) {
331 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
332 initrd_filename);
333 exit(1);
334 }
335 }
336 if (initrd_size > 0) {
337 for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
338 if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
339 == 0x48647253) { // HdrS
340 stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
341 stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
342 break;
343 }
344 }
345 }
420557e8 346 }
36cd9210
BS
347 nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
348 boot_device, ram_size, kernel_size, graphic_width,
349 graphic_height, graphic_depth, machine_id);
350}
351
352static const struct hwdef hwdefs[] = {
353 /* SS-5 */
354 {
355 .iommu_base = 0x10000000,
356 .tcx_base = 0x50000000,
357 .cs_base = 0x6c000000,
358 .slavio_base = 0x71000000,
359 .ms_kb_base = 0x71000000,
360 .serial_base = 0x71100000,
361 .nvram_base = 0x71200000,
362 .fd_base = 0x71400000,
363 .counter_base = 0x71d00000,
364 .intctl_base = 0x71e00000,
365 .dma_base = 0x78400000,
366 .esp_base = 0x78800000,
367 .le_base = 0x78c00000,
368 .vram_size = 0x00100000,
369 .nvram_size = 0x2000,
370 .esp_irq = 18,
371 .le_irq = 16,
372 .clock_irq = 7,
373 .clock1_irq = 19,
374 .ms_kb_irq = 14,
375 .ser_irq = 15,
376 .fd_irq = 22,
377 .me_irq = 30,
378 .cs_irq = 5,
379 .machine_id = 0x80,
e0353fe2
BS
380 .intbit_to_level = {
381 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
382 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
383 },
384 },
385 /* SS-10 */
386 /* XXX: Replace with real values */
387 {
388 .iommu_base = 0x10000000,
389 .tcx_base = 0x50000000,
390 .cs_base = 0x6c000000,
391 .slavio_base = 0x71000000,
392 .ms_kb_base = 0x71000000,
393 .serial_base = 0x71100000,
394 .nvram_base = 0x71200000,
395 .fd_base = 0x71400000,
396 .counter_base = 0x71d00000,
397 .intctl_base = 0x71e00000,
398 .dma_base = 0x78400000,
399 .esp_base = 0x78800000,
400 .le_base = 0x78c00000,
401 .vram_size = 0x00100000,
402 .nvram_size = 0x2000,
403 .esp_irq = 18,
404 .le_irq = 16,
405 .clock_irq = 7,
406 .clock1_irq = 19,
407 .ms_kb_irq = 14,
408 .ser_irq = 15,
409 .fd_irq = 22,
410 .me_irq = 30,
411 .cs_irq = 5,
412 .machine_id = 0x73,
413 .intbit_to_level = {
414 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
415 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
416 },
36cd9210
BS
417 },
418};
419
420static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds,
421 const char *kernel_filename, const char *kernel_cmdline,
422 const char *initrd_filename, const char *cpu_model,
423 unsigned int machine)
424{
425 sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model);
426
427 sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device,
428 kernel_filename, kernel_cmdline, initrd_filename,
429 hwdefs[machine].machine_id);
430}
431
432/* SPARCstation 5 hardware initialisation */
433static void ss5_init(int ram_size, int vga_ram_size, int boot_device,
434 DisplayState *ds, const char **fd_filename, int snapshot,
435 const char *kernel_filename, const char *kernel_cmdline,
436 const char *initrd_filename, const char *cpu_model)
437{
438 if (cpu_model == NULL)
439 cpu_model = "Fujitsu MB86904";
440 sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
441 kernel_cmdline, initrd_filename, cpu_model,
442 0);
420557e8 443}
c0e564d5 444
e0353fe2
BS
445/* SPARCstation 10 hardware initialisation */
446static void ss10_init(int ram_size, int vga_ram_size, int boot_device,
447 DisplayState *ds, const char **fd_filename, int snapshot,
448 const char *kernel_filename, const char *kernel_cmdline,
449 const char *initrd_filename, const char *cpu_model)
450{
451 if (cpu_model == NULL)
452 cpu_model = "TI SuperSparc II";
453 sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
454 kernel_cmdline, initrd_filename, cpu_model,
455 1);
456}
457
36cd9210
BS
458QEMUMachine ss5_machine = {
459 "SS-5",
460 "Sun4m platform, SPARCstation 5",
461 ss5_init,
c0e564d5 462};
e0353fe2
BS
463
464QEMUMachine ss10_machine = {
465 "SS-10",
466 "Sun4m platform, SPARCstation 10",
467 ss10_init,
468};
This page took 0.199643 seconds and 4 git commands to generate.