Blame view

hw/sun4m.c 15.3 KB
1
2
3
/*
 * QEMU Sun4m System Emulator
 * 
4
 * Copyright (c) 2003-2005 Fabrice Bellard
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * 
 * 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.
 */
#include "vl.h"
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
 * Sun4m architecture was used in the following machines:
 *
 * SPARCserver 6xxMP/xx
 * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), SPARCclassic X (4/10)
 * SPARCstation LX/ZX (4/30)
 * SPARCstation Voyager
 * SPARCstation 10/xx, SPARCserver 10/xx
 * SPARCstation 5, SPARCserver 5
 * SPARCstation 20/xx, SPARCserver 20
 * SPARCstation 4
 *
 * See for example: http://www.sunhelp.org/faq/sunref1.html
 */
41
#define KERNEL_LOAD_ADDR     0x00004000
bellard authored
42
#define CMDLINE_ADDR         0x007ff000
bellard authored
43
#define INITRD_LOAD_ADDR     0x00800000
bellard authored
44
#define PROM_SIZE_MAX        (256 * 1024)
bellard authored
45
#define PROM_ADDR	     0xffd00000
46
#define PROM_FILENAME	     "openbios-sparc32"
47
48
#define MAX_CPUS 16
49
50
51
52
53
54
55
56
57
58
59
60
61
struct hwdef {
    target_ulong iommu_base, slavio_base;
    target_ulong intctl_base, counter_base, nvram_base, ms_kb_base, serial_base;
    target_ulong fd_base;
    target_ulong dma_base, esp_base, le_base;
    target_ulong tcx_base, cs_base;
    long vram_size, nvram_size;
    // IRQ numbers are not PIL ones, but master interrupt controller register
    // bit numbers
    int intctl_g_intr, esp_irq, le_irq, cpu_irq, clock_irq, clock1_irq;
    int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq;
    int machine_id; // For NVRAM
62
    uint32_t intbit_to_level[32];
63
64
};
65
66
67
68
69
70
71
/* TSC handling */

uint64_t cpu_get_tsc()
{
    return qemu_get_clock(vm_clock);
}
bellard authored
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
int DMA_get_channel_mode (int nchan)
{
    return 0;
}
int DMA_read_memory (int nchan, void *buf, int pos, int size)
{
    return 0;
}
int DMA_write_memory (int nchan, void *buf, int pos, int size)
{
    return 0;
}
void DMA_hold_DREQ (int nchan) {}
void DMA_release_DREQ (int nchan) {}
void DMA_schedule(int nchan) {}
void DMA_run (void) {}
void DMA_init (int high_page_enable) {}
void DMA_register_channel (int nchan,
                           DMA_transfer_handler transfer_handler,
                           void *opaque)
{
}
95
static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
bellard authored
96
{
97
98
    m48t59_write(nvram, addr++, (value >> 8) & 0xff);
    m48t59_write(nvram, addr++, value & 0xff);
bellard authored
99
100
}
101
static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
bellard authored
102
{
103
104
105
106
    m48t59_write(nvram, addr++, value >> 24);
    m48t59_write(nvram, addr++, (value >> 16) & 0xff);
    m48t59_write(nvram, addr++, (value >> 8) & 0xff);
    m48t59_write(nvram, addr++, value & 0xff);
bellard authored
107
108
}
109
static void nvram_set_string (m48t59_t *nvram, uint32_t addr,
bellard authored
110
111
112
113
114
                       const unsigned char *str, uint32_t max)
{
    unsigned int i;

    for (i = 0; i < max && str[i] != '\0'; i++) {
115
        m48t59_write(nvram, addr + i, str[i]);
bellard authored
116
    }
117
    m48t59_write(nvram, addr + max - 1, '\0');
bellard authored
118
}
119
120
static m48t59_t *nvram;
121
bellard authored
122
123
extern int nographic;
124
static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline,
bellard authored
125
126
		       int boot_device, uint32_t RAM_size,
		       uint32_t kernel_size,
127
128
		       int width, int height, int depth,
                       int machine_id)
bellard authored
129
130
131
132
{
    unsigned char tmp = 0;
    int i, j;
bellard authored
133
134
135
136
    // Try to match PPC NVRAM
    nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
    nvram_set_lword(nvram,  0x10, 0x00000001); /* structure v1 */
    // NVRAM_size, arch not applicable
137
138
    m48t59_write(nvram, 0x2D, smp_cpus & 0xff);
    m48t59_write(nvram, 0x2E, 0);
139
    m48t59_write(nvram, 0x2F, nographic & 0xff);
bellard authored
140
    nvram_set_lword(nvram,  0x30, RAM_size);
141
    m48t59_write(nvram, 0x34, boot_device & 0xff);
bellard authored
142
143
    nvram_set_lword(nvram,  0x38, KERNEL_LOAD_ADDR);
    nvram_set_lword(nvram,  0x3C, kernel_size);
bellard authored
144
145
    if (cmdline) {
	strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
bellard authored
146
147
	nvram_set_lword(nvram,  0x40, CMDLINE_ADDR);
        nvram_set_lword(nvram,  0x44, strlen(cmdline));
bellard authored
148
    }
bellard authored
149
150
151
152
    // initrd_image, initrd_size passed differently
    nvram_set_word(nvram,   0x54, width);
    nvram_set_word(nvram,   0x56, height);
    nvram_set_word(nvram,   0x58, depth);
bellard authored
153
bellard authored
154
    // Sun4m specific use
bellard authored
155
    i = 0x1fd8;
156
    m48t59_write(nvram, i++, 0x01);
157
    m48t59_write(nvram, i++, machine_id);
bellard authored
158
    j = 0;
159
160
161
162
163
164
    m48t59_write(nvram, i++, macaddr[j++]);
    m48t59_write(nvram, i++, macaddr[j++]);
    m48t59_write(nvram, i++, macaddr[j++]);
    m48t59_write(nvram, i++, macaddr[j++]);
    m48t59_write(nvram, i++, macaddr[j++]);
    m48t59_write(nvram, i, macaddr[j]);
bellard authored
165
166
167

    /* Calculate checksum */
    for (i = 0x1fd8; i < 0x1fe7; i++) {
168
	tmp ^= m48t59_read(nvram, i);
bellard authored
169
    }
170
    m48t59_write(nvram, 0x1fe7, tmp);
bellard authored
171
172
173
174
175
176
177
178
179
180
181
182
183
184
}

static void *slavio_intctl;

void pic_info()
{
    slavio_pic_info(slavio_intctl);
}

void irq_info()
{
    slavio_irq_info(slavio_intctl);
}
bellard authored
185
186
187
188
189
190
191
static void *slavio_misc;

void qemu_system_powerdown(void)
{
    slavio_set_power_fail(slavio_misc, 1);
}
bellard authored
192
193
194
195
196
197
static void main_cpu_reset(void *opaque)
{
    CPUState *env = opaque;
    cpu_reset(env);
}
198
199
200
static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size,
                          DisplayState *ds, const char *cpu_model)
201
{
202
    CPUState *env, *envs[MAX_CPUS];
bellard authored
203
    unsigned int i;
204
    void *iommu, *dma, *main_esp, *main_lance = NULL;
blueswir1 authored
205
    const sparc_def_t *def;
pbrook authored
206
    qemu_irq *slavio_irq;
207
208
    /* init CPUs */
blueswir1 authored
209
210
211
212
213
    sparc_find_by_name(cpu_model, &def);
    if (def == NULL) {
        fprintf(stderr, "Unable to find Sparc CPU definition\n");
        exit(1);
    }
214
215
    for(i = 0; i < smp_cpus; i++) {
        env = cpu_init();
blueswir1 authored
216
        cpu_sparc_register(env, def);
217
218
219
220
221
222
        envs[i] = env;
        if (i != 0)
            env->halted = 1;
        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
        qemu_register_reset(main_cpu_reset, env);
    }
223
224
225
    /* allocate RAM */
    cpu_register_physical_memory(0, ram_size, 0);
226
227
    iommu = iommu_init(hwdef->iommu_base);
    slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
228
                                       hwdef->intctl_base + 0x10000,
pbrook authored
229
230
                                       &hwdef->intbit_to_level[0],
                                       &slavio_irq);
231
232
233
    for(i = 0; i < smp_cpus; i++) {
        slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
    }
pbrook authored
234
235
    dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
                           slavio_irq[hwdef->le_irq], iommu);
236
237
238
    tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size,
             hwdef->vram_size, graphic_width, graphic_height);
239
240
241
    if (nd_table[0].vlan) {
        if (nd_table[0].model == NULL
            || strcmp(nd_table[0].model, "lance") == 0) {
pbrook authored
242
243
            main_lance = lance_init(&nd_table[0], hwdef->le_base, dma,
                                    slavio_irq[hwdef->le_irq]);
244
245
246
247
248
        } else {
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
            exit (1);
        }
    }
pbrook authored
249
250
    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
                        hwdef->nvram_size, 8);
251
    for (i = 0; i < MAX_CPUS; i++) {
252
        slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE,
253
                          hwdef->clock_irq, 0, i, slavio_intctl);
254
    }
255
    slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2,
256
                      (unsigned int)-1, slavio_intctl);
pbrook authored
257
    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
258
259
    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
pbrook authored
260
261
262
    slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
                       serial_hds[1], serial_hds[0]);
    fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table);
263
    main_esp = esp_init(bs_table, hwdef->esp_base, dma);
264
265
266
267
268
269
270

    for (i = 0; i < MAX_DISKS; i++) {
        if (bs_table[i]) {
            esp_scsi_attach(main_esp, bs_table[i], i);
        }
    }
pbrook authored
271
272
    slavio_misc = slavio_misc_init(hwdef->slavio_base, 
                                   slavio_irq[hwdef->me_irq]);
273
274
    if (hwdef->cs_base != (target_ulong)-1)
        cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
275
    sparc32_dma_set_reset_data(dma, main_esp, main_lance);
276
277
278
279
280
281
282
283
284
285
286
287
288
289
}

static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device,
                              const char *kernel_filename,
                              const char *kernel_cmdline,
                              const char *initrd_filename,
                              int machine_id)
{
    int ret, linux_boot;
    char buf[1024];
    unsigned int i;
    long prom_offset, initrd_size, kernel_size;

    linux_boot = (kernel_filename != NULL);
290
bellard authored
291
    prom_offset = ram_size + vram_size;
bellard authored
292
293
294
    cpu_register_physical_memory(PROM_ADDR, 
                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, 
                                 prom_offset | IO_MEM_ROM);
bellard authored
295
296
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
297
    ret = load_elf(buf, 0, NULL, NULL, NULL);
bellard authored
298
299
300
301
302
303
    if (ret < 0) {
	fprintf(stderr, "qemu: could not load prom '%s'\n", 
		buf);
	exit(1);
    }
bellard authored
304
    kernel_size = 0;
bellard authored
305
    if (linux_boot) {
306
        kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL);
bellard authored
307
308
309
310
311
        if (kernel_size < 0)
	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
	if (kernel_size < 0)
	    kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
        if (kernel_size < 0) {
312
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
bellard authored
313
314
                    kernel_filename);
	    exit(1);
315
        }
bellard authored
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

        /* load initrd */
        initrd_size = 0;
        if (initrd_filename) {
            initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
            if (initrd_size < 0) {
                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
                        initrd_filename);
                exit(1);
            }
        }
        if (initrd_size > 0) {
	    for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
		if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
		    == 0x48647253) { // HdrS
		    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
		    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
		    break;
		}
	    }
        }
337
    }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
               boot_device, ram_size, kernel_size, graphic_width,
               graphic_height, graphic_depth, machine_id);
}

static const struct hwdef hwdefs[] = {
    /* SS-5 */
    {
        .iommu_base   = 0x10000000,
        .tcx_base     = 0x50000000,
        .cs_base      = 0x6c000000,
        .slavio_base  = 0x71000000,
        .ms_kb_base   = 0x71000000,
        .serial_base  = 0x71100000,
        .nvram_base   = 0x71200000,
        .fd_base      = 0x71400000,
        .counter_base = 0x71d00000,
        .intctl_base  = 0x71e00000,
        .dma_base     = 0x78400000,
        .esp_base     = 0x78800000,
        .le_base      = 0x78c00000,
        .vram_size    = 0x00100000,
        .nvram_size   = 0x2000,
        .esp_irq = 18,
        .le_irq = 16,
        .clock_irq = 7,
        .clock1_irq = 19,
        .ms_kb_irq = 14,
        .ser_irq = 15,
        .fd_irq = 22,
        .me_irq = 30,
        .cs_irq = 5,
        .machine_id = 0x80,
371
372
373
374
375
376
377
        .intbit_to_level = {
            2, 3, 5, 7, 9, 11, 0, 14,	3, 5, 7, 9, 11, 13, 12, 12,
            6, 0, 4, 10, 8, 0, 11, 0,	0, 0, 0, 0, 15, 0, 15, 0,
        },
    },
    /* SS-10 */
    {
378
        .iommu_base   = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits)
blueswir1 authored
379
        .tcx_base     = 0x20000000, // 0xe20000000ULL,
380
381
382
383
384
385
386
387
388
389
390
        .cs_base      = -1,
        .slavio_base  = 0xf1000000, // 0xff1000000ULL,
        .ms_kb_base   = 0xf1000000, // 0xff1000000ULL,
        .serial_base  = 0xf1100000, // 0xff1100000ULL,
        .nvram_base   = 0xf1200000, // 0xff1200000ULL,
        .fd_base      = 0xf1700000, // 0xff1700000ULL,
        .counter_base = 0xf1300000, // 0xff1300000ULL,
        .intctl_base  = 0xf1400000, // 0xff1400000ULL,
        .dma_base     = 0xf0400000, // 0xef0400000ULL,
        .esp_base     = 0xf0800000, // 0xef0800000ULL,
        .le_base      = 0xf0c00000, // 0xef0c00000ULL,
391
392
393
394
395
396
397
398
399
400
        .vram_size    = 0x00100000,
        .nvram_size   = 0x2000,
        .esp_irq = 18,
        .le_irq = 16,
        .clock_irq = 7,
        .clock1_irq = 19,
        .ms_kb_irq = 14,
        .ser_irq = 15,
        .fd_irq = 22,
        .me_irq = 30,
401
402
        .cs_irq = -1,
        .machine_id = 0x72,
403
404
405
406
        .intbit_to_level = {
            2, 3, 5, 7, 9, 11, 0, 14,	3, 5, 7, 9, 11, 13, 12, 12,
            6, 0, 4, 10, 8, 0, 11, 0,	0, 0, 0, 0, 15, 0, 15, 0,
        },
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
    },
};

static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds,
                              const char *kernel_filename, const char *kernel_cmdline,
                              const char *initrd_filename, const char *cpu_model,
                              unsigned int machine)
{
    sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model);

    sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device,
                      kernel_filename, kernel_cmdline, initrd_filename,
                      hwdefs[machine].machine_id);
}

/* SPARCstation 5 hardware initialisation */
static void ss5_init(int ram_size, int vga_ram_size, int boot_device,
                       DisplayState *ds, const char **fd_filename, int snapshot,
                       const char *kernel_filename, const char *kernel_cmdline,
                       const char *initrd_filename, const char *cpu_model)
{
    if (cpu_model == NULL)
        cpu_model = "Fujitsu MB86904";
    sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
                      kernel_cmdline, initrd_filename, cpu_model,
                      0);
433
}
bellard authored
434
435
436
437
438
439
440
441
442
443
444
445
446
447
/* SPARCstation 10 hardware initialisation */
static void ss10_init(int ram_size, int vga_ram_size, int boot_device,
                            DisplayState *ds, const char **fd_filename, int snapshot,
                            const char *kernel_filename, const char *kernel_cmdline,
                            const char *initrd_filename, const char *cpu_model)
{
    if (cpu_model == NULL)
        cpu_model = "TI SuperSparc II";
    sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
                      kernel_cmdline, initrd_filename, cpu_model,
                      1);
}
448
449
450
451
QEMUMachine ss5_machine = {
    "SS-5",
    "Sun4m platform, SPARCstation 5",
    ss5_init,
bellard authored
452
};
453
454
455
456
457
458

QEMUMachine ss10_machine = {
    "SS-10",
    "Sun4m platform, SPARCstation 10",
    ss10_init,
};