pc.c 24.8 KB
Newer Older
B
bellard 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * QEMU PC System Emulator
 * 
 * Copyright (c) 2003-2004 Fabrice Bellard
 * 
 * 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"

B
bellard 已提交
26 27 28
/* output Bochs bios info messages */
//#define DEBUG_BIOS

B
bellard 已提交
29 30
#define BIOS_FILENAME "bios.bin"
#define VGABIOS_FILENAME "vgabios.bin"
B
bellard 已提交
31
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
B
bellard 已提交
32 33 34
#define LINUX_BOOT_FILENAME "linux_boot.bin"

#define KERNEL_LOAD_ADDR     0x00100000
B
bellard 已提交
35
#define INITRD_LOAD_ADDR     0x00600000
B
bellard 已提交
36 37 38
#define KERNEL_PARAMS_ADDR   0x00090000
#define KERNEL_CMDLINE_ADDR  0x00099000

39
static fdctrl_t *floppy_controller;
B
bellard 已提交
40
static RTCState *rtc_state;
B
bellard 已提交
41
static PITState *pit;
42
static IOAPICState *ioapic;
B
bellard 已提交
43
static USBPort *usb_root_ports[2];
B
bellard 已提交
44

B
bellard 已提交
45
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
B
bellard 已提交
46 47 48
{
}

49 50 51 52 53 54 55 56 57 58 59 60
/* MSDOS compatibility mode FPU exception support */
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
    pic_set_irq(13, 1);
}

static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
{
    pic_set_irq(13, 0);
}

B
bellard 已提交
61 62 63 64 65 66 67
/* TSC handling */

uint64_t cpu_get_tsc(CPUX86State *env)
{
    return qemu_get_clock(vm_clock);
}

B
bellard 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
/* IRQ handling */
int cpu_get_pic_interrupt(CPUState *env)
{
    int intno;

    intno = apic_get_interrupt(env);
    if (intno >= 0) {
        /* set irq request if a PIC irq is still pending */
        /* XXX: improve that */
        pic_update_irq(isa_pic); 
        return intno;
    }
    /* read the irq from the PIC */
    intno = pic_read_irq(isa_pic);
    return intno;
}

static void pic_irq_request(void *opaque, int level)
{
87
    CPUState *env = opaque;
B
bellard 已提交
88
    if (level)
89
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
B
bellard 已提交
90
    else
91
        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
B
bellard 已提交
92 93
}

B
bellard 已提交
94 95
/* PC cmos mappings */

B
bellard 已提交
96
#define REG_EQUIPMENT_BYTE          0x14
B
bellard 已提交
97 98 99 100 101 102 103 104
#define REG_IBM_CENTURY_BYTE        0x32
#define REG_IBM_PS2_CENTURY_BYTE    0x37


static inline int to_bcd(RTCState *s, int a)
{
    return ((a / 10) << 4) | (a % 10);
}
B
bellard 已提交
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
static int cmos_get_fd_drive_type(int fd0)
{
    int val;

    switch (fd0) {
    case 0:
        /* 1.44 Mb 3"5 drive */
        val = 4;
        break;
    case 1:
        /* 2.88 Mb 3"5 drive */
        val = 5;
        break;
    case 2:
        /* 1.2 Mb 5"5 drive */
        val = 2;
        break;
    default:
        val = 0;
        break;
    }
    return val;
}

B
bellard 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) 
{
    RTCState *s = rtc_state;
    int cylinders, heads, sectors;
    bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
    rtc_set_memory(s, type_ofs, 47);
    rtc_set_memory(s, info_ofs, cylinders);
    rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
    rtc_set_memory(s, info_ofs + 2, heads);
    rtc_set_memory(s, info_ofs + 3, 0xff);
    rtc_set_memory(s, info_ofs + 4, 0xff);
    rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
    rtc_set_memory(s, info_ofs + 6, cylinders);
    rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
    rtc_set_memory(s, info_ofs + 8, sectors);
}

/* hd_table must contain 4 block drivers */
static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table)
B
bellard 已提交
149
{
B
bellard 已提交
150
    RTCState *s = rtc_state;
B
bellard 已提交
151
    int val;
B
bellard 已提交
152
    int fd0, fd1, nb;
B
bellard 已提交
153 154
    time_t ti;
    struct tm *tm;
B
bellard 已提交
155
    int i;
B
bellard 已提交
156 157 158

    /* set the CMOS date */
    time(&ti);
B
bellard 已提交
159 160 161 162
    if (rtc_utc)
        tm = gmtime(&ti);
    else
        tm = localtime(&ti);
B
bellard 已提交
163 164 165 166 167
    rtc_set_date(s, tm);

    val = to_bcd(s, (tm->tm_year / 100) + 19);
    rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
    rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
B
bellard 已提交
168

B
bellard 已提交
169
    /* various important CMOS locations needed by PC/Bochs bios */
B
bellard 已提交
170 171

    /* memory size */
B
bellard 已提交
172 173 174 175
    val = 640; /* base memory in K */
    rtc_set_memory(s, 0x15, val);
    rtc_set_memory(s, 0x16, val >> 8);

B
bellard 已提交
176 177 178
    val = (ram_size / 1024) - 1024;
    if (val > 65535)
        val = 65535;
B
bellard 已提交
179 180 181 182
    rtc_set_memory(s, 0x17, val);
    rtc_set_memory(s, 0x18, val >> 8);
    rtc_set_memory(s, 0x30, val);
    rtc_set_memory(s, 0x31, val >> 8);
B
bellard 已提交
183

B
bellard 已提交
184 185 186 187
    if (ram_size > (16 * 1024 * 1024))
        val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
    else
        val = 0;
B
bellard 已提交
188 189
    if (val > 65535)
        val = 65535;
B
bellard 已提交
190 191
    rtc_set_memory(s, 0x34, val);
    rtc_set_memory(s, 0x35, val >> 8);
B
bellard 已提交
192 193 194 195
    
    switch(boot_device) {
    case 'a':
    case 'b':
B
bellard 已提交
196
        rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
B
bellard 已提交
197 198 199
        break;
    default:
    case 'c':
B
bellard 已提交
200
        rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */
B
bellard 已提交
201 202
        break;
    case 'd':
B
bellard 已提交
203
        rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */
B
bellard 已提交
204 205 206
        break;
    }

B
bellard 已提交
207 208
    /* floppy type */

209 210
    fd0 = fdctrl_get_drive_type(floppy_controller, 0);
    fd1 = fdctrl_get_drive_type(floppy_controller, 1);
B
bellard 已提交
211

212
    val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
B
bellard 已提交
213 214 215
    rtc_set_memory(s, 0x10, val);
    
    val = 0;
B
bellard 已提交
216
    nb = 0;
B
bellard 已提交
217 218 219 220 221 222 223 224
    if (fd0 < 3)
        nb++;
    if (fd1 < 3)
        nb++;
    switch (nb) {
    case 0:
        break;
    case 1:
B
bellard 已提交
225
        val |= 0x01; /* 1 drive, ready for boot */
B
bellard 已提交
226 227
        break;
    case 2:
B
bellard 已提交
228
        val |= 0x41; /* 2 drives, ready for boot */
B
bellard 已提交
229 230
        break;
    }
B
bellard 已提交
231 232 233 234
    val |= 0x02; /* FPU is there */
    val |= 0x04; /* PS/2 mouse installed */
    rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);

B
bellard 已提交
235 236 237 238 239 240 241 242 243
    /* hard drives */

    rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
    if (hd_table[0])
        cmos_init_hd(0x19, 0x1b, hd_table[0]);
    if (hd_table[1]) 
        cmos_init_hd(0x1a, 0x24, hd_table[1]);

    val = 0;
B
bellard 已提交
244
    for (i = 0; i < 4; i++) {
B
bellard 已提交
245
        if (hd_table[i]) {
B
bellard 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
            int cylinders, heads, sectors, translation;
            /* NOTE: bdrv_get_geometry_hint() returns the physical
                geometry.  It is always such that: 1 <= sects <= 63, 1
                <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
                geometry can be different if a translation is done. */
            translation = bdrv_get_translation_hint(hd_table[i]);
            if (translation == BIOS_ATA_TRANSLATION_AUTO) {
                bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
                if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
                    /* No translation. */
                    translation = 0;
                } else {
                    /* LBA translation. */
                    translation = 1;
                }
B
bellard 已提交
261
            } else {
B
bellard 已提交
262
                translation--;
B
bellard 已提交
263 264 265
            }
            val |= translation << (i * 2);
        }
B
bellard 已提交
266
    }
B
bellard 已提交
267 268 269 270 271
    rtc_set_memory(s, 0x39, val);

    /* Disable check of 0x55AA signature on the last two bytes of
       first sector of disk. XXX: make it the default ? */
    //    rtc_set_memory(s, 0x38, 1);
B
bellard 已提交
272 273
}

274 275 276 277 278 279 280 281 282 283 284
void ioport_set_a20(int enable)
{
    /* XXX: send to all CPUs ? */
    cpu_x86_set_a20(first_cpu, enable);
}

int ioport_get_a20(void)
{
    return ((first_cpu->a20_mask >> 20) & 1);
}

B
bellard 已提交
285 286
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
{
287
    ioport_set_a20((val >> 1) & 1);
B
bellard 已提交
288 289 290 291 292
    /* XXX: bit 0 is fast reset */
}

static uint32_t ioport92_read(void *opaque, uint32_t addr)
{
293
    return ioport_get_a20() << 1;
B
bellard 已提交
294 295
}

B
bellard 已提交
296 297 298
/***********************************************************/
/* Bochs BIOS debug ports */

B
bellard 已提交
299
void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
B
bellard 已提交
300
{
B
bellard 已提交
301 302 303
    static const char shutdown_str[8] = "Shutdown";
    static int shutdown_index = 0;
    
B
bellard 已提交
304 305 306 307 308 309 310 311 312 313 314 315
    switch(addr) {
        /* Bochs BIOS messages */
    case 0x400:
    case 0x401:
        fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
        exit(1);
    case 0x402:
    case 0x403:
#ifdef DEBUG_BIOS
        fprintf(stderr, "%c", val);
#endif
        break;
B
bellard 已提交
316 317 318 319 320 321 322 323 324 325 326 327
    case 0x8900:
        /* same as Bochs power off */
        if (val == shutdown_str[shutdown_index]) {
            shutdown_index++;
            if (shutdown_index == 8) {
                shutdown_index = 0;
                qemu_system_shutdown_request();
            }
        } else {
            shutdown_index = 0;
        }
        break;
B
bellard 已提交
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

        /* LGPL'ed VGA BIOS messages */
    case 0x501:
    case 0x502:
        fprintf(stderr, "VGA BIOS panic, line %d\n", val);
        exit(1);
    case 0x500:
    case 0x503:
#ifdef DEBUG_BIOS
        fprintf(stderr, "%c", val);
#endif
        break;
    }
}

void bochs_bios_init(void)
{
B
bellard 已提交
345 346 347 348
    register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
    register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL);
    register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL);
    register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL);
B
bellard 已提交
349
    register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL);
B
bellard 已提交
350 351 352 353 354

    register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL);
    register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL);
    register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL);
    register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL);
B
bellard 已提交
355 356 357 358 359 360 361 362 363
}


int load_kernel(const char *filename, uint8_t *addr, 
                uint8_t *real_addr)
{
    int fd, size;
    int setup_sects;

B
bellard 已提交
364
    fd = open(filename, O_RDONLY | O_BINARY);
B
bellard 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    if (fd < 0)
        return -1;

    /* load 16 bit code */
    if (read(fd, real_addr, 512) != 512)
        goto fail;
    setup_sects = real_addr[0x1F1];
    if (!setup_sects)
        setup_sects = 4;
    if (read(fd, real_addr + 512, setup_sects * 512) != 
        setup_sects * 512)
        goto fail;
    
    /* load 32 bit code */
    size = read(fd, addr, 16 * 1024 * 1024);
    if (size < 0)
        goto fail;
    close(fd);
    return size;
 fail:
    close(fd);
    return -1;
}

389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 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 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
static void main_cpu_reset(void *opaque)
{
    CPUState *env = opaque;
    cpu_reset(env);
}

/*************************************************/

static void putb(uint8_t **pp, int val)
{
    uint8_t *q;
    q = *pp;
    *q++ = val;
    *pp = q;
}

static void putstr(uint8_t **pp, const char *str)
{
    uint8_t *q;
    q = *pp;
    while (*str)
        *q++ = *str++;
    *pp = q;
}

static void putle16(uint8_t **pp, int val)
{
    uint8_t *q;
    q = *pp;
    *q++ = val;
    *q++ = val >> 8;
    *pp = q;
}

static void putle32(uint8_t **pp, int val)
{
    uint8_t *q;
    q = *pp;
    *q++ = val;
    *q++ = val >> 8;
    *q++ = val >> 16;
    *q++ = val >> 24;
    *pp = q;
}

static int mpf_checksum(const uint8_t *data, int len)
{
    int sum, i;
    sum = 0;
    for(i = 0; i < len; i++)
        sum += data[i];
    return sum & 0xff;
}

/* Build the Multi Processor table in the BIOS. Same values as Bochs. */
static void bios_add_mptable(uint8_t *bios_data)
{
    uint8_t *mp_config_table, *q, *float_pointer_struct;
    int ioapic_id, offset, i, len;
    
    if (smp_cpus <= 1)
        return;

B
bellard 已提交
452
    mp_config_table = bios_data + 0xb000;
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
    q = mp_config_table;
    putstr(&q, "PCMP"); /* "PCMP signature */
    putle16(&q, 0); /* table length (patched later) */
    putb(&q, 4); /* spec rev */
    putb(&q, 0); /* checksum (patched later) */
    putstr(&q, "QEMUCPU "); /* OEM id */
    putstr(&q, "0.1         "); /* vendor id */
    putle32(&q, 0); /* OEM table ptr */
    putle16(&q, 0); /* OEM table size */
    putle16(&q, 20); /* entry count */
    putle32(&q, 0xfee00000); /* local APIC addr */
    putle16(&q, 0); /* ext table length */
    putb(&q, 0); /* ext table checksum */
    putb(&q, 0); /* reserved */
    
    for(i = 0; i < smp_cpus; i++) {
        putb(&q, 0); /* entry type = processor */
        putb(&q, i); /* APIC id */
        putb(&q, 0x11); /* local APIC version number */
        if (i == 0)
            putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
        else
            putb(&q, 1); /* cpu flags: enabled */
        putb(&q, 0); /* cpu signature */
        putb(&q, 6);
        putb(&q, 0);
        putb(&q, 0);
        putle16(&q, 0x201); /* feature flags */
        putle16(&q, 0);

        putle16(&q, 0); /* reserved */
        putle16(&q, 0);
        putle16(&q, 0);
        putle16(&q, 0);
    }

    /* isa bus */
    putb(&q, 1); /* entry type = bus */
    putb(&q, 0); /* bus ID */
    putstr(&q, "ISA   ");
    
    /* ioapic */
    ioapic_id = smp_cpus;
    putb(&q, 2); /* entry type = I/O APIC */
    putb(&q, ioapic_id); /* apic ID */
    putb(&q, 0x11); /* I/O APIC version number */
    putb(&q, 1); /* enable */
    putle32(&q, 0xfec00000); /* I/O APIC addr */

    /* irqs */
    for(i = 0; i < 16; i++) {
        putb(&q, 3); /* entry type = I/O interrupt */
        putb(&q, 0); /* interrupt type = vectored interrupt */
        putb(&q, 0); /* flags: po=0, el=0 */
        putb(&q, 0);
        putb(&q, 0); /* source bus ID = ISA */
        putb(&q, i); /* source bus IRQ */
        putb(&q, ioapic_id); /* dest I/O APIC ID */
        putb(&q, i); /* dest I/O APIC interrupt in */
    }
    /* patch length */
    len = q - mp_config_table;
    mp_config_table[4] = len;
    mp_config_table[5] = len >> 8;

    mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);

    /* align to 16 */
    offset = q - bios_data;
    offset = (offset + 15) & ~15;
    float_pointer_struct = bios_data + offset;
    
    /* floating pointer structure */
    q = float_pointer_struct;
    putstr(&q, "_MP_");
    /* pointer to MP config table */
    putle32(&q, mp_config_table - bios_data + 0x000f0000); 

    putb(&q, 1); /* length in 16 byte units */
    putb(&q, 4); /* MP spec revision */
    putb(&q, 0); /* checksum (patched later) */
    putb(&q, 0); /* MP feature byte 1 */

    putb(&q, 0);
    putb(&q, 0);
    putb(&q, 0);
    putb(&q, 0);
    float_pointer_struct[10] = 
        -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
}


B
bellard 已提交
545 546 547 548 549 550
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };

#define NE2000_NB_MAX 6

551
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
B
bellard 已提交
552 553
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };

554 555 556
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };

557 558 559
static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
{
    struct soundhw *c;
    int audio_enabled = 0;

    for (c = soundhw; !audio_enabled && c->name; ++c) {
        audio_enabled = c->enabled;
    }

    if (audio_enabled) {
        AudioState *s;

        s = AUD_init ();
        if (s) {
            for (c = soundhw; c->name; ++c) {
                if (c->enabled) {
                    if (c->isa) {
                        c->init.init_isa (s);
                    }
                    else {
                        if (pci_bus) {
                            c->init.init_pci (pci_bus, s);
                        }
                    }
                }
            }
        }
    }
}
#endif

592 593 594 595 596 597 598 599 600 601
static void pc_init_ne2k_isa(NICInfo *nd)
{
    static int nb_ne2k = 0;

    if (nb_ne2k == NE2000_NB_MAX)
        return;
    isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd);
    nb_ne2k++;
}

B
bellard 已提交
602
/* PC hardware initialisation */
B
bellard 已提交
603 604 605
static void pc_init1(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,
606 607
                     const char *initrd_filename,
                     int pci_enabled)
B
bellard 已提交
608 609
{
    char buf[1024];
610
    int ret, linux_boot, initrd_size, i;
B
bellard 已提交
611 612
    unsigned long bios_offset, vga_bios_offset;
    int bios_size, isa_bios_size;
B
bellard 已提交
613
    PCIBus *pci_bus;
P
pbrook 已提交
614
    int piix3_devfn;
615
    CPUState *env;
616
    NICInfo *nd;
617

B
bellard 已提交
618 619
    linux_boot = (kernel_filename != NULL);

620 621 622 623
    /* init CPUs */
    for(i = 0; i < smp_cpus; i++) {
        env = cpu_init();
        if (i != 0)
B
bellard 已提交
624
            env->hflags |= HF_HALTED_MASK;
625 626 627 628
        if (smp_cpus > 1) {
            /* XXX: enable it in all cases */
            env->cpuid_features |= CPUID_APIC;
        }
629
        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
630 631 632 633 634 635
        qemu_register_reset(main_cpu_reset, env);
        if (pci_enabled) {
            apic_init(env);
        }
    }

B
bellard 已提交
636 637 638 639
    /* allocate RAM */
    cpu_register_physical_memory(0, ram_size, 0);

    /* BIOS load */
B
bellard 已提交
640 641 642
    bios_offset = ram_size + vga_ram_size;
    vga_bios_offset = bios_offset + 256 * 1024;

B
bellard 已提交
643
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
B
bellard 已提交
644 645 646 647 648 649 650 651 652
    bios_size = get_image_size(buf);
    if (bios_size <= 0 || 
        (bios_size % 65536) != 0 ||
        bios_size > (256 * 1024)) {
        goto bios_error;
    }
    ret = load_image(buf, phys_ram_base + bios_offset);
    if (ret != bios_size) {
    bios_error:
B
bellard 已提交
653 654 655
        fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
        exit(1);
    }
656 657 658
    if (bios_size == 65536) {
        bios_add_mptable(phys_ram_base + bios_offset);
    }
B
bellard 已提交
659

B
bellard 已提交
660
    /* VGA BIOS load */
B
bellard 已提交
661 662 663 664 665
    if (cirrus_vga_enabled) {
        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
    } else {
        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
    }
B
bellard 已提交
666
    ret = load_image(buf, phys_ram_base + vga_bios_offset);
B
bellard 已提交
667 668
    
    /* setup basic memory access */
B
bellard 已提交
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
    cpu_register_physical_memory(0xc0000, 0x10000, 
                                 vga_bios_offset | IO_MEM_ROM);

    /* map the last 128KB of the BIOS in ISA space */
    isa_bios_size = bios_size;
    if (isa_bios_size > (128 * 1024))
        isa_bios_size = 128 * 1024;
    cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, 
                                 IO_MEM_UNASSIGNED);
    cpu_register_physical_memory(0x100000 - isa_bios_size, 
                                 isa_bios_size, 
                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
    /* map all the bios at the top of memory */
    cpu_register_physical_memory((uint32_t)(-bios_size), 
                                 bios_size, bios_offset | IO_MEM_ROM);
B
bellard 已提交
684 685 686 687 688
    
    bochs_bios_init();

    if (linux_boot) {
        uint8_t bootsect[512];
689
        uint8_t old_bootsect[512];
B
bellard 已提交
690 691 692 693 694 695 696 697 698 699 700 701 702

        if (bs_table[0] == NULL) {
            fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n");
            exit(1);
        }
        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
        ret = load_image(buf, bootsect);
        if (ret != sizeof(bootsect)) {
            fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
                    buf);
            exit(1);
        }

703 704 705 706 707
        if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) {
            /* copy the MSDOS partition table */
            memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40);
        }

B
bellard 已提交
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
        bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));

        /* now we can load the kernel */
        ret = load_kernel(kernel_filename, 
                          phys_ram_base + KERNEL_LOAD_ADDR,
                          phys_ram_base + KERNEL_PARAMS_ADDR);
        if (ret < 0) {
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
                    kernel_filename);
            exit(1);
        }
        
        /* 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) {
            stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
            stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
        }
        pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
                kernel_cmdline);
        stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F);
        stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22,
                KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR);
        /* loader type */
        stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
    }

B
bellard 已提交
743
    if (pci_enabled) {
B
bellard 已提交
744
        pci_bus = i440fx_init();
P
pbrook 已提交
745
        piix3_devfn = piix3_init(pci_bus);
B
bellard 已提交
746 747
    } else {
        pci_bus = NULL;
B
bellard 已提交
748 749
    }

B
bellard 已提交
750
    /* init basic PC hardware */
B
bellard 已提交
751
    register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
B
bellard 已提交
752

753 754
    register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);

B
bellard 已提交
755 756
    if (cirrus_vga_enabled) {
        if (pci_enabled) {
B
bellard 已提交
757 758
            pci_cirrus_vga_init(pci_bus, 
                                ds, phys_ram_base + ram_size, ram_size, 
B
bellard 已提交
759 760 761 762 763 764
                                vga_ram_size);
        } else {
            isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, 
                                vga_ram_size);
        }
    } else {
B
bellard 已提交
765
        vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
B
bellard 已提交
766
                       vga_ram_size, 0, 0);
B
bellard 已提交
767
    }
B
bellard 已提交
768

B
bellard 已提交
769
    rtc_state = rtc_init(0x70, 8);
B
bellard 已提交
770

B
bellard 已提交
771 772 773
    register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
    register_ioport_write(0x92, 1, 1, ioport92_write, NULL);

774 775 776
    if (pci_enabled) {
        ioapic = ioapic_init();
    }
777
    isa_pic = pic_init(pic_irq_request, first_cpu);
B
bellard 已提交
778
    pit = pit_init(0x40, 0);
B
bellard 已提交
779
    pcspk_init(pit);
780 781 782
    if (pci_enabled) {
        pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
    }
B
bellard 已提交
783

784 785
    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
        if (serial_hds[i]) {
786 787
            serial_init(&pic_set_irq_new, isa_pic,
                        serial_io[i], serial_irq[i], serial_hds[i]);
788 789
        }
    }
B
bellard 已提交
790

791 792 793 794 795 796
    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
        if (parallel_hds[i]) {
            parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
        }
    }

797 798 799 800 801 802 803 804
    for(i = 0; i < nb_nics; i++) {
        nd = &nd_table[i];
        if (!nd->model) {
            if (pci_enabled) {
                nd->model = "ne2k_pci";
            } else {
                nd->model = "ne2k_isa";
            }
B
bellard 已提交
805
        }
806 807 808 809 810 811 812
        if (strcmp(nd->model, "ne2k_isa") == 0) {
            pc_init_ne2k_isa(nd);
        } else if (pci_enabled) {
            pci_nic_init(pci_bus, nd);
        } else {
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
            exit(1);
B
bellard 已提交
813
        }
814
    }
B
bellard 已提交
815

816
    if (pci_enabled) {
P
pbrook 已提交
817
        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
818
    } else {
B
bellard 已提交
819 820 821 822
        for(i = 0; i < 2; i++) {
            isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
                         bs_table[2 * i], bs_table[2 * i + 1]);
        }
B
bellard 已提交
823
    }
B
bellard 已提交
824

B
bellard 已提交
825
    kbd_init();
B
bellard 已提交
826
    DMA_init(0);
827 828
#ifdef HAS_AUDIO
    audio_init(pci_enabled ? pci_bus : NULL);
B
bellard 已提交
829
#endif
B
bellard 已提交
830

831
    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
B
bellard 已提交
832

B
bellard 已提交
833
    cmos_init(ram_size, boot_device, bs_table);
B
bellard 已提交
834

B
bellard 已提交
835
    if (pci_enabled && usb_enabled) {
P
pbrook 已提交
836
        usb_uhci_init(pci_bus, usb_root_ports, piix3_devfn + 2);
B
bellard 已提交
837
        usb_attach(usb_root_ports[0], vm_usb_hub);
B
bellard 已提交
838 839
    }

B
bellard 已提交
840
    if (pci_enabled && acpi_enabled) {
P
pbrook 已提交
841
        piix4_pm_init(pci_bus, piix3_devfn + 3);
B
bellard 已提交
842
    }
B
bellard 已提交
843 844 845 846
    /* must be done after all PCI devices are instanciated */
    /* XXX: should be done in the Bochs BIOS */
    if (pci_enabled) {
        pci_bios_init();
B
bellard 已提交
847 848
        if (acpi_enabled)
            acpi_bios_init();
B
bellard 已提交
849
    }
B
bellard 已提交
850
}
B
bellard 已提交
851

852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
static void pc_init_pci(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)
{
    pc_init1(ram_size, vga_ram_size, boot_device,
             ds, fd_filename, snapshot,
             kernel_filename, kernel_cmdline,
             initrd_filename, 1);
}

static void pc_init_isa(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)
{
    pc_init1(ram_size, vga_ram_size, boot_device,
             ds, fd_filename, snapshot,
             kernel_filename, kernel_cmdline,
             initrd_filename, 0);
}

B
bellard 已提交
878 879 880
QEMUMachine pc_machine = {
    "pc",
    "Standard PC",
881 882 883 884 885 886 887
    pc_init_pci,
};

QEMUMachine isapc_machine = {
    "isapc",
    "ISA-only PC",
    pc_init_isa,
B
bellard 已提交
888
};