xref: /qemu/hw/alpha/dp264.c (revision e2e5e114624ac1a46ce9e23975d5dbf5837f4c86)
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 
9*e2e5e114SPeter Maydell #include "qemu/osdep.h"
1083c9f4caSPaolo Bonzini #include "hw/hw.h"
1180bb2ff7SRichard Henderson #include "elf.h"
1283c9f4caSPaolo Bonzini #include "hw/loader.h"
1383c9f4caSPaolo Bonzini #include "hw/boards.h"
1447b43a1fSPaolo Bonzini #include "alpha_sys.h"
15c525436eSMarkus Armbruster #include "qemu/error-report.h"
169c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
170d09e41aSPaolo Bonzini #include "hw/timer/mc146818rtc.h"
1883c9f4caSPaolo Bonzini #include "hw/ide.h"
190d09e41aSPaolo Bonzini #include "hw/timer/i8254.h"
200d09e41aSPaolo Bonzini #include "hw/char/serial.h"
2180bb2ff7SRichard Henderson 
2280bb2ff7SRichard Henderson #define MAX_IDE_BUS 2
2380bb2ff7SRichard Henderson 
2480bb2ff7SRichard Henderson static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
2580bb2ff7SRichard Henderson {
2680bb2ff7SRichard Henderson     if (((addr >> 41) & 3) == 2) {
2780bb2ff7SRichard Henderson         addr &= 0xffffffffffull;
2880bb2ff7SRichard Henderson     }
2980bb2ff7SRichard Henderson     return addr;
3080bb2ff7SRichard Henderson }
3180bb2ff7SRichard Henderson 
3280bb2ff7SRichard Henderson /* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
3380bb2ff7SRichard Henderson     (0) The dev_irq_n lines into the cpu, which we totally ignore,
3480bb2ff7SRichard Henderson     (1) The DRIR lines in the typhoon chipset,
3580bb2ff7SRichard Henderson     (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
3680bb2ff7SRichard Henderson     (3) The interrupt number assigned by the kernel.
3780bb2ff7SRichard Henderson    The following function is concerned with (1) only.  */
3880bb2ff7SRichard Henderson 
3980bb2ff7SRichard Henderson static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
4080bb2ff7SRichard Henderson {
4180bb2ff7SRichard Henderson     int slot = d->devfn >> 3;
4280bb2ff7SRichard Henderson 
4380bb2ff7SRichard Henderson     assert(irq_num >= 0 && irq_num <= 3);
4480bb2ff7SRichard Henderson 
4580bb2ff7SRichard Henderson     return (slot + 1) * 4 + irq_num;
4680bb2ff7SRichard Henderson }
4780bb2ff7SRichard Henderson 
483ef96221SMarcel Apfelbaum static void clipper_init(MachineState *machine)
4980bb2ff7SRichard Henderson {
503ef96221SMarcel Apfelbaum     ram_addr_t ram_size = machine->ram_size;
513ef96221SMarcel Apfelbaum     const char *cpu_model = machine->cpu_model;
523ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
533ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
543ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
55ad601177SAndreas Färber     AlphaCPU *cpus[4];
5680bb2ff7SRichard Henderson     PCIBus *pci_bus;
5748a18b3cSHervé Poussineau     ISABus *isa_bus;
5880bb2ff7SRichard Henderson     qemu_irq rtc_irq;
5980bb2ff7SRichard Henderson     long size, i;
60c18f8556SShannon Zhao     char *palcode_filename;
6180bb2ff7SRichard Henderson     uint64_t palcode_entry, palcode_low, palcode_high;
6280bb2ff7SRichard Henderson     uint64_t kernel_entry, kernel_low, kernel_high;
6380bb2ff7SRichard Henderson 
6480bb2ff7SRichard Henderson     /* Create up to 4 cpus.  */
6580bb2ff7SRichard Henderson     memset(cpus, 0, sizeof(cpus));
6680bb2ff7SRichard Henderson     for (i = 0; i < smp_cpus; ++i) {
67ad601177SAndreas Färber         cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67");
6880bb2ff7SRichard Henderson     }
6980bb2ff7SRichard Henderson 
70ad601177SAndreas Färber     cpus[0]->env.trap_arg0 = ram_size;
71ad601177SAndreas Färber     cpus[0]->env.trap_arg1 = 0;
72ad601177SAndreas Färber     cpus[0]->env.trap_arg2 = smp_cpus;
7380bb2ff7SRichard Henderson 
7480bb2ff7SRichard Henderson     /* Init the chipset.  */
7571baa303SHervé Poussineau     pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus,
7671baa303SHervé Poussineau                            clipper_pci_map_irq);
7780bb2ff7SRichard Henderson 
78e605e969SRichard Henderson     /* Since we have an SRM-compatible PALcode, use the SRM epoch.  */
79e605e969SRichard Henderson     rtc_init(isa_bus, 1900, rtc_irq);
80e605e969SRichard Henderson 
81319ba9f5SJan Kiszka     pit_init(isa_bus, 0x40, 0, NULL);
8248a18b3cSHervé Poussineau     isa_create_simple(isa_bus, "i8042");
8380bb2ff7SRichard Henderson 
8480bb2ff7SRichard Henderson     /* VGA setup.  Don't bother loading the bios.  */
85606f90ccSAurelien Jarno     pci_vga_init(pci_bus);
8680bb2ff7SRichard Henderson 
8780bb2ff7SRichard Henderson     /* Serial code setup.  */
88b6607a1aSMarkus Armbruster     serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
8980bb2ff7SRichard Henderson 
9080bb2ff7SRichard Henderson     /* Network setup.  e1000 is good enough, failing Tulip support.  */
9180bb2ff7SRichard Henderson     for (i = 0; i < nb_nics; i++) {
9229b358f9SDavid Gibson         pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
9380bb2ff7SRichard Henderson     }
9480bb2ff7SRichard Henderson 
9580bb2ff7SRichard Henderson     /* IDE disk setup.  */
9680bb2ff7SRichard Henderson     {
9780bb2ff7SRichard Henderson         DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
98d8f94e1bSJohn Snow         ide_drive_get(hd, ARRAY_SIZE(hd));
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.  */
106c18f8556SShannon Zhao     palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
107c18f8556SShannon Zhao                                 bios_name ? bios_name : "palcode-clipper");
10880bb2ff7SRichard Henderson     if (palcode_filename == NULL) {
109c525436eSMarkus Armbruster         error_report("no palcode provided");
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) {
116c525436eSMarkus Armbruster         error_report("could not load palcode '%s'", palcode_filename);
11780bb2ff7SRichard Henderson         exit(1);
11880bb2ff7SRichard Henderson     }
119c18f8556SShannon Zhao     g_free(palcode_filename);
12080bb2ff7SRichard Henderson 
12180bb2ff7SRichard Henderson     /* Start all cpus at the PALcode RESET entry point.  */
12280bb2ff7SRichard Henderson     for (i = 0; i < smp_cpus; ++i) {
123ad601177SAndreas Färber         cpus[i]->env.pal_mode = 1;
124ad601177SAndreas Färber         cpus[i]->env.pc = palcode_entry;
125ad601177SAndreas Färber         cpus[i]->env.palbr = palcode_entry;
12680bb2ff7SRichard Henderson     }
12780bb2ff7SRichard Henderson 
12880bb2ff7SRichard Henderson     /* Load a kernel.  */
12980bb2ff7SRichard Henderson     if (kernel_filename) {
13080bb2ff7SRichard Henderson         uint64_t param_offset;
13180bb2ff7SRichard Henderson 
13280bb2ff7SRichard Henderson         size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
13380bb2ff7SRichard Henderson                         NULL, &kernel_entry, &kernel_low, &kernel_high,
13480bb2ff7SRichard Henderson                         0, EM_ALPHA, 0);
13580bb2ff7SRichard Henderson         if (size < 0) {
136c525436eSMarkus Armbruster             error_report("could not load kernel '%s'", kernel_filename);
13780bb2ff7SRichard Henderson             exit(1);
13880bb2ff7SRichard Henderson         }
13980bb2ff7SRichard Henderson 
140ad601177SAndreas Färber         cpus[0]->env.trap_arg1 = kernel_entry;
14180bb2ff7SRichard Henderson 
14280bb2ff7SRichard Henderson         param_offset = kernel_low - 0x6000;
14380bb2ff7SRichard Henderson 
14480bb2ff7SRichard Henderson         if (kernel_cmdline) {
14580bb2ff7SRichard Henderson             pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
14680bb2ff7SRichard Henderson         }
14780bb2ff7SRichard Henderson 
14880bb2ff7SRichard Henderson         if (initrd_filename) {
14980bb2ff7SRichard Henderson             long initrd_base, initrd_size;
15080bb2ff7SRichard Henderson 
15180bb2ff7SRichard Henderson             initrd_size = get_image_size(initrd_filename);
15280bb2ff7SRichard Henderson             if (initrd_size < 0) {
153c525436eSMarkus Armbruster                 error_report("could not load initial ram disk '%s'",
15480bb2ff7SRichard Henderson                              initrd_filename);
15580bb2ff7SRichard Henderson                 exit(1);
15680bb2ff7SRichard Henderson             }
15780bb2ff7SRichard Henderson 
15880bb2ff7SRichard Henderson             /* Put the initrd image as high in memory as possible.  */
15980bb2ff7SRichard Henderson             initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
16080bb2ff7SRichard Henderson             load_image_targphys(initrd_filename, initrd_base,
16180bb2ff7SRichard Henderson                                 ram_size - initrd_base);
16280bb2ff7SRichard Henderson 
16342874d3aSPeter Maydell             address_space_stq(&address_space_memory, param_offset + 0x100,
16442874d3aSPeter Maydell                               initrd_base + 0xfffffc0000000000ULL,
16542874d3aSPeter Maydell                               MEMTXATTRS_UNSPECIFIED,
16642874d3aSPeter Maydell                               NULL);
16742874d3aSPeter Maydell             address_space_stq(&address_space_memory, param_offset + 0x108,
16842874d3aSPeter Maydell                               initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
16980bb2ff7SRichard Henderson         }
17080bb2ff7SRichard Henderson     }
17180bb2ff7SRichard Henderson }
17280bb2ff7SRichard Henderson 
173e264d29dSEduardo Habkost static void clipper_machine_init(MachineClass *mc)
17480bb2ff7SRichard Henderson {
175e264d29dSEduardo Habkost     mc->desc = "Alpha DP264/CLIPPER";
176e264d29dSEduardo Habkost     mc->init = clipper_init;
177e264d29dSEduardo Habkost     mc->max_cpus = 4;
178e264d29dSEduardo Habkost     mc->is_default = 1;
17980bb2ff7SRichard Henderson }
18080bb2ff7SRichard Henderson 
181e264d29dSEduardo Habkost DEFINE_MACHINE("clipper", clipper_machine_init)
182