xref: /qemu/hw/alpha/dp264.c (revision 0d09e41a51aa0752b1ce525ce084f7cd210e461b)
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"
1383c9f4caSPaolo Bonzini #include "hw/alpha_sys.h"
149c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
15*0d09e41aSPaolo Bonzini #include "hw/timer/mc146818rtc.h"
1683c9f4caSPaolo Bonzini #include "hw/ide.h"
17*0d09e41aSPaolo Bonzini #include "hw/timer/i8254.h"
18*0d09e41aSPaolo 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 
465f072e1fSEduardo Habkost static void clipper_init(QEMUMachineInitArgs *args)
4780bb2ff7SRichard Henderson {
485f072e1fSEduardo Habkost     ram_addr_t ram_size = args->ram_size;
495f072e1fSEduardo Habkost     const char *cpu_model = args->cpu_model;
505f072e1fSEduardo Habkost     const char *kernel_filename = args->kernel_filename;
515f072e1fSEduardo Habkost     const char *kernel_cmdline = args->kernel_cmdline;
525f072e1fSEduardo Habkost     const char *initrd_filename = args->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;
5880bb2ff7SRichard Henderson     const 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 
7648a18b3cSHervé Poussineau     rtc_init(isa_bus, 1980, rtc_irq);
77319ba9f5SJan Kiszka     pit_init(isa_bus, 0x40, 0, NULL);
7848a18b3cSHervé Poussineau     isa_create_simple(isa_bus, "i8042");
7980bb2ff7SRichard Henderson 
8080bb2ff7SRichard Henderson     /* VGA setup.  Don't bother loading the bios.  */
81606f90ccSAurelien Jarno     pci_vga_init(pci_bus);
8280bb2ff7SRichard Henderson 
8380bb2ff7SRichard Henderson     /* Serial code setup.  */
8480bb2ff7SRichard Henderson     for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
8580bb2ff7SRichard Henderson         if (serial_hds[i]) {
8648a18b3cSHervé Poussineau             serial_isa_init(isa_bus, i, serial_hds[i]);
8780bb2ff7SRichard Henderson         }
8880bb2ff7SRichard Henderson     }
8980bb2ff7SRichard Henderson 
9080bb2ff7SRichard Henderson     /* Network setup.  e1000 is good enough, failing Tulip support.  */
9180bb2ff7SRichard Henderson     for (i = 0; i < nb_nics; i++) {
9280bb2ff7SRichard Henderson         pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
9380bb2ff7SRichard Henderson     }
9480bb2ff7SRichard Henderson 
9580bb2ff7SRichard Henderson     /* IDE disk setup.  */
9680bb2ff7SRichard Henderson     {
9780bb2ff7SRichard Henderson         DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
9880bb2ff7SRichard Henderson         ide_drive_get(hd, MAX_IDE_BUS);
9980bb2ff7SRichard Henderson 
10080bb2ff7SRichard Henderson         pci_cmd646_ide_init(pci_bus, hd, 0);
10180bb2ff7SRichard Henderson     }
10280bb2ff7SRichard Henderson 
10380bb2ff7SRichard Henderson     /* Load PALcode.  Given that this is not "real" cpu palcode,
10480bb2ff7SRichard Henderson        but one explicitly written for the emulation, we might as
10580bb2ff7SRichard Henderson        well load it directly from and ELF image.  */
10680bb2ff7SRichard Henderson     palcode_filename = (bios_name ? bios_name : "palcode-clipper");
10780bb2ff7SRichard Henderson     palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
10880bb2ff7SRichard Henderson     if (palcode_filename == NULL) {
10980bb2ff7SRichard Henderson         hw_error("no palcode provided\n");
11080bb2ff7SRichard Henderson         exit(1);
11180bb2ff7SRichard Henderson     }
11280bb2ff7SRichard Henderson     size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
11380bb2ff7SRichard Henderson                     NULL, &palcode_entry, &palcode_low, &palcode_high,
11480bb2ff7SRichard Henderson                     0, EM_ALPHA, 0);
11580bb2ff7SRichard Henderson     if (size < 0) {
11680bb2ff7SRichard Henderson         hw_error("could not load palcode '%s'\n", palcode_filename);
11780bb2ff7SRichard Henderson         exit(1);
11880bb2ff7SRichard Henderson     }
11980bb2ff7SRichard Henderson 
12080bb2ff7SRichard Henderson     /* Start all cpus at the PALcode RESET entry point.  */
12180bb2ff7SRichard Henderson     for (i = 0; i < smp_cpus; ++i) {
122ad601177SAndreas Färber         cpus[i]->env.pal_mode = 1;
123ad601177SAndreas Färber         cpus[i]->env.pc = palcode_entry;
124ad601177SAndreas Färber         cpus[i]->env.palbr = palcode_entry;
12580bb2ff7SRichard Henderson     }
12680bb2ff7SRichard Henderson 
12780bb2ff7SRichard Henderson     /* Load a kernel.  */
12880bb2ff7SRichard Henderson     if (kernel_filename) {
12980bb2ff7SRichard Henderson         uint64_t param_offset;
13080bb2ff7SRichard Henderson 
13180bb2ff7SRichard Henderson         size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
13280bb2ff7SRichard Henderson                         NULL, &kernel_entry, &kernel_low, &kernel_high,
13380bb2ff7SRichard Henderson                         0, EM_ALPHA, 0);
13480bb2ff7SRichard Henderson         if (size < 0) {
13580bb2ff7SRichard Henderson             hw_error("could not load kernel '%s'\n", kernel_filename);
13680bb2ff7SRichard Henderson             exit(1);
13780bb2ff7SRichard Henderson         }
13880bb2ff7SRichard Henderson 
139ad601177SAndreas Färber         cpus[0]->env.trap_arg1 = kernel_entry;
14080bb2ff7SRichard Henderson 
14180bb2ff7SRichard Henderson         param_offset = kernel_low - 0x6000;
14280bb2ff7SRichard Henderson 
14380bb2ff7SRichard Henderson         if (kernel_cmdline) {
14480bb2ff7SRichard Henderson             pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
14580bb2ff7SRichard Henderson         }
14680bb2ff7SRichard Henderson 
14780bb2ff7SRichard Henderson         if (initrd_filename) {
14880bb2ff7SRichard Henderson             long initrd_base, initrd_size;
14980bb2ff7SRichard Henderson 
15080bb2ff7SRichard Henderson             initrd_size = get_image_size(initrd_filename);
15180bb2ff7SRichard Henderson             if (initrd_size < 0) {
15280bb2ff7SRichard Henderson                 hw_error("could not load initial ram disk '%s'\n",
15380bb2ff7SRichard Henderson                          initrd_filename);
15480bb2ff7SRichard Henderson                 exit(1);
15580bb2ff7SRichard Henderson             }
15680bb2ff7SRichard Henderson 
15780bb2ff7SRichard Henderson             /* Put the initrd image as high in memory as possible.  */
15880bb2ff7SRichard Henderson             initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
15980bb2ff7SRichard Henderson             load_image_targphys(initrd_filename, initrd_base,
16080bb2ff7SRichard Henderson                                 ram_size - initrd_base);
16180bb2ff7SRichard Henderson 
16202d6516cSStefan Weil             stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
16380bb2ff7SRichard Henderson             stq_phys(param_offset + 0x108, initrd_size);
16480bb2ff7SRichard Henderson         }
16580bb2ff7SRichard Henderson     }
16680bb2ff7SRichard Henderson }
16780bb2ff7SRichard Henderson 
16880bb2ff7SRichard Henderson static QEMUMachine clipper_machine = {
16980bb2ff7SRichard Henderson     .name = "clipper",
17080bb2ff7SRichard Henderson     .desc = "Alpha DP264/CLIPPER",
17180bb2ff7SRichard Henderson     .init = clipper_init,
17280bb2ff7SRichard Henderson     .max_cpus = 4,
17380bb2ff7SRichard Henderson     .is_default = 1,
174e4ada29eSAvik Sil     DEFAULT_MACHINE_OPTIONS,
17580bb2ff7SRichard Henderson };
17680bb2ff7SRichard Henderson 
17780bb2ff7SRichard Henderson static void clipper_machine_init(void)
17880bb2ff7SRichard Henderson {
17980bb2ff7SRichard Henderson     qemu_register_machine(&clipper_machine);
18080bb2ff7SRichard Henderson }
18180bb2ff7SRichard Henderson 
18280bb2ff7SRichard Henderson machine_init(clipper_machine_init);
183