2011-08-26 01:38:59 +04:00
|
|
|
/*
|
|
|
|
* QEMU Alpha DP264/CLIPPER hardware system emulator.
|
|
|
|
*
|
|
|
|
* Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
|
2011-11-29 12:52:39 +04:00
|
|
|
* variants because CLIPPER doesn't have an SMC669 SuperIO controller
|
2011-08-26 01:38:59 +04:00
|
|
|
* that we need to emulate as well.
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:17:04 +03:00
|
|
|
#include "qemu/osdep.h"
|
2016-01-19 23:51:44 +03:00
|
|
|
#include "qemu-common.h"
|
|
|
|
#include "cpu.h"
|
2011-08-26 01:38:59 +04:00
|
|
|
#include "elf.h"
|
2013-02-04 18:40:22 +04:00
|
|
|
#include "hw/loader.h"
|
2013-03-18 20:36:02 +04:00
|
|
|
#include "alpha_sys.h"
|
2015-12-17 19:35:09 +03:00
|
|
|
#include "qemu/error-report.h"
|
2019-10-04 02:03:53 +03:00
|
|
|
#include "hw/rtc/mc146818rtc.h"
|
2020-03-07 12:13:12 +03:00
|
|
|
#include "hw/ide/pci.h"
|
2018-03-09 01:39:45 +03:00
|
|
|
#include "hw/isa/superio.h"
|
2019-12-12 19:15:43 +03:00
|
|
|
#include "net/net.h"
|
2016-03-20 20:16:19 +03:00
|
|
|
#include "qemu/cutils.h"
|
2020-10-28 14:36:57 +03:00
|
|
|
#include "qemu/datadir.h"
|
2020-02-28 14:46:39 +03:00
|
|
|
#include "net/net.h"
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
#define MAX_IDE_BUS 2
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-05-07 18:42:57 +04:00
|
|
|
static void clipper_init(MachineState *machine)
|
2011-08-26 01:38:59 +04:00
|
|
|
{
|
2014-05-07 18:42:57 +04:00
|
|
|
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;
|
2012-10-16 04:45:53 +04:00
|
|
|
AlphaCPU *cpus[4];
|
2011-08-26 01:38:59 +04:00
|
|
|
PCIBus *pci_bus;
|
2020-03-17 18:05:37 +03:00
|
|
|
PCIDevice *pci_dev;
|
2021-06-16 17:15:38 +03:00
|
|
|
DeviceState *i82378_dev;
|
2011-12-16 01:09:51 +04:00
|
|
|
ISABus *isa_bus;
|
2011-08-26 01:38:59 +04:00
|
|
|
qemu_irq rtc_irq;
|
2021-06-16 17:15:38 +03:00
|
|
|
qemu_irq isa_irq;
|
2011-08-26 01:38:59 +04:00
|
|
|
long size, i;
|
2015-05-28 15:39:42 +03:00
|
|
|
char *palcode_filename;
|
2020-07-05 20:22:11 +03:00
|
|
|
uint64_t palcode_entry;
|
|
|
|
uint64_t kernel_entry, kernel_low;
|
2019-05-18 23:54:27 +03:00
|
|
|
unsigned int smp_cpus = machine->smp.cpus;
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
/* Create up to 4 cpus. */
|
|
|
|
memset(cpus, 0, sizeof(cpus));
|
|
|
|
for (i = 0; i < smp_cpus; ++i) {
|
2017-10-05 16:50:39 +03:00
|
|
|
cpus[i] = ALPHA_CPU(cpu_create(machine->cpu_type));
|
2011-08-26 01:38:59 +04:00
|
|
|
}
|
|
|
|
|
2021-06-14 00:15:49 +03:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-10-16 04:45:53 +04:00
|
|
|
cpus[0]->env.trap_arg0 = ram_size;
|
|
|
|
cpus[0]->env.trap_arg1 = 0;
|
2021-06-14 00:15:49 +03:00
|
|
|
cpus[0]->env.trap_arg2 = smp_cpus | (!machine->enable_graphics << 6);
|
2011-08-26 01:38:59 +04:00
|
|
|
|
2021-06-14 00:15:47 +03:00
|
|
|
/*
|
|
|
|
* Init the chipset. Because we're using CLIPPER IRQ mappings,
|
|
|
|
* the minimum PCI device IdSel is 1.
|
|
|
|
*/
|
2021-06-16 17:15:38 +03:00
|
|
|
pci_bus = typhoon_init(machine->ram, &isa_irq, &rtc_irq, cpus,
|
2021-06-14 00:15:47 +03:00
|
|
|
clipper_pci_map_irq, PCI_DEVFN(1, 0));
|
2011-08-26 01:38:59 +04:00
|
|
|
|
2021-06-16 17:15:38 +03:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2013-07-14 04:23:37 +04:00
|
|
|
/* Since we have an SRM-compatible PALcode, use the SRM epoch. */
|
2017-10-17 19:44:16 +03:00
|
|
|
mc146818_rtc_init(isa_bus, 1900, rtc_irq);
|
2013-07-14 04:23:37 +04:00
|
|
|
|
2011-08-26 01:38:59 +04:00
|
|
|
/* VGA setup. Don't bother loading the bios. */
|
2012-09-08 14:16:28 +04:00
|
|
|
pci_vga_init(pci_bus);
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
/* Network setup. e1000 is good enough, failing Tulip support. */
|
|
|
|
for (i = 0; i < nb_nics; i++) {
|
2013-06-06 12:48:51 +04:00
|
|
|
pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
|
2011-08-26 01:38:59 +04:00
|
|
|
}
|
|
|
|
|
2018-03-09 01:39:45 +03:00
|
|
|
/* Super I/O */
|
|
|
|
isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
|
|
|
|
|
2011-08-26 01:38:59 +04:00
|
|
|
/* IDE disk setup. */
|
2020-03-17 18:05:37 +03:00
|
|
|
pci_dev = pci_create_simple(pci_bus, -1, "cmd646-ide");
|
|
|
|
pci_ide_create_devs(pci_dev);
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
/* 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. */
|
2015-05-28 15:39:42 +03:00
|
|
|
palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
|
2020-10-26 17:30:14 +03:00
|
|
|
machine->firmware ?: "palcode-clipper");
|
2011-08-26 01:38:59 +04:00
|
|
|
if (palcode_filename == NULL) {
|
2015-12-17 19:35:09 +03:00
|
|
|
error_report("no palcode provided");
|
2011-08-26 01:38:59 +04:00
|
|
|
exit(1);
|
|
|
|
}
|
2019-01-15 15:18:03 +03:00
|
|
|
size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
|
2020-07-05 20:22:11 +03:00
|
|
|
NULL, &palcode_entry, NULL, NULL, NULL,
|
2016-03-04 14:30:21 +03:00
|
|
|
0, EM_ALPHA, 0, 0);
|
2011-08-26 01:38:59 +04:00
|
|
|
if (size < 0) {
|
2015-12-17 19:35:09 +03:00
|
|
|
error_report("could not load palcode '%s'", palcode_filename);
|
2011-08-26 01:38:59 +04:00
|
|
|
exit(1);
|
|
|
|
}
|
2015-05-28 15:39:42 +03:00
|
|
|
g_free(palcode_filename);
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
/* Start all cpus at the PALcode RESET entry point. */
|
|
|
|
for (i = 0; i < smp_cpus; ++i) {
|
2012-10-16 04:45:53 +04:00
|
|
|
cpus[i]->env.pc = palcode_entry;
|
|
|
|
cpus[i]->env.palbr = palcode_entry;
|
2011-08-26 01:38:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Load a kernel. */
|
|
|
|
if (kernel_filename) {
|
|
|
|
uint64_t param_offset;
|
|
|
|
|
2019-01-15 15:18:03 +03:00
|
|
|
size = load_elf(kernel_filename, NULL, cpu_alpha_superpage_to_phys,
|
2020-07-05 20:22:11 +03:00
|
|
|
NULL, &kernel_entry, &kernel_low, NULL, NULL,
|
2016-03-04 14:30:21 +03:00
|
|
|
0, EM_ALPHA, 0, 0);
|
2011-08-26 01:38:59 +04:00
|
|
|
if (size < 0) {
|
2015-12-17 19:35:09 +03:00
|
|
|
error_report("could not load kernel '%s'", kernel_filename);
|
2011-08-26 01:38:59 +04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-10-16 04:45:53 +04:00
|
|
|
cpus[0]->env.trap_arg1 = kernel_entry;
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
param_offset = kernel_low - 0x6000;
|
|
|
|
|
|
|
|
if (kernel_cmdline) {
|
|
|
|
pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (initrd_filename) {
|
2018-09-13 13:07:13 +03:00
|
|
|
long initrd_base;
|
|
|
|
int64_t initrd_size;
|
2011-08-26 01:38:59 +04:00
|
|
|
|
|
|
|
initrd_size = get_image_size(initrd_filename);
|
|
|
|
if (initrd_size < 0) {
|
2015-12-17 19:35:09 +03:00
|
|
|
error_report("could not load initial ram disk '%s'",
|
|
|
|
initrd_filename);
|
2011-08-26 01:38:59 +04:00
|
|
|
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);
|
|
|
|
|
Switch non-CPU callers from ld/st*_phys to address_space_ld/st*
Switch all the uses of ld/st*_phys to address_space_ld/st*,
except for those cases where the address space is the CPU's
(ie cs->as). This was done with the following script which
generates a Coccinelle patch.
A few over-80-columns lines in the result were rewrapped by
hand where Coccinelle failed to do the wrapping automatically,
as well as one location where it didn't put a line-continuation
'\' when wrapping lines on a change made to a match inside
a macro definition.
===begin===
#!/bin/sh -e
# Usage:
# ./ldst-phys.spatch.sh > ldst-phys.spatch
# spatch -sp_file ldst-phys.spatch -dir . | sed -e '/^+/s/\t/ /g' > out.patch
# patch -p1 < out.patch
for FN in ub uw_le uw_be l_le l_be q_le q_be uw l q; do
cat <<EOF
@ cpu_matches_ld_${FN} @
expression E1,E2;
identifier as;
@@
ld${FN}_phys(E1->as,E2)
@ other_matches_ld_${FN} depends on !cpu_matches_ld_${FN} @
expression E1,E2;
@@
-ld${FN}_phys(E1,E2)
+address_space_ld${FN}(E1,E2, MEMTXATTRS_UNSPECIFIED, NULL)
EOF
done
for FN in b w_le w_be l_le l_be q_le q_be w l q; do
cat <<EOF
@ cpu_matches_st_${FN} @
expression E1,E2,E3;
identifier as;
@@
st${FN}_phys(E1->as,E2,E3)
@ other_matches_st_${FN} depends on !cpu_matches_st_${FN} @
expression E1,E2,E3;
@@
-st${FN}_phys(E1,E2,E3)
+address_space_st${FN}(E1,E2,E3, MEMTXATTRS_UNSPECIFIED, NULL)
EOF
done
===endit===
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2015-04-26 18:49:24 +03:00
|
|
|
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);
|
2011-08-26 01:38:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-04 21:37:08 +03:00
|
|
|
static void clipper_machine_init(MachineClass *mc)
|
2011-08-26 01:38:59 +04:00
|
|
|
{
|
2015-09-04 21:37:08 +03:00
|
|
|
mc->desc = "Alpha DP264/CLIPPER";
|
|
|
|
mc->init = clipper_init;
|
2017-02-15 13:05:40 +03:00
|
|
|
mc->block_default_type = IF_IDE;
|
2015-09-04 21:37:08 +03:00
|
|
|
mc->max_cpus = 4;
|
2020-02-07 19:19:47 +03:00
|
|
|
mc->is_default = true;
|
2017-10-05 16:50:39 +03:00
|
|
|
mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67");
|
2020-02-19 19:08:42 +03:00
|
|
|
mc->default_ram_id = "ram";
|
2011-08-26 01:38:59 +04:00
|
|
|
}
|
|
|
|
|
2015-09-04 21:37:08 +03:00
|
|
|
DEFINE_MACHINE("clipper", clipper_machine_init)
|