| /* | 
 |  * 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 "hw.h" | 
 | #include "elf.h" | 
 | #include "loader.h" | 
 | #include "boards.h" | 
 | #include "alpha_sys.h" | 
 | #include "sysemu/sysemu.h" | 
 | #include "mc146818rtc.h" | 
 | #include "ide.h" | 
 | #include "i8254.h" | 
 | #include "serial.h" | 
 |  | 
 | #define MAX_IDE_BUS 2 | 
 |  | 
 | 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(QEMUMachineInitArgs *args) | 
 | { | 
 |     ram_addr_t ram_size = args->ram_size; | 
 |     const char *cpu_model = args->cpu_model; | 
 |     const char *kernel_filename = args->kernel_filename; | 
 |     const char *kernel_cmdline = args->kernel_cmdline; | 
 |     const char *initrd_filename = args->initrd_filename; | 
 |     AlphaCPU *cpus[4]; | 
 |     PCIBus *pci_bus; | 
 |     ISABus *isa_bus; | 
 |     qemu_irq rtc_irq; | 
 |     long size, i; | 
 |     const char *palcode_filename; | 
 |     uint64_t palcode_entry, palcode_low, palcode_high; | 
 |     uint64_t kernel_entry, kernel_low, kernel_high; | 
 |  | 
 |     /* Create up to 4 cpus.  */ | 
 |     memset(cpus, 0, sizeof(cpus)); | 
 |     for (i = 0; i < smp_cpus; ++i) { | 
 |         cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); | 
 |     } | 
 |  | 
 |     cpus[0]->env.trap_arg0 = ram_size; | 
 |     cpus[0]->env.trap_arg1 = 0; | 
 |     cpus[0]->env.trap_arg2 = smp_cpus; | 
 |  | 
 |     /* Init the chipset.  */ | 
 |     pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, | 
 |                            clipper_pci_map_irq); | 
 |  | 
 |     rtc_init(isa_bus, 1980, rtc_irq); | 
 |     pit_init(isa_bus, 0x40, 0, NULL); | 
 |     isa_create_simple(isa_bus, "i8042"); | 
 |  | 
 |     /* VGA setup.  Don't bother loading the bios.  */ | 
 |     pci_vga_init(pci_bus); | 
 |  | 
 |     /* Serial code setup.  */ | 
 |     for (i = 0; i < MAX_SERIAL_PORTS; ++i) { | 
 |         if (serial_hds[i]) { | 
 |             serial_isa_init(isa_bus, i, serial_hds[i]); | 
 |         } | 
 |     } | 
 |  | 
 |     /* Network setup.  e1000 is good enough, failing Tulip support.  */ | 
 |     for (i = 0; i < nb_nics; i++) { | 
 |         pci_nic_init_nofail(&nd_table[i], "e1000", NULL); | 
 |     } | 
 |  | 
 |     /* IDE disk setup.  */ | 
 |     { | 
 |         DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; | 
 |         ide_drive_get(hd, MAX_IDE_BUS); | 
 |  | 
 |         pci_cmd646_ide_init(pci_bus, hd, 0); | 
 |     } | 
 |  | 
 |     /* 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 = (bios_name ? bios_name : "palcode-clipper"); | 
 |     palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename); | 
 |     if (palcode_filename == NULL) { | 
 |         hw_error("no palcode provided\n"); | 
 |         exit(1); | 
 |     } | 
 |     size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, | 
 |                     NULL, &palcode_entry, &palcode_low, &palcode_high, | 
 |                     0, EM_ALPHA, 0); | 
 |     if (size < 0) { | 
 |         hw_error("could not load palcode '%s'\n", palcode_filename); | 
 |         exit(1); | 
 |     } | 
 |  | 
 |     /* Start all cpus at the PALcode RESET entry point.  */ | 
 |     for (i = 0; i < smp_cpus; ++i) { | 
 |         cpus[i]->env.pal_mode = 1; | 
 |         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, cpu_alpha_superpage_to_phys, | 
 |                         NULL, &kernel_entry, &kernel_low, &kernel_high, | 
 |                         0, EM_ALPHA, 0); | 
 |         if (size < 0) { | 
 |             hw_error("could not load kernel '%s'\n", 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, initrd_size; | 
 |  | 
 |             initrd_size = get_image_size(initrd_filename); | 
 |             if (initrd_size < 0) { | 
 |                 hw_error("could not load initial ram disk '%s'\n", | 
 |                          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); | 
 |  | 
 |             stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL); | 
 |             stq_phys(param_offset + 0x108, initrd_size); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | static QEMUMachine clipper_machine = { | 
 |     .name = "clipper", | 
 |     .desc = "Alpha DP264/CLIPPER", | 
 |     .init = clipper_init, | 
 |     .max_cpus = 4, | 
 |     .is_default = 1, | 
 |     DEFAULT_MACHINE_OPTIONS, | 
 | }; | 
 |  | 
 | static void clipper_machine_init(void) | 
 | { | 
 |     qemu_register_machine(&clipper_machine); | 
 | } | 
 |  | 
 | machine_init(clipper_machine_init); |