180bb2ff7SRichard Henderson /* 280bb2ff7SRichard Henderson * QEMU Alpha DP264/CLIPPER hardware system emulator. 380bb2ff7SRichard Henderson * 480bb2ff7SRichard Henderson * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK 566a0a2cbSDong Xu Wang * variants because CLIPPER doesn't have an SMC669 SuperIO controller 680bb2ff7SRichard Henderson * that we need to emulate as well. 780bb2ff7SRichard Henderson */ 880bb2ff7SRichard Henderson 9e2e5e114SPeter Maydell #include "qemu/osdep.h" 104771d756SPaolo Bonzini #include "qemu-common.h" 114771d756SPaolo Bonzini #include "cpu.h" 1283c9f4caSPaolo Bonzini #include "hw/hw.h" 1380bb2ff7SRichard Henderson #include "elf.h" 1483c9f4caSPaolo Bonzini #include "hw/loader.h" 1583c9f4caSPaolo Bonzini #include "hw/boards.h" 1647b43a1fSPaolo Bonzini #include "alpha_sys.h" 17c525436eSMarkus Armbruster #include "qemu/error-report.h" 189c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 190d09e41aSPaolo Bonzini #include "hw/timer/mc146818rtc.h" 2083c9f4caSPaolo Bonzini #include "hw/ide.h" 210d09e41aSPaolo Bonzini #include "hw/timer/i8254.h" 220d09e41aSPaolo Bonzini #include "hw/char/serial.h" 23f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 2480bb2ff7SRichard Henderson 2580bb2ff7SRichard Henderson #define MAX_IDE_BUS 2 2680bb2ff7SRichard Henderson 2780bb2ff7SRichard Henderson static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) 2880bb2ff7SRichard Henderson { 2980bb2ff7SRichard Henderson if (((addr >> 41) & 3) == 2) { 3080bb2ff7SRichard Henderson addr &= 0xffffffffffull; 3180bb2ff7SRichard Henderson } 3280bb2ff7SRichard Henderson return addr; 3380bb2ff7SRichard Henderson } 3480bb2ff7SRichard Henderson 3580bb2ff7SRichard Henderson /* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems. 3680bb2ff7SRichard Henderson (0) The dev_irq_n lines into the cpu, which we totally ignore, 3780bb2ff7SRichard Henderson (1) The DRIR lines in the typhoon chipset, 3880bb2ff7SRichard Henderson (2) The "vector" aka mangled interrupt number reported by SRM PALcode, 3980bb2ff7SRichard Henderson (3) The interrupt number assigned by the kernel. 4080bb2ff7SRichard Henderson The following function is concerned with (1) only. */ 4180bb2ff7SRichard Henderson 4280bb2ff7SRichard Henderson static int clipper_pci_map_irq(PCIDevice *d, int irq_num) 4380bb2ff7SRichard Henderson { 4480bb2ff7SRichard Henderson int slot = d->devfn >> 3; 4580bb2ff7SRichard Henderson 4680bb2ff7SRichard Henderson assert(irq_num >= 0 && irq_num <= 3); 4780bb2ff7SRichard Henderson 4880bb2ff7SRichard Henderson return (slot + 1) * 4 + irq_num; 4980bb2ff7SRichard Henderson } 5080bb2ff7SRichard Henderson 513ef96221SMarcel Apfelbaum static void clipper_init(MachineState *machine) 5280bb2ff7SRichard Henderson { 533ef96221SMarcel Apfelbaum ram_addr_t ram_size = machine->ram_size; 543ef96221SMarcel Apfelbaum const char *kernel_filename = machine->kernel_filename; 553ef96221SMarcel Apfelbaum const char *kernel_cmdline = machine->kernel_cmdline; 563ef96221SMarcel Apfelbaum const char *initrd_filename = machine->initrd_filename; 57ad601177SAndreas Färber AlphaCPU *cpus[4]; 5880bb2ff7SRichard Henderson PCIBus *pci_bus; 5948a18b3cSHervé Poussineau ISABus *isa_bus; 6080bb2ff7SRichard Henderson qemu_irq rtc_irq; 6180bb2ff7SRichard Henderson long size, i; 62c18f8556SShannon Zhao char *palcode_filename; 6380bb2ff7SRichard Henderson uint64_t palcode_entry, palcode_low, palcode_high; 6480bb2ff7SRichard Henderson uint64_t kernel_entry, kernel_low, kernel_high; 6580bb2ff7SRichard Henderson 6680bb2ff7SRichard Henderson /* Create up to 4 cpus. */ 6780bb2ff7SRichard Henderson memset(cpus, 0, sizeof(cpus)); 6880bb2ff7SRichard Henderson for (i = 0; i < smp_cpus; ++i) { 69*fb92da84SIgor Mammedov cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type)); 7080bb2ff7SRichard Henderson } 7180bb2ff7SRichard Henderson 72ad601177SAndreas Färber cpus[0]->env.trap_arg0 = ram_size; 73ad601177SAndreas Färber cpus[0]->env.trap_arg1 = 0; 74ad601177SAndreas Färber cpus[0]->env.trap_arg2 = smp_cpus; 7580bb2ff7SRichard Henderson 7680bb2ff7SRichard Henderson /* Init the chipset. */ 7771baa303SHervé Poussineau pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, 7871baa303SHervé Poussineau clipper_pci_map_irq); 7980bb2ff7SRichard Henderson 80e605e969SRichard Henderson /* Since we have an SRM-compatible PALcode, use the SRM epoch. */ 81e605e969SRichard Henderson rtc_init(isa_bus, 1900, rtc_irq); 82e605e969SRichard Henderson 83319ba9f5SJan Kiszka pit_init(isa_bus, 0x40, 0, NULL); 8448a18b3cSHervé Poussineau isa_create_simple(isa_bus, "i8042"); 8580bb2ff7SRichard Henderson 8680bb2ff7SRichard Henderson /* VGA setup. Don't bother loading the bios. */ 87606f90ccSAurelien Jarno pci_vga_init(pci_bus); 8880bb2ff7SRichard Henderson 8980bb2ff7SRichard Henderson /* Serial code setup. */ 904496dc49SMarc-André Lureau serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); 9180bb2ff7SRichard Henderson 9280bb2ff7SRichard Henderson /* Network setup. e1000 is good enough, failing Tulip support. */ 9380bb2ff7SRichard Henderson for (i = 0; i < nb_nics; i++) { 9429b358f9SDavid Gibson pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL); 9580bb2ff7SRichard Henderson } 9680bb2ff7SRichard Henderson 9780bb2ff7SRichard Henderson /* IDE disk setup. */ 9880bb2ff7SRichard Henderson { 9980bb2ff7SRichard Henderson DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; 100d8f94e1bSJohn Snow ide_drive_get(hd, ARRAY_SIZE(hd)); 10180bb2ff7SRichard Henderson 10280bb2ff7SRichard Henderson pci_cmd646_ide_init(pci_bus, hd, 0); 10380bb2ff7SRichard Henderson } 10480bb2ff7SRichard Henderson 10580bb2ff7SRichard Henderson /* Load PALcode. Given that this is not "real" cpu palcode, 10680bb2ff7SRichard Henderson but one explicitly written for the emulation, we might as 10780bb2ff7SRichard Henderson well load it directly from and ELF image. */ 108c18f8556SShannon Zhao palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, 109c18f8556SShannon Zhao bios_name ? bios_name : "palcode-clipper"); 11080bb2ff7SRichard Henderson if (palcode_filename == NULL) { 111c525436eSMarkus Armbruster error_report("no palcode provided"); 11280bb2ff7SRichard Henderson exit(1); 11380bb2ff7SRichard Henderson } 11480bb2ff7SRichard Henderson size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, 11580bb2ff7SRichard Henderson NULL, &palcode_entry, &palcode_low, &palcode_high, 1167ef295eaSPeter Crosthwaite 0, EM_ALPHA, 0, 0); 11780bb2ff7SRichard Henderson if (size < 0) { 118c525436eSMarkus Armbruster error_report("could not load palcode '%s'", palcode_filename); 11980bb2ff7SRichard Henderson exit(1); 12080bb2ff7SRichard Henderson } 121c18f8556SShannon Zhao g_free(palcode_filename); 12280bb2ff7SRichard Henderson 12380bb2ff7SRichard Henderson /* Start all cpus at the PALcode RESET entry point. */ 12480bb2ff7SRichard Henderson for (i = 0; i < smp_cpus; ++i) { 125ad601177SAndreas Färber cpus[i]->env.pc = palcode_entry; 126ad601177SAndreas Färber cpus[i]->env.palbr = palcode_entry; 12780bb2ff7SRichard Henderson } 12880bb2ff7SRichard Henderson 12980bb2ff7SRichard Henderson /* Load a kernel. */ 13080bb2ff7SRichard Henderson if (kernel_filename) { 13180bb2ff7SRichard Henderson uint64_t param_offset; 13280bb2ff7SRichard Henderson 13380bb2ff7SRichard Henderson size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys, 13480bb2ff7SRichard Henderson NULL, &kernel_entry, &kernel_low, &kernel_high, 1357ef295eaSPeter Crosthwaite 0, EM_ALPHA, 0, 0); 13680bb2ff7SRichard Henderson if (size < 0) { 137c525436eSMarkus Armbruster error_report("could not load kernel '%s'", kernel_filename); 13880bb2ff7SRichard Henderson exit(1); 13980bb2ff7SRichard Henderson } 14080bb2ff7SRichard Henderson 141ad601177SAndreas Färber cpus[0]->env.trap_arg1 = kernel_entry; 14280bb2ff7SRichard Henderson 14380bb2ff7SRichard Henderson param_offset = kernel_low - 0x6000; 14480bb2ff7SRichard Henderson 14580bb2ff7SRichard Henderson if (kernel_cmdline) { 14680bb2ff7SRichard Henderson pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline); 14780bb2ff7SRichard Henderson } 14880bb2ff7SRichard Henderson 14980bb2ff7SRichard Henderson if (initrd_filename) { 15080bb2ff7SRichard Henderson long initrd_base, initrd_size; 15180bb2ff7SRichard Henderson 15280bb2ff7SRichard Henderson initrd_size = get_image_size(initrd_filename); 15380bb2ff7SRichard Henderson if (initrd_size < 0) { 154c525436eSMarkus Armbruster error_report("could not load initial ram disk '%s'", 15580bb2ff7SRichard Henderson initrd_filename); 15680bb2ff7SRichard Henderson exit(1); 15780bb2ff7SRichard Henderson } 15880bb2ff7SRichard Henderson 15980bb2ff7SRichard Henderson /* Put the initrd image as high in memory as possible. */ 16080bb2ff7SRichard Henderson initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; 16180bb2ff7SRichard Henderson load_image_targphys(initrd_filename, initrd_base, 16280bb2ff7SRichard Henderson ram_size - initrd_base); 16380bb2ff7SRichard Henderson 16442874d3aSPeter Maydell address_space_stq(&address_space_memory, param_offset + 0x100, 16542874d3aSPeter Maydell initrd_base + 0xfffffc0000000000ULL, 16642874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 16742874d3aSPeter Maydell NULL); 16842874d3aSPeter Maydell address_space_stq(&address_space_memory, param_offset + 0x108, 16942874d3aSPeter Maydell initrd_size, MEMTXATTRS_UNSPECIFIED, NULL); 17080bb2ff7SRichard Henderson } 17180bb2ff7SRichard Henderson } 17280bb2ff7SRichard Henderson } 17380bb2ff7SRichard Henderson 174e264d29dSEduardo Habkost static void clipper_machine_init(MachineClass *mc) 17580bb2ff7SRichard Henderson { 176e264d29dSEduardo Habkost mc->desc = "Alpha DP264/CLIPPER"; 177e264d29dSEduardo Habkost mc->init = clipper_init; 1782059839bSMarkus Armbruster mc->block_default_type = IF_IDE; 179e264d29dSEduardo Habkost mc->max_cpus = 4; 180e264d29dSEduardo Habkost mc->is_default = 1; 181*fb92da84SIgor Mammedov mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67"); 18280bb2ff7SRichard Henderson } 18380bb2ff7SRichard Henderson 184e264d29dSEduardo Habkost DEFINE_MACHINE("clipper", clipper_machine_init) 185