Statistics
| Branch: | Revision:

root / hw / sun4m.c @ 5aca8c3b

History | View | Annotate | Download (17.5 kB)

1
/*
2
 * QEMU Sun4m System Emulator
3
 * 
4
 * Copyright (c) 2003-2005 Fabrice Bellard
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"
25

    
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

    
41
#define KERNEL_LOAD_ADDR     0x00004000
42
#define CMDLINE_ADDR         0x007ff000
43
#define INITRD_LOAD_ADDR     0x00800000
44
#define PROM_SIZE_MAX        (256 * 1024)
45
#define PROM_ADDR             0xffd00000
46
#define PROM_FILENAME             "openbios-sparc32"
47

    
48
#define MAX_CPUS 16
49

    
50
struct hwdef {
51
    target_phys_addr_t iommu_base, slavio_base;
52
    target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base;
53
    target_phys_addr_t serial_base, fd_base;
54
    target_phys_addr_t dma_base, esp_base, le_base;
55
    target_phys_addr_t tcx_base, cs_base, power_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
62
    uint32_t intbit_to_level[32];
63
};
64

    
65
/* TSC handling */
66

    
67
uint64_t cpu_get_tsc()
68
{
69
    return qemu_get_clock(vm_clock);
70
}
71

    
72
int DMA_get_channel_mode (int nchan)
73
{
74
    return 0;
75
}
76
int DMA_read_memory (int nchan, void *buf, int pos, int size)
77
{
78
    return 0;
79
}
80
int DMA_write_memory (int nchan, void *buf, int pos, int size)
81
{
82
    return 0;
83
}
84
void DMA_hold_DREQ (int nchan) {}
85
void DMA_release_DREQ (int nchan) {}
86
void DMA_schedule(int nchan) {}
87
void DMA_run (void) {}
88
void DMA_init (int high_page_enable) {}
89
void DMA_register_channel (int nchan,
90
                           DMA_transfer_handler transfer_handler,
91
                           void *opaque)
92
{
93
}
94

    
95
static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
96
{
97
    m48t59_write(nvram, addr++, (value >> 8) & 0xff);
98
    m48t59_write(nvram, addr++, value & 0xff);
99
}
100

    
101
static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
102
{
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);
107
}
108

    
109
static void nvram_set_string (m48t59_t *nvram, uint32_t addr,
110
                       const unsigned char *str, uint32_t max)
111
{
112
    unsigned int i;
113

    
114
    for (i = 0; i < max && str[i] != '\0'; i++) {
115
        m48t59_write(nvram, addr + i, str[i]);
116
    }
117
    m48t59_write(nvram, addr + max - 1, '\0');
118
}
119

    
120
static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr,
121
                                const unsigned char *str)
122
{
123
    uint32_t len;
124

    
125
    len = strlen(str) + 1;
126
    nvram_set_string(nvram, addr, str, len);
127

    
128
    return addr + len;
129
}
130

    
131
static void nvram_finish_partition (m48t59_t *nvram, uint32_t start,
132
                                    uint32_t end)
133
{
134
    unsigned int i, sum;
135

    
136
    // Length divided by 16
137
    m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff);
138
    m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff);
139
    // Checksum
140
    sum = m48t59_read(nvram, start);
141
    for (i = 0; i < 14; i++) {
142
        sum += m48t59_read(nvram, start + 2 + i);
143
        sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
144
    }
145
    m48t59_write(nvram, start + 1, sum & 0xff);
146
}
147

    
148
static m48t59_t *nvram;
149

    
150
extern int nographic;
151

    
152
static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline,
153
                       int boot_device, uint32_t RAM_size,
154
                       uint32_t kernel_size,
155
                       int width, int height, int depth,
156
                       int machine_id)
157
{
158
    unsigned char tmp = 0;
159
    unsigned int i, j;
160
    uint32_t start, end;
161

    
162
    // Try to match PPC NVRAM
163
    nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
164
    nvram_set_lword(nvram,  0x10, 0x00000001); /* structure v1 */
165
    // NVRAM_size, arch not applicable
166
    m48t59_write(nvram, 0x2D, smp_cpus & 0xff);
167
    m48t59_write(nvram, 0x2E, 0);
168
    m48t59_write(nvram, 0x2F, nographic & 0xff);
169
    nvram_set_lword(nvram,  0x30, RAM_size);
170
    m48t59_write(nvram, 0x34, boot_device & 0xff);
171
    nvram_set_lword(nvram,  0x38, KERNEL_LOAD_ADDR);
172
    nvram_set_lword(nvram,  0x3C, kernel_size);
173
    if (cmdline) {
174
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
175
        nvram_set_lword(nvram,  0x40, CMDLINE_ADDR);
176
        nvram_set_lword(nvram,  0x44, strlen(cmdline));
177
    }
178
    // initrd_image, initrd_size passed differently
179
    nvram_set_word(nvram,   0x54, width);
180
    nvram_set_word(nvram,   0x56, height);
181
    nvram_set_word(nvram,   0x58, depth);
182

    
183
    // OpenBIOS nvram variables
184
    // Variable partition
185
    start = 252;
186
    m48t59_write(nvram, start, 0x70);
187
    nvram_set_string(nvram, start + 4, "system", 12);
188

    
189
    end = start + 16;
190
    for (i = 0; i < nb_prom_envs; i++)
191
        end = nvram_set_var(nvram, end, prom_envs[i]);
192

    
193
    m48t59_write(nvram, end++ , 0);
194
    end = start + ((end - start + 15) & ~15);
195
    nvram_finish_partition(nvram, start, end);
196

    
197
    // free partition
198
    start = end;
199
    m48t59_write(nvram, start, 0x7f);
200
    nvram_set_string(nvram, start + 4, "free", 12);
201

    
202
    end = 0x1fd0;
203
    nvram_finish_partition(nvram, start, end);
204

    
205
    // Sun4m specific use
206
    start = i = 0x1fd8;
207
    m48t59_write(nvram, i++, 0x01);
208
    m48t59_write(nvram, i++, machine_id);
209
    j = 0;
210
    m48t59_write(nvram, i++, macaddr[j++]);
211
    m48t59_write(nvram, i++, macaddr[j++]);
212
    m48t59_write(nvram, i++, macaddr[j++]);
213
    m48t59_write(nvram, i++, macaddr[j++]);
214
    m48t59_write(nvram, i++, macaddr[j++]);
215
    m48t59_write(nvram, i, macaddr[j]);
216

    
217
    /* Calculate checksum */
218
    for (i = start; i < start + 15; i++) {
219
        tmp ^= m48t59_read(nvram, i);
220
    }
221
    m48t59_write(nvram, start + 15, tmp);
222
}
223

    
224
static void *slavio_intctl;
225

    
226
void pic_info()
227
{
228
    slavio_pic_info(slavio_intctl);
229
}
230

    
231
void irq_info()
232
{
233
    slavio_irq_info(slavio_intctl);
234
}
235

    
236
static void *slavio_misc;
237

    
238
void qemu_system_powerdown(void)
239
{
240
    slavio_set_power_fail(slavio_misc, 1);
241
}
242

    
243
static void main_cpu_reset(void *opaque)
244
{
245
    CPUState *env = opaque;
246

    
247
    cpu_reset(env);
248
    env->halted = 0;
249
}
250

    
251
static void secondary_cpu_reset(void *opaque)
252
{
253
    CPUState *env = opaque;
254

    
255
    cpu_reset(env);
256
    env->halted = 1;
257
}
258

    
259
static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size,
260
                          DisplayState *ds, const char *cpu_model)
261

    
262
{
263
    CPUState *env, *envs[MAX_CPUS];
264
    unsigned int i;
265
    void *iommu, *espdma, *ledma, *main_esp, *main_lance = NULL;
266
    const sparc_def_t *def;
267
    qemu_irq *slavio_irq;
268

    
269
    /* init CPUs */
270
    sparc_find_by_name(cpu_model, &def);
271
    if (def == NULL) {
272
        fprintf(stderr, "Unable to find Sparc CPU definition\n");
273
        exit(1);
274
    }
275
    for(i = 0; i < smp_cpus; i++) {
276
        env = cpu_init();
277
        cpu_sparc_register(env, def);
278
        envs[i] = env;
279
        if (i == 0) {
280
            qemu_register_reset(main_cpu_reset, env);
281
        } else {
282
            qemu_register_reset(secondary_cpu_reset, env);
283
            env->halted = 1;
284
        }
285
        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
286
    }
287
    /* allocate RAM */
288
    cpu_register_physical_memory(0, ram_size, 0);
289

    
290
    iommu = iommu_init(hwdef->iommu_base);
291
    slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
292
                                       hwdef->intctl_base + 0x10000ULL,
293
                                       &hwdef->intbit_to_level[0],
294
                                       &slavio_irq);
295
    for(i = 0; i < smp_cpus; i++) {
296
        slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
297
    }
298
    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
299
                              iommu);
300
    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
301
                             slavio_irq[hwdef->le_irq], iommu);
302

    
303
    if (graphic_depth != 8 && graphic_depth != 24) {
304
        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
305
        exit (1);
306
    }
307
    tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size,
308
             hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
309
    if (nd_table[0].vlan) {
310
        if (nd_table[0].model == NULL
311
            || strcmp(nd_table[0].model, "lance") == 0) {
312
            main_lance = lance_init(&nd_table[0], hwdef->le_base, ledma,
313
                                    slavio_irq[hwdef->le_irq]);
314
        } else {
315
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
316
            exit (1);
317
        }
318
    }
319
    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
320
                        hwdef->nvram_size, 8);
321
    for (i = 0; i < MAX_CPUS; i++) {
322
        slavio_timer_init(hwdef->counter_base +
323
                          (target_phys_addr_t)(i * TARGET_PAGE_SIZE),
324
                          hwdef->clock_irq, 0, i, slavio_intctl);
325
    }
326
    slavio_timer_init(hwdef->counter_base + 0x10000ULL, hwdef->clock1_irq, 2,
327
                      (unsigned int)-1, slavio_intctl);
328
    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
329
    // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
330
    // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
331
    slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
332
                       serial_hds[1], serial_hds[0]);
333
    fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table);
334
    main_esp = esp_init(bs_table, hwdef->esp_base, espdma);
335

    
336
    for (i = 0; i < MAX_DISKS; i++) {
337
        if (bs_table[i]) {
338
            esp_scsi_attach(main_esp, bs_table[i], i);
339
        }
340
    }
341

    
342
    slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base,
343
                                   slavio_irq[hwdef->me_irq]);
344
    if (hwdef->cs_base != (target_phys_addr_t)-1)
345
        cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
346
}
347

    
348
static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device,
349
                              const char *kernel_filename,
350
                              const char *kernel_cmdline,
351
                              const char *initrd_filename,
352
                              int machine_id)
353
{
354
    int ret, linux_boot;
355
    char buf[1024];
356
    unsigned int i;
357
    long prom_offset, initrd_size, kernel_size;
358

    
359
    linux_boot = (kernel_filename != NULL);
360

    
361
    prom_offset = ram_size + vram_size;
362
    cpu_register_physical_memory(PROM_ADDR, 
363
                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, 
364
                                 prom_offset | IO_MEM_ROM);
365

    
366
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
367
    ret = load_elf(buf, 0, NULL, NULL, NULL);
368
    if (ret < 0) {
369
        fprintf(stderr, "qemu: could not load prom '%s'\n", 
370
                buf);
371
        exit(1);
372
    }
373

    
374
    kernel_size = 0;
375
    if (linux_boot) {
376
        kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL);
377
        if (kernel_size < 0)
378
            kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
379
        if (kernel_size < 0)
380
            kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
381
        if (kernel_size < 0) {
382
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
383
                    kernel_filename);
384
            exit(1);
385
        }
386

    
387
        /* load initrd */
388
        initrd_size = 0;
389
        if (initrd_filename) {
390
            initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
391
            if (initrd_size < 0) {
392
                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
393
                        initrd_filename);
394
                exit(1);
395
            }
396
        }
397
        if (initrd_size > 0) {
398
            for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
399
                if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
400
                    == 0x48647253) { // HdrS
401
                    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
402
                    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
403
                    break;
404
                }
405
            }
406
        }
407
    }
408
    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
409
               boot_device, ram_size, kernel_size, graphic_width,
410
               graphic_height, graphic_depth, machine_id);
411
}
412

    
413
static const struct hwdef hwdefs[] = {
414
    /* SS-5 */
415
    {
416
        .iommu_base   = 0x10000000,
417
        .tcx_base     = 0x50000000,
418
        .cs_base      = 0x6c000000,
419
        .slavio_base  = 0x70000000,
420
        .ms_kb_base   = 0x71000000,
421
        .serial_base  = 0x71100000,
422
        .nvram_base   = 0x71200000,
423
        .fd_base      = 0x71400000,
424
        .counter_base = 0x71d00000,
425
        .intctl_base  = 0x71e00000,
426
        .dma_base     = 0x78400000,
427
        .esp_base     = 0x78800000,
428
        .le_base      = 0x78c00000,
429
        .power_base   = 0x7a000000,
430
        .vram_size    = 0x00100000,
431
        .nvram_size   = 0x2000,
432
        .esp_irq = 18,
433
        .le_irq = 16,
434
        .clock_irq = 7,
435
        .clock1_irq = 19,
436
        .ms_kb_irq = 14,
437
        .ser_irq = 15,
438
        .fd_irq = 22,
439
        .me_irq = 30,
440
        .cs_irq = 5,
441
        .machine_id = 0x80,
442
        .intbit_to_level = {
443
            2, 3, 5, 7, 9, 11, 0, 14,        3, 5, 7, 9, 11, 13, 12, 12,
444
            6, 0, 4, 10, 8, 0, 11, 0,        0, 0, 0, 0, 15, 0, 15, 0,
445
        },
446
    },
447
    /* SS-10 */
448
    {
449
        .iommu_base   = 0xfe0000000ULL,
450
        .tcx_base     = 0xe20000000ULL,
451
        .cs_base      = -1,
452
        .slavio_base  = 0xff0000000ULL,
453
        .ms_kb_base   = 0xff1000000ULL,
454
        .serial_base  = 0xff1100000ULL,
455
        .nvram_base   = 0xff1200000ULL,
456
        .fd_base      = 0xff1700000ULL,
457
        .counter_base = 0xff1300000ULL,
458
        .intctl_base  = 0xff1400000ULL,
459
        .dma_base     = 0xef0400000ULL,
460
        .esp_base     = 0xef0800000ULL,
461
        .le_base      = 0xef0c00000ULL,
462
        .power_base   = 0xefa000000ULL,
463
        .vram_size    = 0x00100000,
464
        .nvram_size   = 0x2000,
465
        .esp_irq = 18,
466
        .le_irq = 16,
467
        .clock_irq = 7,
468
        .clock1_irq = 19,
469
        .ms_kb_irq = 14,
470
        .ser_irq = 15,
471
        .fd_irq = 22,
472
        .me_irq = 30,
473
        .cs_irq = -1,
474
        .machine_id = 0x72,
475
        .intbit_to_level = {
476
            2, 3, 5, 7, 9, 11, 0, 14,        3, 5, 7, 9, 11, 13, 12, 12,
477
            6, 0, 4, 10, 8, 0, 11, 0,        0, 0, 0, 0, 15, 0, 15, 0,
478
        },
479
    },
480
};
481

    
482
static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds,
483
                              const char *kernel_filename, const char *kernel_cmdline,
484
                              const char *initrd_filename, const char *cpu_model,
485
                              unsigned int machine, int max_ram)
486
{
487
    if ((unsigned int)ram_size > (unsigned int)max_ram) {
488
        fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n",
489
                (unsigned int)ram_size / (1024 * 1024),
490
                (unsigned int)max_ram / (1024 * 1024));
491
        exit(1);
492
    }
493
    sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model);
494

    
495
    sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device,
496
                      kernel_filename, kernel_cmdline, initrd_filename,
497
                      hwdefs[machine].machine_id);
498
}
499

    
500
/* SPARCstation 5 hardware initialisation */
501
static void ss5_init(int ram_size, int vga_ram_size, int boot_device,
502
                       DisplayState *ds, const char **fd_filename, int snapshot,
503
                       const char *kernel_filename, const char *kernel_cmdline,
504
                       const char *initrd_filename, const char *cpu_model)
505
{
506
    if (cpu_model == NULL)
507
        cpu_model = "Fujitsu MB86904";
508
    sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
509
                      kernel_cmdline, initrd_filename, cpu_model,
510
                      0, 0x10000000);
511
}
512

    
513
/* SPARCstation 10 hardware initialisation */
514
static void ss10_init(int ram_size, int vga_ram_size, int boot_device,
515
                            DisplayState *ds, const char **fd_filename, int snapshot,
516
                            const char *kernel_filename, const char *kernel_cmdline,
517
                            const char *initrd_filename, const char *cpu_model)
518
{
519
    if (cpu_model == NULL)
520
        cpu_model = "TI SuperSparc II";
521
    sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
522
                      kernel_cmdline, initrd_filename, cpu_model,
523
                      1, PROM_ADDR); // XXX prom overlap, actually first 4GB ok
524
}
525

    
526
QEMUMachine ss5_machine = {
527
    "SS-5",
528
    "Sun4m platform, SPARCstation 5",
529
    ss5_init,
530
};
531

    
532
QEMUMachine ss10_machine = {
533
    "SS-10",
534
    "Sun4m platform, SPARCstation 10",
535
    ss10_init,
536
};