qemu/hw/alpha/dp264.c
<<
>>
Prefs
   1/*
   2 * QEMU Alpha DP264/CLIPPER hardware system emulator.
   3 *
   4 * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
   5 * variants because CLIPPER doesn't have an SMC669 SuperIO controller
   6 * that we need to emulate as well.
   7 */
   8
   9#include "qemu/osdep.h"
  10#include "cpu.h"
  11#include "elf.h"
  12#include "hw/loader.h"
  13#include "alpha_sys.h"
  14#include "qemu/error-report.h"
  15#include "hw/rtc/mc146818rtc.h"
  16#include "hw/ide/pci.h"
  17#include "hw/isa/superio.h"
  18#include "net/net.h"
  19#include "qemu/cutils.h"
  20#include "qemu/datadir.h"
  21#include "net/net.h"
  22
  23static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
  24{
  25    if (((addr >> 41) & 3) == 2) {
  26        addr &= 0xffffffffffull;
  27    }
  28    return addr;
  29}
  30
  31/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
  32    (0) The dev_irq_n lines into the cpu, which we totally ignore,
  33    (1) The DRIR lines in the typhoon chipset,
  34    (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
  35    (3) The interrupt number assigned by the kernel.
  36   The following function is concerned with (1) only.  */
  37
  38static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
  39{
  40    int slot = d->devfn >> 3;
  41
  42    assert(irq_num >= 0 && irq_num <= 3);
  43
  44    return (slot + 1) * 4 + irq_num;
  45}
  46
  47static void clipper_init(MachineState *machine)
  48{
  49    ram_addr_t ram_size = machine->ram_size;
  50    const char *kernel_filename = machine->kernel_filename;
  51    const char *kernel_cmdline = machine->kernel_cmdline;
  52    const char *initrd_filename = machine->initrd_filename;
  53    AlphaCPU *cpus[4];
  54    PCIBus *pci_bus;
  55    PCIDevice *pci_dev;
  56    DeviceState *i82378_dev;
  57    ISABus *isa_bus;
  58    qemu_irq rtc_irq;
  59    qemu_irq isa_irq;
  60    long size, i;
  61    char *palcode_filename;
  62    uint64_t palcode_entry;
  63    uint64_t kernel_entry, kernel_low;
  64    unsigned int smp_cpus = machine->smp.cpus;
  65
  66    /* Create up to 4 cpus.  */
  67    memset(cpus, 0, sizeof(cpus));
  68    for (i = 0; i < smp_cpus; ++i) {
  69        cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type));
  70    }
  71
  72    /*
  73     * arg0 -> memory size
  74     * arg1 -> kernel entry point
  75     * arg2 -> config word
  76     *
  77     * Config word: bits 0-5 -> ncpus
  78     *              bit  6   -> nographics option (for HWRPB CTB)
  79     *
  80     * See init_hwrpb() in the PALcode.
  81     */
  82    cpus[0]->env.trap_arg0 = ram_size;
  83    cpus[0]->env.trap_arg1 = 0;
  84    cpus[0]->env.trap_arg2 = smp_cpus | (!machine->enable_graphics << 6);
  85
  86    /*
  87     * Init the chipset.  Because we're using CLIPPER IRQ mappings,
  88     * the minimum PCI device IdSel is 1.
  89     */
  90    pci_bus = typhoon_init(machine->ram, &isa_irq, &rtc_irq, cpus,
  91                           clipper_pci_map_irq, PCI_DEVFN(1, 0));
  92
  93    /*
  94     * Init the PCI -> ISA bridge.
  95     *
  96     * Technically, PCI-based Alphas shipped with one of three different
  97     * PCI-ISA bridges:
  98     *
  99     * - Intel i82378 SIO
 100     * - Cypress CY82c693UB
 101     * - ALI M1533
 102     *
 103     * (An Intel i82375 PCI-EISA bridge was also used on some models.)
 104     *
 105     * For simplicity, we model an i82378 here, even though it wouldn't
 106     * have been on any Tsunami/Typhoon systems; it's close enough, and
 107     * we don't want to deal with modelling the CY82c693UB (which has
 108     * incompatible edge/level control registers, plus other peripherals
 109     * like IDE and USB) or the M1533 (which also has IDE and USB).
 110     *
 111     * Importantly, we need to provide a PCI device node for it, otherwise
 112     * some operating systems won't notice there's an ISA bus to configure.
 113     */
 114    i82378_dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(7, 0), "i82378"));
 115    isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0"));
 116
 117    /* Connect the ISA PIC to the Typhoon IRQ used for ISA interrupts. */
 118    qdev_connect_gpio_out(i82378_dev, 0, isa_irq);
 119
 120    /* Since we have an SRM-compatible PALcode, use the SRM epoch.  */
 121    mc146818_rtc_init(isa_bus, 1900, rtc_irq);
 122
 123    /* VGA setup.  Don't bother loading the bios.  */
 124    pci_vga_init(pci_bus);
 125
 126    /* Network setup.  e1000 is good enough, failing Tulip support.  */
 127    for (i = 0; i < nb_nics; i++) {
 128        pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
 129    }
 130
 131    /* Super I/O */
 132    isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
 133
 134    /* IDE disk setup.  */
 135    pci_dev = pci_create_simple(pci_bus, -1, "cmd646-ide");
 136    pci_ide_create_devs(pci_dev);
 137
 138    /* Load PALcode.  Given that this is not "real" cpu palcode,
 139       but one explicitly written for the emulation, we might as
 140       well load it directly from and ELF image.  */
 141    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
 142                                      machine->firmware ?: "palcode-clipper");
 143    if (palcode_filename == NULL) {
 144        error_report("no palcode provided");
 145        exit(1);
 146    }
 147    size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
 148                    NULL, &palcode_entry, NULL, NULL, NULL,
 149                    0, EM_ALPHA, 0, 0);
 150    if (size < 0) {
 151        error_report("could not load palcode '%s'", palcode_filename);
 152        exit(1);
 153    }
 154    g_free(palcode_filename);
 155
 156    /* Start all cpus at the PALcode RESET entry point.  */
 157    for (i = 0; i < smp_cpus; ++i) {
 158        cpus[i]->env.pc = palcode_entry;
 159        cpus[i]->env.palbr = palcode_entry;
 160    }
 161
 162    /* Load a kernel.  */
 163    if (kernel_filename) {
 164        uint64_t param_offset;
 165
 166        size = load_elf(kernel_filename, NULL, cpu_alpha_superpage_to_phys,
 167                        NULL, &kernel_entry, &kernel_low, NULL, NULL,
 168                        0, EM_ALPHA, 0, 0);
 169        if (size < 0) {
 170            error_report("could not load kernel '%s'", kernel_filename);
 171            exit(1);
 172        }
 173
 174        cpus[0]->env.trap_arg1 = kernel_entry;
 175
 176        param_offset = kernel_low - 0x6000;
 177
 178        if (kernel_cmdline) {
 179            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
 180        }
 181
 182        if (initrd_filename) {
 183            long initrd_base;
 184            int64_t initrd_size;
 185
 186            initrd_size = get_image_size(initrd_filename);
 187            if (initrd_size < 0) {
 188                error_report("could not load initial ram disk '%s'",
 189                             initrd_filename);
 190                exit(1);
 191            }
 192
 193            /* Put the initrd image as high in memory as possible.  */
 194            initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
 195            load_image_targphys(initrd_filename, initrd_base,
 196                                ram_size - initrd_base);
 197
 198            address_space_stq(&address_space_memory, param_offset + 0x100,
 199                              initrd_base + 0xfffffc0000000000ULL,
 200                              MEMTXATTRS_UNSPECIFIED,
 201                              NULL);
 202            address_space_stq(&address_space_memory, param_offset + 0x108,
 203                              initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
 204        }
 205    }
 206}
 207
 208static void clipper_machine_init(MachineClass *mc)
 209{
 210    mc->desc = "Alpha DP264/CLIPPER";
 211    mc->init = clipper_init;
 212    mc->block_default_type = IF_IDE;
 213    mc->max_cpus = 4;
 214    mc->is_default = true;
 215    mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67");
 216    mc->default_ram_id = "ram";
 217}
 218
 219DEFINE_MACHINE("clipper", clipper_machine_init)
 220