Statistics
| Branch: | Revision:

root / hw / sun4m.c @ 5dcb6b91

History | View | Annotate | Download (17.4 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, *dma, *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
    dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
299
                           slavio_irq[hwdef->le_irq], iommu);
300

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

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

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

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

    
358
    linux_boot = (kernel_filename != NULL);
359

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

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

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

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

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

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

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

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

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

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

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