xref: /openbmc/qemu/hw/alpha/dp264.c (revision ab938ae4)
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 "hw/hw.h"
13 #include "elf.h"
14 #include "hw/loader.h"
15 #include "hw/boards.h"
16 #include "alpha_sys.h"
17 #include "qemu/error-report.h"
18 #include "sysemu/sysemu.h"
19 #include "hw/timer/mc146818rtc.h"
20 #include "hw/ide.h"
21 #include "hw/timer/i8254.h"
22 #include "hw/char/serial.h"
23 #include "qemu/cutils.h"
24 
25 #define MAX_IDE_BUS 2
26 
27 static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
28 {
29     if (((addr >> 41) & 3) == 2) {
30         addr &= 0xffffffffffull;
31     }
32     return addr;
33 }
34 
35 /* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
36     (0) The dev_irq_n lines into the cpu, which we totally ignore,
37     (1) The DRIR lines in the typhoon chipset,
38     (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
39     (3) The interrupt number assigned by the kernel.
40    The following function is concerned with (1) only.  */
41 
42 static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
43 {
44     int slot = d->devfn >> 3;
45 
46     assert(irq_num >= 0 && irq_num <= 3);
47 
48     return (slot + 1) * 4 + irq_num;
49 }
50 
51 static void clipper_init(MachineState *machine)
52 {
53     ram_addr_t ram_size = machine->ram_size;
54     const char *cpu_model = machine->cpu_model ? machine->cpu_model : "ev67";
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 
67     /* Create up to 4 cpus.  */
68     memset(cpus, 0, sizeof(cpus));
69     for (i = 0; i < smp_cpus; ++i) {
70         cpus[i] = ALPHA_CPU(cpu_generic_init(TYPE_ALPHA_CPU, cpu_model));
71         if (!cpus[i]) {
72             error_report("Unable to find CPU definition");
73             exit(1);
74         }
75     }
76 
77     cpus[0]->env.trap_arg0 = ram_size;
78     cpus[0]->env.trap_arg1 = 0;
79     cpus[0]->env.trap_arg2 = smp_cpus;
80 
81     /* Init the chipset.  */
82     pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus,
83                            clipper_pci_map_irq);
84 
85     /* Since we have an SRM-compatible PALcode, use the SRM epoch.  */
86     rtc_init(isa_bus, 1900, rtc_irq);
87 
88     pit_init(isa_bus, 0x40, 0, NULL);
89     isa_create_simple(isa_bus, "i8042");
90 
91     /* VGA setup.  Don't bother loading the bios.  */
92     pci_vga_init(pci_bus);
93 
94     /* Serial code setup.  */
95     serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
96 
97     /* Network setup.  e1000 is good enough, failing Tulip support.  */
98     for (i = 0; i < nb_nics; i++) {
99         pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
100     }
101 
102     /* IDE disk setup.  */
103     {
104         DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
105         ide_drive_get(hd, ARRAY_SIZE(hd));
106 
107         pci_cmd646_ide_init(pci_bus, hd, 0);
108     }
109 
110     /* Load PALcode.  Given that this is not "real" cpu palcode,
111        but one explicitly written for the emulation, we might as
112        well load it directly from and ELF image.  */
113     palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
114                                 bios_name ? bios_name : "palcode-clipper");
115     if (palcode_filename == NULL) {
116         error_report("no palcode provided");
117         exit(1);
118     }
119     size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
120                     NULL, &palcode_entry, &palcode_low, &palcode_high,
121                     0, EM_ALPHA, 0, 0);
122     if (size < 0) {
123         error_report("could not load palcode '%s'", palcode_filename);
124         exit(1);
125     }
126     g_free(palcode_filename);
127 
128     /* Start all cpus at the PALcode RESET entry point.  */
129     for (i = 0; i < smp_cpus; ++i) {
130         cpus[i]->env.pc = palcode_entry;
131         cpus[i]->env.palbr = palcode_entry;
132     }
133 
134     /* Load a kernel.  */
135     if (kernel_filename) {
136         uint64_t param_offset;
137 
138         size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
139                         NULL, &kernel_entry, &kernel_low, &kernel_high,
140                         0, EM_ALPHA, 0, 0);
141         if (size < 0) {
142             error_report("could not load kernel '%s'", kernel_filename);
143             exit(1);
144         }
145 
146         cpus[0]->env.trap_arg1 = kernel_entry;
147 
148         param_offset = kernel_low - 0x6000;
149 
150         if (kernel_cmdline) {
151             pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
152         }
153 
154         if (initrd_filename) {
155             long initrd_base, 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 = 1;
186 }
187 
188 DEFINE_MACHINE("clipper", clipper_machine_init)
189