Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
Frederic Konrad <konrad@adacore.com> <fred.konrad@greensocs.com>
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
+Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
+Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
PowerPC TCG CPUs
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Maintained
F: target/ppc/
F: target/arm/kvm.c
MIPS KVM CPUs
-M: Huacai Chen <chenhc@lemote.com>
+M: Huacai Chen <chenhuacai@kernel.org>
S: Odd Fixes
F: target/mips/kvm.c
PPC KVM CPUs
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
S: Maintained
F: target/ppc/kvm.c
F: hw/net/mipsnet.c
Fuloong 2E
-M: Huacai Chen <chenhc@lemote.com>
+M: Huacai Chen <chenhuacai@kernel.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes
F: include/hw/isa/vt82c686.h
Loongson-3 virtual platforms
-M: Huacai Chen <chenhc@lemote.com>
+M: Huacai Chen <chenhuacai@kernel.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Maintained
F: hw/intc/loongson_liointc.c
----------------
405
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/ppc405_boards.c
Bamboo
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/ppc440_bamboo.c
e500
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/e500*
mpc8544ds
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/mpc8544ds.c
New World (mac99)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
R: David Gibson <david@gibson.dropbear.id.au>
+R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/mac_newworld.c
Old World (g3beige)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
R: David Gibson <david@gibson.dropbear.id.au>
+R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/mac_oldworld.c
PReP
M: Hervé Poussineau <hpoussin@reactos.org>
+R: David Gibson <david@gibson.dropbear.id.au>
+R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/prep.c
sPAPR
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/*/spapr*
PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org>
M: David Gibson <david@gibson.dropbear.id.au>
+M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/pnv*
sam460ex
M: BALATON Zoltan <balaton@eik.bme.hu>
+R: David Gibson <david@gibson.dropbear.id.au>
+R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/sam460ex.c
T: git https://github.com/philmd/qemu.git fw_cfg-next
XIVE
-M: David Gibson <david@gibson.dropbear.id.au>
M: Cédric Le Goater <clg@kaod.org>
+R: David Gibson <david@gibson.dropbear.id.au>
+R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
S: Supported
F: hw/*/*xive*
MIPS TCG target
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Aurelien Jarno <aurelien@aurel32.net>
-R: Huacai Chen <chenhc@lemote.com>
+R: Huacai Chen <chenhuacai@kernel.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Odd Fixes
CPU emulation in QEMU, and there are no test images available to make
sure that the code is still working.
-``compat`` property of server class POWER CPUs (since 5.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-The ``compat`` property used to set backwards compatibility modes for
-the processor has been deprecated. The ``max-cpu-compat`` property of
-the ``pseries`` machine type should be used instead.
-
``lm32`` CPUs (since 5.2.0)
'''''''''''''''''''''''''''
#include "hw/ppc/xive.h"
#include "hw/ppc/xive_regs.h"
#include "hw/qdev-properties.h"
+#include "trace.h"
/*
* XIVE Virtualization Controller BAR and Thread Managment BAR that we
XiveENDSource *end_xsrc = &xive->end_source;
Error *local_err = NULL;
+ /* Set by spapr_irq_init() */
+ g_assert(xive->nr_irqs);
+ g_assert(xive->nr_ends);
+
sxc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
- if (!xive->nr_irqs) {
- error_setg(errp, "Number of interrupt needs to be greater 0");
- return;
- }
-
- if (!xive->nr_ends) {
- error_setg(errp, "Number of interrupt needs to be greater 0");
- return;
- }
-
/*
* Initialize the internal sources, for IPIs and virtual devices.
*/
assert(lisn < xive->nr_irqs);
+ trace_spapr_xive_claim_irq(lisn, lsi);
+
if (xive_eas_is_valid(&xive->eat[lisn])) {
error_setg(errp, "IRQ %d is not free", lisn);
return -EBUSY;
SpaprXive *xive = SPAPR_XIVE(intc);
assert(lisn < xive->nr_irqs);
+ trace_spapr_xive_free_irq(lisn);
+
xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
}
{
SpaprXive *xive = SPAPR_XIVE(intc);
+ trace_spapr_xive_set_irq(irq, val);
+
if (spapr_xive_in_kernel(xive)) {
kvmppc_xive_source_set_irq(&xive->source, irq, val);
} else {
target_ulong flags = args[0];
target_ulong lisn = args[1];
+ trace_spapr_xive_get_source_info(flags, lisn);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
uint8_t end_blk;
uint32_t end_idx;
+ trace_spapr_xive_set_source_config(flags, lisn, target, priority, eisn);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
uint8_t nvt_blk;
uint32_t end_idx, nvt_idx;
+ trace_spapr_xive_get_source_config(flags, lisn);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
uint8_t end_blk;
uint32_t end_idx;
+ trace_spapr_xive_get_queue_info(flags, target, priority);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
uint8_t end_blk, nvt_blk;
uint32_t end_idx, nvt_idx;
+ trace_spapr_xive_set_queue_config(flags, target, priority, qpage, qsize);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
uint8_t end_blk;
uint32_t end_idx;
+ trace_spapr_xive_get_queue_config(flags, target, priority);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
target_ulong opcode,
target_ulong *args)
{
+ target_ulong flags = args[0];
+
+ trace_spapr_xive_set_os_reporting_line(flags);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
target_ulong opcode,
target_ulong *args)
{
+ target_ulong flags = args[0];
+
+ trace_spapr_xive_get_os_reporting_line(flags);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
hwaddr mmio_addr;
XiveSource *xsrc = &xive->source;
+ trace_spapr_xive_esb(flags, lisn, offset, data);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
target_ulong flags = args[0];
target_ulong lisn = args[1];
+ trace_spapr_xive_sync(flags, lisn);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
SpaprXive *xive = spapr->xive;
target_ulong flags = args[0];
+ trace_spapr_xive_reset(flags);
+
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
return H_FUNCTION;
}
#include "hw/ppc/spapr_xive.h"
#include "hw/ppc/xive.h"
#include "kvm_ppc.h"
+#include "trace.h"
#include <sys/ioctl.h>
vcpu_id = kvm_arch_vcpu_id(tctx->cs);
+ trace_kvm_xive_cpu_connect(vcpu_id);
+
ret = kvm_vcpu_enable_cap(tctx->cs, KVM_CAP_PPC_IRQ_XIVE, 0, xive->fd,
vcpu_id, 0);
if (ret < 0) {
return xive_esb_rw(xsrc, srcno, offset, data, 1);
}
+ trace_kvm_xive_source_reset(srcno);
+
/*
* Special Load EOI handling for LSI sources. Q bit is never set
* and the interrupt should be re-triggered if the level is still
# bcm2835_ic.c
bcm2835_ic_set_gpu_irq(int irq, int level) "GPU irq #%d level %d"
bcm2835_ic_set_cpu_irq(int irq, int level) "CPU irq #%d level %d"
+
+# spapr_xive.c
+spapr_xive_claim_irq(uint32_t lisn, bool lsi) "lisn=0x%x lsi=%d"
+spapr_xive_free_irq(uint32_t lisn) "lisn=0x%x"
+spapr_xive_set_irq(uint32_t lisn, uint32_t val) "lisn=0x%x val=%d"
+spapr_xive_get_source_info(uint64_t flags, uint64_t lisn) "flags=0x%"PRIx64" lisn=0x%"PRIx64
+spapr_xive_set_source_config(uint64_t flags, uint64_t lisn, uint64_t target, uint64_t priority, uint64_t eisn) "flags=0x%"PRIx64" lisn=0x%"PRIx64" target=0x%"PRIx64" priority=0x%"PRIx64" eisn=0x%"PRIx64
+spapr_xive_get_source_config(uint64_t flags, uint64_t lisn) "flags=0x%"PRIx64" lisn=0x%"PRIx64
+spapr_xive_get_queue_info(uint64_t flags, uint64_t target, uint64_t priority) "flags=0x%"PRIx64" target=0x%"PRIx64" priority=0x%"PRIx64
+spapr_xive_set_queue_config(uint64_t flags, uint64_t target, uint64_t priority, uint64_t qpage, uint64_t qsize) "flags=0x%"PRIx64" target=0x%"PRIx64" priority=0x%"PRIx64" qpage=0x%"PRIx64" qsize=0x%"PRIx64
+spapr_xive_get_queue_config(uint64_t flags, uint64_t target, uint64_t priority) "flags=0x%"PRIx64" target=0x%"PRIx64" priority=0x%"PRIx64
+spapr_xive_set_os_reporting_line(uint64_t flags) "flags=0x%"PRIx64
+spapr_xive_get_os_reporting_line(uint64_t flags) "flags=0x%"PRIx64
+spapr_xive_esb(uint64_t flags, uint64_t lisn, uint64_t offset, uint64_t data) "flags=0x%"PRIx64" lisn=0x%"PRIx64" offset=0x%"PRIx64" data=0x%"PRIx64
+spapr_xive_sync(uint64_t flags, uint64_t lisn) "flags=0x%"PRIx64" lisn=0x%"PRIx64
+spapr_xive_reset(uint64_t flags) "flags=0x%"PRIx64
+
+# spapr_xive_kvm.c
+kvm_xive_cpu_connect(uint32_t id) "connect CPU%d to KVM device"
+kvm_xive_source_reset(uint32_t srcno) "IRQ 0x%x"
+
+# xive.c
+xive_tctx_accept(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IBP=0x%02x PIPR=0x%02x CPPR=0x%02x NSR=0x%02x ACK"
+xive_tctx_notify(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IBP=0x%02x PIPR=0x%02x CPPR=0x%02x NSR=0x%02x raise !"
+xive_tctx_set_cppr(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IBP=0x%02x PIPR=0x%02x new CPPR=0x%02x NSR=0x%02x"
+xive_source_esb_read(uint64_t addr, uint32_t srcno, uint64_t value) "@0x0x%"PRIx64" IRQ 0x%x val=0x0x%"PRIx64
+xive_source_esb_write(uint64_t addr, uint32_t srcno, uint64_t value) "@0x0x%"PRIx64" IRQ 0x%x val=0x0x%"PRIx64
+xive_router_end_notify(uint8_t end_blk, uint32_t end_idx, uint32_t end_data) "END 0x%02x/0x%04x -> enqueue 0x%08x"
+xive_router_end_escalate(uint8_t end_blk, uint32_t end_idx, uint8_t esc_blk, uint32_t esc_idx, uint32_t end_data) "END 0x%02x/0x%04x -> escalate END 0x%02x/0x%04x data 0x%08x"
+xive_tctx_tm_write(uint64_t offset, unsigned int size, uint64_t value) "@0x0x%"PRIx64" sz=%d val=0x%" PRIx64
+xive_tctx_tm_read(uint64_t offset, unsigned int size, uint64_t value) "@0x0x%"PRIx64" sz=%d val=0x%" PRIx64
+xive_presenter_notify(uint8_t nvt_blk, uint32_t nvt_idx, uint8_t ring) "found NVT 0x%x/0x%x ring=0x%x"
+xive_end_source_read(uint8_t end_blk, uint32_t end_idx, uint64_t addr) "END 0x%x/0x%x @0x0x%"PRIx64
* support destruction of a KVM XICS device while the VM is running.
* Required to start a spapr machine with ic-mode=dual,kernel-irqchip=on.
*/
-bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr)
+bool xics_kvm_has_broken_disconnect(void)
{
int rc;
#include "hw/irq.h"
#include "hw/ppc/xive.h"
#include "hw/ppc/xive_regs.h"
+#include "trace.h"
/*
* XIVE Thread Interrupt Management context
/* Drop Exception bit */
regs[TM_NSR] &= ~mask;
+
+ trace_xive_tctx_accept(tctx->cs->cpu_index, ring,
+ regs[TM_IPB], regs[TM_PIPR],
+ regs[TM_CPPR], regs[TM_NSR]);
}
return (nsr << 8) | regs[TM_CPPR];
default:
g_assert_not_reached();
}
+ trace_xive_tctx_notify(tctx->cs->cpu_index, ring,
+ regs[TM_IPB], regs[TM_PIPR],
+ regs[TM_CPPR], regs[TM_NSR]);
qemu_irq_raise(xive_tctx_output(tctx, ring));
}
}
static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
{
+ uint8_t *regs = &tctx->regs[ring];
+
+ trace_xive_tctx_set_cppr(tctx->cs->cpu_index, ring,
+ regs[TM_IPB], regs[TM_PIPR],
+ cppr, regs[TM_NSR]);
+
if (cppr > XIVE_PRIORITY_MAX) {
cppr = 0xff;
}
{
const XiveTmOp *xto;
+ trace_xive_tctx_tm_write(offset, size, value);
+
/*
* TODO: check V bit in Q[0-3]W2
*/
unsigned size)
{
const XiveTmOp *xto;
+ uint64_t ret;
/*
* TODO: check V bit in Q[0-3]W2
"@%"HWADDR_PRIx"\n", offset);
return -1;
}
- return xto->read_handler(xptr, tctx, offset, size);
+ ret = xto->read_handler(xptr, tctx, offset, size);
+ goto out;
}
/*
*/
xto = xive_tm_find_op(offset, size, false);
if (xto) {
- return xto->read_handler(xptr, tctx, offset, size);
+ ret = xto->read_handler(xptr, tctx, offset, size);
+ goto out;
}
/*
* Finish with raw access to the register values
*/
- return xive_tm_raw_read(tctx, offset, size);
+ ret = xive_tm_raw_read(tctx, offset, size);
+out:
+ trace_xive_tctx_tm_read(offset, size, ret);
+ return ret;
}
static char *xive_tctx_ring_print(uint8_t *ring)
offset);
}
+ trace_xive_source_esb_read(addr, srcno, ret);
+
return ret;
}
uint32_t srcno = addr >> xsrc->esb_shift;
bool notify = false;
+ trace_xive_source_esb_write(addr, srcno, value);
+
/* In a two pages ESB MMIO setting, trigger page only triggers */
if (xive_source_is_trigger_page(xsrc, addr)) {
notify = xive_source_esb_trigger(xsrc, srcno);
/* handle CPU exception delivery */
if (count) {
+ trace_xive_presenter_notify(nvt_blk, nvt_idx, match.ring);
xive_tctx_ipb_update(match.tctx, match.ring, priority_to_ipb(priority));
}
}
if (!xive_end_is_valid(&end)) {
+ trace_xive_router_end_notify(end_blk, end_idx, end_data);
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: END %x/%x is invalid\n",
end_blk, end_idx);
return;
}
}
+ trace_xive_router_end_escalate(end_blk, end_idx,
+ (uint8_t) xive_get_field32(END_W4_ESC_END_BLOCK, end.w4),
+ (uint32_t) xive_get_field32(END_W4_ESC_END_INDEX, end.w4),
+ (uint32_t) xive_get_field32(END_W5_ESC_END_DATA, end.w5));
/*
* The END trigger becomes an Escalation trigger
*/
end_blk = xive_router_get_block_id(xsrc->xrtr);
end_idx = addr >> (xsrc->esb_shift + 1);
+ trace_xive_end_source_read(end_blk, end_idx, addr);
+
if (xive_router_get_end(xsrc->xrtr, end_blk, end_idx, &end)) {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk,
end_idx);
+++ /dev/null
-/*
- * QEMU MIPS address translation support
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/mips/cpudevs.h"
-
-static int mips_um_ksegs;
-
-uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
-{
- return addr & 0x1fffffffll;
-}
-
-uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
-{
- return addr | ~0x7fffffffll;
-}
-
-uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
-{
- return addr | 0x40000000ll;
-}
-
-bool mips_um_ksegs_enabled(void)
-{
- return mips_um_ksegs;
-}
-
-void mips_um_ksegs_enable(void)
-{
- mips_um_ksegs = 1;
-}
#include "hw/loader.h"
#include "hw/loader-fit.h"
#include "hw/mips/cps.h"
-#include "hw/mips/cpudevs.h"
#include "hw/pci-host/xilinx-pcie.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
s = BOSTON(dev);
s->mach = machine;
- if (!cpu_supports_cps_smp(machine->cpu_type)) {
+ if (!cpu_type_supports_cps_smp(machine->cpu_type)) {
error_report("Boston requires CPUs which support CPS");
exit(1);
}
- is_64b = cpu_supports_isa(machine->cpu_type, ISA_MIPS64);
+ is_64b = cpu_type_supports_isa(machine->cpu_type, ISA_MIPS64);
object_initialize_child(OBJECT(machine), "cps", &s->cps, TYPE_MIPS_CPS);
object_property_set_str(OBJECT(&s->cps), "cpu-type", machine->cpu_type,
static bool cpu_mips_itu_supported(CPUMIPSState *env)
{
- bool is_mt = (env->CP0_Config5 & (1 << CP0C5_VP)) ||
- (env->CP0_Config3 & (1 << CP0C3_MT));
+ bool is_mt = (env->CP0_Config5 & (1 << CP0C5_VP)) || ase_mt_available(env);
return is_mt && !kvm_enabled();
}
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/bitops.h"
#include "qemu-common.h"
#include "qemu/datadir.h"
#include "cpu.h"
CPUMIPSState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) |
- ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC);
+ if (ase_mt_available(env)) {
+ env->mvp->CP0_MVPConf0 = deposit32(env->mvp->CP0_MVPConf0,
+ CP0MVPC0_PTC, 8,
+ smp_cpus * cs->nr_threads - 1);
+ env->mvp->CP0_MVPConf0 = deposit32(env->mvp->CP0_MVPConf0,
+ CP0MVPC0_PVPE, 4, smp_cpus - 1);
+ }
}
static void main_cpu_reset(void *opaque)
static void mips_create_cpu(MachineState *ms, MaltaState *s,
qemu_irq *cbus_irq, qemu_irq *i8259_irq)
{
- if ((ms->smp.cpus > 1) && cpu_supports_cps_smp(ms->cpu_type)) {
+ if ((ms->smp.cpus > 1) && cpu_type_supports_cps_smp(ms->cpu_type)) {
create_cps(ms, s, cbus_irq, i8259_irq);
} else {
create_cpu_without_cps(ms, s, cbus_irq, i8259_irq);
loaderparams.initrd_filename = initrd_filename;
kernel_entry = load_kernel();
- if (!cpu_supports_isa(machine->cpu_type, ISA_NANOMIPS32)) {
+ if (!cpu_type_supports_isa(machine->cpu_type, ISA_NANOMIPS32)) {
write_bootloader(memory_region_get_ram_ptr(bios),
bootloader_run_addr, kernel_entry);
} else {
mips_ss = ss.source_set()
-mips_ss.add(files('addr.c', 'mips_int.c'))
+mips_ss.add(files('mips_int.c'))
mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
ccsr_addr_space);
mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
+ g_free(irqs);
/* Serial */
if (serial_hd(0)) {
} else {
cpu_ppc_tb_stop(env);
}
+ break;
case PPC6xx_INPUT_INT:
/* Level sensitive - active high */
LOG_IRQ("%s: set the external IRQ state to %d\n",
*/
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
- tb->runstate_paused = runstate_check(RUN_STATE_PAUSED);
+ tb->runstate_paused =
+ runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM);
}
static void timebase_load(PPCTimebase *tb)
{
PPCTimebase *tb = opaque;
- /* guest_timebase won't be overridden in case of paused guest */
+ /* guest_timebase won't be overridden in case of paused guest or savevm */
if (!tb->runstate_paused) {
timebase_save(tb);
}
qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
}
+#define DEFAULT_KVM_TYPE "auto"
static int spapr_kvm_type(MachineState *machine, const char *vm_type)
{
- if (!vm_type) {
+ /*
+ * The use of g_ascii_strcasecmp() for 'hv' and 'pr' is to
+ * accomodate the 'HV' and 'PV' formats that exists in the
+ * wild. The 'auto' mode is being introduced already as
+ * lower-case, thus we don't need to bother checking for
+ * "AUTO".
+ */
+ if (!vm_type || !strcmp(vm_type, DEFAULT_KVM_TYPE)) {
return 0;
}
- if (!strcmp(vm_type, "HV")) {
+ if (!g_ascii_strcasecmp(vm_type, "hv")) {
return 1;
}
- if (!strcmp(vm_type, "PR")) {
+ if (!g_ascii_strcasecmp(vm_type, "pr")) {
return 2;
}
spapr->htab_fd = -1;
spapr->use_hotplug_event_source = true;
+ spapr->kvm_type = g_strdup(DEFAULT_KVM_TYPE);
object_property_add_str(obj, "kvm-type",
spapr_get_kvm_type, spapr_set_kvm_type);
object_property_set_description(obj, "kvm-type",
- "Specifies the KVM virtualization mode (HV, PR)");
+ "Specifies the KVM virtualization mode (auto,"
+ " hv, pr). Defaults to 'auto'. This mode will use"
+ " any available KVM module loaded in the host,"
+ " where kvm_hv takes precedence if both kvm_hv and"
+ " kvm_pr are loaded.");
object_property_add_bool(obj, "modern-hotplug-events",
spapr_get_modern_hotplug_events,
spapr_set_modern_hotplug_events);
return 0;
}
-static bool spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
- bool dedicated_hp_event_source, Error **errp)
+static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
+ bool dedicated_hp_event_source)
{
SpaprDrc *drc;
uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
addr / SPAPR_MEMORY_BLOCK_SIZE);
g_assert(drc);
- if (!spapr_drc_attach(drc, dev, errp)) {
- while (addr > addr_start) {
- addr -= SPAPR_MEMORY_BLOCK_SIZE;
- drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
- addr / SPAPR_MEMORY_BLOCK_SIZE);
- spapr_drc_detach(drc);
- }
- return false;
- }
+ /*
+ * memory_device_get_free_addr() provided a range of free addresses
+ * that doesn't overlap with any existing mapping at pre-plug. The
+ * corresponding LMB DRCs are thus assumed to be all attachable.
+ */
+ spapr_drc_attach(drc, dev);
if (!hotplugged) {
spapr_drc_reset(drc);
}
nr_lmbs);
}
}
- return true;
}
-static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
+static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
{
SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
if (!is_nvdimm) {
addr = object_property_get_uint(OBJECT(dimm),
PC_DIMM_ADDR_PROP, &error_abort);
- if (!spapr_add_lmbs(dev, addr, size,
- spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT), errp)) {
- goto out_unplug;
- }
+ spapr_add_lmbs(dev, addr, size,
+ spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT));
} else {
slot = object_property_get_int(OBJECT(dimm),
PC_DIMM_SLOT_PROP, &error_abort);
/* We should have valid slot number at this point */
g_assert(slot >= 0);
- if (!spapr_add_nvdimm(dev, slot, errp)) {
- goto out_unplug;
- }
+ spapr_add_nvdimm(dev, slot);
}
-
- return;
-
-out_unplug:
- pc_dimm_unplug(dimm, MACHINE(ms));
}
static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return 0;
}
-static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
+static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
{
SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
MachineClass *mc = MACHINE_GET_CLASS(spapr);
int i;
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
- if (!core_slot) {
- error_setg(errp, "Unable to find CPU core with core-id: %d",
- cc->core_id);
- return;
- }
+ g_assert(core_slot); /* Already checked in spapr_core_pre_plug() */
+
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
spapr_vcpu_id(spapr, cc->core_id));
g_assert(drc || !mc->has_hotpluggable_cpus);
if (drc) {
- if (!spapr_drc_attach(drc, dev, errp)) {
- return;
- }
+ /*
+ * spapr_core_pre_plug() already buys us this is a brand new
+ * core being plugged into a free slot. Nothing should already
+ * be attached to the corresponding DRC.
+ */
+ spapr_drc_attach(drc, dev);
if (hotplugged) {
/*
core_slot->cpu = OBJECT(dev);
- if (smc->pre_2_10_has_unused_icps) {
- for (i = 0; i < cc->nr_threads; i++) {
- cs = CPU(core->threads[i]);
- pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
- }
- }
-
/*
* Set compatibility mode to match the boot CPU, which was either set
- * by the machine reset code or by CAS.
+ * by the machine reset code or by CAS. This really shouldn't fail at
+ * this point.
*/
if (hotplugged) {
for (i = 0; i < cc->nr_threads; i++) {
- if (ppc_set_compat(core->threads[i],
- POWERPC_CPU(first_cpu)->compat_pvr,
- errp) < 0) {
- return;
- }
+ ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
+ &error_abort);
+ }
+ }
+
+ if (smc->pre_2_10_has_unused_icps) {
+ for (i = 0; i < cc->nr_threads; i++) {
+ cs = CPU(core->threads[i]);
+ pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
}
}
}
return 0;
}
-static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static bool spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
const unsigned windows_supported = spapr_phb_windows_supported(sphb);
+ SpaprDrc *drc;
if (dev->hotplugged && !smc->dr_phb_enabled) {
error_setg(errp, "PHB hotplug not supported for this machine");
- return;
+ return false;
}
if (sphb->index == (uint32_t)-1) {
error_setg(errp, "\"index\" for PAPR PHB is mandatory");
- return;
+ return false;
+ }
+
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
+ if (drc && drc->dev) {
+ error_setg(errp, "PHB %d already attached", sphb->index);
+ return false;
}
/*
* This will check that sphb->index doesn't exceed the maximum number of
* PHBs for the current machine type.
*/
- smc->phb_placement(spapr, sphb->index,
- &sphb->buid, &sphb->io_win_addr,
- &sphb->mem_win_addr, &sphb->mem64_win_addr,
- windows_supported, sphb->dma_liobn,
- &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
- errp);
+ return
+ smc->phb_placement(spapr, sphb->index,
+ &sphb->buid, &sphb->io_win_addr,
+ &sphb->mem_win_addr, &sphb->mem64_win_addr,
+ windows_supported, sphb->dma_liobn,
+ &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
+ errp);
}
-static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
+static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
{
SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
/* hotplug hooks should check it's enabled before getting this far */
assert(drc);
- if (!spapr_drc_attach(drc, dev, errp)) {
- return;
- }
+ /* spapr_phb_pre_plug() already checked the DRC is attachable */
+ spapr_drc_attach(drc, dev);
if (hotplugged) {
spapr_hotplug_req_add_by_index(drc);
}
}
-static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
+static
+bool spapr_tpm_proxy_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
- SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
if (spapr->tpm_proxy != NULL) {
error_setg(errp, "Only one TPM proxy can be specified for this machine");
- return;
+ return false;
}
+ return true;
+}
+
+static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
+
+ /* Already checked in spapr_tpm_proxy_pre_plug() */
+ g_assert(spapr->tpm_proxy == NULL);
+
spapr->tpm_proxy = tpm_proxy;
}
DeviceState *dev, Error **errp)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- spapr_memory_plug(hotplug_dev, dev, errp);
+ spapr_memory_plug(hotplug_dev, dev);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
- spapr_core_plug(hotplug_dev, dev, errp);
+ spapr_core_plug(hotplug_dev, dev);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
- spapr_phb_plug(hotplug_dev, dev, errp);
+ spapr_phb_plug(hotplug_dev, dev);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
- spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
+ spapr_tpm_proxy_plug(hotplug_dev, dev);
}
}
spapr_core_pre_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
spapr_phb_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_pre_plug(hotplug_dev, dev, errp);
}
}
return machine->possible_cpus;
}
-static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
+static bool spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns,
if (index >= SPAPR_MAX_PHBS) {
error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
SPAPR_MAX_PHBS - 1);
- return;
+ return false;
}
*buid = base_buid + index;
*nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
*nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
+ return true;
}
static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
/*
* pseries-4.0
*/
-static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
+static bool phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns,
hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
{
- spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma, liobns,
- nv2gpa, nv2atsd, errp);
+ if (!spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma,
+ liobns, nv2gpa, nv2atsd, errp)) {
+ return false;
+ }
+
*nv2gpa = 0;
*nv2atsd = 0;
+ return true;
}
-
static void spapr_machine_4_0_class_options(MachineClass *mc)
{
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
* pseries-2.7
*/
-static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
+static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns,
if (index > max_index) {
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
max_index);
- return;
+ return false;
}
*buid = base_buid + index;
*nv2gpa = 0;
*nv2atsd = 0;
+ return true;
}
static void spapr_machine_2_7_class_options(MachineClass *mc)
} while (fdt_depth != 0);
}
-bool spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp)
+void spapr_drc_attach(SpaprDrc *drc, DeviceState *d)
{
trace_spapr_drc_attach(spapr_drc_index(drc));
- if (drc->dev) {
- error_setg(errp, "an attached device is still awaiting release");
- return false;
- }
+ g_assert(!drc->dev);
g_assert((drc->state == SPAPR_DRC_STATE_LOGICAL_UNUSABLE)
|| (drc->state == SPAPR_DRC_STATE_PHYSICAL_POWERON));
object_get_typename(OBJECT(drc->dev)),
(Object **)(&drc->dev),
NULL, 0);
- return true;
}
static void spapr_drc_release(SpaprDrc *drc)
return entry;
}
-static bool rtas_event_log_contains(uint32_t event_mask)
+static bool rtas_event_log_contains(SpaprMachineState *spapr, uint32_t event_mask)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
SpaprEventLogEntry *entry = NULL;
QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM);
}
-static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
+static void spapr_init_maina(SpaprMachineState *spapr,
+ struct rtas_event_log_v6_maina *maina,
int section_count)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
struct tm tm;
int year;
entry->extended_length = sizeof(*new_epow);
spapr_init_v6hdr(v6hdr);
- spapr_init_maina(maina, 3 /* Main-A, Main-B and EPOW */);
+ spapr_init_maina(spapr, maina, 3 /* Main-A, Main-B and EPOW */);
mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
entry->extended_length = sizeof(*new_hp);
spapr_init_v6hdr(v6hdr);
- spapr_init_maina(maina, 3 /* Main-A, Main-B, HP */);
+ spapr_init_maina(spapr, maina, 3 /* Main-A, Main-B, HP */);
mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
return summary;
}
-static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
+static void spapr_mce_dispatch_elog(SpaprMachineState *spapr, PowerPCCPU *cpu,
+ bool recovered)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
uint64_t rtas_addr;
warn_report("Received a fwnmi while migration was in progress");
}
- spapr_mce_dispatch_elog(cpu, recovered);
+ spapr_mce_dispatch_elog(spapr, cpu, recovered);
}
static void check_exception(PowerPCCPU *cpu, SpaprMachineState *spapr,
* interrupts.
*/
for (i = 0; i < EVENT_CLASS_MAX; i++) {
- if (rtas_event_log_contains(EVENT_CLASS_MASK(i))) {
+ if (rtas_event_log_contains(spapr, EVENT_CLASS_MASK(i))) {
const SpaprEventSource *source =
spapr_event_sources_get_source(spapr->event_sources, i);
}
for (i = 0; i < EVENT_CLASS_MAX; i++) {
- if (rtas_event_log_contains(EVENT_CLASS_MASK(i))) {
+ if (rtas_event_log_contains(spapr, EVENT_CLASS_MASK(i))) {
const SpaprEventSource *source =
spapr_event_sources_get_source(spapr->event_sources, i);
}
static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
target_ulong mflags,
target_ulong value1,
target_ulong value2)
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
spapr_set_all_lpcrs(0, LPCR_ILE);
- spapr_pci_switch_vga(true);
+ spapr_pci_switch_vga(spapr, true);
return H_SUCCESS;
case H_SET_MODE_ENDIAN_LITTLE:
spapr_set_all_lpcrs(LPCR_ILE, LPCR_ILE);
- spapr_pci_switch_vga(false);
+ spapr_pci_switch_vga(spapr, false);
return H_SUCCESS;
}
switch (resource) {
case H_SET_MODE_RESOURCE_LE:
- ret = h_set_mode_resource_le(cpu, args[0], args[2], args[3]);
+ ret = h_set_mode_resource_le(cpu, spapr, args[0], args[2], args[3]);
break;
case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE:
ret = h_set_mode_resource_addr_trans_mode(cpu, args[0],
if (kvm_enabled() &&
spapr->irq == &spapr_irq_dual &&
kvm_kernel_irqchip_required() &&
- xics_kvm_has_broken_disconnect(spapr)) {
+ xics_kvm_has_broken_disconnect()) {
error_setg(errp,
"KVM is incompatible with ic-mode=dual,kernel-irqchip=on");
error_append_hint(errp,
}
-bool spapr_add_nvdimm(DeviceState *dev, uint64_t slot, Error **errp)
+void spapr_add_nvdimm(DeviceState *dev, uint64_t slot)
{
SpaprDrc *drc;
bool hotplugged = spapr_drc_hotplugged(dev);
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot);
g_assert(drc);
- if (!spapr_drc_attach(drc, dev, errp)) {
- return false;
- }
+ /*
+ * pc_dimm_get_free_slot() provided a free slot at pre-plug. The
+ * corresponding DRC is thus assumed to be attachable.
+ */
+ spapr_drc_attach(drc, dev);
if (hotplugged) {
spapr_hotplug_req_add_by_index(drc);
}
- return true;
}
static int spapr_dt_nvdimm(SpaprMachineState *spapr, void *fdt,
static void spapr_msi_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = opaque;
uint32_t irq = data;
trace_spapr_pci_msi_write(addr, data, irq);
return true;
}
-static void spapr_pci_plug(HotplugHandler *plug_handler,
- DeviceState *plugged_dev, Error **errp)
+static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
{
SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
- /* if DR is disabled we don't need to do anything in the case of
- * hotplug or coldplug callbacks
- */
if (!phb->dr_enabled) {
/* if this is a hotplug operation initiated by the user
* we need to let them know it's not enabled
if (plugged_dev->hotplugged) {
error_setg(errp, QERR_BUS_NO_HOTPLUG,
object_get_typename(OBJECT(phb)));
+ return;
}
- return;
}
- g_assert(drc);
-
if (pc->is_bridge) {
if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) {
return;
}
- spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev));
}
/* Following the QEMU convention used for PCIe multifunction
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" additional functions can no longer be exposed to guest.",
slotnr, bus->devices[PCI_DEVFN(slotnr, 0)]->name);
+ }
+
+ if (drc && drc->dev) {
+ error_setg(errp, "PCI: slot %d already occupied by %s", slotnr,
+ pci_get_function_0(PCI_DEVICE(drc->dev))->name);
return;
}
+}
+
+static void spapr_pci_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
+{
+ SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
+ PCIDevice *pdev = PCI_DEVICE(plugged_dev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev);
+ SpaprDrc *drc = drc_from_dev(phb, pdev);
+ uint32_t slotnr = PCI_SLOT(pdev->devfn);
- if (!spapr_drc_attach(drc, DEVICE(pdev), errp)) {
+ /*
+ * If DR is disabled we don't need to do anything in the case of
+ * hotplug or coldplug callbacks.
+ */
+ if (!phb->dr_enabled) {
return;
}
+ g_assert(drc);
+
+ if (pc->is_bridge) {
+ spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev));
+ }
+
+ /* spapr_pci_pre_plug() already checked the DRC is attachable */
+ spapr_drc_attach(drc, DEVICE(pdev));
+
/* If this is function 0, signal hotplug for all the device functions.
* Otherwise defer sending the hotplug event.
*/
/* Supported by TYPE_SPAPR_MACHINE */
dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ hp->pre_plug = spapr_pci_pre_plug;
hp->plug = spapr_pci_plug;
hp->unplug = spapr_pci_unplug;
hp->unplug_request = spapr_pci_unplug_request;
return 0;
}
-void spapr_pci_switch_vga(bool big_endian)
+void spapr_pci_switch_vga(SpaprMachineState *spapr, bool big_endian)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
SpaprPhbState *sphb;
/*
spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
# spapr_tpm_proxy.c
-spapr_h_tpm_comm(const char *device_path, uint64_t operation) "tpm_device_path=%s operation=0x%"PRIu64
+spapr_h_tpm_comm(const char *device_path, uint64_t operation) "tpm_device_path=%s operation=0x%"PRIx64
spapr_tpm_execute(uint64_t data_in, uint64_t data_in_sz, uint64_t data_out, uint64_t data_out_sz) "data_in=0x%"PRIx64", data_in_sz=%"PRIu64", data_out=0x%"PRIx64", data_out_sz=%"PRIu64
# spapr_iommu.c
/* Definitions for MIPS CPU internal devices. */
-/* addr.c */
-uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
-uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
-uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr);
-bool mips_um_ksegs_enabled(void);
-void mips_um_ksegs_enable(void);
-
/* mips_int.c */
void cpu_mips_irq_init_cpu(MIPSCPU *cpu);
bool pre_5_1_assoc_refpoints;
bool pre_5_2_numa_associativity;
- void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
+ bool (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns, hwaddr *nv2gpa,
uint32_t liobn, uint64_t window, uint32_t size);
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
SpaprTceTable *tcet);
-void spapr_pci_switch_vga(bool big_endian);
+void spapr_pci_switch_vga(SpaprMachineState *spapr, bool big_endian);
void spapr_hotplug_req_add_by_index(SpaprDrc *drc);
void spapr_hotplug_req_remove_by_index(SpaprDrc *drc);
void spapr_hotplug_req_add_by_count(SpaprDrcType drc_type,
SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id);
int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask);
-bool spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp);
+/*
+ * These functions respectively abort if called with a device already
+ * attached or no device attached. In the case of spapr_drc_attach(),
+ * this means that the attachability of the DRC *must* be checked
+ * beforehand (eg. check drc->dev at pre-plug).
+ */
+void spapr_drc_attach(SpaprDrc *drc, DeviceState *d);
void spapr_drc_detach(SpaprDrc *drc);
/* Returns true if a hot plug/unplug request is pending */
void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt);
bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
uint64_t size, Error **errp);
-bool spapr_add_nvdimm(DeviceState *dev, uint64_t slot, Error **errp);
+void spapr_add_nvdimm(DeviceState *dev, uint64_t slot);
#endif
int xics_kvm_connect(SpaprInterruptController *intc, uint32_t nr_servers,
Error **errp);
void xics_kvm_disconnect(SpaprInterruptController *intc);
-bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr);
+bool xics_kvm_has_broken_disconnect(void);
#endif /* XICS_SPAPR_H */
--- /dev/null
+/*
+ * QEMU MIPS address translation support
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+
+static int mips_um_ksegs;
+
+uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
+{
+ return addr & 0x1fffffffll;
+}
+
+uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
+{
+ return addr | ~0x7fffffffll;
+}
+
+uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
+{
+ return addr | 0x40000000ll;
+}
+
+bool mips_um_ksegs_enabled(void)
+{
+ return mips_um_ksegs;
+}
+
+void mips_um_ksegs_enable(void)
+{
+ mips_um_ksegs = 1;
+}
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "cpu.h"
#include "internal.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "exec/memop.h"
-#include "sysemu/kvm.h"
-#ifndef CONFIG_USER_ONLY
/* SMP helpers. */
static bool mips_vpe_is_wfi(MIPSCPU *c)
{
goto invalid;
}
/* We don't support VTLB entry smaller than target page */
- if ((maskbits + 12) < TARGET_PAGE_BITS) {
+ if ((maskbits + TARGET_PAGE_BITS_MIN) < TARGET_PAGE_BITS) {
goto invalid;
}
env->CP0_PageMask = mask << CP0PM_MASK;
invalid:
/* When invalid, set to default target page size. */
- env->CP0_PageMask = (~TARGET_PAGE_MASK >> 12) << CP0PM_MASK;
+ mask = (~TARGET_PAGE_MASK >> TARGET_PAGE_BITS_MIN);
+ env->CP0_PageMask = mask << CP0PM_MASK;
}
void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
old = env->CP0_EntryHi;
val = (arg1 & mask) | (old & ~mask);
env->CP0_EntryHi = val;
- if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+ if (ase_mt_available(env)) {
sync_c0_entryhi(env, env->current_tc);
}
/* If the ASID changes, flush qemu's TLB. */
}
return prev;
}
-#endif /* !CONFIG_USER_ONLY */
/* R6 Multi-threading */
-#ifndef CONFIG_USER_ONLY
target_ulong helper_dvp(CPUMIPSState *env)
{
CPUState *other_cs = first_cpu;
}
return prev;
}
-#endif /* !CONFIG_USER_ONLY */
#include "qemu/osdep.h"
#include "qemu/cutils.h"
+#include "qemu/qemu-print.h"
#include "qapi/error.h"
#include "cpu.h"
#include "internal.h"
#include "exec/exec-all.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-clock.h"
+#include "hw/semihosting/semihost.h"
+#include "qapi/qapi-commands-machine-target.h"
static void mips_cpu_set_pc(CPUState *cs, vaddr value)
{
}
/* MIPS-MT has the ability to halt the CPU. */
- if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+ if (ase_mt_available(env)) {
/*
* The QEMU model will issue an _WAKE request whenever the CPUs
* should be woken up.
return has_work;
}
+#include "translate_init.c.inc"
+
+/* TODO QOM'ify CPU reset and remove */
+static void cpu_state_reset(CPUMIPSState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ /* Reset registers to their default values */
+ env->CP0_PRid = env->cpu_model->CP0_PRid;
+ env->CP0_Config0 = env->cpu_model->CP0_Config0;
+#ifdef TARGET_WORDS_BIGENDIAN
+ env->CP0_Config0 |= (1 << CP0C0_BE);
+#endif
+ env->CP0_Config1 = env->cpu_model->CP0_Config1;
+ env->CP0_Config2 = env->cpu_model->CP0_Config2;
+ env->CP0_Config3 = env->cpu_model->CP0_Config3;
+ env->CP0_Config4 = env->cpu_model->CP0_Config4;
+ env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask;
+ env->CP0_Config5 = env->cpu_model->CP0_Config5;
+ env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
+ env->CP0_Config6 = env->cpu_model->CP0_Config6;
+ env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
+ env->CP0_Config7 = env->cpu_model->CP0_Config7;
+ env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
+ env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
+ << env->cpu_model->CP0_LLAddr_shift;
+ env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
+ env->SYNCI_Step = env->cpu_model->SYNCI_Step;
+ env->CCRes = env->cpu_model->CCRes;
+ env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
+ env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
+ env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
+ env->current_tc = 0;
+ env->SEGBITS = env->cpu_model->SEGBITS;
+ env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
+#if defined(TARGET_MIPS64)
+ if (env->cpu_model->insn_flags & ISA_MIPS3) {
+ env->SEGMask |= 3ULL << 62;
+ }
+#endif
+ env->PABITS = env->cpu_model->PABITS;
+ env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
+ env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
+ env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
+ env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
+ env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
+ env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
+ env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
+ env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
+ env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
+ env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
+ env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
+ env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
+ env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
+ env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
+ env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
+ env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
+ env->msair = env->cpu_model->MSAIR;
+ env->insn_flags = env->cpu_model->insn_flags;
+
+#if defined(CONFIG_USER_ONLY)
+ env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
+# ifdef TARGET_MIPS64
+ /* Enable 64-bit register mode. */
+ env->CP0_Status |= (1 << CP0St_PX);
+# endif
+# ifdef TARGET_ABI_MIPSN64
+ /* Enable 64-bit address mode. */
+ env->CP0_Status |= (1 << CP0St_UX);
+# endif
+ /*
+ * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
+ * hardware registers.
+ */
+ env->CP0_HWREna |= 0x0000000F;
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ env->CP0_Status |= (1 << CP0St_CU1);
+ }
+ if (env->CP0_Config3 & (1 << CP0C3_DSPP)) {
+ env->CP0_Status |= (1 << CP0St_MX);
+ }
+# if defined(TARGET_MIPS64)
+ /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */
+ if ((env->CP0_Config1 & (1 << CP0C1_FP)) &&
+ (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
+ env->CP0_Status |= (1 << CP0St_FR);
+ }
+# endif
+#else /* !CONFIG_USER_ONLY */
+ if (env->hflags & MIPS_HFLAG_BMASK) {
+ /*
+ * If the exception was raised from a delay slot,
+ * come back to the jump.
+ */
+ env->CP0_ErrorEPC = (env->active_tc.PC
+ - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4));
+ } else {
+ env->CP0_ErrorEPC = env->active_tc.PC;
+ }
+ env->active_tc.PC = env->exception_base;
+ env->CP0_Random = env->tlb->nb_tlb - 1;
+ env->tlb->tlb_in_use = env->tlb->nb_tlb;
+ env->CP0_Wired = 0;
+ env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
+ env->CP0_EBase = (cs->cpu_index & 0x3FF);
+ if (mips_um_ksegs_enabled()) {
+ env->CP0_EBase |= 0x40000000;
+ } else {
+ env->CP0_EBase |= (int32_t)0x80000000;
+ }
+ if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) {
+ env->CP0_CMGCRBase = 0x1fbf8000 >> 4;
+ }
+ env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
+ 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
+ env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
+ /*
+ * Vectored interrupts not implemented, timer on int 7,
+ * no performance counters.
+ */
+ env->CP0_IntCtl = 0xe0000000;
+ {
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ env->CP0_WatchLo[i] = 0;
+ env->CP0_WatchHi[i] = 0x80000000;
+ }
+ env->CP0_WatchLo[7] = 0;
+ env->CP0_WatchHi[7] = 0;
+ }
+ /* Count register increments in debug mode, EJTAG version 1 */
+ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
+
+ cpu_mips_store_count(env, 1);
+
+ if (ase_mt_available(env)) {
+ int i;
+
+ /* Only TC0 on VPE 0 starts as active. */
+ for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
+ env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE;
+ env->tcs[i].CP0_TCHalt = 1;
+ }
+ env->active_tc.CP0_TCHalt = 1;
+ cs->halted = 1;
+
+ if (cs->cpu_index == 0) {
+ /* VPE0 starts up enabled. */
+ env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
+ env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
+
+ /* TC0 starts up unhalted. */
+ cs->halted = 0;
+ env->active_tc.CP0_TCHalt = 0;
+ env->tcs[0].CP0_TCHalt = 0;
+ /* With thread 0 active. */
+ env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
+ env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
+ }
+ }
+
+ /*
+ * Configure default legacy segmentation control. We use this regardless of
+ * whether segmentation control is presented to the guest.
+ */
+ /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */
+ env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM);
+ /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */
+ env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16;
+ /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */
+ env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
+ (2 << CP0SC_C);
+ /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */
+ env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
+ (3 << CP0SC_C)) << 16;
+ /* USeg (seg4 0x40000000..0x7FFFFFFF) */
+ env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
+ (1 << CP0SC_EU) | (2 << CP0SC_C);
+ /* USeg (seg5 0x00000000..0x3FFFFFFF) */
+ env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
+ (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16;
+ /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */
+ env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM);
+#endif /* !CONFIG_USER_ONLY */
+ if ((env->insn_flags & ISA_MIPS32R6) &&
+ (env->active_fpu.fcr0 & (1 << FCR0_F64))) {
+ /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */
+ env->CP0_Status |= (1 << CP0St_FR);
+ }
+
+ if (env->insn_flags & ISA_MIPS32R6) {
+ /* PTW = 1 */
+ env->CP0_PWSize = 0x40;
+ /* GDI = 12 */
+ /* UDI = 12 */
+ /* MDI = 12 */
+ /* PRI = 12 */
+ /* PTEI = 2 */
+ env->CP0_PWField = 0x0C30C302;
+ } else {
+ /* GDI = 0 */
+ /* UDI = 0 */
+ /* MDI = 0 */
+ /* PRI = 0 */
+ /* PTEI = 2 */
+ env->CP0_PWField = 0x02;
+ }
+
+ if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) {
+ /* microMIPS on reset when Config3.ISA is 3 */
+ env->hflags |= MIPS_HFLAG_M16;
+ }
+
+ /* MSA */
+ if (env->CP0_Config3 & (1 << CP0C3_MSAP)) {
+ msa_reset(env);
+ }
+
+ compute_hflags(env);
+ restore_fp_status(env);
+ restore_pamask(env);
+ cs->exception_index = EXCP_NONE;
+
+ if (semihosting_get_argc()) {
+ /* UHI interface can be used to obtain argc and argv */
+ env->active_tc.gpr[4] = -1;
+ }
+}
+
static void mips_cpu_reset(DeviceState *dev)
{
CPUState *s = CPU(dev);
{
CPUState *cs = CPU(dev);
MIPSCPU *cpu = MIPS_CPU(dev);
+ CPUMIPSState *env = &cpu->env;
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
Error *local_err = NULL;
return;
}
- cpu_mips_realize_env(&cpu->env);
+ env->exception_base = (int32_t)0xBFC00000;
+
+#ifndef CONFIG_USER_ONLY
+ mmu_init(env, env->cpu_model);
+#endif
+ fpu_init(env, env->cpu_model);
+ mvp_init(env);
cpu_reset(cs);
qemu_init_vcpu(cs);
type_init(mips_cpu_register_types)
+static void mips_cpu_add_definition(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CpuDefinitionInfoList **cpu_list = user_data;
+ CpuDefinitionInfoList *entry;
+ CpuDefinitionInfo *info;
+ const char *typename;
+
+ typename = object_class_get_name(oc);
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strndup(typename,
+ strlen(typename) - strlen("-" TYPE_MIPS_CPU));
+ info->q_typename = g_strdup(typename);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = *cpu_list;
+ *cpu_list = entry;
+}
+
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+ CpuDefinitionInfoList *cpu_list = NULL;
+ GSList *list;
+
+ list = object_class_get_list(TYPE_MIPS_CPU, false);
+ g_slist_foreach(list, mips_cpu_add_definition, &cpu_list);
+ g_slist_free(list);
+
+ return cpu_list;
+}
+
/* Could be used by generic CPU object */
MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
{
return MIPS_CPU(cpu);
}
+
+bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask)
+{
+ return (env->cpu_model->insn_flags & isa_mask) != 0;
+}
+
+bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa)
+{
+ const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
+ return (mcc->cpu_def->insn_flags & isa) != 0;
+}
+
+bool cpu_type_supports_cps_smp(const char *cpu_type)
+{
+ const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
+ return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
+}
+
+void cpu_set_exception_base(int vp_index, target_ulong address)
+{
+ MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
+ vp->env.exception_base = address;
+}
#define MIPS_CPU_TYPE_NAME(model) model MIPS_CPU_TYPE_SUFFIX
#define CPU_RESOLVING_TYPE TYPE_MIPS_CPU
-bool cpu_supports_cps_smp(const char *cpu_type);
-bool cpu_supports_isa(const char *cpu_type, uint64_t isa);
+bool cpu_type_supports_cps_smp(const char *cpu_type);
+bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask);
+bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa);
+
+/* Check presence of multi-threading ASE implementation */
+static inline bool ase_mt_available(CPUMIPSState *env)
+{
+ return env->CP0_Config3 & (1 << CP0C3_MT);
+}
+
void cpu_set_exception_base(int vp_index, target_ulong address);
+/* addr.c */
+uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
+uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
+
+uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr);
+bool mips_um_ksegs_enabled(void);
+void mips_um_ksegs_enable(void);
+
/* mips_int.c */
void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level);
*/
#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
#include "cpu.h"
#include "internal.h"
-#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
-#include "exec/memop.h"
-#include "sysemu/kvm.h"
#include "fpu/softfloat.h"
#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
/* convert MIPS rounding mode in FCR31 to IEEE library */
-unsigned int ieee_rm[] = {
+const FloatRoundMode ieee_rm[4] = {
float_round_nearest_even,
float_round_to_zero,
float_round_up,
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "hw/mips/cpudevs.h"
-#include "qapi/qapi-commands-machine-target.h"
enum {
TLBRET_XI = -6,
tlb_flush(env_cpu(env));
}
#endif
- if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+ if (ase_mt_available(env)) {
sync_c0_status(env, env, env->current_tc);
} else {
compute_hflags(env);
break;
}
}
- pw_pagemask = m >> 12;
- update_pagemask(env, pw_pagemask << 13, &pw_pagemask);
+ pw_pagemask = m >> TARGET_PAGE_BITS_MIN;
+ update_pagemask(env, pw_pagemask << CP0PM_MASK, &pw_pagemask);
pw_entryhi = (address & ~0x1fff) | (env->CP0_EntryHi & 0xFF);
{
target_ulong tmp_entryhi = env->CP0_EntryHi;
return physical;
}
}
+#endif /* !CONFIG_USER_ONLY */
static const char * const excp_names[EXCP_LAST + 1] = {
[EXCP_RESET] = "reset",
[EXCP_MSADIS] = "MSA disabled",
[EXCP_MSAFPE] = "MSA floating point",
};
-#endif
+
+static const char *mips_exception_name(int32_t exception)
+{
+ if (exception < 0 || exception > EXCP_LAST) {
+ return "unknown";
+ }
+ return excp_names[exception];
+}
target_ulong exception_resume_pc(CPUMIPSState *env)
{
bool update_badinstr = 0;
target_ulong offset;
int cause = -1;
- const char *name;
if (qemu_loglevel_mask(CPU_LOG_INT)
&& cs->exception_index != EXCP_EXT_INTERRUPT) {
- if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) {
- name = "unknown";
- } else {
- name = excp_names[cs->exception_index];
- }
-
qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx
" %s exception\n",
- __func__, env->active_tc.PC, env->CP0_EPC, name);
+ __func__, env->active_tc.PC, env->CP0_EPC,
+ mips_exception_name(cs->exception_index));
}
if (cs->exception_index == EXCP_EXT_INTERRUPT &&
(env->hflags & MIPS_HFLAG_DM)) {
{
CPUState *cs = env_cpu(env);
- qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n",
- __func__, exception, error_code);
+ qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n",
+ __func__, exception, mips_exception_name(exception),
+ error_code);
cs->exception_index = exception;
env->error_code = error_code;
cpu_loop_exit_restore(cs, pc);
}
-
-static void mips_cpu_add_definition(gpointer data, gpointer user_data)
-{
- ObjectClass *oc = data;
- CpuDefinitionInfoList **cpu_list = user_data;
- CpuDefinitionInfoList *entry;
- CpuDefinitionInfo *info;
- const char *typename;
-
- typename = object_class_get_name(oc);
- info = g_malloc0(sizeof(*info));
- info->name = g_strndup(typename,
- strlen(typename) - strlen("-" TYPE_MIPS_CPU));
- info->q_typename = g_strdup(typename);
-
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = *cpu_list;
- *cpu_list = entry;
-}
-
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
-{
- CpuDefinitionInfoList *cpu_list = NULL;
- GSList *list;
-
- list = object_class_get_list(TYPE_MIPS_CPU, false);
- g_slist_foreach(list, mips_cpu_add_definition, &cpu_list);
- g_slist_free(list);
-
- return cpu_list;
-}
#ifndef MIPS_INTERNAL_H
#define MIPS_INTERNAL_H
+#include "exec/memattrs.h"
#include "fpu/softfloat-helpers.h"
/*
* CP0C0_MT field.
*/
enum mips_mmu_types {
- MMU_TYPE_NONE,
- MMU_TYPE_R4000,
- MMU_TYPE_RESERVED,
- MMU_TYPE_FMT,
+ MMU_TYPE_NONE = 0,
+ MMU_TYPE_R4000 = 1, /* Standard TLB */
+ MMU_TYPE_BAT = 2, /* Block Address Translation */
+ MMU_TYPE_FMT = 3, /* Fixed Mapping */
+ MMU_TYPE_DVF = 4, /* Dual VTLB and FTLB */
MMU_TYPE_R3000,
MMU_TYPE_R6000,
MMU_TYPE_R8000
void mips_tcg_init(void);
-/* TODO QOM'ify CPU reset and remove */
-void cpu_state_reset(CPUMIPSState *s);
-void cpu_mips_realize_env(CPUMIPSState *env);
-
/* cp0_timer.c */
uint32_t cpu_mips_get_count(CPUMIPSState *env);
void cpu_mips_store_count(CPUMIPSState *env, uint32_t value);
uint32_t float_class_s(uint32_t arg, float_status *fst);
uint64_t float_class_d(uint64_t arg, float_status *fst);
-extern unsigned int ieee_rm[];
+extern const FloatRoundMode ieee_rm[4];
+
void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
static inline void restore_rounding_mode(CPUMIPSState *env)
#include "internal.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
-#include "qemu/timer.h"
#include "sysemu/kvm.h"
#include "sysemu/kvm_int.h"
#include "sysemu/runstate.h"
-#include "sysemu/cpus.h"
#include "kvm_mips.h"
-#include "exec/memattrs.h"
#include "hw/boards.h"
#define DEBUG_KVM 0
CPUState *cs = CPU(cpu);
struct kvm_mips_interrupt intr;
- if (!kvm_enabled()) {
- return 0;
- }
+ assert(kvm_enabled());
intr.cpu = -1;
CPUState *dest_cs = CPU(cpu);
struct kvm_mips_interrupt intr;
- if (!kvm_enabled()) {
- return 0;
- }
+ assert(kvm_enabled());
intr.cpu = dest_cs->cpu_index;
mips_ss = ss.source_set()
mips_ss.add(files(
- 'cp0_helper.c',
'cpu.c',
'dsp_helper.c',
'fpu_helper.c',
mips_softmmu_ss = ss.source_set()
mips_softmmu_ss.add(files(
+ 'addr.c',
+ 'cp0_helper.c',
'cp0_timer.c',
'machine.c',
'mips-semi.c',
*/
#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
#include "cpu.h"
#include "internal.h"
-#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
#include "exec/memop.h"
-#include "sysemu/kvm.h"
/*****************************************************************************/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
-#include "disas/disas.h"
-#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "exec/cpu_ldst.h"
-#include "hw/mips/cpudevs.h"
-
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "hw/semihosting/semihost.h"
#endif
}
-#include "translate_init.c.inc"
-
-void cpu_mips_realize_env(CPUMIPSState *env)
-{
- env->exception_base = (int32_t)0xBFC00000;
-
-#ifndef CONFIG_USER_ONLY
- mmu_init(env, env->cpu_model);
-#endif
- fpu_init(env, env->cpu_model);
- mvp_init(env, env->cpu_model);
-}
-
-bool cpu_supports_cps_smp(const char *cpu_type)
-{
- const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
- return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
-}
-
-bool cpu_supports_isa(const char *cpu_type, uint64_t isa)
-{
- const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
- return (mcc->cpu_def->insn_flags & isa) != 0;
-}
-
-void cpu_set_exception_base(int vp_index, target_ulong address)
-{
- MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
- vp->env.exception_base = address;
-}
-
-void cpu_state_reset(CPUMIPSState *env)
-{
- CPUState *cs = env_cpu(env);
-
- /* Reset registers to their default values */
- env->CP0_PRid = env->cpu_model->CP0_PRid;
- env->CP0_Config0 = env->cpu_model->CP0_Config0;
-#ifdef TARGET_WORDS_BIGENDIAN
- env->CP0_Config0 |= (1 << CP0C0_BE);
-#endif
- env->CP0_Config1 = env->cpu_model->CP0_Config1;
- env->CP0_Config2 = env->cpu_model->CP0_Config2;
- env->CP0_Config3 = env->cpu_model->CP0_Config3;
- env->CP0_Config4 = env->cpu_model->CP0_Config4;
- env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask;
- env->CP0_Config5 = env->cpu_model->CP0_Config5;
- env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
- env->CP0_Config6 = env->cpu_model->CP0_Config6;
- env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
- env->CP0_Config7 = env->cpu_model->CP0_Config7;
- env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
- env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
- << env->cpu_model->CP0_LLAddr_shift;
- env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
- env->SYNCI_Step = env->cpu_model->SYNCI_Step;
- env->CCRes = env->cpu_model->CCRes;
- env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
- env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
- env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
- env->current_tc = 0;
- env->SEGBITS = env->cpu_model->SEGBITS;
- env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
-#if defined(TARGET_MIPS64)
- if (env->cpu_model->insn_flags & ISA_MIPS3) {
- env->SEGMask |= 3ULL << 62;
- }
-#endif
- env->PABITS = env->cpu_model->PABITS;
- env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
- env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
- env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
- env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
- env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
- env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
- env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
- env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
- env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
- env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
- env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
- env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
- env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
- env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
- env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
- env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
- env->msair = env->cpu_model->MSAIR;
- env->insn_flags = env->cpu_model->insn_flags;
-
-#if defined(CONFIG_USER_ONLY)
- env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
-# ifdef TARGET_MIPS64
- /* Enable 64-bit register mode. */
- env->CP0_Status |= (1 << CP0St_PX);
-# endif
-# ifdef TARGET_ABI_MIPSN64
- /* Enable 64-bit address mode. */
- env->CP0_Status |= (1 << CP0St_UX);
-# endif
- /*
- * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
- * hardware registers.
- */
- env->CP0_HWREna |= 0x0000000F;
- if (env->CP0_Config1 & (1 << CP0C1_FP)) {
- env->CP0_Status |= (1 << CP0St_CU1);
- }
- if (env->CP0_Config3 & (1 << CP0C3_DSPP)) {
- env->CP0_Status |= (1 << CP0St_MX);
- }
-# if defined(TARGET_MIPS64)
- /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */
- if ((env->CP0_Config1 & (1 << CP0C1_FP)) &&
- (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
- env->CP0_Status |= (1 << CP0St_FR);
- }
-# endif
-#else
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /*
- * If the exception was raised from a delay slot,
- * come back to the jump.
- */
- env->CP0_ErrorEPC = (env->active_tc.PC
- - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4));
- } else {
- env->CP0_ErrorEPC = env->active_tc.PC;
- }
- env->active_tc.PC = env->exception_base;
- env->CP0_Random = env->tlb->nb_tlb - 1;
- env->tlb->tlb_in_use = env->tlb->nb_tlb;
- env->CP0_Wired = 0;
- env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
- env->CP0_EBase = (cs->cpu_index & 0x3FF);
- if (mips_um_ksegs_enabled()) {
- env->CP0_EBase |= 0x40000000;
- } else {
- env->CP0_EBase |= (int32_t)0x80000000;
- }
- if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) {
- env->CP0_CMGCRBase = 0x1fbf8000 >> 4;
- }
- env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
- 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
- env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
- /*
- * Vectored interrupts not implemented, timer on int 7,
- * no performance counters.
- */
- env->CP0_IntCtl = 0xe0000000;
- {
- int i;
-
- for (i = 0; i < 7; i++) {
- env->CP0_WatchLo[i] = 0;
- env->CP0_WatchHi[i] = 0x80000000;
- }
- env->CP0_WatchLo[7] = 0;
- env->CP0_WatchHi[7] = 0;
- }
- /* Count register increments in debug mode, EJTAG version 1 */
- env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
-
- cpu_mips_store_count(env, 1);
-
- if (env->CP0_Config3 & (1 << CP0C3_MT)) {
- int i;
-
- /* Only TC0 on VPE 0 starts as active. */
- for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
- env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE;
- env->tcs[i].CP0_TCHalt = 1;
- }
- env->active_tc.CP0_TCHalt = 1;
- cs->halted = 1;
-
- if (cs->cpu_index == 0) {
- /* VPE0 starts up enabled. */
- env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
- env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
-
- /* TC0 starts up unhalted. */
- cs->halted = 0;
- env->active_tc.CP0_TCHalt = 0;
- env->tcs[0].CP0_TCHalt = 0;
- /* With thread 0 active. */
- env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
- env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
- }
- }
-
- /*
- * Configure default legacy segmentation control. We use this regardless of
- * whether segmentation control is presented to the guest.
- */
- /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */
- env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM);
- /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */
- env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16;
- /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */
- env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
- (2 << CP0SC_C);
- /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */
- env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
- (3 << CP0SC_C)) << 16;
- /* USeg (seg4 0x40000000..0x7FFFFFFF) */
- env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
- (1 << CP0SC_EU) | (2 << CP0SC_C);
- /* USeg (seg5 0x00000000..0x3FFFFFFF) */
- env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
- (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16;
- /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */
- env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM);
-#endif
- if ((env->insn_flags & ISA_MIPS32R6) &&
- (env->active_fpu.fcr0 & (1 << FCR0_F64))) {
- /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */
- env->CP0_Status |= (1 << CP0St_FR);
- }
-
- if (env->insn_flags & ISA_MIPS32R6) {
- /* PTW = 1 */
- env->CP0_PWSize = 0x40;
- /* GDI = 12 */
- /* UDI = 12 */
- /* MDI = 12 */
- /* PRI = 12 */
- /* PTEI = 2 */
- env->CP0_PWField = 0x0C30C302;
- } else {
- /* GDI = 0 */
- /* UDI = 0 */
- /* MDI = 0 */
- /* PRI = 0 */
- /* PTEI = 2 */
- env->CP0_PWField = 0x02;
- }
-
- if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) {
- /* microMIPS on reset when Config3.ISA is 3 */
- env->hflags |= MIPS_HFLAG_M16;
- }
-
- /* MSA */
- if (env->CP0_Config3 & (1 << CP0C3_MSAP)) {
- msa_reset(env);
- }
-
- compute_hflags(env);
- restore_fp_status(env);
- restore_pamask(env);
- cs->exception_index = EXCP_NONE;
-
- if (semihosting_get_argc()) {
- /* UHI interface can be used to obtain argc and argv */
- env->active_tc.gpr[4] = -1;
- }
-}
-
void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb,
target_ulong *data)
{
.mmu_type = MMU_TYPE_R4000,
},
{
- .name = "Loongson-3A4000",
+ .name = "Loongson-3A4000", /* GS464V-based */
.CP0_PRid = 0x14C000,
/* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 48,
.PABITS = 48,
- .insn_flags = CPU_LOONGSON3A,
+ .insn_flags = CPU_LOONGSON3A | ASE_MSA,
.mmu_type = MMU_TYPE_R4000,
},
{
memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu));
}
-static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
+static void mvp_init(CPUMIPSState *env)
{
env->mvp = g_malloc0(sizeof(CPUMIPSMVPContext));
+ if (!ase_mt_available(env)) {
+ return;
+ }
+
/* MVPConf1 implemented, TLB sharable, no gating storage support,
programmable cache partitioning implemented, number of allocatable
and shareable TLB entries, MVP has allocatable TCs, 2 VPEs
POWERPC_MMU_3_00 = POWERPC_MMU_64 | 0x00000005,
};
+static inline bool mmu_is_64bit(powerpc_mmu_t mmu_model)
+{
+ return mmu_model & POWERPC_MMU_64;
+}
+
/*****************************************************************************/
/* Exception model */
typedef enum powerpc_excp_t powerpc_excp_t;
*/
if (excp == POWERPC_EXCP_HV_EMU
#if defined(TARGET_PPC64)
- && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB))
+ && !(mmu_is_64bit(env->mmu_model) && (env->msr_mask & MSR_HVB))
#endif /* defined(TARGET_PPC64) */
) {
vector = (uint32_t)vector;
}
} else {
- if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
+ if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
vector = (uint32_t)vector;
} else {
new_msr |= (target_ulong)1 << MSR_SF;
do_float_check_status(env, GETPC());
}
-#define VSX_SCALAR_CMP(op, ordered) \
-void helper_##op(CPUPPCState *env, uint32_t opcode, \
- ppc_vsr_t *xa, ppc_vsr_t *xb) \
-{ \
- uint32_t cc = 0; \
- bool vxsnan_flag = false, vxvc_flag = false; \
- \
- helper_reset_fpstatus(env); \
- \
- if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \
- float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \
- vxsnan_flag = true; \
- cc = CRF_SO; \
- if (fpscr_ve == 0 && ordered) { \
- vxvc_flag = true; \
- } \
- } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || \
- float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) { \
- cc = CRF_SO; \
- if (ordered) { \
- vxvc_flag = true; \
- } \
- } \
- if (vxsnan_flag) { \
- float_invalid_op_vxsnan(env, GETPC()); \
- } \
- if (vxvc_flag) { \
- float_invalid_op_vxvc(env, 0, GETPC()); \
- } \
- \
- if (float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { \
- cc |= CRF_LT; \
- } else if (!float64_le(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { \
- cc |= CRF_GT; \
- } else { \
- cc |= CRF_EQ; \
- } \
- \
- env->fpscr &= ~FP_FPCC; \
- env->fpscr |= cc << FPSCR_FPCC; \
- env->crf[BF(opcode)] = cc; \
- \
- do_float_check_status(env, GETPC()); \
-}
-
-VSX_SCALAR_CMP(xscmpodp, 1)
-VSX_SCALAR_CMP(xscmpudp, 0)
-
-#define VSX_SCALAR_CMPQ(op, ordered) \
-void helper_##op(CPUPPCState *env, uint32_t opcode, \
- ppc_vsr_t *xa, ppc_vsr_t *xb) \
-{ \
- uint32_t cc = 0; \
- bool vxsnan_flag = false, vxvc_flag = false; \
- \
- helper_reset_fpstatus(env); \
- \
- if (float128_is_signaling_nan(xa->f128, &env->fp_status) || \
- float128_is_signaling_nan(xb->f128, &env->fp_status)) { \
- vxsnan_flag = true; \
- cc = CRF_SO; \
- if (fpscr_ve == 0 && ordered) { \
- vxvc_flag = true; \
- } \
- } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || \
- float128_is_quiet_nan(xb->f128, &env->fp_status)) { \
- cc = CRF_SO; \
- if (ordered) { \
- vxvc_flag = true; \
- } \
- } \
- if (vxsnan_flag) { \
- float_invalid_op_vxsnan(env, GETPC()); \
- } \
- if (vxvc_flag) { \
- float_invalid_op_vxvc(env, 0, GETPC()); \
- } \
- \
- if (float128_lt(xa->f128, xb->f128, &env->fp_status)) { \
- cc |= CRF_LT; \
- } else if (!float128_le(xa->f128, xb->f128, &env->fp_status)) { \
- cc |= CRF_GT; \
- } else { \
- cc |= CRF_EQ; \
- } \
- \
- env->fpscr &= ~FP_FPCC; \
- env->fpscr |= cc << FPSCR_FPCC; \
- env->crf[BF(opcode)] = cc; \
- \
- do_float_check_status(env, GETPC()); \
+static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb,
+ int crf_idx, bool ordered)
+{
+ uint32_t cc;
+ bool vxsnan_flag = false, vxvc_flag = false;
+
+ helper_reset_fpstatus(env);
+
+ switch (float64_compare(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) {
+ case float_relation_less:
+ cc = CRF_LT;
+ break;
+ case float_relation_equal:
+ cc = CRF_EQ;
+ break;
+ case float_relation_greater:
+ cc = CRF_GT;
+ break;
+ case float_relation_unordered:
+ cc = CRF_SO;
+
+ if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) ||
+ float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) {
+ vxsnan_flag = true;
+ if (fpscr_ve == 0 && ordered) {
+ vxvc_flag = true;
+ }
+ } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) ||
+ float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) {
+ if (ordered) {
+ vxvc_flag = true;
+ }
+ }
+
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= cc << FPSCR_FPCC;
+ env->crf[crf_idx] = cc;
+
+ if (vxsnan_flag) {
+ float_invalid_op_vxsnan(env, GETPC());
+ }
+ if (vxvc_flag) {
+ float_invalid_op_vxvc(env, 0, GETPC());
+ }
+
+ do_float_check_status(env, GETPC());
+}
+
+void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
+ ppc_vsr_t *xb)
+{
+ do_scalar_cmp(env, xa, xb, BF(opcode), true);
+}
+
+void helper_xscmpudp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
+ ppc_vsr_t *xb)
+{
+ do_scalar_cmp(env, xa, xb, BF(opcode), false);
+}
+
+static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa,
+ ppc_vsr_t *xb, int crf_idx, bool ordered)
+{
+ uint32_t cc;
+ bool vxsnan_flag = false, vxvc_flag = false;
+
+ helper_reset_fpstatus(env);
+
+ switch (float128_compare(xa->f128, xb->f128, &env->fp_status)) {
+ case float_relation_less:
+ cc = CRF_LT;
+ break;
+ case float_relation_equal:
+ cc = CRF_EQ;
+ break;
+ case float_relation_greater:
+ cc = CRF_GT;
+ break;
+ case float_relation_unordered:
+ cc = CRF_SO;
+
+ if (float128_is_signaling_nan(xa->f128, &env->fp_status) ||
+ float128_is_signaling_nan(xb->f128, &env->fp_status)) {
+ vxsnan_flag = true;
+ if (fpscr_ve == 0 && ordered) {
+ vxvc_flag = true;
+ }
+ } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) ||
+ float128_is_quiet_nan(xb->f128, &env->fp_status)) {
+ if (ordered) {
+ vxvc_flag = true;
+ }
+ }
+
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= cc << FPSCR_FPCC;
+ env->crf[crf_idx] = cc;
+
+ if (vxsnan_flag) {
+ float_invalid_op_vxsnan(env, GETPC());
+ }
+ if (vxvc_flag) {
+ float_invalid_op_vxvc(env, 0, GETPC());
+ }
+
+ do_float_check_status(env, GETPC());
}
-VSX_SCALAR_CMPQ(xscmpoqp, 1)
-VSX_SCALAR_CMPQ(xscmpuqp, 0)
+void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
+ ppc_vsr_t *xb)
+{
+ do_scalar_cmpq(env, xa, xb, BF(opcode), true);
+}
+
+void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
+ ppc_vsr_t *xb)
+{
+ do_scalar_cmpq(env, xa, xb, BF(opcode), false);
+}
/*
* VSX_MAX_MIN - VSX floating point maximum/minimum
#ifdef TARGET_PPC64
PowerPCCPU *cpu = opaque;
- return !(cpu->env.mmu_model & POWERPC_MMU_64);
+ return !mmu_is_64bit(cpu->env.mmu_model);
#else
return true;
#endif
PowerPCCPU *cpu = opaque;
/* We don't support any of the old segment table based 64-bit CPUs */
- return cpu->env.mmu_model & POWERPC_MMU_64;
+ return mmu_is_64bit(cpu->env.mmu_model);
}
static int slb_post_load(void *opaque, int version_id)
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
if (!pcc->hash64_opts) {
- assert(!(env->mmu_model & POWERPC_MMU_64));
+ assert(!mmu_is_64bit(env->mmu_model));
return;
}
break;
case POWERPC_MMU_3_00:
if (ppc64_v3_radix(env_archcpu(env))) {
- /* TODO - Unsupported */
+ qemu_log_mask(LOG_UNIMP, "%s: the PPC64 MMU is unsupported\n",
+ __func__);
} else {
dump_slb(env_archcpu(env));
- break;
}
+ break;
#endif
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
void ppc_tlb_invalidate_all(CPUPPCState *env)
{
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
+ if (mmu_is_64bit(env->mmu_model)) {
env->tlb_need_flush = 0;
tlb_flush(env_cpu(env));
} else
#if !defined(FLUSH_ALL_TLBS)
addr &= TARGET_PAGE_MASK;
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
+ if (mmu_is_64bit(env->mmu_model)) {
/* tlbie invalidate TLBs for all segments */
/*
* XXX: given the fact that there are too many segments to invalidate,
qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
assert(!cpu->vhyp);
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
+ if (mmu_is_64bit(env->mmu_model)) {
target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
target_ulong htabsize = value & SDR_64_HTABSIZE;
target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
{
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
+ if (mmu_is_64bit(env->mmu_model)) {
/* XXX */
return 0;
}
"%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
(int)srnum, value, env->sr[srnum]);
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
+ if (mmu_is_64bit(env->mmu_model)) {
PowerPCCPU *cpu = env_archcpu(env);
uint64_t esid, vsid;
ctx->insns_flags = env->insns_flags;
ctx->insns_flags2 = env->insns_flags2;
ctx->access_type = -1;
- ctx->need_access_type = !(env->mmu_model & POWERPC_MMU_64B);
+ ctx->need_access_type = !mmu_is_64bit(env->mmu_model);
ctx->le_mode = !!(env->hflags & (1 << MSR_LE));
ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE;
ctx->flags = env->flags;
#endif
ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B
|| env->mmu_model == POWERPC_MMU_601
- || (env->mmu_model & POWERPC_MMU_64B);
+ || env->mmu_model & POWERPC_MMU_64;
ctx->fpu_enabled = !!msr_fp;
if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) {
tcg_temp_free_i64(t0);
}
-static void gen_lxvdsx(DisasContext *ctx)
-{
- TCGv EA;
- TCGv_i64 t0;
- TCGv_i64 t1;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- gen_qemu_ld64_i64(ctx, t0, EA);
- set_cpu_vsrh(xT(ctx->opcode), t0);
- tcg_gen_mov_i64(t1, t0);
- set_cpu_vsrl(xT(ctx->opcode), t1);
- tcg_temp_free(EA);
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
-}
-
static void gen_lxvw4x(DisasContext *ctx)
{
TCGv EA;
tcg_temp_free_i32(data);
}
+static void gen_lxvdsx(DisasContext *ctx)
+{
+ TCGv EA;
+ TCGv_i64 data;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = tcg_temp_new();
+
+ gen_addr_reg_index(ctx, EA);
+
+ data = tcg_temp_new_i64();
+ tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, MO_TEQ);
+ tcg_gen_gvec_dup_i64(MO_Q, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
+
+ tcg_temp_free(EA);
+ tcg_temp_free_i64(data);
+}
+
static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl,
TCGv_i64 inh, TCGv_i64 inl)
{
return oc;
}
-static void ppc_cpu_parse_featurestr(const char *type, char *features,
- Error **errp)
-{
- Object *machine = qdev_get_machine();
- const PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(object_class_by_name(type));
-
- if (!features) {
- return;
- }
-
- if (object_property_find(machine, "max-cpu-compat")) {
- int i;
- char **inpieces;
- char *s = features;
- Error *local_err = NULL;
- char *compat_str = NULL;
-
- /*
- * Backwards compatibility hack:
- *
- * CPUs had a "compat=" property which didn't make sense for
- * anything except pseries. It was replaced by "max-cpu-compat"
- * machine option. This supports old command lines like
- * -cpu POWER8,compat=power7
- * By stripping the compat option and applying it to the machine
- * before passing it on to the cpu level parser.
- */
- inpieces = g_strsplit(features, ",", 0);
- *s = '\0';
- for (i = 0; inpieces[i]; i++) {
- if (g_str_has_prefix(inpieces[i], "compat=")) {
- warn_report_once("CPU 'compat' property is deprecated; "
- "use max-cpu-compat machine property instead");
- compat_str = inpieces[i];
- continue;
- }
- if ((i != 0) && (s != features)) {
- s = g_stpcpy(s, ",");
- }
- s = g_stpcpy(s, inpieces[i]);
- }
-
- if (compat_str) {
- char *v = compat_str + strlen("compat=");
- object_property_set_str(machine, "max-cpu-compat", v, &local_err);
- }
- g_strfreev(inpieces);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
- /* do property processing with generic handler */
- pcc->parent_parse_features(type, features, errp);
-}
-
PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc)
{
ObjectClass *oc = OBJECT_CLASS(pcc);
#endif
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
+ if (mmu_is_64bit(env->mmu_model)) {
msr |= (1ULL << MSR_SF);
}
#endif
device_class_set_parent_reset(dc, ppc_cpu_reset, &pcc->parent_reset);
cc->class_by_name = ppc_cpu_class_by_name;
- pcc->parent_parse_features = cc->parse_features;
- cc->parse_features = ppc_cpu_parse_featurestr;
cc->has_work = ppc_cpu_has_work;
cc->do_interrupt = ppc_cpu_do_interrupt;
cc->cpu_exec_interrupt = ppc_cpu_exec_interrupt;
--bin $< --test $(MULTIARCH_SRC)/gdbstub/sha1.py, \
"basic gdbstub support")
-EXTRA_RUNS += run-gdbstub-sha1
+# Disable this for now -- it provokes a gdb internal-error on
+# Ubuntu gdb 8.1.1-0ubuntu1.
+# EXTRA_RUNS += run-gdbstub-sha1
endif