 cdd684b8e1
			
		
	
	
		cdd684b8e1
		
	
	
	
	
		
			
			Mark the default NIC via the new MachineClass->default_nic setting so that the machine-defaults code in vl.c can decide whether the default NIC is usable or not (for example when compiling with the "--without-default-devices" configure switch). Message-Id: <20230523110435.1375774-3-thuth@redhat.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Thomas Huth <thuth@redhat.com>
		
			
				
	
	
		
			221 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 "qemu/osdep.h"
 | |
| #include "cpu.h"
 | |
| #include "elf.h"
 | |
| #include "hw/loader.h"
 | |
| #include "alpha_sys.h"
 | |
| #include "qemu/error-report.h"
 | |
| #include "hw/rtc/mc146818rtc.h"
 | |
| #include "hw/ide/pci.h"
 | |
| #include "hw/isa/superio.h"
 | |
| #include "net/net.h"
 | |
| #include "qemu/cutils.h"
 | |
| #include "qemu/datadir.h"
 | |
| 
 | |
| 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(MachineState *machine)
 | |
| {
 | |
|     ram_addr_t ram_size = machine->ram_size;
 | |
|     const char *kernel_filename = machine->kernel_filename;
 | |
|     const char *kernel_cmdline = machine->kernel_cmdline;
 | |
|     const char *initrd_filename = machine->initrd_filename;
 | |
|     MachineClass *mc = MACHINE_GET_CLASS(machine);
 | |
|     AlphaCPU *cpus[4];
 | |
|     PCIBus *pci_bus;
 | |
|     PCIDevice *pci_dev;
 | |
|     DeviceState *i82378_dev;
 | |
|     ISABus *isa_bus;
 | |
|     qemu_irq rtc_irq;
 | |
|     qemu_irq isa_irq;
 | |
|     long size, i;
 | |
|     char *palcode_filename;
 | |
|     uint64_t palcode_entry;
 | |
|     uint64_t kernel_entry, kernel_low;
 | |
|     unsigned int smp_cpus = machine->smp.cpus;
 | |
| 
 | |
|     /* Create up to 4 cpus.  */
 | |
|     memset(cpus, 0, sizeof(cpus));
 | |
|     for (i = 0; i < smp_cpus; ++i) {
 | |
|         cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type));
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * arg0 -> memory size
 | |
|      * arg1 -> kernel entry point
 | |
|      * arg2 -> config word
 | |
|      *
 | |
|      * Config word: bits 0-5 -> ncpus
 | |
|      *              bit  6   -> nographics option (for HWRPB CTB)
 | |
|      *
 | |
|      * See init_hwrpb() in the PALcode.
 | |
|      */
 | |
|     cpus[0]->env.trap_arg0 = ram_size;
 | |
|     cpus[0]->env.trap_arg1 = 0;
 | |
|     cpus[0]->env.trap_arg2 = smp_cpus | (!machine->enable_graphics << 6);
 | |
| 
 | |
|     /*
 | |
|      * Init the chipset.  Because we're using CLIPPER IRQ mappings,
 | |
|      * the minimum PCI device IdSel is 1.
 | |
|      */
 | |
|     pci_bus = typhoon_init(machine->ram, &isa_irq, &rtc_irq, cpus,
 | |
|                            clipper_pci_map_irq, PCI_DEVFN(1, 0));
 | |
| 
 | |
|     /*
 | |
|      * Init the PCI -> ISA bridge.
 | |
|      *
 | |
|      * Technically, PCI-based Alphas shipped with one of three different
 | |
|      * PCI-ISA bridges:
 | |
|      *
 | |
|      * - Intel i82378 SIO
 | |
|      * - Cypress CY82c693UB
 | |
|      * - ALI M1533
 | |
|      *
 | |
|      * (An Intel i82375 PCI-EISA bridge was also used on some models.)
 | |
|      *
 | |
|      * For simplicity, we model an i82378 here, even though it wouldn't
 | |
|      * have been on any Tsunami/Typhoon systems; it's close enough, and
 | |
|      * we don't want to deal with modelling the CY82c693UB (which has
 | |
|      * incompatible edge/level control registers, plus other peripherals
 | |
|      * like IDE and USB) or the M1533 (which also has IDE and USB).
 | |
|      *
 | |
|      * Importantly, we need to provide a PCI device node for it, otherwise
 | |
|      * some operating systems won't notice there's an ISA bus to configure.
 | |
|      */
 | |
|     i82378_dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(7, 0), "i82378"));
 | |
|     isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0"));
 | |
| 
 | |
|     /* Connect the ISA PIC to the Typhoon IRQ used for ISA interrupts. */
 | |
|     qdev_connect_gpio_out(i82378_dev, 0, isa_irq);
 | |
| 
 | |
|     /* Since we have an SRM-compatible PALcode, use the SRM epoch.  */
 | |
|     mc146818_rtc_init(isa_bus, 1900, rtc_irq);
 | |
| 
 | |
|     /* VGA setup.  Don't bother loading the bios.  */
 | |
|     pci_vga_init(pci_bus);
 | |
| 
 | |
|     /* Network setup.  e1000 is good enough, failing Tulip support.  */
 | |
|     for (i = 0; i < nb_nics; i++) {
 | |
|         pci_nic_init_nofail(&nd_table[i], pci_bus, mc->default_nic, NULL);
 | |
|     }
 | |
| 
 | |
|     /* Super I/O */
 | |
|     isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
 | |
| 
 | |
|     /* IDE disk setup.  */
 | |
|     pci_dev = pci_create_simple(pci_bus, -1, "cmd646-ide");
 | |
|     pci_ide_create_devs(pci_dev);
 | |
| 
 | |
|     /* 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 = qemu_find_file(QEMU_FILE_TYPE_BIOS,
 | |
|                                       machine->firmware ?: "palcode-clipper");
 | |
|     if (palcode_filename == NULL) {
 | |
|         error_report("no palcode provided");
 | |
|         exit(1);
 | |
|     }
 | |
|     size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
 | |
|                     NULL, &palcode_entry, NULL, NULL, NULL,
 | |
|                     0, EM_ALPHA, 0, 0);
 | |
|     if (size < 0) {
 | |
|         error_report("could not load palcode '%s'", palcode_filename);
 | |
|         exit(1);
 | |
|     }
 | |
|     g_free(palcode_filename);
 | |
| 
 | |
|     /* Start all cpus at the PALcode RESET entry point.  */
 | |
|     for (i = 0; i < smp_cpus; ++i) {
 | |
|         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, NULL, cpu_alpha_superpage_to_phys,
 | |
|                         NULL, &kernel_entry, &kernel_low, NULL, NULL,
 | |
|                         0, EM_ALPHA, 0, 0);
 | |
|         if (size < 0) {
 | |
|             error_report("could not load kernel '%s'", 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;
 | |
|             int64_t initrd_size;
 | |
| 
 | |
|             initrd_size = get_image_size(initrd_filename);
 | |
|             if (initrd_size < 0) {
 | |
|                 error_report("could not load initial ram disk '%s'",
 | |
|                              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);
 | |
| 
 | |
|             address_space_stq(&address_space_memory, param_offset + 0x100,
 | |
|                               initrd_base + 0xfffffc0000000000ULL,
 | |
|                               MEMTXATTRS_UNSPECIFIED,
 | |
|                               NULL);
 | |
|             address_space_stq(&address_space_memory, param_offset + 0x108,
 | |
|                               initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void clipper_machine_init(MachineClass *mc)
 | |
| {
 | |
|     mc->desc = "Alpha DP264/CLIPPER";
 | |
|     mc->init = clipper_init;
 | |
|     mc->block_default_type = IF_IDE;
 | |
|     mc->max_cpus = 4;
 | |
|     mc->is_default = true;
 | |
|     mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67");
 | |
|     mc->default_ram_id = "ram";
 | |
|     mc->default_nic = "e1000";
 | |
| }
 | |
| 
 | |
| DEFINE_MACHINE("clipper", clipper_machine_init)
 |