mips_malta.c 39.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU Malta board support
 *
 * Copyright (c) 2006 Aurelien Jarno
 *
 * 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.
 */

25
#include "hw/hw.h"
P
Paolo Bonzini 已提交
26 27 28
#include "hw/i386/pc.h"
#include "hw/char/serial.h"
#include "hw/block/fdc.h"
P
Paolo Bonzini 已提交
29
#include "net/net.h"
30
#include "hw/boards.h"
P
Paolo Bonzini 已提交
31
#include "hw/i2c/smbus.h"
32
#include "sysemu/block-backend.h"
P
Paolo Bonzini 已提交
33 34 35
#include "hw/block/flash.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
36
#include "hw/pci/pci.h"
37
#include "sysemu/char.h"
38 39
#include "sysemu/sysemu.h"
#include "sysemu/arch_init.h"
40
#include "qemu/log.h"
P
Paolo Bonzini 已提交
41
#include "hw/mips/bios.h"
42 43
#include "hw/ide.h"
#include "hw/loader.h"
B
Blue Swirl 已提交
44
#include "elf.h"
P
Paolo Bonzini 已提交
45 46
#include "hw/timer/mc146818rtc.h"
#include "hw/timer/i8254.h"
47
#include "sysemu/block-backend.h"
48
#include "sysemu/blockdev.h"
49
#include "exec/address-spaces.h"
50
#include "hw/sysbus.h"             /* SysBusDevice */
51
#include "qemu/host-utils.h"
52
#include "sysemu/qtest.h"
53
#include "qemu/error-report.h"
54
#include "hw/empty_slot.h"
J
James Hogan 已提交
55
#include "sysemu/kvm.h"
56

T
ths 已提交
57 58
//#define DEBUG_BOARD_INIT

59
#define ENVP_ADDR		0x80002000l
60 61 62
#define ENVP_NB_ENTRIES	 	16
#define ENVP_ENTRY_SIZE	 	256

63 64 65 66 67 68 69
/* Hardware addresses */
#define FLASH_ADDRESS 0x1e000000ULL
#define FPGA_ADDRESS  0x1f000000ULL
#define RESET_ADDRESS 0x1fc00000ULL

#define FLASH_SIZE    0x400000

T
ths 已提交
70 71
#define MAX_IDE_BUS 2

72
typedef struct {
A
Avi Kivity 已提交
73 74 75
    MemoryRegion iomem;
    MemoryRegion iomem_lo; /* 0 - 0x900 */
    MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
76 77 78
    uint32_t leds;
    uint32_t brk;
    uint32_t gpout;
79
    uint32_t i2cin;
80 81 82 83 84
    uint32_t i2coe;
    uint32_t i2cout;
    uint32_t i2csel;
    CharDriverState *display;
    char display_text[9];
T
ths 已提交
85
    SerialState *uart;
86 87
} MaltaFPGAState;

A
Andreas Färber 已提交
88 89 90
#define TYPE_MIPS_MALTA "mips-malta"
#define MIPS_MALTA(obj) OBJECT_CHECK(MaltaState, (obj), TYPE_MIPS_MALTA)

91
typedef struct {
A
Andreas Färber 已提交
92 93
    SysBusDevice parent_obj;

94 95 96
    qemu_irq *i8259;
} MaltaState;

B
Blue Swirl 已提交
97
static ISADevice *pit;
98

99 100 101 102 103 104 105
static struct _loaderparams {
    int ram_size;
    const char *kernel_filename;
    const char *kernel_cmdline;
    const char *initrd_filename;
} loaderparams;

106 107 108 109 110 111 112
/* Malta FPGA */
static void malta_fpga_update_display(void *opaque)
{
    char leds_text[9];
    int i;
    MaltaFPGAState *s = opaque;

T
ths 已提交
113 114 115 116 117
    for (i = 7 ; i >= 0 ; i--) {
        if (s->leds & (1 << i))
            leds_text[i] = '#';
        else
            leds_text[i] = ' ';
118
    }
T
ths 已提交
119 120
    leds_text[8] = '\0';

121 122
    qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
    qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
123 124
}

125 126 127 128 129 130 131 132 133 134 135 136 137
/*
 * EEPROM 24C01 / 24C02 emulation.
 *
 * Emulation for serial EEPROMs:
 * 24C01 - 1024 bit (128 x 8)
 * 24C02 - 2048 bit (256 x 8)
 *
 * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
 */

//~ #define DEBUG

#if defined(DEBUG)
138
#  define logout(fmt, ...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
139
#else
140
#  define logout(fmt, ...) ((void)0)
141 142
#endif

A
Anthony Liguori 已提交
143
struct _eeprom24c0x_t {
144 145 146 147 148 149 150 151 152 153 154
  uint8_t tick;
  uint8_t address;
  uint8_t command;
  uint8_t ack;
  uint8_t scl;
  uint8_t sda;
  uint8_t data;
  //~ uint16_t size;
  uint8_t contents[256];
};

A
Anthony Liguori 已提交
155
typedef struct _eeprom24c0x_t eeprom24c0x_t;
156

157
static eeprom24c0x_t spd_eeprom = {
158
    .contents = {
159
        /* 00000000: */ 0x80,0x08,0xFF,0x0D,0x0A,0xFF,0x40,0x00,
160
        /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
161 162
        /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x00,0x00,
        /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0xFF,
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
        /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
        /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
        /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
    },
};

178
static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
179 180
{
    enum { SDR = 0x4, DDR2 = 0x8 } type;
181
    uint8_t *spd = spd_eeprom.contents;
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
    uint8_t nbanks = 0;
    uint16_t density = 0;
    int i;

    /* work in terms of MB */
    ram_size >>= 20;

    while ((ram_size >= 4) && (nbanks <= 2)) {
        int sz_log2 = MIN(31 - clz32(ram_size), 14);
        nbanks++;
        density |= 1 << (sz_log2 - 2);
        ram_size -= 1 << sz_log2;
    }

    /* split to 2 banks if possible */
    if ((nbanks == 1) && (density > 1)) {
        nbanks++;
        density >>= 1;
    }

    if (density & 0xff00) {
        density = (density & 0xe0) | ((density >> 8) & 0x1f);
        type = DDR2;
    } else if (!(density & 0x1f)) {
        type = DDR2;
    } else {
        type = SDR;
    }

    if (ram_size) {
        fprintf(stderr, "Warning: SPD cannot represent final %dMB"
                " of SDRAM\n", (int)ram_size);
    }

    /* fill in SPD memory information */
    spd[2] = type;
    spd[5] = nbanks;
    spd[31] = density;

    /* checksum */
    spd[63] = 0;
    for (i = 0; i < 63; i++) {
        spd[63] += spd[i];
    }
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

    /* copy for SMBUS */
    memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
}

static void generate_eeprom_serial(uint8_t *eeprom)
{
    int i, pos = 0;
    uint8_t mac[6] = { 0x00 };
    uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };

    /* version */
    eeprom[pos++] = 0x01;

    /* count */
    eeprom[pos++] = 0x02;

    /* MAC address */
    eeprom[pos++] = 0x01; /* MAC */
    eeprom[pos++] = 0x06; /* length */
    memcpy(&eeprom[pos], mac, sizeof(mac));
    pos += sizeof(mac);

    /* serial number */
    eeprom[pos++] = 0x02; /* serial */
    eeprom[pos++] = 0x05; /* length */
    memcpy(&eeprom[pos], sn, sizeof(sn));
    pos += sizeof(sn);

    /* checksum */
    eeprom[pos] = 0;
    for (i = 0; i < pos; i++) {
        eeprom[pos] += eeprom[i];
    }
260 261
}

262
static uint8_t eeprom24c0x_read(eeprom24c0x_t *eeprom)
263 264
{
    logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
265 266
        eeprom->tick, eeprom->scl, eeprom->sda, eeprom->data);
    return eeprom->sda;
267 268
}

269
static void eeprom24c0x_write(eeprom24c0x_t *eeprom, int scl, int sda)
270
{
271
    if (eeprom->scl && scl && (eeprom->sda != sda)) {
272
        logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
273 274
                eeprom->tick, eeprom->scl, scl, eeprom->sda, sda,
                sda ? "stop" : "start");
275
        if (!sda) {
276 277
            eeprom->tick = 1;
            eeprom->command = 0;
278
        }
279
    } else if (eeprom->tick == 0 && !eeprom->ack) {
280 281
        /* Waiting for start. */
        logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
282 283
                eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
    } else if (!eeprom->scl && scl) {
284
        logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
285 286
                eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
        if (eeprom->ack) {
287 288
            logout("\ti2c ack bit = 0\n");
            sda = 0;
289 290
            eeprom->ack = 0;
        } else if (eeprom->sda == sda) {
291 292
            uint8_t bit = (sda != 0);
            logout("\ti2c bit = %d\n", bit);
293 294 295 296 297 298 299 300
            if (eeprom->tick < 9) {
                eeprom->command <<= 1;
                eeprom->command += bit;
                eeprom->tick++;
                if (eeprom->tick == 9) {
                    logout("\tcommand 0x%04x, %s\n", eeprom->command,
                           bit ? "read" : "write");
                    eeprom->ack = 1;
301
                }
302 303 304
            } else if (eeprom->tick < 17) {
                if (eeprom->command & 1) {
                    sda = ((eeprom->data & 0x80) != 0);
305
                }
306 307 308 309 310 311 312 313 314 315
                eeprom->address <<= 1;
                eeprom->address += bit;
                eeprom->tick++;
                eeprom->data <<= 1;
                if (eeprom->tick == 17) {
                    eeprom->data = eeprom->contents[eeprom->address];
                    logout("\taddress 0x%04x, data 0x%02x\n",
                           eeprom->address, eeprom->data);
                    eeprom->ack = 1;
                    eeprom->tick = 0;
316
                }
317
            } else if (eeprom->tick >= 17) {
318 319 320 321 322 323
                sda = 0;
            }
        } else {
            logout("\tsda changed with raising scl\n");
        }
    } else {
324 325
        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom->tick, eeprom->scl,
               scl, eeprom->sda, sda);
326
    }
327 328
    eeprom->scl = scl;
    eeprom->sda = sda;
329 330
}

A
Avi Kivity 已提交
331
static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
332
                                unsigned size)
333 334 335 336 337 338 339 340 341 342 343 344
{
    MaltaFPGAState *s = opaque;
    uint32_t val = 0;
    uint32_t saddr;

    saddr = (addr & 0xfffff);

    switch (saddr) {

    /* SWITCH Register */
    case 0x00200:
        val = 0x00000000;		/* All switches closed */
A
Aurelien Jarno 已提交
345
        break;
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

    /* STATUS Register */
    case 0x00208:
#ifdef TARGET_WORDS_BIGENDIAN
        val = 0x00000012;
#else
        val = 0x00000010;
#endif
        break;

    /* JMPRS Register */
    case 0x00210:
        val = 0x00;
        break;

    /* LEDBAR Register */
    case 0x00408:
        val = s->leds;
        break;

    /* BRKRES Register */
    case 0x00508:
        val = s->brk;
        break;

T
ths 已提交
371
    /* UART Registers are handled directly by the serial device */
T
ths 已提交
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
    /* GPOUT Register */
    case 0x00a00:
        val = s->gpout;
        break;

    /* XXX: implement a real I2C controller */

    /* GPINP Register */
    case 0x00a08:
        /* IN = OUT until a real I2C control is implemented */
        if (s->i2csel)
            val = s->i2cout;
        else
            val = 0x00;
        break;

    /* I2CINP Register */
    case 0x00b00:
391
        val = ((s->i2cin & ~1) | eeprom24c0x_read(&spd_eeprom));
392 393 394 395 396 397 398 399 400 401 402 403 404 405
        break;

    /* I2COE Register */
    case 0x00b08:
        val = s->i2coe;
        break;

    /* I2COUT Register */
    case 0x00b10:
        val = s->i2cout;
        break;

    /* I2CSEL Register */
    case 0x00b18:
406
        val = s->i2csel;
407 408 409 410
        break;

    default:
#if 0
T
ths 已提交
411
        printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
A
Aurelien Jarno 已提交
412
                addr);
413 414 415 416 417 418
#endif
        break;
    }
    return val;
}

A
Avi Kivity 已提交
419
static void malta_fpga_write(void *opaque, hwaddr addr,
A
Avi Kivity 已提交
420
                             uint64_t val, unsigned size)
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
{
    MaltaFPGAState *s = opaque;
    uint32_t saddr;

    saddr = (addr & 0xfffff);

    switch (saddr) {

    /* SWITCH Register */
    case 0x00200:
        break;

    /* JMPRS Register */
    case 0x00210:
        break;

    /* LEDBAR Register */
    case 0x00408:
        s->leds = val & 0xff;
S
Stefan Weil 已提交
440
        malta_fpga_update_display(s);
441 442 443 444
        break;

    /* ASCIIWORD Register */
    case 0x00410:
A
Avi Kivity 已提交
445
        snprintf(s->display_text, 9, "%08X", (uint32_t)val);
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
        malta_fpga_update_display(s);
        break;

    /* ASCIIPOS0 to ASCIIPOS7 Registers */
    case 0x00418:
    case 0x00420:
    case 0x00428:
    case 0x00430:
    case 0x00438:
    case 0x00440:
    case 0x00448:
    case 0x00450:
        s->display_text[(saddr - 0x00418) >> 3] = (char) val;
        malta_fpga_update_display(s);
        break;

    /* SOFTRES Register */
    case 0x00500:
        if (val == 0x42)
            qemu_system_reset_request ();
        break;

    /* BRKRES Register */
    case 0x00508:
        s->brk = val & 0xff;
        break;

T
ths 已提交
473
    /* UART Registers are handled directly by the serial device */
T
ths 已提交
474

475 476 477 478 479 480 481 482 483 484 485 486
    /* GPOUT Register */
    case 0x00a00:
        s->gpout = val & 0xff;
        break;

    /* I2COE Register */
    case 0x00b08:
        s->i2coe = val & 0x03;
        break;

    /* I2COUT Register */
    case 0x00b10:
487
        eeprom24c0x_write(&spd_eeprom, val & 0x02, val & 0x01);
488
        s->i2cout = val;
489 490 491 492
        break;

    /* I2CSEL Register */
    case 0x00b18:
493
        s->i2csel = val & 0x01;
494 495 496 497
        break;

    default:
#if 0
T
ths 已提交
498
        printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
A
Aurelien Jarno 已提交
499
                addr);
500 501 502 503 504
#endif
        break;
    }
}

A
Avi Kivity 已提交
505 506 507 508
static const MemoryRegionOps malta_fpga_ops = {
    .read = malta_fpga_read,
    .write = malta_fpga_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
509 510
};

511
static void malta_fpga_reset(void *opaque)
512 513 514 515 516 517
{
    MaltaFPGAState *s = opaque;

    s->leds   = 0x00;
    s->brk    = 0x0a;
    s->gpout  = 0x00;
518
    s->i2cin  = 0x3;
519 520 521 522 523 524
    s->i2coe  = 0x0;
    s->i2cout = 0x3;
    s->i2csel = 0x1;

    s->display_text[8] = '\0';
    snprintf(s->display_text, 9, "        ");
525 526 527 528
}

static void malta_fpga_led_init(CharDriverState *chr)
{
529 530 531 532 533 534 535 536 537
    qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
    qemu_chr_fe_printf(chr, "+--------+\r\n");
    qemu_chr_fe_printf(chr, "+        +\r\n");
    qemu_chr_fe_printf(chr, "+--------+\r\n");
    qemu_chr_fe_printf(chr, "\n");
    qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
    qemu_chr_fe_printf(chr, "+--------+\r\n");
    qemu_chr_fe_printf(chr, "+        +\r\n");
    qemu_chr_fe_printf(chr, "+--------+\r\n");
538 539
}

A
Avi Kivity 已提交
540
static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
A
Avi Kivity 已提交
541
         hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
542 543 544
{
    MaltaFPGAState *s;

545
    s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
546

547
    memory_region_init_io(&s->iomem, NULL, &malta_fpga_ops, s,
A
Avi Kivity 已提交
548
                          "malta-fpga", 0x100000);
549
    memory_region_init_alias(&s->iomem_lo, NULL, "malta-fpga",
A
Avi Kivity 已提交
550
                             &s->iomem, 0, 0x900);
551
    memory_region_init_alias(&s->iomem_hi, NULL, "malta-fpga",
A
Avi Kivity 已提交
552
                             &s->iomem, 0xa00, 0x10000-0xa00);
T
ths 已提交
553

A
Avi Kivity 已提交
554 555
    memory_region_add_subregion(address_space, base, &s->iomem_lo);
    memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
556

557
    s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
558

559 560
    s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
                             230400, uart_chr, DEVICE_NATIVE_ENDIAN);
T
ths 已提交
561

562
    malta_fpga_reset(s);
563
    qemu_register_reset(malta_fpga_reset, s);
564 565 566 567 568

    return s;
}

/* Network support */
569
static void network_init(PCIBus *pci_bus)
570 571 572 573
{
    int i;

    for(i = 0; i < nb_nics; i++) {
574
        NICInfo *nd = &nd_table[i];
575
        const char *default_devaddr = NULL;
576 577

        if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0))
578
            /* The malta board has a PCNet card using PCI SLOT 11 */
579
            default_devaddr = "0b";
580

581
        pci_nic_init_nofail(nd, pci_bus, "pcnet", default_devaddr);
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
    }
}

/* ROM and pseudo bootloader

   The following code implements a very very simple bootloader. It first
   loads the registers a0 to a3 to the values expected by the OS, and
   then jump at the kernel address.

   The bootloader should pass the locations of the kernel arguments and
   environment variables tables. Those tables contain the 32-bit address
   of NULL terminated strings. The environment variables table should be
   terminated by a NULL address.

   For a simpler implementation, the number of kernel arguments is fixed
   to two (the name of the kernel and the command line), and the two
   tables are actually the same one.

   The registers a0 to a3 should contain the following values:
     a0 - number of kernel arguments
     a1 - 32-bit address of the kernel arguments table
     a2 - 32-bit address of the environment variables table
     a3 - RAM size in bytes
*/

A
Andreas Färber 已提交
607
static void write_bootloader (CPUMIPSState *env, uint8_t *base,
J
James Hogan 已提交
608
                              int64_t run_addr, int64_t kernel_entry)
609 610 611 612
{
    uint32_t *p;

    /* Small bootloader */
P
pbrook 已提交
613
    p = (uint32_t *)base;
J
James Hogan 已提交
614 615 616

    stl_p(p++, 0x08000000 |                                      /* j 0x1fc00580 */
                 ((run_addr + 0x580) & 0x0fffffff) >> 2);
617
    stl_p(p++, 0x00000000);                                      /* nop */
618

619
    /* YAMON service vector */
J
James Hogan 已提交
620 621 622 623 624 625 626 627 628 629 630 631 632
    stl_p(base + 0x500, run_addr + 0x0580);      /* start: */
    stl_p(base + 0x504, run_addr + 0x083c);      /* print_count: */
    stl_p(base + 0x520, run_addr + 0x0580);      /* start: */
    stl_p(base + 0x52c, run_addr + 0x0800);      /* flush_cache: */
    stl_p(base + 0x534, run_addr + 0x0808);      /* print: */
    stl_p(base + 0x538, run_addr + 0x0800);      /* reg_cpu_isr: */
    stl_p(base + 0x53c, run_addr + 0x0800);      /* unred_cpu_isr: */
    stl_p(base + 0x540, run_addr + 0x0800);      /* reg_ic_isr: */
    stl_p(base + 0x544, run_addr + 0x0800);      /* unred_ic_isr: */
    stl_p(base + 0x548, run_addr + 0x0800);      /* reg_esr: */
    stl_p(base + 0x54c, run_addr + 0x0800);      /* unreg_esr: */
    stl_p(base + 0x550, run_addr + 0x0800);      /* getchar: */
    stl_p(base + 0x554, run_addr + 0x0800);      /* syscon_read: */
633 634


635
    /* Second part of the bootloader */
P
pbrook 已提交
636
    p = (uint32_t *) (base + 0x580);
637 638 639 640 641 642 643 644 645
    stl_p(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
    stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
    stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
    stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
    stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
    stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
    stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
    stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16));     /* lui a3, high(ram_size) */
    stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff));  /* ori a3, a3, low(ram_size) */
646 647

    /* Load BAR registers as done by YAMON */
648
    stl_p(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
T
ths 已提交
649 650

#ifdef TARGET_WORDS_BIGENDIAN
651
    stl_p(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
T
ths 已提交
652
#else
653
    stl_p(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
T
ths 已提交
654
#endif
655
    stl_p(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
T
ths 已提交
656

657
    stl_p(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
658 659

#ifdef TARGET_WORDS_BIGENDIAN
660
    stl_p(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
661
#else
662
    stl_p(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
663
#endif
664
    stl_p(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
665
#ifdef TARGET_WORDS_BIGENDIAN
666
    stl_p(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
667
#else
668
    stl_p(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
669
#endif
670
    stl_p(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
671 672

#ifdef TARGET_WORDS_BIGENDIAN
673
    stl_p(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
674
#else
675
    stl_p(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
676
#endif
677
    stl_p(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
678
#ifdef TARGET_WORDS_BIGENDIAN
679
    stl_p(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
680
#else
681
    stl_p(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
682
#endif
683
    stl_p(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
684 685

#ifdef TARGET_WORDS_BIGENDIAN
686
    stl_p(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
687
#else
688
    stl_p(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
689
#endif
690
    stl_p(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
691
#ifdef TARGET_WORDS_BIGENDIAN
692
    stl_p(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
693
#else
694
    stl_p(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
695
#endif
696
    stl_p(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
697 698

    /* Jump to kernel code */
699 700
    stl_p(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
    stl_p(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
701
    stl_p(p++, 0x03e00009);                                      /* jalr ra */
702
    stl_p(p++, 0x00000000);                                      /* nop */
703 704

    /* YAMON subroutines */
P
pbrook 已提交
705
    p = (uint32_t *) (base + 0x800);
706
    stl_p(p++, 0x03e00009);                                     /* jalr ra */
707
    stl_p(p++, 0x24020000);                                     /* li v0,0 */
J
James Hogan 已提交
708
    /* 808 YAMON print */
709 710 711 712 713 714 715 716 717 718 719
    stl_p(p++, 0x03e06821);                                     /* move t5,ra */
    stl_p(p++, 0x00805821);                                     /* move t3,a0 */
    stl_p(p++, 0x00a05021);                                     /* move t2,a1 */
    stl_p(p++, 0x91440000);                                     /* lbu a0,0(t2) */
    stl_p(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
    stl_p(p++, 0x10800005);                                     /* beqz a0,834 */
    stl_p(p++, 0x00000000);                                     /* nop */
    stl_p(p++, 0x0ff0021c);                                     /* jal 870 */
    stl_p(p++, 0x00000000);                                     /* nop */
    stl_p(p++, 0x08000205);                                     /* j 814 */
    stl_p(p++, 0x00000000);                                     /* nop */
720
    stl_p(p++, 0x01a00009);                                     /* jalr t5 */
721
    stl_p(p++, 0x01602021);                                     /* move a0,t3 */
722
    /* 0x83c YAMON print_count */
723 724 725 726 727 728 729 730 731 732 733
    stl_p(p++, 0x03e06821);                                     /* move t5,ra */
    stl_p(p++, 0x00805821);                                     /* move t3,a0 */
    stl_p(p++, 0x00a05021);                                     /* move t2,a1 */
    stl_p(p++, 0x00c06021);                                     /* move t4,a2 */
    stl_p(p++, 0x91440000);                                     /* lbu a0,0(t2) */
    stl_p(p++, 0x0ff0021c);                                     /* jal 870 */
    stl_p(p++, 0x00000000);                                     /* nop */
    stl_p(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
    stl_p(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
    stl_p(p++, 0x1580fffa);                                     /* bnez t4,84c */
    stl_p(p++, 0x00000000);                                     /* nop */
734
    stl_p(p++, 0x01a00009);                                     /* jalr t5 */
735
    stl_p(p++, 0x01602021);                                     /* move a0,t3 */
736
    /* 0x870 */
737 738 739 740 741 742 743
    stl_p(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
    stl_p(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
    stl_p(p++, 0x91090005);                                     /* lbu t1,5(t0) */
    stl_p(p++, 0x00000000);                                     /* nop */
    stl_p(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
    stl_p(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
    stl_p(p++, 0x00000000);                                     /* nop */
744
    stl_p(p++, 0x03e00009);                                     /* jalr ra */
745
    stl_p(p++, 0xa1040000);                                     /* sb a0,0(t0) */
746

747 748
}

S
Stefan Weil 已提交
749 750
static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
                                        const char *string, ...)
751 752
{
    va_list ap;
753
    int32_t table_addr;
754 755 756 757 758

    if (index >= ENVP_NB_ENTRIES)
        return;

    if (string == NULL) {
A
Aurelien Jarno 已提交
759
        prom_buf[index] = 0;
760 761 762
        return;
    }

A
Aurelien Jarno 已提交
763 764
    table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
    prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
765 766

    va_start(ap, string);
A
Aurelien Jarno 已提交
767
    vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
768 769 770 771
    va_end(ap);
}

/* Kernel */
A
Aurelien Jarno 已提交
772
static int64_t load_kernel (void)
773
{
774
    int64_t kernel_entry, kernel_high;
775
    long initrd_size;
A
Anthony Liguori 已提交
776
    ram_addr_t initrd_offset;
B
Blue Swirl 已提交
777
    int big_endian;
A
Aurelien Jarno 已提交
778 779 780
    uint32_t *prom_buf;
    long prom_size;
    int prom_index = 0;
J
James Hogan 已提交
781
    uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr);
B
Blue Swirl 已提交
782 783 784 785 786 787

#ifdef TARGET_WORDS_BIGENDIAN
    big_endian = 1;
#else
    big_endian = 0;
#endif
788

789 790 791
    if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
                 (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
                 big_endian, ELF_MACHINE, 1) < 0) {
792
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
793
                loaderparams.kernel_filename);
T
ths 已提交
794
        exit(1);
795
    }
796 797

    /* Sanity check where the kernel has been linked */
J
James Hogan 已提交
798
    if (kvm_enabled()) {
799 800 801 802 803 804
        if (kernel_entry & 0x80000000ll) {
            error_report("KVM guest kernels must be linked in useg. "
                         "Did you forget to enable CONFIG_KVM_GUEST?");
            exit(1);
        }

J
James Hogan 已提交
805 806
        xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
    } else {
807 808 809 810 811 812
        if (!(kernel_entry & 0x80000000ll)) {
            error_report("KVM guest kernels aren't supported with TCG. "
                         "Did you unintentionally enable CONFIG_KVM_GUEST?");
            exit(1);
        }

J
James Hogan 已提交
813 814
        xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
    }
815 816 817

    /* load initrd */
    initrd_size = 0;
T
ths 已提交
818
    initrd_offset = 0;
819 820
    if (loaderparams.initrd_filename) {
        initrd_size = get_image_size (loaderparams.initrd_filename);
T
ths 已提交
821
        if (initrd_size > 0) {
822
            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
823
            if (initrd_offset + initrd_size > ram_size) {
T
ths 已提交
824 825
                fprintf(stderr,
                        "qemu: memory too small for initial ram disk '%s'\n",
826
                        loaderparams.initrd_filename);
T
ths 已提交
827 828
                exit(1);
            }
829 830 831
            initrd_size = load_image_targphys(loaderparams.initrd_filename,
                                              initrd_offset,
                                              ram_size - initrd_offset);
T
ths 已提交
832
        }
833 834
        if (initrd_size == (target_ulong) -1) {
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
835
                    loaderparams.initrd_filename);
836 837 838 839
            exit(1);
        }
    }

A
Aurelien Jarno 已提交
840 841
    /* Setup prom parameters. */
    prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
842
    prom_buf = g_malloc(prom_size);
A
Aurelien Jarno 已提交
843

S
Stefan Weil 已提交
844
    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
A
Aurelien Jarno 已提交
845
    if (initrd_size > 0) {
846
        prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
J
James Hogan 已提交
847
                 xlate_to_kseg0(NULL, initrd_offset), initrd_size,
848
                 loaderparams.kernel_cmdline);
A
Aurelien Jarno 已提交
849
    } else {
S
Stefan Weil 已提交
850
        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
A
Aurelien Jarno 已提交
851 852 853
    }

    prom_set(prom_buf, prom_index++, "memsize");
P
Paul Burton 已提交
854 855
    prom_set(prom_buf, prom_index++, "%i",
             MIN(loaderparams.ram_size, 256 << 20));
J
James Hogan 已提交
856

A
Aurelien Jarno 已提交
857 858 859 860 861
    prom_set(prom_buf, prom_index++, "modetty0");
    prom_set(prom_buf, prom_index++, "38400n8r");
    prom_set(prom_buf, prom_index++, NULL);

    rom_add_blob_fixed("prom", prom_buf, prom_size,
862
                       cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
863

T
ths 已提交
864
    return kernel_entry;
865 866
}

867
static void malta_mips_config(MIPSCPU *cpu)
868
{
869 870 871
    CPUMIPSState *env = &cpu->env;
    CPUState *cs = CPU(cpu);

872
    env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
873
                         ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC);
874 875
}

876 877
static void main_cpu_reset(void *opaque)
{
878 879 880 881
    MIPSCPU *cpu = opaque;
    CPUMIPSState *env = &cpu->env;

    cpu_reset(CPU(cpu));
882

A
Aurelien Jarno 已提交
883
    /* The bootloader does not need to be rewritten as it is located in a
884 885
       read only location. The kernel location and the arguments table
       location does not change. */
886
    if (loaderparams.kernel_filename) {
T
ths 已提交
887 888
        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
    }
889

890
    malta_mips_config(cpu);
J
James Hogan 已提交
891 892 893 894 895

    if (kvm_enabled()) {
        /* Start running from the bootloader we wrote to end of RAM */
        env->active_tc.PC = 0x40000000 + loaderparams.ram_size;
    }
896 897
}

B
Blue Swirl 已提交
898 899
static void cpu_request_exit(void *opaque, int irq, int level)
{
900
    CPUState *cpu = current_cpu;
B
Blue Swirl 已提交
901

902 903
    if (cpu && level) {
        cpu_exit(cpu);
B
Blue Swirl 已提交
904 905 906
    }
}

907
static
908
void mips_malta_init(MachineState *machine)
909
{
910
    ram_addr_t ram_size = machine->ram_size;
J
James Hogan 已提交
911
    ram_addr_t ram_low_size;
912 913 914 915
    const char *cpu_model = machine->cpu_model;
    const char *kernel_filename = machine->kernel_filename;
    const char *kernel_cmdline = machine->kernel_cmdline;
    const char *initrd_filename = machine->initrd_filename;
P
Paul Brook 已提交
916
    char *filename;
917 918
    pflash_t *fl;
    MemoryRegion *system_memory = get_system_memory();
P
Paul Burton 已提交
919 920 921
    MemoryRegion *ram_high = g_new(MemoryRegion, 1);
    MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1);
    MemoryRegion *ram_low_postio;
922
    MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1);
923
    target_long bios_size = FLASH_SIZE;
924 925
    const size_t smbus_eeprom_size = 8 * 256;
    uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
J
James Hogan 已提交
926
    int64_t kernel_entry, bootloader_run_addr;
927
    PCIBus *pci_bus;
928
    ISABus *isa_bus;
929
    MIPSCPU *cpu;
A
Andreas Färber 已提交
930
    CPUMIPSState *env;
931
    qemu_irq *isa_irq;
B
Blue Swirl 已提交
932
    qemu_irq *cpu_exit_irq;
T
ths 已提交
933
    int piix4_devfn;
A
Andreas Färber 已提交
934
    I2CBus *smbus;
T
ths 已提交
935
    int i;
G
Gerd Hoffmann 已提交
936
    DriveInfo *dinfo;
937
    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
G
Gerd Hoffmann 已提交
938
    DriveInfo *fd[MAX_FD];
T
ths 已提交
939
    int fl_idx = 0;
940
    int fl_sectors = bios_size >> 16;
941
    int be;
942

A
Andreas Färber 已提交
943 944
    DeviceState *dev = qdev_create(NULL, TYPE_MIPS_MALTA);
    MaltaState *s = MIPS_MALTA(dev);
945

946 947 948 949 950
    /* The whole address space decoded by the GT-64120A doesn't generate
       exception when accessing invalid memory. Create an empty slot to
       emulate this feature. */
    empty_slot_init(0, 0x20000000);

951 952
    qdev_init_nofail(dev);

953 954 955 956 957
    /* Make sure the first 3 serial ports are associated with a device. */
    for(i = 0; i < 3; i++) {
        if (!serial_hds[i]) {
            char label[32];
            snprintf(label, sizeof(label), "serial%d", i);
958
            serial_hds[i] = qemu_chr_new(label, "null", NULL);
959 960 961
        }
    }

962 963
    /* init CPUs */
    if (cpu_model == NULL) {
T
ths 已提交
964
#ifdef TARGET_MIPS64
965
        cpu_model = "20Kc";
966
#else
967
        cpu_model = "24Kf";
968 969
#endif
    }
970 971

    for (i = 0; i < smp_cpus; i++) {
972 973
        cpu = cpu_mips_init(cpu_model);
        if (cpu == NULL) {
974 975 976
            fprintf(stderr, "Unable to find CPU definition\n");
            exit(1);
        }
977 978
        env = &cpu->env;

979 980 981
        /* Init internal devices */
        cpu_mips_irq_init_cpu(env);
        cpu_mips_clock_init(env);
982
        qemu_register_reset(main_cpu_reset, cpu);
B
bellard 已提交
983
    }
984 985
    cpu = MIPS_CPU(first_cpu);
    env = &cpu->env;
986 987

    /* allocate RAM */
P
Paul Burton 已提交
988
    if (ram_size > (2048u << 20)) {
989
        fprintf(stderr,
P
Paul Burton 已提交
990
                "qemu: Too much memory for this machine: %d MB, maximum 2048 MB\n",
991 992 993
                ((unsigned int)ram_size / (1 << 20)));
        exit(1);
    }
P
Paul Burton 已提交
994 995

    /* register RAM at high address where it is undisturbed by IO */
996 997
    memory_region_init_ram(ram_high, NULL, "mips_malta.ram", ram_size,
                           &error_abort);
P
Paul Burton 已提交
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
    vmstate_register_ram_global(ram_high);
    memory_region_add_subregion(system_memory, 0x80000000, ram_high);

    /* alias for pre IO hole access */
    memory_region_init_alias(ram_low_preio, NULL, "mips_malta_low_preio.ram",
                             ram_high, 0, MIN(ram_size, (256 << 20)));
    memory_region_add_subregion(system_memory, 0, ram_low_preio);

    /* alias for post IO hole access, if there is enough RAM */
    if (ram_size > (512 << 20)) {
        ram_low_postio = g_new(MemoryRegion, 1);
        memory_region_init_alias(ram_low_postio, NULL,
                                 "mips_malta_low_postio.ram",
                                 ram_high, 512 << 20,
                                 ram_size - (512 << 20));
        memory_region_add_subregion(system_memory, 512 << 20, ram_low_postio);
    }
1015

1016
    /* generate SPD EEPROM data */
1017 1018
    generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
    generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
1019

1020 1021 1022 1023 1024
#ifdef TARGET_WORDS_BIGENDIAN
    be = 1;
#else
    be = 0;
#endif
1025
    /* FPGA */
1026 1027
    /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
    malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
1028

1029 1030 1031 1032 1033 1034
    /* Load firmware in flash / BIOS. */
    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
#ifdef DEBUG_BOARD_INIT
    if (dinfo) {
        printf("Register parallel flash %d size " TARGET_FMT_lx " at "
               "addr %08llx '%s' %x\n",
1035
               fl_idx, bios_size, FLASH_ADDRESS,
1036
               blk_name(dinfo->bdrv), fl_sectors);
1037 1038
    }
#endif
1039
    fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
1040
                               BIOS_SIZE,
1041
                               dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
1042 1043 1044 1045
                               65536, fl_sectors,
                               4, 0x0000, 0x0000, 0x0000, 0x0000, be);
    bios = pflash_cfi01_get_memory(fl);
    fl_idx++;
T
ths 已提交
1046
    if (kernel_filename) {
J
James Hogan 已提交
1047
        ram_low_size = MIN(ram_size, 256 << 20);
1048
        /* For KVM we reserve 1MB of RAM for running bootloader */
J
James Hogan 已提交
1049 1050 1051 1052 1053 1054 1055
        if (kvm_enabled()) {
            ram_low_size -= 0x100000;
            bootloader_run_addr = 0x40000000 + ram_low_size;
        } else {
            bootloader_run_addr = 0xbfc00000;
        }

T
ths 已提交
1056
        /* Write a small bootloader to the flash location. */
J
James Hogan 已提交
1057
        loaderparams.ram_size = ram_low_size;
T
ths 已提交
1058 1059 1060
        loaderparams.kernel_filename = kernel_filename;
        loaderparams.kernel_cmdline = kernel_cmdline;
        loaderparams.initrd_filename = initrd_filename;
A
Aurelien Jarno 已提交
1061
        kernel_entry = load_kernel();
J
James Hogan 已提交
1062 1063 1064 1065 1066 1067 1068 1069 1070

        write_bootloader(env, memory_region_get_ram_ptr(bios),
                         bootloader_run_addr, kernel_entry);
        if (kvm_enabled()) {
            /* Write the bootloader code @ the end of RAM, 1MB reserved */
            write_bootloader(env, memory_region_get_ram_ptr(ram_low_preio) +
                                    ram_low_size,
                             bootloader_run_addr, kernel_entry);
        }
T
ths 已提交
1071
    } else {
1072
        /* The flash region isn't executable from a KVM guest */
1073 1074
        if (kvm_enabled()) {
            error_report("KVM enabled but no -kernel argument was specified. "
1075
                         "Booting from flash is not supported with KVM.");
1076 1077
            exit(1);
        }
1078 1079
        /* Load firmware from flash. */
        if (!dinfo) {
T
ths 已提交
1080
            /* Load a BIOS image. */
1081
            if (bios_name == NULL) {
T
ths 已提交
1082
                bios_name = BIOS_FILENAME;
1083
            }
P
Paul Brook 已提交
1084 1085
            filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
            if (filename) {
1086
                bios_size = load_image_targphys(filename, FLASH_ADDRESS,
P
Paul Brook 已提交
1087
                                                BIOS_SIZE);
1088
                g_free(filename);
P
Paul Brook 已提交
1089 1090 1091
            } else {
                bios_size = -1;
            }
1092 1093
            if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
                !kernel_filename && !qtest_enabled()) {
1094 1095 1096
                error_report("Could not load MIPS bios '%s', and no "
                             "-kernel argument was specified", bios_name);
                exit(1);
T
ths 已提交
1097
            }
1098
        }
T
ths 已提交
1099 1100 1101 1102
        /* In little endian mode the 32bit words in the bios are swapped,
           a neat trick which allows bi-endian firmware. */
#ifndef TARGET_WORDS_BIGENDIAN
        {
1103 1104 1105 1106
            uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS);
            if (!addr) {
                addr = memory_region_get_ram_ptr(bios);
            }
1107
            end = (void *)addr + MIN(bios_size, 0x3e0000);
P
pbrook 已提交
1108 1109
            while (addr < end) {
                bswap32s(addr);
1110
                addr++;
T
ths 已提交
1111 1112 1113
            }
        }
#endif
1114 1115
    }

1116 1117 1118 1119 1120 1121
    /*
     * Map the BIOS at a 2nd physical location, as on the real board.
     * Copy it so that we can patch in the MIPS revision, which cannot be
     * handled by an overlapping region as the resulting ROM code subpage
     * regions are not executable.
     */
1122 1123
    memory_region_init_ram(bios_copy, NULL, "bios.1fc", BIOS_SIZE,
                           &error_abort);
1124
    if (!rom_copy(memory_region_get_ram_ptr(bios_copy),
1125
                  FLASH_ADDRESS, BIOS_SIZE)) {
1126
        memcpy(memory_region_get_ram_ptr(bios_copy),
1127
               memory_region_get_ram_ptr(bios), BIOS_SIZE);
1128 1129 1130
    }
    memory_region_set_readonly(bios_copy, true);
    memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_copy);
1131

1132 1133
    /* Board ID = 0x420 (Malta Board with CoreLV) */
    stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
1134 1135

    /* Init internal devices */
P
pbrook 已提交
1136
    cpu_mips_irq_init_cpu(env);
1137 1138
    cpu_mips_clock_init(env);

1139 1140 1141 1142 1143 1144 1145
    /*
     * We have a circular dependency problem: pci_bus depends on isa_irq,
     * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
     * on piix4, and piix4 depends on pci_bus.  To stop the cycle we have
     * qemu_irq_proxy() adds an extra bit of indirection, allowing us
     * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
     */
1146
    isa_irq = qemu_irq_proxy(&s->i8259, 16);
1147 1148

    /* Northbridge */
1149
    pci_bus = gt64120_register(isa_irq);
1150 1151

    /* Southbridge */
1152
    ide_drive_get(hd, ARRAY_SIZE(hd));
T
ths 已提交
1153

1154
    piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
1155 1156 1157

    /* Interrupt controller */
    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
1158
    s->i8259 = i8259_init(isa_bus, env->irq[2]);
1159

1160
    isa_bus_irqs(isa_bus, s->i8259);
1161
    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
1162
    pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
1163
    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
1164
                          isa_get_irq(NULL, 9), NULL, 0, NULL, NULL);
1165 1166
    smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
    g_free(smbus_eeprom_buf);
1167
    pit = pit_init(isa_bus, 0x40, 0, NULL);
B
Blue Swirl 已提交
1168 1169
    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
    DMA_init(0, cpu_exit_irq);
1170 1171

    /* Super I/O */
1172
    isa_create_simple(isa_bus, "i8042");
B
Blue Swirl 已提交
1173

1174
    rtc_init(isa_bus, 2000, NULL);
1175
    serial_hds_isa_init(isa_bus, 2);
1176 1177
    parallel_hds_isa_init(isa_bus, 1);

T
ths 已提交
1178
    for(i = 0; i < MAX_FD; i++) {
G
Gerd Hoffmann 已提交
1179
        fd[i] = drive_get(IF_FLOPPY, 0, i);
T
ths 已提交
1180
    }
1181
    fdctrl_init_isa(isa_bus, fd);
1182 1183

    /* Network card */
1184
    network_init(pci_bus);
T
ths 已提交
1185 1186

    /* Optional PCI video card */
1187
    pci_vga_init(pci_bus);
1188 1189
}

1190 1191 1192 1193 1194
static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
{
    return 0;
}

1195 1196 1197 1198 1199 1200 1201
static void mips_malta_class_init(ObjectClass *klass, void *data)
{
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = mips_malta_sysbus_device_init;
}

1202
static const TypeInfo mips_malta_device = {
A
Andreas Färber 已提交
1203
    .name          = TYPE_MIPS_MALTA,
1204 1205 1206
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(MaltaState),
    .class_init    = mips_malta_class_init,
1207 1208
};

1209
static QEMUMachine mips_malta_machine = {
1210 1211 1212
    .name = "malta",
    .desc = "MIPS Malta Core LV",
    .init = mips_malta_init,
1213
    .max_cpus = 16,
1214
    .is_default = 1,
1215
};
1216

A
Andreas Färber 已提交
1217
static void mips_malta_register_types(void)
1218
{
1219
    type_register_static(&mips_malta_device);
1220 1221
}

1222 1223 1224 1225 1226
static void mips_malta_machine_init(void)
{
    qemu_register_machine(&mips_malta_machine);
}

A
Andreas Färber 已提交
1227
type_init(mips_malta_register_types)
1228
machine_init(mips_malta_machine_init);