aboutsummaryrefslogtreecommitdiff
path: root/hw/i386/isapc.c
blob: 44f4a4467243959214c4fceef5c07bc27a4172ec (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 * QEMU PC System Emulator
 *
 * Copyright (c) 2003-2004 Fabrice Bellard
 *
 * SPDX-License-Identifier: MIT
 */

#include "qemu/osdep.h"

#include "qemu/units.h"
#include "qemu/error-report.h"
#include "hw/char/parallel-isa.h"
#include "hw/dma/i8257.h"
#include "hw/i386/pc.h"
#include "hw/ide/isa.h"
#include "hw/ide/ide-bus.h"
#include "system/kvm.h"
#include "hw/i386/kvm/clock.h"
#include "hw/xen/xen-x86.h"
#include "system/xen.h"
#include "hw/rtc/mc146818rtc.h"
#include "target/i386/cpu.h"

static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };


static void pc_init_isa(MachineState *machine)
{
    PCMachineState *pcms = PC_MACHINE(machine);
    PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
    X86MachineState *x86ms = X86_MACHINE(machine);
    MemoryRegion *system_memory = get_system_memory();
    MemoryRegion *system_io = get_system_io();
    ISABus *isa_bus;
    uint32_t irq;
    GSIState *gsi_state;
    MemoryRegion *ram_memory;
    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
    int i;

    /*
     * There is a small chance that someone unintentionally passes "-cpu max"
     * for the isapc machine, which will provide a much more modern 32-bit
     * CPU than would be expected for an ISA-era PC. If the "max" cpu type has
     * been specified, choose the "best" 32-bit cpu possible which we consider
     * be the pentium3 (deliberately choosing an Intel CPU given that the
     * default 486 CPU for the isapc machine is also an Intel CPU).
     */
    if (!strcmp(machine->cpu_type, X86_CPU_TYPE_NAME("max"))) {
        machine->cpu_type = X86_CPU_TYPE_NAME("pentium3");
        warn_report("-cpu max is invalid for isapc machine, using pentium3");
    }

    /*
     * Similarly if someone unintentionally passes "-cpu host" for the isapc
     * machine then display a warning and also switch to the "best" 32-bit
     * cpu possible which we consider to be the pentium3. This is because any
     * host CPU will already be modern than this, but it also ensures any
     * newer CPU flags/features are filtered out for older guests.
     */
    if (!strcmp(machine->cpu_type, X86_CPU_TYPE_NAME("host"))) {
        machine->cpu_type = X86_CPU_TYPE_NAME("pentium3");
        warn_report("-cpu host is invalid for isapc machine, using pentium3");
    }

    if (machine->ram_size > 3.5 * GiB) {
        error_report("Too much memory for this machine: %" PRId64 " MiB, "
                     "maximum 3584 MiB", machine->ram_size / MiB);
        exit(1);
    }

    /*
     * There is no RAM split for the isapc machine
     */
    if (xen_enabled()) {
        xen_hvm_init_pc(pcms, &ram_memory);
    } else {
        ram_memory = machine->ram;

        pcms->max_ram_below_4g = 3.5 * GiB;
        x86ms->above_4g_mem_size = 0;
        x86ms->below_4g_mem_size = machine->ram_size;
    }

    x86_cpus_init(x86ms, pcmc->default_cpu_version);

    if (kvm_enabled()) {
        kvmclock_create(pcmc->kvmclock_create_always);
    }

    /* allocate ram and load rom/bios */
    if (!xen_enabled()) {
        pc_memory_init(pcms, system_memory, system_memory, 0);
    } else {
        assert(machine->ram_size == x86ms->below_4g_mem_size +
                                    x86ms->above_4g_mem_size);

        if (machine->kernel_filename != NULL) {
            /* For xen HVM direct kernel boot, load linux here */
            xen_load_linux(pcms);
        }
    }

    gsi_state = pc_gsi_create(&x86ms->gsi, false);

    isa_bus = isa_bus_new(NULL, system_memory, system_io,
                          &error_abort);
    isa_bus_register_input_irqs(isa_bus, x86ms->gsi);

    x86ms->rtc = isa_new(TYPE_MC146818_RTC);
    qdev_prop_set_int32(DEVICE(x86ms->rtc), "base_year", 2000);
    isa_realize_and_unref(x86ms->rtc, isa_bus, &error_fatal);
    irq = object_property_get_uint(OBJECT(x86ms->rtc), "irq",
                                   &error_fatal);
    isa_connect_gpio_out(ISA_DEVICE(x86ms->rtc), 0, irq);

    i8257_dma_init(OBJECT(machine), isa_bus, 0);
    pcms->hpet_enabled = false;

    if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) {
        pc_i8259_create(isa_bus, gsi_state->i8259_irq);
    }

    if (tcg_enabled()) {
        x86_register_ferr_irq(x86ms->gsi[13]);
    }

    pc_vga_init(isa_bus, NULL);

    /* init basic PC hardware */
    pc_basic_device_init(pcms, isa_bus, x86ms->gsi, x86ms->rtc,
                         !MACHINE_CLASS(pcmc)->no_floppy, 0x4);

    pc_nic_init(pcmc, isa_bus, NULL);

    ide_drive_get(hd, ARRAY_SIZE(hd));
    for (i = 0; i < MAX_IDE_BUS; i++) {
        ISADevice *dev;
        char busname[] = "ide.0";
        dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
                            ide_irq[i],
                            hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
        /*
         * The ide bus name is ide.0 for the first bus and ide.1 for the
         * second one.
         */
        busname[4] = '0' + i;
        pcms->idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
    }
}

static void isapc_machine_options(MachineClass *m)
{
    static const char * const valid_cpu_types[] = {
        X86_CPU_TYPE_NAME("486"),
        X86_CPU_TYPE_NAME("athlon"),
        X86_CPU_TYPE_NAME("kvm32"),
        X86_CPU_TYPE_NAME("pentium"),
        X86_CPU_TYPE_NAME("pentium2"),
        X86_CPU_TYPE_NAME("pentium3"),
        X86_CPU_TYPE_NAME("qemu32"),
        X86_CPU_TYPE_NAME("max"),
        X86_CPU_TYPE_NAME("host"),
        NULL
    };
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);

    m->desc = "ISA-only PC";
    m->max_cpus = 1;
    m->option_rom_has_mr = true;
    m->rom_file_has_mr = false;
    pcmc->pci_enabled = false;
    pcmc->has_acpi_build = false;
    pcmc->smbios_defaults = false;
    pcmc->gigabyte_align = false;
    pcmc->smbios_legacy_mode = true;
    pcmc->has_reserved_memory = false;
    m->default_nic = "ne2k_isa";
    m->default_cpu_type = X86_CPU_TYPE_NAME("486");
    m->valid_cpu_types = valid_cpu_types;
    m->no_floppy = !module_object_class_by_name(TYPE_ISA_FDC);
    m->no_parallel = !module_object_class_by_name(TYPE_ISA_PARALLEL);
}

DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
                  isapc_machine_options);