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 983c9f4caSPaolo Bonzini #include "hw/hw.h" 1080bb2ff7SRichard Henderson #include "elf.h" 1183c9f4caSPaolo Bonzini #include "hw/loader.h" 1283c9f4caSPaolo Bonzini #include "hw/boards.h" 1347b43a1fSPaolo Bonzini #include "alpha_sys.h" 149c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 150d09e41aSPaolo Bonzini #include "hw/timer/mc146818rtc.h" 1683c9f4caSPaolo Bonzini #include "hw/ide.h" 170d09e41aSPaolo Bonzini #include "hw/timer/i8254.h" 180d09e41aSPaolo Bonzini #include "hw/char/serial.h" 1980bb2ff7SRichard Henderson 2080bb2ff7SRichard Henderson #define MAX_IDE_BUS 2 2180bb2ff7SRichard Henderson 2280bb2ff7SRichard Henderson static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) 2380bb2ff7SRichard Henderson { 2480bb2ff7SRichard Henderson if (((addr >> 41) & 3) == 2) { 2580bb2ff7SRichard Henderson addr &= 0xffffffffffull; 2680bb2ff7SRichard Henderson } 2780bb2ff7SRichard Henderson return addr; 2880bb2ff7SRichard Henderson } 2980bb2ff7SRichard Henderson 3080bb2ff7SRichard Henderson /* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems. 3180bb2ff7SRichard Henderson (0) The dev_irq_n lines into the cpu, which we totally ignore, 3280bb2ff7SRichard Henderson (1) The DRIR lines in the typhoon chipset, 3380bb2ff7SRichard Henderson (2) The "vector" aka mangled interrupt number reported by SRM PALcode, 3480bb2ff7SRichard Henderson (3) The interrupt number assigned by the kernel. 3580bb2ff7SRichard Henderson The following function is concerned with (1) only. */ 3680bb2ff7SRichard Henderson 3780bb2ff7SRichard Henderson static int clipper_pci_map_irq(PCIDevice *d, int irq_num) 3880bb2ff7SRichard Henderson { 3980bb2ff7SRichard Henderson int slot = d->devfn >> 3; 4080bb2ff7SRichard Henderson 4180bb2ff7SRichard Henderson assert(irq_num >= 0 && irq_num <= 3); 4280bb2ff7SRichard Henderson 4380bb2ff7SRichard Henderson return (slot + 1) * 4 + irq_num; 4480bb2ff7SRichard Henderson } 4580bb2ff7SRichard Henderson 463ef96221SMarcel Apfelbaum static void clipper_init(MachineState *machine) 4780bb2ff7SRichard Henderson { 483ef96221SMarcel Apfelbaum ram_addr_t ram_size = machine->ram_size; 493ef96221SMarcel Apfelbaum const char *cpu_model = machine->cpu_model; 503ef96221SMarcel Apfelbaum const char *kernel_filename = machine->kernel_filename; 513ef96221SMarcel Apfelbaum const char *kernel_cmdline = machine->kernel_cmdline; 523ef96221SMarcel Apfelbaum const char *initrd_filename = machine->initrd_filename; 53ad601177SAndreas Färber AlphaCPU *cpus[4]; 5480bb2ff7SRichard Henderson PCIBus *pci_bus; 5548a18b3cSHervé Poussineau ISABus *isa_bus; 5680bb2ff7SRichard Henderson qemu_irq rtc_irq; 5780bb2ff7SRichard Henderson long size, i; 58c18f8556SShannon Zhao char *palcode_filename; 5980bb2ff7SRichard Henderson uint64_t palcode_entry, palcode_low, palcode_high; 6080bb2ff7SRichard Henderson uint64_t kernel_entry, kernel_low, kernel_high; 6180bb2ff7SRichard Henderson 6280bb2ff7SRichard Henderson /* Create up to 4 cpus. */ 6380bb2ff7SRichard Henderson memset(cpus, 0, sizeof(cpus)); 6480bb2ff7SRichard Henderson for (i = 0; i < smp_cpus; ++i) { 65ad601177SAndreas Färber cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); 6680bb2ff7SRichard Henderson } 6780bb2ff7SRichard Henderson 68ad601177SAndreas Färber cpus[0]->env.trap_arg0 = ram_size; 69ad601177SAndreas Färber cpus[0]->env.trap_arg1 = 0; 70ad601177SAndreas Färber cpus[0]->env.trap_arg2 = smp_cpus; 7180bb2ff7SRichard Henderson 7280bb2ff7SRichard Henderson /* Init the chipset. */ 7371baa303SHervé Poussineau pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, 7471baa303SHervé Poussineau clipper_pci_map_irq); 7580bb2ff7SRichard Henderson 76e605e969SRichard Henderson /* Since we have an SRM-compatible PALcode, use the SRM epoch. */ 77e605e969SRichard Henderson rtc_init(isa_bus, 1900, rtc_irq); 78e605e969SRichard Henderson 79319ba9f5SJan Kiszka pit_init(isa_bus, 0x40, 0, NULL); 8048a18b3cSHervé Poussineau isa_create_simple(isa_bus, "i8042"); 8180bb2ff7SRichard Henderson 8280bb2ff7SRichard Henderson /* VGA setup. Don't bother loading the bios. */ 83606f90ccSAurelien Jarno pci_vga_init(pci_bus); 8480bb2ff7SRichard Henderson 8580bb2ff7SRichard Henderson /* Serial code setup. */ 86b6607a1aSMarkus Armbruster serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); 8780bb2ff7SRichard Henderson 8880bb2ff7SRichard Henderson /* Network setup. e1000 is good enough, failing Tulip support. */ 8980bb2ff7SRichard Henderson for (i = 0; i < nb_nics; i++) { 9029b358f9SDavid Gibson pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL); 9180bb2ff7SRichard Henderson } 9280bb2ff7SRichard Henderson 9380bb2ff7SRichard Henderson /* IDE disk setup. */ 9480bb2ff7SRichard Henderson { 9580bb2ff7SRichard Henderson DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; 96d8f94e1bSJohn Snow ide_drive_get(hd, ARRAY_SIZE(hd)); 9780bb2ff7SRichard Henderson 9880bb2ff7SRichard Henderson pci_cmd646_ide_init(pci_bus, hd, 0); 9980bb2ff7SRichard Henderson } 10080bb2ff7SRichard Henderson 10180bb2ff7SRichard Henderson /* Load PALcode. Given that this is not "real" cpu palcode, 10280bb2ff7SRichard Henderson but one explicitly written for the emulation, we might as 10380bb2ff7SRichard Henderson well load it directly from and ELF image. */ 104c18f8556SShannon Zhao palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, 105c18f8556SShannon Zhao bios_name ? bios_name : "palcode-clipper"); 10680bb2ff7SRichard Henderson if (palcode_filename == NULL) { 10780bb2ff7SRichard Henderson hw_error("no palcode provided\n"); 10880bb2ff7SRichard Henderson exit(1); 10980bb2ff7SRichard Henderson } 11080bb2ff7SRichard Henderson size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, 11180bb2ff7SRichard Henderson NULL, &palcode_entry, &palcode_low, &palcode_high, 11280bb2ff7SRichard Henderson 0, EM_ALPHA, 0); 11380bb2ff7SRichard Henderson if (size < 0) { 11480bb2ff7SRichard Henderson hw_error("could not load palcode '%s'\n", palcode_filename); 11580bb2ff7SRichard Henderson exit(1); 11680bb2ff7SRichard Henderson } 117c18f8556SShannon Zhao g_free(palcode_filename); 11880bb2ff7SRichard Henderson 11980bb2ff7SRichard Henderson /* Start all cpus at the PALcode RESET entry point. */ 12080bb2ff7SRichard Henderson for (i = 0; i < smp_cpus; ++i) { 121ad601177SAndreas Färber cpus[i]->env.pal_mode = 1; 122ad601177SAndreas Färber cpus[i]->env.pc = palcode_entry; 123ad601177SAndreas Färber cpus[i]->env.palbr = palcode_entry; 12480bb2ff7SRichard Henderson } 12580bb2ff7SRichard Henderson 12680bb2ff7SRichard Henderson /* Load a kernel. */ 12780bb2ff7SRichard Henderson if (kernel_filename) { 12880bb2ff7SRichard Henderson uint64_t param_offset; 12980bb2ff7SRichard Henderson 13080bb2ff7SRichard Henderson size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys, 13180bb2ff7SRichard Henderson NULL, &kernel_entry, &kernel_low, &kernel_high, 13280bb2ff7SRichard Henderson 0, EM_ALPHA, 0); 13380bb2ff7SRichard Henderson if (size < 0) { 13480bb2ff7SRichard Henderson hw_error("could not load kernel '%s'\n", kernel_filename); 13580bb2ff7SRichard Henderson exit(1); 13680bb2ff7SRichard Henderson } 13780bb2ff7SRichard Henderson 138ad601177SAndreas Färber cpus[0]->env.trap_arg1 = kernel_entry; 13980bb2ff7SRichard Henderson 14080bb2ff7SRichard Henderson param_offset = kernel_low - 0x6000; 14180bb2ff7SRichard Henderson 14280bb2ff7SRichard Henderson if (kernel_cmdline) { 14380bb2ff7SRichard Henderson pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline); 14480bb2ff7SRichard Henderson } 14580bb2ff7SRichard Henderson 14680bb2ff7SRichard Henderson if (initrd_filename) { 14780bb2ff7SRichard Henderson long initrd_base, initrd_size; 14880bb2ff7SRichard Henderson 14980bb2ff7SRichard Henderson initrd_size = get_image_size(initrd_filename); 15080bb2ff7SRichard Henderson if (initrd_size < 0) { 15180bb2ff7SRichard Henderson hw_error("could not load initial ram disk '%s'\n", 15280bb2ff7SRichard Henderson initrd_filename); 15380bb2ff7SRichard Henderson exit(1); 15480bb2ff7SRichard Henderson } 15580bb2ff7SRichard Henderson 15680bb2ff7SRichard Henderson /* Put the initrd image as high in memory as possible. */ 15780bb2ff7SRichard Henderson initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; 15880bb2ff7SRichard Henderson load_image_targphys(initrd_filename, initrd_base, 15980bb2ff7SRichard Henderson ram_size - initrd_base); 16080bb2ff7SRichard Henderson 16142874d3aSPeter Maydell address_space_stq(&address_space_memory, param_offset + 0x100, 16242874d3aSPeter Maydell initrd_base + 0xfffffc0000000000ULL, 16342874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 16442874d3aSPeter Maydell NULL); 16542874d3aSPeter Maydell address_space_stq(&address_space_memory, param_offset + 0x108, 16642874d3aSPeter Maydell initrd_size, MEMTXATTRS_UNSPECIFIED, NULL); 16780bb2ff7SRichard Henderson } 16880bb2ff7SRichard Henderson } 16980bb2ff7SRichard Henderson } 17080bb2ff7SRichard Henderson 171*e264d29dSEduardo Habkost static void clipper_machine_init(MachineClass *mc) 17280bb2ff7SRichard Henderson { 173*e264d29dSEduardo Habkost mc->desc = "Alpha DP264/CLIPPER"; 174*e264d29dSEduardo Habkost mc->init = clipper_init; 175*e264d29dSEduardo Habkost mc->max_cpus = 4; 176*e264d29dSEduardo Habkost mc->is_default = 1; 17780bb2ff7SRichard Henderson } 17880bb2ff7SRichard Henderson 179*e264d29dSEduardo Habkost DEFINE_MACHINE("clipper", clipper_machine_init) 180