123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- /*
- * QEMU Alpha DP264/CLIPPER hardware system emulator.
- *
- * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
- * variants because CLIPPER doesn't have an SMC669 SuperIO controller
- * that we need to emulate as well.
- */
- #include "qemu/osdep.h"
- #include "cpu.h"
- #include "elf.h"
- #include "hw/loader.h"
- #include "alpha_sys.h"
- #include "qemu/error-report.h"
- #include "hw/rtc/mc146818rtc.h"
- #include "hw/ide/pci.h"
- #include "hw/isa/superio.h"
- #include "net/net.h"
- #include "qemu/cutils.h"
- #include "qemu/datadir.h"
- static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
- {
- if (((addr >> 41) & 3) == 2) {
- addr &= 0xffffffffffull;
- }
- return addr;
- }
- /* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
- (0) The dev_irq_n lines into the cpu, which we totally ignore,
- (1) The DRIR lines in the typhoon chipset,
- (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
- (3) The interrupt number assigned by the kernel.
- The following function is concerned with (1) only. */
- static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
- {
- int slot = d->devfn >> 3;
- assert(irq_num >= 0 && irq_num <= 3);
- return (slot + 1) * 4 + irq_num;
- }
- static void clipper_init(MachineState *machine)
- {
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- AlphaCPU *cpus[4];
- PCIBus *pci_bus;
- PCIDevice *pci_dev;
- DeviceState *i82378_dev;
- ISABus *isa_bus;
- qemu_irq rtc_irq;
- qemu_irq isa_irq;
- long size, i;
- char *palcode_filename;
- uint64_t palcode_entry;
- uint64_t kernel_entry, kernel_low;
- unsigned int smp_cpus = machine->smp.cpus;
- /* Create up to 4 cpus. */
- memset(cpus, 0, sizeof(cpus));
- for (i = 0; i < smp_cpus; ++i) {
- cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type));
- }
- /*
- * arg0 -> memory size
- * arg1 -> kernel entry point
- * arg2 -> config word
- *
- * Config word: bits 0-5 -> ncpus
- * bit 6 -> nographics option (for HWRPB CTB)
- *
- * See init_hwrpb() in the PALcode.
- */
- cpus[0]->env.trap_arg0 = ram_size;
- cpus[0]->env.trap_arg1 = 0;
- cpus[0]->env.trap_arg2 = smp_cpus | (!machine->enable_graphics << 6);
- /*
- * Init the chipset. Because we're using CLIPPER IRQ mappings,
- * the minimum PCI device IdSel is 1.
- */
- pci_bus = typhoon_init(machine->ram, &isa_irq, &rtc_irq, cpus,
- clipper_pci_map_irq, PCI_DEVFN(1, 0));
- /*
- * Init the PCI -> ISA bridge.
- *
- * Technically, PCI-based Alphas shipped with one of three different
- * PCI-ISA bridges:
- *
- * - Intel i82378 SIO
- * - Cypress CY82c693UB
- * - ALI M1533
- *
- * (An Intel i82375 PCI-EISA bridge was also used on some models.)
- *
- * For simplicity, we model an i82378 here, even though it wouldn't
- * have been on any Tsunami/Typhoon systems; it's close enough, and
- * we don't want to deal with modelling the CY82c693UB (which has
- * incompatible edge/level control registers, plus other peripherals
- * like IDE and USB) or the M1533 (which also has IDE and USB).
- *
- * Importantly, we need to provide a PCI device node for it, otherwise
- * some operating systems won't notice there's an ISA bus to configure.
- */
- i82378_dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(7, 0), "i82378"));
- isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0"));
- /* Connect the ISA PIC to the Typhoon IRQ used for ISA interrupts. */
- qdev_connect_gpio_out(i82378_dev, 0, isa_irq);
- /* Since we have an SRM-compatible PALcode, use the SRM epoch. */
- mc146818_rtc_init(isa_bus, 1900, rtc_irq);
- /* VGA setup. Don't bother loading the bios. */
- pci_vga_init(pci_bus);
- /* Network setup. e1000 is good enough, failing Tulip support. */
- pci_init_nic_devices(pci_bus, mc->default_nic);
- /* Super I/O */
- isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
- /* IDE disk setup. */
- pci_dev = pci_create_simple(pci_bus, -1, "cmd646-ide");
- pci_ide_create_devs(pci_dev);
- /* Load PALcode. Given that this is not "real" cpu palcode,
- but one explicitly written for the emulation, we might as
- well load it directly from and ELF image. */
- palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
- machine->firmware ?: "palcode-clipper");
- if (palcode_filename == NULL) {
- error_report("no palcode provided");
- exit(1);
- }
- size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
- NULL, &palcode_entry, NULL, NULL, NULL,
- ELFDATA2LSB, EM_ALPHA, 0, 0);
- if (size < 0) {
- error_report("could not load palcode '%s'", palcode_filename);
- exit(1);
- }
- g_free(palcode_filename);
- /* Start all cpus at the PALcode RESET entry point. */
- for (i = 0; i < smp_cpus; ++i) {
- cpus[i]->env.pc = palcode_entry;
- cpus[i]->env.palbr = palcode_entry;
- }
- /* Load a kernel. */
- if (kernel_filename) {
- uint64_t param_offset;
- size = load_elf(kernel_filename, NULL, cpu_alpha_superpage_to_phys,
- NULL, &kernel_entry, &kernel_low, NULL, NULL,
- ELFDATA2LSB, EM_ALPHA, 0, 0);
- if (size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- cpus[0]->env.trap_arg1 = kernel_entry;
- param_offset = kernel_low - 0x6000;
- if (kernel_cmdline) {
- pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
- }
- if (initrd_filename) {
- long initrd_base;
- int64_t initrd_size;
- initrd_size = get_image_size(initrd_filename);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- initrd_filename);
- exit(1);
- }
- /* Put the initrd image as high in memory as possible. */
- initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
- load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
- address_space_stq(&address_space_memory, param_offset + 0x100,
- initrd_base + 0xfffffc0000000000ULL,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- address_space_stq(&address_space_memory, param_offset + 0x108,
- initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
- }
- }
- }
- static void clipper_machine_init(MachineClass *mc)
- {
- mc->desc = "Alpha DP264/CLIPPER";
- mc->init = clipper_init;
- mc->block_default_type = IF_IDE;
- mc->max_cpus = 4;
- mc->is_default = true;
- mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67");
- mc->default_ram_id = "ram";
- mc->default_nic = "e1000";
- }
- DEFINE_MACHINE("clipper", clipper_machine_init)
|