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 "qemu-common.h"
  11#include "cpu.h"
  12#include "hw/hw.h"
  13#include "elf.h"
  14#include "hw/loader.h"
  15#include "hw/boards.h"
  16#include "alpha_sys.h"
  17#include "qemu/error-report.h"
  18#include "sysemu/sysemu.h"
  19#include "hw/timer/mc146818rtc.h"
  20#include "hw/ide.h"
  21#include "hw/timer/i8254.h"
  22#include "hw/isa/superio.h"
  23#include "hw/dma/i8257.h"
  24#include "qemu/cutils.h"
  25
  26#define MAX_IDE_BUS 2
  27
  28static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
  29{
  30    if (((addr >> 41) & 3) == 2) {
  31        addr &= 0xffffffffffull;
  32    }
  33    return addr;
  34}
  35
  36/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
  37    (0) The dev_irq_n lines into the cpu, which we totally ignore,
  38    (1) The DRIR lines in the typhoon chipset,
  39    (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
  40    (3) The interrupt number assigned by the kernel.
  41   The following function is concerned with (1) only.  */
  42
  43static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
  44{
  45    int slot = d->devfn >> 3;
  46
  47    assert(irq_num >= 0 && irq_num <= 3);
  48
  49    return (slot + 1) * 4 + irq_num;
  50}
  51
  52static void clipper_init(MachineState *machine)
  53{
  54    ram_addr_t ram_size = machine->ram_size;
  55    const char *kernel_filename = machine->kernel_filename;
  56    const char *kernel_cmdline = machine->kernel_cmdline;
  57    const char *initrd_filename = machine->initrd_filename;
  58    AlphaCPU *cpus[4];
  59    PCIBus *pci_bus;
  60    ISABus *isa_bus;
  61    qemu_irq rtc_irq;
  62    long size, i;
  63    char *palcode_filename;
  64    uint64_t palcode_entry, palcode_low, palcode_high;
  65    uint64_t kernel_entry, kernel_low, kernel_high;
  66    unsigned int smp_cpus = machine->smp.cpus;
  67
  68    /* Create up to 4 cpus.  */
  69    memset(cpus, 0, sizeof(cpus));
  70    for (i = 0; i < smp_cpus; ++i) {
  71        cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type));
  72    }
  73
  74    cpus[0]->env.trap_arg0 = ram_size;
  75    cpus[0]->env.trap_arg1 = 0;
  76    cpus[0]->env.trap_arg2 = smp_cpus;
  77
  78    /* Init the chipset.  */
  79    pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus,
  80                           clipper_pci_map_irq);
  81
  82    /* Since we have an SRM-compatible PALcode, use the SRM epoch.  */
  83    mc146818_rtc_init(isa_bus, 1900, rtc_irq);
  84
  85    i8254_pit_init(isa_bus, 0x40, 0, NULL);
  86
  87    /* VGA setup.  Don't bother loading the bios.  */
  88    pci_vga_init(pci_bus);
  89
  90    /* Network setup.  e1000 is good enough, failing Tulip support.  */
  91    for (i = 0; i < nb_nics; i++) {
  92        pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
  93    }
  94
  95    /* 2 82C37 (dma) */
  96    isa_create_simple(isa_bus, "i82374");
  97
  98    /* Super I/O */
  99    isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
 100
 101    /* IDE disk setup.  */
 102    {
 103        DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
 104        ide_drive_get(hd, ARRAY_SIZE(hd));
 105
 106        pci_cmd646_ide_init(pci_bus, hd, 0);
 107    }
 108
 109    /* Load PALcode.  Given that this is not "real" cpu palcode,
 110       but one explicitly written for the emulation, we might as
 111       well load it directly from and ELF image.  */
 112    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
 113                                bios_name ? bios_name : "palcode-clipper");
 114    if (palcode_filename == NULL) {
 115        error_report("no palcode provided");
 116        exit(1);
 117    }
 118    size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
 119                    NULL, &palcode_entry, &palcode_low, &palcode_high,
 120                    0, EM_ALPHA, 0, 0);
 121    if (size < 0) {
 122        error_report("could not load palcode '%s'", palcode_filename);
 123        exit(1);
 124    }
 125    g_free(palcode_filename);
 126
 127    /* Start all cpus at the PALcode RESET entry point.  */
 128    for (i = 0; i < smp_cpus; ++i) {
 129        cpus[i]->env.pc = palcode_entry;
 130        cpus[i]->env.palbr = palcode_entry;
 131    }
 132
 133    /* Load a kernel.  */
 134    if (kernel_filename) {
 135        uint64_t param_offset;
 136
 137        size = load_elf(kernel_filename, NULL, cpu_alpha_superpage_to_phys,
 138                        NULL, &kernel_entry, &kernel_low, &kernel_high,
 139                        0, EM_ALPHA, 0, 0);
 140        if (size < 0) {
 141            error_report("could not load kernel '%s'", kernel_filename);
 142            exit(1);
 143        }
 144
 145        cpus[0]->env.trap_arg1 = kernel_entry;
 146
 147        param_offset = kernel_low - 0x6000;
 148
 149        if (kernel_cmdline) {
 150            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
 151        }
 152
 153        if (initrd_filename) {
 154            long initrd_base;
 155            int64_t initrd_size;
 156
 157            initrd_size = get_image_size(initrd_filename);
 158            if (initrd_size < 0) {
 159                error_report("could not load initial ram disk '%s'",
 160                             initrd_filename);
 161                exit(1);
 162            }
 163
 164            /* Put the initrd image as high in memory as possible.  */
 165            initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
 166            load_image_targphys(initrd_filename, initrd_base,
 167                                ram_size - initrd_base);
 168
 169            address_space_stq(&address_space_memory, param_offset + 0x100,
 170                              initrd_base + 0xfffffc0000000000ULL,
 171                              MEMTXATTRS_UNSPECIFIED,
 172                              NULL);
 173            address_space_stq(&address_space_memory, param_offset + 0x108,
 174                              initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
 175        }
 176    }
 177}
 178
 179static void clipper_machine_init(MachineClass *mc)
 180{
 181    mc->desc = "Alpha DP264/CLIPPER";
 182    mc->init = clipper_init;
 183    mc->block_default_type = IF_IDE;
 184    mc->max_cpus = 4;
 185    mc->is_default = 1;
 186    mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67");
 187}
 188
 189DEFINE_MACHINE("clipper", clipper_machine_init)
 190