Merge tag 'pull-ppc-20230906' of https://github.com/legoater/qemu into staging

ppc queue :

* debug facility improvements
* timebase and decrementer fixes
* record-replay fixes
* TCG fixes
* XIVE model improvements for multichip

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmT4WKoACgkQUaNDx8/7
# 7KHjOg//bwENCptopnvX5XVTdGLRgBKoMWPkQhWPv4aHYz4t+bxHVWopdMU7i0aL
# hge+ZCCkMKsg2rADczbpWytAvC3vo1Pn4zZhZNQuEvYKIpiWVN6hSflmXWP/bN1I
# AGHlptKvNYKlPfGsmzZ2OZ2yItzrOwKFC/PnPSEc6dxjWfe9hEwzApxaAkOfX8wf
# C+oH8DPvFmh3PH3rI4psCn/xYtxAPW1zosBtgT7Ii1XreABMHLIfIpOmPPh1yF0d
# J7BgBdmxIvsN+syH/vh5jTtU4N/gQVorwyds9MX82Y3j0roxBVVLqH8rFjJA3Jsq
# c/g8WTi1hHiDd8G4m1JcLI1VAhsgh1KhqG9pDaSdQXhP0E4p8N/XjxOR5ro+KxM3
# Dz/Q77VoEKuat+AXg71kc68i11CninhTVSyGnjI80ISWWYvHFQ2Sv8J9U6sS/d0m
# +fo6hed7DDgfXg4OMtedF4HMmc6JAfm9eBzHUoanaoIzX0vX6vetXeMfWh6iceYW
# KNcQuUi3Pvvh/AjE36jusqTkbTleP5Yo4OKNJz4pEP4sU2wQPYU32Lo7Kg7p4WPA
# j+emWmWX4gcn9zTvm2LPYwkdgQ5HgigUJzq9i9qlMqfOOCpRwAsE7V0KxyV0NwDT
# cAAOBCdNm4t94Ni3KEING7xuDzERvJ7H2D6uRQjVsre8cMUO0QE=
# =BUg6
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 06 Sep 2023 06:47:06 EDT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [unknown]
# gpg:                 aka "Cédric Le Goater <clg@kaod.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-ppc-20230906' of https://github.com/legoater/qemu: (35 commits)
  ppc/xive: Add support for the PC MMIOs
  ppc/xive: Handle END triggers between chips with MMIOs
  ppc/xive: Introduce a new XiveRouter end_notify() handler
  ppc/xive: Use address_space routines to access the machine RAM
  target/ppc: Fix the order of kvm_enable judgment about kvmppc_set_interrupt()
  hw/ppc/e500: fix broken snapshot replay
  target/ppc: Flush inputs to zero with NJ in ppc_store_vscr
  target/ppc: Fix LQ, STQ register-pair order for big-endian
  tests/avocado: ppc64 reverse debugging tests for pseries and powernv
  tests/avocado: reverse-debugging cope with re-executing breakpoints
  tests/avocado: boot ppc64 pseries replay-record test to Linux VFS mount
  spapr: Fix record-replay machine reset consuming too many events
  spapr: Fix machine reset deadlock from replay-record
  target/ppc: Fix timebase reset with record-replay
  target/ppc: Fix CPU reservation migration for record-replay
  hw/ppc: Read time only once to perform decrementer write
  hw/ppc: Reset timebase facilities on machine reset
  target/ppc: Migrate DECR SPR
  hw/ppc: Always store the decrementer value
  target/ppc: Sign-extend large decrementer to 64-bits
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2023-09-07 10:23:25 -04:00
34 changed files with 925 additions and 205 deletions
+133 -37
View File
@@ -84,28 +84,6 @@ static uint8_t pnv_xive_block_id(PnvXive *xive)
return blk;
}
/*
* Remote access to controllers. HW uses MMIOs. For now, a simple scan
* of the chips is good enough.
*
* TODO: Block scope support
*/
static PnvXive *pnv_xive_get_remote(uint8_t blk)
{
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
int i;
for (i = 0; i < pnv->num_chips; i++) {
Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
PnvXive *xive = &chip9->xive;
if (pnv_xive_block_id(xive) == blk) {
return xive;
}
}
return NULL;
}
/*
* VST accessors for SBE, EAT, ENDT, NVT
*
@@ -209,6 +187,42 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
return pnv_xive_vst_addr_direct(xive, type, vsd, (idx % vst_per_page));
}
/*
* This is a simplified model of operation forwarding on a remote IC.
*
* A PC MMIO address is built to identify the NVT structure. The load
* on the remote IC will return the address of the structure in RAM,
* which will then be used by pnv_xive_vst_write/read to perform the
* RAM operation.
*/
static uint64_t pnv_xive_vst_addr_remote(PnvXive *xive, uint32_t type,
uint64_t vsd, uint8_t blk,
uint32_t idx)
{
const XiveVstInfo *info = &vst_infos[type];
uint64_t remote_addr = vsd & VSD_ADDRESS_MASK;
uint64_t vst_addr;
MemTxResult result;
if (type != VST_TSEL_VPDT) {
xive_error(xive, "VST: invalid access on remote VST %s %x/%x !?",
info->name, blk, idx);
return 0;
}
remote_addr |= idx << xive->pc_shift;
vst_addr = address_space_ldq_be(&address_space_memory, remote_addr,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
xive_error(xive, "VST: read failed at @0x%" HWADDR_PRIx
" for NVT %x/%x\n", remote_addr, blk, idx);
return 0;
}
return vst_addr;
}
static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
uint32_t idx)
{
@@ -225,9 +239,7 @@ static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
/* Remote VST access */
if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
xive = pnv_xive_get_remote(blk);
return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0;
return pnv_xive_vst_addr_remote(xive, type, vsd, blk, idx);
}
if (VSD_INDIRECT & vsd) {
@@ -242,12 +254,20 @@ static int pnv_xive_vst_read(PnvXive *xive, uint32_t type, uint8_t blk,
{
const XiveVstInfo *info = &vst_infos[type];
uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
MemTxResult result;
if (!addr) {
return -1;
}
cpu_physical_memory_read(addr, data, info->size);
result = address_space_read(&address_space_memory, addr,
MEMTXATTRS_UNSPECIFIED, data,
info->size);
if (result != MEMTX_OK) {
xive_error(xive, "VST: read failed at @0x%" HWADDR_PRIx
" for VST %s %x/%x\n", addr, info->name, blk, idx);
return -1;
}
return 0;
}
@@ -258,16 +278,27 @@ static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
{
const XiveVstInfo *info = &vst_infos[type];
uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
MemTxResult result;
if (!addr) {
return -1;
}
if (word_number == XIVE_VST_WORD_ALL) {
cpu_physical_memory_write(addr, data, info->size);
result = address_space_write(&address_space_memory, addr,
MEMTXATTRS_UNSPECIFIED, data,
info->size);
} else {
cpu_physical_memory_write(addr + word_number * 4,
data + word_number * 4, 4);
result = address_space_write(&address_space_memory,
addr + word_number * 4,
MEMTXATTRS_UNSPECIFIED,
data + word_number * 4, 4);
}
if (result != MEMTX_OK) {
xive_error(xive, "VST: write failed at @0x%" HWADDR_PRIx
"for VST %s %x/%x\n", addr, info->name, blk, idx);
return -1;
}
return 0;
}
@@ -275,12 +306,26 @@ static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
XiveEND *end)
{
PnvXive *xive = PNV_XIVE(xrtr);
if (pnv_xive_block_id(xive) != blk) {
xive_error(xive, "VST: END %x/%x is remote !?", blk, idx);
return -1;
}
return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end);
}
static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
XiveEND *end, uint8_t word_number)
{
PnvXive *xive = PNV_XIVE(xrtr);
if (pnv_xive_block_id(xive) != blk) {
xive_error(xive, "VST: END %x/%x is remote !?", blk, idx);
return -1;
}
return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end,
word_number);
}
@@ -1349,6 +1394,50 @@ static const MemoryRegionOps pnv_xive_ic_reg_ops = {
#define PNV_XIVE_SYNC_PUSH 0xf00 /* Sync push context */
#define PNV_XIVE_SYNC_VPC 0xf80 /* Sync remove VPC store */
static void pnv_xive_end_notify(XiveRouter *xrtr, XiveEAS *eas)
{
PnvXive *xive = PNV_XIVE(xrtr);
uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w);
uint64_t end_vsd = xive->vsds[VST_TSEL_EQDT][end_blk];
switch (GETFIELD(VSD_MODE, end_vsd)) {
case VSD_MODE_EXCLUSIVE:
/* Perform the END notification on the local IC. */
xive_router_end_notify(xrtr, eas);
break;
case VSD_MODE_FORWARD: {
MemTxResult result;
uint64_t notif_port = end_vsd & VSD_ADDRESS_MASK;
uint64_t data = XIVE_TRIGGER_END | XIVE_TRIGGER_PQ |
be64_to_cpu(eas->w);
/* Forward the store on the remote IC notify page. */
address_space_stq_be(&address_space_memory, notif_port, data,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
xive_error(xive, "IC: Forward notif END %x/%x [%x] failed @%"
HWADDR_PRIx, end_blk, end_idx, end_data, notif_port);
return;
}
break;
}
case VSD_MODE_INVALID:
default:
/* Set FIR */
xive_error(xive, "IC: Invalid END VSD for block %x", end_blk);
return;
}
}
/*
* The notify page can either be used to receive trigger events from
* the HW controllers (PHB, PSI) or to reroute interrupts between
* Interrupt controllers.
*/
static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
{
uint8_t blk;
@@ -1357,8 +1446,8 @@ static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
trace_pnv_xive_ic_hw_trigger(addr, val);
if (val & XIVE_TRIGGER_END) {
xive_error(xive, "IC: END trigger at @0x%"HWADDR_PRIx" data 0x%"PRIx64,
addr, val);
val = cpu_to_be64(val);
pnv_xive_end_notify(XIVE_ROUTER(xive), (XiveEAS *) &val);
return;
}
@@ -1703,16 +1792,20 @@ static const MemoryRegionOps pnv_xive_vc_ops = {
};
/*
* Presenter Controller MMIO region. The Virtualization Controller
* updates the IPB in the NVT table when required. Not modeled.
* Presenter Controller MMIO region. Points to the NVT sets.
*
* HW implements all possible mem ops to the underlying NVT structure
* but QEMU does not need to be so precise. The model implementation
* simply returns the RAM address of the NVT structure which is then
* used by pnv_xive_vst_write/read to perform the RAM operation.
*/
static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr,
unsigned size)
static uint64_t pnv_xive_pc_read(void *opaque, hwaddr offset, unsigned size)
{
PnvXive *xive = PNV_XIVE(opaque);
uint32_t nvt_idx = offset >> xive->pc_shift;
uint8_t blk = pnv_xive_block_id(xive); /* TODO: VDT -> block xlate */
xive_error(xive, "PC: invalid read @%"HWADDR_PRIx, addr);
return -1;
return pnv_xive_vst_addr(xive, VST_TSEL_VPDT, blk, nvt_idx);
}
static void pnv_xive_pc_write(void *opaque, hwaddr addr,
@@ -1898,6 +1991,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev),
&pnv_xive_ic_notify_ops,
xive, "xive-ic-notify", 1 << xive->ic_shift);
xive->ic_notify_mmio.disable_reentrancy_guard = true;
/* The Pervasive LSI trigger and EOI pages (not modeled) */
memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops,
@@ -1933,6 +2027,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp)
/* Presenter Controller MMIO region (not modeled) */
memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, xive,
"xive-pc", PNV9_XIVE_PC_SIZE);
xive->pc_mmio.disable_reentrancy_guard = true;
/* Thread Interrupt Management Area (Direct) */
memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &pnv_xive_tm_ops,
@@ -1998,6 +2093,7 @@ static void pnv_xive_class_init(ObjectClass *klass, void *data)
xrc->get_nvt = pnv_xive_get_nvt;
xrc->write_nvt = pnv_xive_write_nvt;
xrc->get_block_id = pnv_xive_get_block_id;
xrc->end_notify = pnv_xive_end_notify;
xnc->notify = pnv_xive_notify;
xpc->match_nvt = pnv_xive_match_nvt;
+23 -4
View File
@@ -240,12 +240,20 @@ static int pnv_xive2_vst_read(PnvXive2 *xive, uint32_t type, uint8_t blk,
{
const XiveVstInfo *info = &vst_infos[type];
uint64_t addr = pnv_xive2_vst_addr(xive, type, blk, idx);
MemTxResult result;
if (!addr) {
return -1;
}
cpu_physical_memory_read(addr, data, info->size);
result = address_space_read(&address_space_memory, addr,
MEMTXATTRS_UNSPECIFIED, data,
info->size);
if (result != MEMTX_OK) {
xive2_error(xive, "VST: read failed at @0x%" HWADDR_PRIx
" for VST %s %x/%x\n", addr, info->name, blk, idx);
return -1;
}
return 0;
}
@@ -256,16 +264,27 @@ static int pnv_xive2_vst_write(PnvXive2 *xive, uint32_t type, uint8_t blk,
{
const XiveVstInfo *info = &vst_infos[type];
uint64_t addr = pnv_xive2_vst_addr(xive, type, blk, idx);
MemTxResult result;
if (!addr) {
return -1;
}
if (word_number == XIVE_VST_WORD_ALL) {
cpu_physical_memory_write(addr, data, info->size);
result = address_space_write(&address_space_memory, addr,
MEMTXATTRS_UNSPECIFIED, data,
info->size);
} else {
cpu_physical_memory_write(addr + word_number * 4,
data + word_number * 4, 4);
result = address_space_write(&address_space_memory,
addr + word_number * 4,
MEMTXATTRS_UNSPECIFIED,
data + word_number * 4, 4);
}
if (result != MEMTX_OK) {
xive2_error(xive, "VST: write failed at @0x%" HWADDR_PRIx
"for VST %s %x/%x\n", addr, info->name, blk, idx);
return -1;
}
return 0;
}
+1
View File
@@ -228,6 +228,7 @@
* VSD and is only meant to be used in indirect mode !
*/
#define VSD_MODE PPC_BITMASK(0, 1)
#define VSD_MODE_INVALID 0
#define VSD_MODE_SHARED 1
#define VSD_MODE_EXCLUSIVE 2
#define VSD_MODE_FORWARD 3
+18 -10
View File
@@ -1518,6 +1518,13 @@ static void xive_router_realize(DeviceState *dev, Error **errp)
assert(xrtr->xfb);
}
static void xive_router_end_notify_handler(XiveRouter *xrtr, XiveEAS *eas)
{
XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
return xrc->end_notify(xrtr, eas);
}
/*
* Encode the HW CAM line in the block group mode format :
*
@@ -1664,8 +1671,7 @@ static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk,
* another chip. We don't model the PowerBus but the END trigger
* message has the same parameters than in the function below.
*/
static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
uint32_t end_idx, uint32_t end_data)
void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
{
XiveEND end;
uint8_t priority;
@@ -1675,6 +1681,10 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
XiveNVT nvt;
bool found;
uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w);
/* END cache lookup */
if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk,
@@ -1817,10 +1827,7 @@ do_escalation:
/*
* The END trigger becomes an Escalation trigger
*/
xive_router_end_notify(xrtr,
xive_get_field32(END_W4_ESC_END_BLOCK, end.w4),
xive_get_field32(END_W4_ESC_END_INDEX, end.w4),
xive_get_field32(END_W5_ESC_END_DATA, end.w5));
xive_router_end_notify_handler(xrtr, (XiveEAS *) &end.w4);
}
void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked)
@@ -1871,10 +1878,7 @@ void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked)
/*
* The event trigger becomes an END trigger
*/
xive_router_end_notify(xrtr,
xive_get_field64(EAS_END_BLOCK, eas.w),
xive_get_field64(EAS_END_INDEX, eas.w),
xive_get_field64(EAS_END_DATA, eas.w));
xive_router_end_notify_handler(xrtr, &eas);
}
static Property xive_router_properties[] = {
@@ -1887,12 +1891,16 @@ static void xive_router_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
dc->desc = "XIVE Router Engine";
device_class_set_props(dc, xive_router_properties);
/* Parent is SysBusDeviceClass. No need to call its realize hook */
dc->realize = xive_router_realize;
xnc->notify = xive_router_notify;
/* By default, the router handles END triggers locally */
xrc->end_notify = xive_router_end_notify;
}
static const TypeInfo xive_router_info = {
+1 -1
View File
@@ -712,7 +712,7 @@ static int ppce500_prep_device_tree(PPCE500MachineState *machine,
p->kernel_base = kernel_base;
p->kernel_size = kernel_size;
qemu_register_reset(ppce500_reset_device_tree, p);
qemu_register_reset_nosnapshotload(ppce500_reset_device_tree, p);
p->notifier.notify = ppce500_init_notify;
qemu_add_machine_init_done_notifier(&p->notifier);
+1
View File
@@ -81,6 +81,7 @@ static void ppc_heathrow_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
cpu_ppc_tb_reset(&cpu->env);
cpu_reset(CPU(cpu));
}
+1
View File
@@ -99,6 +99,7 @@ static void pegasos2_cpu_reset(void *opaque)
cpu->env.gpr[1] = 2 * VOF_STACK_SIZE - 0x20;
cpu->env.nip = 0x100;
}
cpu_ppc_tb_reset(&cpu->env);
}
static void pegasos2_pci_irq(void *opaque, int n, int level)
+2
View File
@@ -61,6 +61,8 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
hreg_compute_hflags(env);
ppc_maybe_interrupt(env);
cpu_ppc_tb_reset(env);
pcc->intc_reset(pc->chip, cpu);
}
+157 -86
View File
@@ -32,6 +32,7 @@
#include "qemu/main-loop.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
#include "sysemu/replay.h"
#include "sysemu/runstate.h"
#include "kvm_ppc.h"
#include "migration/vmstate.h"
@@ -58,7 +59,9 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
if (old_pending != env->pending_interrupts) {
ppc_maybe_interrupt(env);
kvmppc_set_interrupt(cpu, irq, level);
if (kvm_enabled()) {
kvmppc_set_interrupt(cpu, irq, level);
}
}
trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
@@ -482,10 +485,32 @@ void ppce500_set_mpic_proxy(bool enabled)
/*****************************************************************************/
/* PowerPC time base and decrementer emulation */
/*
* Conversion between QEMU_CLOCK_VIRTUAL ns and timebase (TB) ticks:
* TB ticks are arrived at by multiplying tb_freq then dividing by
* ns per second, and rounding down. TB ticks drive all clocks and
* timers in the target machine.
*
* Converting TB intervals to ns for the purpose of setting a
* QEMU_CLOCK_VIRTUAL timer should go the other way, but rounding
* up. Rounding down could cause the timer to fire before the TB
* value has been reached.
*/
static uint64_t ns_to_tb(uint32_t freq, int64_t clock)
{
return muldiv64(clock, freq, NANOSECONDS_PER_SECOND);
}
/* virtual clock in TB ticks, not adjusted by TB offset */
static int64_t tb_to_ns_round_up(uint32_t freq, uint64_t tb)
{
return muldiv64_round_up(tb, NANOSECONDS_PER_SECOND, freq);
}
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
{
/* TB time in tb periods */
return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset;
return ns_to_tb(tb_env->tb_freq, vmclk) + tb_offset;
}
uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
@@ -497,7 +522,8 @@ uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
return env->spr[SPR_TBL];
}
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
tb_env->tb_offset);
trace_ppc_tb_load(tb);
return tb;
@@ -508,7 +534,8 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
tb_env->tb_offset);
trace_ppc_tb_load(tb);
return tb >> 32;
@@ -526,8 +553,7 @@ uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
int64_t *tb_offsetp, uint64_t value)
{
*tb_offsetp = value -
muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
*tb_offsetp = value - ns_to_tb(tb_env->tb_freq, vmclk);
trace_ppc_tb_store(value, *tb_offsetp);
}
@@ -565,7 +591,8 @@ uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
tb_env->atb_offset);
trace_ppc_tb_load(tb);
return tb;
@@ -576,7 +603,8 @@ uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
tb_env->atb_offset);
trace_ppc_tb_load(tb);
return tb >> 32;
@@ -683,64 +711,77 @@ bool ppc_decr_clear_on_delivery(CPUPPCState *env)
return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
}
static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now,
uint64_t next)
{
ppc_tb_t *tb_env = env->tb_env;
int64_t decr, diff;
uint64_t n;
int64_t decr;
diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (diff >= 0) {
decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
} else if (tb_env->flags & PPC_TIMER_BOOKE) {
n = ns_to_tb(tb_env->decr_freq, now);
if (next > n && tb_env->flags & PPC_TIMER_BOOKE) {
decr = 0;
} else {
decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
} else {
decr = next - n;
}
trace_ppc_decr_load(decr);
return decr;
}
target_ulong cpu_ppc_load_decr(CPUPPCState *env)
static target_ulong _cpu_ppc_load_decr(CPUPPCState *env, int64_t now)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t decr;
if (kvm_enabled()) {
return env->spr[SPR_DECR];
}
decr = _cpu_ppc_load_decr(env, tb_env->decr_next);
decr = __cpu_ppc_load_decr(env, now, tb_env->decr_next);
/*
* If large decrementer is enabled then the decrementer is signed extened
* to 64 bits, otherwise it is a 32 bit value.
*/
if (env->spr[SPR_LPCR] & LPCR_LD) {
return decr;
PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
return sextract64(decr, 0, pcc->lrg_decr_bits);
}
return (uint32_t) decr;
}
target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
target_ulong cpu_ppc_load_decr(CPUPPCState *env)
{
if (kvm_enabled()) {
return env->spr[SPR_DECR];
} else {
return _cpu_ppc_load_decr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
}
}
static target_ulong _cpu_ppc_load_hdecr(CPUPPCState *env, int64_t now)
{
PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
ppc_tb_t *tb_env = env->tb_env;
uint64_t hdecr;
hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next);
hdecr = __cpu_ppc_load_decr(env, now, tb_env->hdecr_next);
/*
* If we have a large decrementer (POWER9 or later) then hdecr is sign
* extended to 64 bits, otherwise it is 32 bits.
*/
if (pcc->lrg_decr_bits > 32) {
return hdecr;
return sextract64(hdecr, 0, pcc->lrg_decr_bits);
}
return (uint32_t) hdecr;
}
target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
{
return _cpu_ppc_load_hdecr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
}
uint64_t cpu_ppc_load_purr (CPUPPCState *env)
{
ppc_tb_t *tb_env = env->tb_env;
@@ -785,7 +826,7 @@ static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
}
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, uint64_t *nextp,
QEMUTimer *timer,
void (*raise_excp)(void *),
void (*lower_excp)(PowerPCCPU *),
@@ -794,7 +835,7 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
{
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next;
uint64_t next;
int64_t signed_value;
int64_t signed_decr;
@@ -806,10 +847,14 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
trace_ppc_decr_store(nr_bits, decr, value);
if (kvm_enabled()) {
/* KVM handles decrementer exceptions, we don't need our own timer */
return;
}
/*
* Calculate the next decrementer event and set a timer.
* decr_next is in timebase units to keep rounding simple. Note it is
* not adjusted by tb_offset because if TB changes via tb_offset changing,
* decrementer does not change, so not directly comparable with TB.
*/
next = ns_to_tb(tb_env->decr_freq, now) + value;
*nextp = next; /* nextp is in timebase units */
/*
* Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt.
@@ -832,21 +877,17 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
(*lower_excp)(cpu);
}
/* Calculate the next timer event */
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
*nextp = next;
/* Adjust timer */
timer_mod(timer, next);
timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, next));
}
static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr,
target_ulong value, int nr_bits)
static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now,
target_ulong decr, target_ulong value,
int nr_bits)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
__cpu_ppc_store_decr(cpu, now, &tb_env->decr_next, tb_env->decr_timer,
tb_env->decr_timer->cb, &cpu_ppc_decr_lower,
tb_env->flags, decr, value, nr_bits);
}
@@ -855,13 +896,22 @@ void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
int64_t now;
target_ulong decr;
int nr_bits = 32;
if (kvm_enabled()) {
/* KVM handles decrementer exceptions, we don't need our own timer */
return;
}
if (env->spr[SPR_LPCR] & LPCR_LD) {
nr_bits = pcc->lrg_decr_bits;
}
_cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits);
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
decr = _cpu_ppc_load_decr(env, now);
_cpu_ppc_store_decr(cpu, now, decr, value, nr_bits);
}
static void cpu_ppc_decr_cb(void *opaque)
@@ -871,14 +921,15 @@ static void cpu_ppc_decr_cb(void *opaque)
cpu_ppc_decr_excp(cpu);
}
static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr,
target_ulong value, int nr_bits)
static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, int64_t now,
target_ulong hdecr, target_ulong value,
int nr_bits)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
if (tb_env->hdecr_timer != NULL) {
/* HDECR (Book3S 64bit) is edge-based, not level like DECR */
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
__cpu_ppc_store_decr(cpu, now, &tb_env->hdecr_next, tb_env->hdecr_timer,
tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
PPC_DECR_UNDERFLOW_TRIGGERED,
hdecr, value, nr_bits);
@@ -889,9 +940,12 @@ void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
int64_t now;
target_ulong hdecr;
_cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value,
pcc->lrg_decr_bits);
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
hdecr = _cpu_ppc_load_hdecr(env, now);
_cpu_ppc_store_hdecr(cpu, now, hdecr, value, pcc->lrg_decr_bits);
}
static void cpu_ppc_hdecr_cb(void *opaque)
@@ -901,29 +955,16 @@ static void cpu_ppc_hdecr_cb(void *opaque)
cpu_ppc_hdecr_excp(cpu);
}
void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
static void _cpu_ppc_store_purr(CPUPPCState *env, int64_t now, uint64_t value)
{
ppc_tb_t *tb_env = env->tb_env;
cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
&tb_env->purr_offset, value);
cpu_ppc_store_tb(tb_env, now, &tb_env->purr_offset, value);
}
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
{
CPUPPCState *env = opaque;
PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env = env->tb_env;
tb_env->tb_freq = freq;
tb_env->decr_freq = freq;
/* There is a bug in Linux 2.4 kernels:
* if a decrementer exception is pending when it enables msr_ee at startup,
* it's not ready to handle it...
*/
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
cpu_ppc_store_purr(env, 0x0000000000000000ULL);
_cpu_ppc_store_purr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), value);
}
static void timebase_save(PPCTimebase *tb)
@@ -936,8 +977,14 @@ static void timebase_save(PPCTimebase *tb)
return;
}
/* not used anymore, we keep it for compatibility */
tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
if (replay_mode == REPLAY_MODE_NONE) {
/* not used anymore, we keep it for compatibility */
tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
} else {
/* simpler for record-replay to avoid this event, compat not needed */
tb->time_of_the_day_ns = 0;
}
/*
* tb_offset is only expected to be changed by QEMU so
* there is no need to update it from KVM here
@@ -1027,7 +1074,7 @@ const VMStateDescription vmstate_ppc_timebase = {
};
/* Set up (once) timebase frequency (in Hz) */
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq)
{
PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env;
@@ -1040,16 +1087,41 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
}
/* Create new timer */
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
&cpu_ppc_decr_cb, cpu);
if (env->has_hv_mode && !cpu->vhyp) {
tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
cpu);
tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
&cpu_ppc_hdecr_cb, cpu);
} else {
tb_env->hdecr_timer = NULL;
}
cpu_ppc_set_tb_clk(env, freq);
return &cpu_ppc_set_tb_clk;
tb_env->tb_freq = freq;
tb_env->decr_freq = freq;
}
void cpu_ppc_tb_reset(CPUPPCState *env)
{
PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env = env->tb_env;
timer_del(tb_env->decr_timer);
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
tb_env->decr_next = 0;
if (tb_env->hdecr_timer != NULL) {
timer_del(tb_env->hdecr_timer);
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
tb_env->hdecr_next = 0;
}
/*
* There is a bug in Linux 2.4 kernels:
* if a decrementer exception is pending when it enables msr_ee at startup,
* it's not ready to handle it...
*/
cpu_ppc_store_decr(env, -1);
cpu_ppc_store_hdecr(env, -1);
cpu_ppc_store_purr(env, 0x0000000000000000ULL);
}
void cpu_ppc_tb_free(CPUPPCState *env)
@@ -1125,9 +1197,7 @@ static void cpu_4xx_fit_cb (void *opaque)
/* Cannot occur, but makes gcc happy */
return;
}
next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
if (next == now)
next++;
next = now + tb_to_ns_round_up(tb_env->tb_freq, next);
timer_mod(ppc40x_timer->fit_timer, next);
env->spr[SPR_40x_TSR] |= 1 << 26;
if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
@@ -1153,14 +1223,15 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
} else {
trace_ppc4xx_pit_start(ppc40x_timer->pit_reload);
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
next = now + muldiv64(ppc40x_timer->pit_reload,
NANOSECONDS_PER_SECOND, tb_env->decr_freq);
if (is_excp)
next += tb_env->decr_next - now;
if (next == now)
next++;
if (is_excp) {
tb_env->decr_next += ppc40x_timer->pit_reload;
} else {
tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now)
+ ppc40x_timer->pit_reload;
}
next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next);
timer_mod(tb_env->decr_timer, next);
tb_env->decr_next = next;
}
}
@@ -1213,9 +1284,7 @@ static void cpu_4xx_wdt_cb (void *opaque)
/* Cannot occur, but makes gcc happy */
return;
}
next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
if (next == now)
next++;
next = now + tb_to_ns_round_up(tb_env->decr_freq, next);
trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
case 0x0:
@@ -1465,5 +1534,7 @@ void ppc_irq_reset(PowerPCCPU *cpu)
CPUPPCState *env = &cpu->env;
env->irq_input_state = 0;
kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
if (kvm_enabled()) {
kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
}
}
+1
View File
@@ -67,6 +67,7 @@ static void ppc_prep_reset(void *opaque)
PowerPCCPU *cpu = opaque;
cpu_reset(CPU(cpu));
cpu_ppc_tb_reset(&cpu->env);
}
+27 -5
View File
@@ -1022,7 +1022,6 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
{
MachineState *machine = MACHINE(spapr);
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
uint8_t rng_seed[32];
int chosen;
_FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
@@ -1100,8 +1099,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
spapr_dt_ov5_platform_support(spapr, fdt, chosen);
}
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
_FDT(fdt_setprop(fdt, chosen, "rng-seed", rng_seed, sizeof(rng_seed)));
_FDT(fdt_setprop(fdt, chosen, "rng-seed", spapr->fdt_rng_seed, 32));
_FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
}
@@ -1322,6 +1320,22 @@ void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
}
}
/* May be used when the machine is not running */
void spapr_init_all_lpcrs(target_ulong value, target_ulong mask)
{
CPUState *cs;
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
target_ulong lpcr;
lpcr = env->spr[SPR_LPCR];
lpcr &= ~(LPCR_HR | LPCR_UPRT);
ppc_store_lpcr(cpu, lpcr);
}
}
static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
target_ulong lpid, ppc_v3_pate_t *entry)
{
@@ -1583,7 +1597,7 @@ int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp)
}
/* We're setting up a hash table, so that means we're not radix */
spapr->patb_entry = 0;
spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
spapr_init_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
return 0;
}
@@ -1638,6 +1652,14 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
void *fdt;
int rc;
if (reason != SHUTDOWN_CAUSE_SNAPSHOT_LOAD) {
/*
* Record-replay snapshot load must not consume random, this was
* already replayed from initial machine reset.
*/
qemu_guest_getrandom_nofail(spapr->fdt_rng_seed, 32);
}
pef_kvm_reset(machine->cgs, &error_fatal);
spapr_caps_apply(spapr);
@@ -1661,7 +1683,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new();
ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
ppc_init_compat_all(spapr->max_compat_pvr, &error_fatal);
/*
* This is fixing some of the default configuration of the XIVE
+2
View File
@@ -74,6 +74,8 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
kvm_check_mmu(cpu, &error_fatal);
cpu_ppc_tb_reset(env);
spapr_irq_cpu_intc_reset(spapr, cpu);
}
+57
View File
@@ -3,6 +3,7 @@
#include "qapi/error.h"
#include "sysemu/hw_accel.h"
#include "sysemu/runstate.h"
#include "sysemu/tcg.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -789,6 +790,54 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, SpaprMachineState *spapr,
return H_SUCCESS;
}
static target_ulong h_set_mode_resource_set_ciabr(PowerPCCPU *cpu,
SpaprMachineState *spapr,
target_ulong mflags,
target_ulong value1,
target_ulong value2)
{
CPUPPCState *env = &cpu->env;
assert(tcg_enabled()); /* KVM will have handled this */
if (mflags) {
return H_UNSUPPORTED_FLAG;
}
if (value2) {
return H_P4;
}
if ((value1 & PPC_BITMASK(62, 63)) == 0x3) {
return H_P3;
}
ppc_store_ciabr(env, value1);
return H_SUCCESS;
}
static target_ulong h_set_mode_resource_set_dawr0(PowerPCCPU *cpu,
SpaprMachineState *spapr,
target_ulong mflags,
target_ulong value1,
target_ulong value2)
{
CPUPPCState *env = &cpu->env;
assert(tcg_enabled()); /* KVM will have handled this */
if (mflags) {
return H_UNSUPPORTED_FLAG;
}
if (value2 & PPC_BIT(61)) {
return H_P4;
}
ppc_store_dawr0(env, value1);
ppc_store_dawrx0(env, value2);
return H_SUCCESS;
}
static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu,
SpaprMachineState *spapr,
target_ulong mflags,
@@ -858,6 +907,14 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong ret = H_P2;
switch (resource) {
case H_SET_MODE_RESOURCE_SET_CIABR:
ret = h_set_mode_resource_set_ciabr(cpu, spapr, args[0], args[2],
args[3]);
break;
case H_SET_MODE_RESOURCE_SET_DAWR0:
ret = h_set_mode_resource_set_dawr0(cpu, spapr, args[0], args[2],
args[3]);
break;
case H_SET_MODE_RESOURCE_LE:
ret = h_set_mode_resource_le(cpu, spapr, args[0], args[2], args[3]);
break;
+2
View File
@@ -1024,6 +1024,8 @@ void vof_cleanup(Vof *vof)
}
vof->claimed = NULL;
vof->of_instances = NULL;
vof->of_instance_last = 0;
vof->claimed_base = 0;
}
void vof_build_dt(void *fdt, Vof *vof)
+2 -1
View File
@@ -54,7 +54,8 @@ struct ppc_tb_t {
*/
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
void cpu_ppc_tb_reset(CPUPPCState *env);
void cpu_ppc_tb_free(CPUPPCState *env);
void cpu_ppc_hdecr_init(CPUPPCState *env);
void cpu_ppc_hdecr_exit(CPUPPCState *env);
+2
View File
@@ -204,6 +204,7 @@ struct SpaprMachineState {
uint32_t fdt_size;
uint32_t fdt_initial_size;
void *fdt_blob;
uint8_t fdt_rng_seed[32];
long kernel_size;
bool kernel_le;
uint64_t kernel_addr;
@@ -1012,6 +1013,7 @@ bool spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize,
#define SPAPR_OV5_XIVE_BOTH 0x80 /* Only to advertise on the platform */
void spapr_set_all_lpcrs(target_ulong value, target_ulong mask);
void spapr_init_all_lpcrs(target_ulong value, target_ulong mask);
hwaddr spapr_get_rtas_addr(void);
bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr);
+2
View File
@@ -401,6 +401,7 @@ struct XiveRouterClass {
int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
XiveNVT *nvt, uint8_t word_number);
uint8_t (*get_block_id)(XiveRouter *xrtr);
void (*end_notify)(XiveRouter *xrtr, XiveEAS *eas);
};
int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
@@ -414,6 +415,7 @@ int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
XiveNVT *nvt, uint8_t word_number);
void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked);
void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas);
/*
* XIVE Presenter
+20 -1
View File
@@ -56,6 +56,11 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
return (__int128_t)a * b / c;
}
static inline uint64_t muldiv64_round_up(uint64_t a, uint32_t b, uint32_t c)
{
return ((__int128_t)a * b + c - 1) / c;
}
static inline uint64_t divu128(uint64_t *plow, uint64_t *phigh,
uint64_t divisor)
{
@@ -83,7 +88,8 @@ void mulu64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b);
uint64_t divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor);
int64_t divs128(uint64_t *plow, int64_t *phigh, int64_t divisor);
static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
static inline uint64_t muldiv64_rounding(uint64_t a, uint32_t b, uint32_t c,
bool round_up)
{
union {
uint64_t ll;
@@ -99,12 +105,25 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
u.ll = a;
rl = (uint64_t)u.l.low * (uint64_t)b;
if (round_up) {
rl += c - 1;
}
rh = (uint64_t)u.l.high * (uint64_t)b;
rh += (rl >> 32);
res.l.high = rh / c;
res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
return res.ll;
}
static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
{
return muldiv64_rounding(a, b, c, false);
}
static inline uint64_t muldiv64_round_up(uint64_t a, uint32_t b, uint32_t c)
{
return muldiv64_rounding(a, b, c, true);
}
#endif
/**
+19
View File
@@ -229,6 +229,25 @@ int ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
return 0;
}
/* To be used when the machine is not running */
int ppc_init_compat_all(uint32_t compat_pvr, Error **errp)
{
CPUState *cs;
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
int ret;
ret = ppc_set_compat(cpu, compat_pvr, errp);
if (ret < 0) {
return ret;
}
}
return 0;
}
int ppc_compat_max_vthreads(PowerPCCPU *cpu)
{
const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
+87
View File
@@ -59,6 +59,7 @@ void ppc_store_vscr(CPUPPCState *env, uint32_t vscr)
env->vscr_sat.u64[0] = vscr & (1u << VSCR_SAT);
env->vscr_sat.u64[1] = 0;
set_flush_to_zero((vscr >> VSCR_NJ) & 1, &env->vec_status);
set_flush_inputs_to_zero((vscr >> VSCR_NJ) & 1, &env->vec_status);
}
uint32_t ppc_get_vscr(CPUPPCState *env)
@@ -102,6 +103,92 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
ppc_maybe_interrupt(env);
}
#if defined(TARGET_PPC64)
void ppc_update_ciabr(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
target_ulong ciabr = env->spr[SPR_CIABR];
target_ulong ciea, priv;
ciea = ciabr & PPC_BITMASK(0, 61);
priv = ciabr & PPC_BITMASK(62, 63);
if (env->ciabr_breakpoint) {
cpu_breakpoint_remove_by_ref(cs, env->ciabr_breakpoint);
env->ciabr_breakpoint = NULL;
}
if (priv) {
cpu_breakpoint_insert(cs, ciea, BP_CPU, &env->ciabr_breakpoint);
}
}
void ppc_store_ciabr(CPUPPCState *env, target_ulong val)
{
env->spr[SPR_CIABR] = val;
ppc_update_ciabr(env);
}
void ppc_update_daw0(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
target_ulong deaw = env->spr[SPR_DAWR0] & PPC_BITMASK(0, 60);
uint32_t dawrx = env->spr[SPR_DAWRX0];
int mrd = extract32(dawrx, PPC_BIT_NR(48), 54 - 48);
bool dw = extract32(dawrx, PPC_BIT_NR(57), 1);
bool dr = extract32(dawrx, PPC_BIT_NR(58), 1);
bool hv = extract32(dawrx, PPC_BIT_NR(61), 1);
bool sv = extract32(dawrx, PPC_BIT_NR(62), 1);
bool pr = extract32(dawrx, PPC_BIT_NR(62), 1);
vaddr len;
int flags;
if (env->dawr0_watchpoint) {
cpu_watchpoint_remove_by_ref(cs, env->dawr0_watchpoint);
env->dawr0_watchpoint = NULL;
}
if (!dr && !dw) {
return;
}
if (!hv && !sv && !pr) {
return;
}
len = (mrd + 1) * 8;
flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
if (dr) {
flags |= BP_MEM_READ;
}
if (dw) {
flags |= BP_MEM_WRITE;
}
cpu_watchpoint_insert(cs, deaw, len, flags, &env->dawr0_watchpoint);
}
void ppc_store_dawr0(CPUPPCState *env, target_ulong val)
{
env->spr[SPR_DAWR0] = val;
ppc_update_daw0(env);
}
void ppc_store_dawrx0(CPUPPCState *env, uint32_t val)
{
int hrammc = extract32(val, PPC_BIT_NR(56), 1);
if (hrammc) {
/* This might be done with a second watchpoint at the xor of DEAW[0] */
qemu_log_mask(LOG_UNIMP, "%s: DAWRX0[HRAMMC] is unimplemented\n",
__func__);
}
env->spr[SPR_DAWRX0] = val;
ppc_update_daw0(env);
}
#endif
#endif
static inline void fpscr_set_rounding_mode(CPUPPCState *env)

Some files were not shown because too many files have changed in this diff Show More