xref: /openbmc/qemu/hw/alpha/dp264.c (revision ed5abf46)
1 /*
2  * QEMU Alpha DP264/CLIPPER hardware system emulator.
3  *
4  * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
5  * variants because CLIPPER doesn't have an SMC669 SuperIO controller
6  * that we need to emulate as well.
7  */
8 
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "cpu.h"
12 #include "elf.h"
13 #include "hw/loader.h"
14 #include "alpha_sys.h"
15 #include "qemu/error-report.h"
16 #include "sysemu/sysemu.h"
17 #include "hw/rtc/mc146818rtc.h"
18 #include "hw/ide.h"
19 #include "hw/timer/i8254.h"
20 #include "hw/isa/superio.h"
21 #include "hw/dma/i8257.h"
22 #include "net/net.h"
23 #include "qemu/cutils.h"
24 #include "net/net.h"
25 
26 #define MAX_IDE_BUS 2
27 
28 static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
29 {
30     if (((addr >> 41) & 3) == 2) {
31         addr &= 0xffffffffffull;
32     }
33     return addr;
34 }
35 
36 /* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
37     (0) The dev_irq_n lines into the cpu, which we totally ignore,
38     (1) The DRIR lines in the typhoon chipset,
39     (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
40     (3) The interrupt number assigned by the kernel.
41    The following function is concerned with (1) only.  */
42 
43 static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
44 {
45     int slot = d->devfn >> 3;
46 
47     assert(irq_num >= 0 && irq_num <= 3);
48 
49     return (slot + 1) * 4 + irq_num;
50 }
51 
52 static void clipper_init(MachineState *machine)
53 {
54     ram_addr_t ram_size = machine->ram_size;
55     const char *kernel_filename = machine->kernel_filename;
56     const char *kernel_cmdline = machine->kernel_cmdline;
57     const char *initrd_filename = machine->initrd_filename;
58     AlphaCPU *cpus[4];
59     PCIBus *pci_bus;
60     ISABus *isa_bus;
61     qemu_irq rtc_irq;
62     long size, i;
63     char *palcode_filename;
64     uint64_t palcode_entry, palcode_low, palcode_high;
65     uint64_t kernel_entry, kernel_low, kernel_high;
66     unsigned int smp_cpus = machine->smp.cpus;
67 
68     /* Create up to 4 cpus.  */
69     memset(cpus, 0, sizeof(cpus));
70     for (i = 0; i < smp_cpus; ++i) {
71         cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type));
72     }
73 
74     cpus[0]->env.trap_arg0 = ram_size;
75     cpus[0]->env.trap_arg1 = 0;
76     cpus[0]->env.trap_arg2 = smp_cpus;
77 
78     /* Init the chipset.  */
79     pci_bus = typhoon_init(machine->ram, &isa_bus, &rtc_irq, cpus,
80                            clipper_pci_map_irq);
81 
82     /* Since we have an SRM-compatible PALcode, use the SRM epoch.  */
83     mc146818_rtc_init(isa_bus, 1900, rtc_irq);
84 
85     i8254_pit_init(isa_bus, 0x40, 0, NULL);
86 
87     /* VGA setup.  Don't bother loading the bios.  */
88     pci_vga_init(pci_bus);
89 
90     /* Network setup.  e1000 is good enough, failing Tulip support.  */
91     for (i = 0; i < nb_nics; i++) {
92         pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
93     }
94 
95     /* 2 82C37 (dma) */
96     isa_create_simple(isa_bus, "i82374");
97 
98     /* Super I/O */
99     isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
100 
101     /* IDE disk setup.  */
102     {
103         DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
104         ide_drive_get(hd, ARRAY_SIZE(hd));
105 
106         pci_cmd646_ide_init(pci_bus, hd, 0);
107     }
108 
109     /* Load PALcode.  Given that this is not "real" cpu palcode,
110        but one explicitly written for the emulation, we might as
111        well load it directly from and ELF image.  */
112     palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
113                                 bios_name ? bios_name : "palcode-clipper");
114     if (palcode_filename == NULL) {
115         error_report("no palcode provided");
116         exit(1);
117     }
118     size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
119                     NULL, &palcode_entry, &palcode_low, &palcode_high, NULL,
120                     0, EM_ALPHA, 0, 0);
121     if (size < 0) {
122         error_report("could not load palcode '%s'", palcode_filename);
123         exit(1);
124     }
125     g_free(palcode_filename);
126 
127     /* Start all cpus at the PALcode RESET entry point.  */
128     for (i = 0; i < smp_cpus; ++i) {
129         cpus[i]->env.pc = palcode_entry;
130         cpus[i]->env.palbr = palcode_entry;
131     }
132 
133     /* Load a kernel.  */
134     if (kernel_filename) {
135         uint64_t param_offset;
136 
137         size = load_elf(kernel_filename, NULL, cpu_alpha_superpage_to_phys,
138                         NULL, &kernel_entry, &kernel_low, &kernel_high, NULL,
139                         0, EM_ALPHA, 0, 0);
140         if (size < 0) {
141             error_report("could not load kernel '%s'", kernel_filename);
142             exit(1);
143         }
144 
145         cpus[0]->env.trap_arg1 = kernel_entry;
146 
147         param_offset = kernel_low - 0x6000;
148 
149         if (kernel_cmdline) {
150             pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
151         }
152 
153         if (initrd_filename) {
154             long initrd_base;
155             int64_t initrd_size;
156 
157             initrd_size = get_image_size(initrd_filename);
158             if (initrd_size < 0) {
159                 error_report("could not load initial ram disk '%s'",
160                              initrd_filename);
161                 exit(1);
162             }
163 
164             /* Put the initrd image as high in memory as possible.  */
165             initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
166             load_image_targphys(initrd_filename, initrd_base,
167                                 ram_size - initrd_base);
168 
169             address_space_stq(&address_space_memory, param_offset + 0x100,
170                               initrd_base + 0xfffffc0000000000ULL,
171                               MEMTXATTRS_UNSPECIFIED,
172                               NULL);
173             address_space_stq(&address_space_memory, param_offset + 0x108,
174                               initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
175         }
176     }
177 }
178 
179 static void clipper_machine_init(MachineClass *mc)
180 {
181     mc->desc = "Alpha DP264/CLIPPER";
182     mc->init = clipper_init;
183     mc->block_default_type = IF_IDE;
184     mc->max_cpus = 4;
185     mc->is_default = true;
186     mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67");
187     mc->default_ram_id = "ram";
188 }
189 
190 DEFINE_MACHINE("clipper", clipper_machine_init)
191