* PAPR nested hypervisor host implementation for spapr TCG
* excp_helper.c code cleanups and improvements * Move more ops to decodetree * Deprecate pseries-2.12 machines and P9 and P10 DD1.0 CPUs * Document running Linux on AmigaNG * Update dt feature advertising POWER CPUs. * Add P10 PMU SPRs * Improve pnv topology calculation for SMT8 CPUs. * Various bug fixes. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmXwiT8ACgkQZ7MCdqhi HK7C/w//XxEO2bQTFPLFDTrP/voq7pcX8XeQNVyXCkXYjvsbu05oQow50k+Y5UAE US4MFjt8jFz0vuIKuKyoA3kG41zDSOzoX4TQXMM+tyTWbuFF3KAyfizb1xE6SYAN xJEGvmiXv/EgoSBD7BTKQp1tMPdIGZLwSdYiA0lmOo7YaMCgYAXaujW5hnNjQecT 873sN+10pHtQY++mINtD9Nfb6AcDGMWw0b+bykqIXhNRkI8IGOS4WF4vAuMBrwfe UM00wDnNRb86Dk14bv2XVNDr6/i0VRtUMwM4yiptrQ1TQx18LZaPSQFYjQfPaan7 LwN4QkMFnBX54yJ7Npvjvu8BCBF47kwOVu4CIAFJ4sIm0WfTmozDpPttwcZ5w7Ve iXDOB9ECAB4pQ2rCgbSNG8MYUZgoHHOuThqolOP0Vh9NHRRJxpdw6CyAbmCGftc0 lvRDPFiKp8xmCNJ/j3XzoUdHoG7NMwpUmHv9ruGU18SdQ8hyJN9AcQGWYrB4v0RV /hs2RAbwntG7ahkcwd8uy5aFw88Wph/uGXPXc49EWj7i49vHeIV2y5+gtthMywje qqjFXkistXuF+JHVnyoYmqqCyXaHX5CEwtawMv4EQeaJs76bLhMeMTKKl9rRp8qB DtbIZphO8iMsocrBnje48sA5HR0PM+H4HTjw10i8R0fLlWitaIY= =XnY5 -----END PGP SIGNATURE----- Merge tag 'pull-ppc-for-9.0-2-20240313' of https://gitlab.com/npiggin/qemu into staging * PAPR nested hypervisor host implementation for spapr TCG * excp_helper.c code cleanups and improvements * Move more ops to decodetree * Deprecate pseries-2.12 machines and P9 and P10 DD1.0 CPUs * Document running Linux on AmigaNG * Update dt feature advertising POWER CPUs. * Add P10 PMU SPRs * Improve pnv topology calculation for SMT8 CPUs. * Various bug fixes. # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmXwiT8ACgkQZ7MCdqhi # HK7C/w//XxEO2bQTFPLFDTrP/voq7pcX8XeQNVyXCkXYjvsbu05oQow50k+Y5UAE # US4MFjt8jFz0vuIKuKyoA3kG41zDSOzoX4TQXMM+tyTWbuFF3KAyfizb1xE6SYAN # xJEGvmiXv/EgoSBD7BTKQp1tMPdIGZLwSdYiA0lmOo7YaMCgYAXaujW5hnNjQecT # 873sN+10pHtQY++mINtD9Nfb6AcDGMWw0b+bykqIXhNRkI8IGOS4WF4vAuMBrwfe # UM00wDnNRb86Dk14bv2XVNDr6/i0VRtUMwM4yiptrQ1TQx18LZaPSQFYjQfPaan7 # LwN4QkMFnBX54yJ7Npvjvu8BCBF47kwOVu4CIAFJ4sIm0WfTmozDpPttwcZ5w7Ve # iXDOB9ECAB4pQ2rCgbSNG8MYUZgoHHOuThqolOP0Vh9NHRRJxpdw6CyAbmCGftc0 # lvRDPFiKp8xmCNJ/j3XzoUdHoG7NMwpUmHv9ruGU18SdQ8hyJN9AcQGWYrB4v0RV # /hs2RAbwntG7ahkcwd8uy5aFw88Wph/uGXPXc49EWj7i49vHeIV2y5+gtthMywje # qqjFXkistXuF+JHVnyoYmqqCyXaHX5CEwtawMv4EQeaJs76bLhMeMTKKl9rRp8qB # DtbIZphO8iMsocrBnje48sA5HR0PM+H4HTjw10i8R0fLlWitaIY= # =XnY5 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 12 Mar 2024 16:56:31 GMT # gpg: using RSA key 4E437DDA56616F4329B0A79567B30276A8621CAE # gpg: Good signature from "Nicholas Piggin <npiggin@gmail.com>" [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: 4E43 7DDA 5661 6F43 29B0 A795 67B3 0276 A862 1CAE * tag 'pull-ppc-for-9.0-2-20240313' of https://gitlab.com/npiggin/qemu: (38 commits) spapr: nested: Introduce cap-nested-papr for Nested PAPR API spapr: nested: Introduce H_GUEST_RUN_VCPU hcall. spapr: nested: Use correct source for parttbl info for nested PAPR API. spapr: nested: Introduce H_GUEST_[GET|SET]_STATE hcalls. spapr: nested: Initialize the GSB elements lookup table. spapr: nested: Extend nested_ppc_state for nested PAPR API spapr: nested: Introduce H_GUEST_CREATE_VCPU hcall. spapr: nested: Introduce H_GUEST_[CREATE|DELETE] hcalls. spapr: nested: Introduce H_GUEST_[GET|SET]_CAPABILITIES hcalls. spapr: nested: Document Nested PAPR API spapr: nested: keep nested-hv related code restricted to its API. spapr: nested: Introduce SpaprMachineStateNested to store related info. spapr: nested: move nested part of spapr_get_pate into spapr_nested.c spapr: nested: register nested-hv api hcalls only for cap-nested-hv target/ppc: Remove interrupt handler wrapper functions target/ppc: Clean up ifdefs in excp_helper.c, part 3 target/ppc: Clean up ifdefs in excp_helper.c, part 2 target/ppc: Clean up ifdefs in excp_helper.c, part 1 target/ppc: Add gen_exception_err_nip() function target/ppc: Readability improvements in exception handlers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
51e31f2140
@ -316,7 +316,6 @@ F: tests/tcg/openrisc/
|
||||
PowerPC TCG CPUs
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
M: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: Cédric Le Goater <clg@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: target/ppc/
|
||||
@ -468,7 +467,6 @@ F: target/mips/sysemu/
|
||||
PPC KVM CPUs
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: Cédric Le Goater <clg@kaod.org>
|
||||
S: Odd Fixes
|
||||
F: target/ppc/kvm.c
|
||||
|
||||
@ -1508,7 +1506,6 @@ F: tests/avocado/ppc_prep_40p.py
|
||||
sPAPR (pseries)
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: Cédric Le Goater <clg@kaod.org>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Harsh Prateek Bora <harshpb@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
@ -1575,6 +1572,7 @@ F: hw/rtc/m41t80.c
|
||||
F: pc-bios/canyonlands.dt[sb]
|
||||
F: pc-bios/u-boot-sam460ex-20100605.bin
|
||||
F: roms/u-boot-sam460ex
|
||||
F: docs/system/ppc/amigang.rst
|
||||
|
||||
pegasos2
|
||||
M: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
|
@ -237,13 +237,13 @@ The Nios II architecture is orphan.
|
||||
The machine is no longer in existence and has been long unmaintained
|
||||
in QEMU. This also holds for the TC51828 16MiB flash that it uses.
|
||||
|
||||
``pseries-2.1`` up to ``pseries-2.11`` (since 9.0)
|
||||
``pseries-2.1`` up to ``pseries-2.12`` (since 9.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Older pseries machines before version 2.12 have undergone many changes
|
||||
Older pseries machines before version 3.0 have undergone many changes
|
||||
to correct issues, mostly regarding migration compatibility. These are
|
||||
no longer maintained and removing them will make the code easier to
|
||||
read and maintain. Use versions 2.12 and above as a replacement.
|
||||
read and maintain. Use versions 3.0 and above as a replacement.
|
||||
|
||||
Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (since 9.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
119
docs/devel/nested-papr.txt
Normal file
119
docs/devel/nested-papr.txt
Normal file
@ -0,0 +1,119 @@
|
||||
Nested PAPR API (aka KVM on PowerVM)
|
||||
====================================
|
||||
|
||||
This API aims at providing support to enable nested virtualization with
|
||||
KVM on PowerVM. While the existing support for nested KVM on PowerNV was
|
||||
introduced with cap-nested-hv option, however, with a slight design change,
|
||||
to enable this on papr/pseries, a new cap-nested-papr option is added. eg:
|
||||
|
||||
qemu-system-ppc64 -cpu POWER10 -machine pseries,cap-nested-papr=true ...
|
||||
|
||||
Work by:
|
||||
Michael Neuling <mikey@neuling.org>
|
||||
Vaibhav Jain <vaibhav@linux.ibm.com>
|
||||
Jordan Niethe <jniethe5@gmail.com>
|
||||
Harsh Prateek Bora <harshpb@linux.ibm.com>
|
||||
Shivaprasad G Bhat <sbhat@linux.ibm.com>
|
||||
Kautuk Consul <kconsul@linux.vnet.ibm.com>
|
||||
|
||||
Below taken from the kernel documentation:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document explains how a guest operating system can act as a
|
||||
hypervisor and run nested guests through the use of hypercalls, if the
|
||||
hypervisor has implemented them. The terms L0, L1, and L2 are used to
|
||||
refer to different software entities. L0 is the hypervisor mode entity
|
||||
that would normally be called the "host" or "hypervisor". L1 is a
|
||||
guest virtual machine that is directly run under L0 and is initiated
|
||||
and controlled by L0. L2 is a guest virtual machine that is initiated
|
||||
and controlled by L1 acting as a hypervisor. A significant design change
|
||||
wrt existing API is that now the entire L2 state is maintained within L0.
|
||||
|
||||
Existing Nested-HV API
|
||||
======================
|
||||
|
||||
Linux/KVM has had support for Nesting as an L0 or L1 since 2018
|
||||
|
||||
The L0 code was added::
|
||||
|
||||
commit 8e3f5fc1045dc49fd175b978c5457f5f51e7a2ce
|
||||
Author: Paul Mackerras <paulus@ozlabs.org>
|
||||
Date: Mon Oct 8 16:31:03 2018 +1100
|
||||
KVM: PPC: Book3S HV: Framework and hcall stubs for nested virtualization
|
||||
|
||||
The L1 code was added::
|
||||
|
||||
commit 360cae313702cdd0b90f82c261a8302fecef030a
|
||||
Author: Paul Mackerras <paulus@ozlabs.org>
|
||||
Date: Mon Oct 8 16:31:04 2018 +1100
|
||||
KVM: PPC: Book3S HV: Nested guest entry via hypercall
|
||||
|
||||
This API works primarily using a signal hcall h_enter_nested(). This
|
||||
call made by the L1 to tell the L0 to start an L2 vCPU with the given
|
||||
state. The L0 then starts this L2 and runs until an L2 exit condition
|
||||
is reached. Once the L2 exits, the state of the L2 is given back to
|
||||
the L1 by the L0. The full L2 vCPU state is always transferred from
|
||||
and to L1 when the L2 is run. The L0 doesn't keep any state on the L2
|
||||
vCPU (except in the short sequence in the L0 on L1 -> L2 entry and L2
|
||||
-> L1 exit).
|
||||
|
||||
The only state kept by the L0 is the partition table. The L1 registers
|
||||
it's partition table using the h_set_partition_table() hcall. All
|
||||
other state held by the L0 about the L2s is cached state (such as
|
||||
shadow page tables).
|
||||
|
||||
The L1 may run any L2 or vCPU without first informing the L0. It
|
||||
simply starts the vCPU using h_enter_nested(). The creation of L2s and
|
||||
vCPUs is done implicitly whenever h_enter_nested() is called.
|
||||
|
||||
In this document, we call this existing API the v1 API.
|
||||
|
||||
New PAPR API
|
||||
===============
|
||||
|
||||
The new PAPR API changes from the v1 API such that the creating L2 and
|
||||
associated vCPUs is explicit. In this document, we call this the v2
|
||||
API.
|
||||
|
||||
h_enter_nested() is replaced with H_GUEST_VCPU_RUN(). Before this can
|
||||
be called the L1 must explicitly create the L2 using h_guest_create()
|
||||
and any associated vCPUs() created with h_guest_create_vCPU(). Getting
|
||||
and setting vCPU state can also be performed using h_guest_{g|s}et
|
||||
hcall.
|
||||
|
||||
The basic execution flow is for an L1 to create an L2, run it, and
|
||||
delete it is:
|
||||
|
||||
- L1 and L0 negotiate capabilities with H_GUEST_{G,S}ET_CAPABILITIES()
|
||||
(normally at L1 boot time).
|
||||
|
||||
- L1 requests the L0 to create an L2 with H_GUEST_CREATE() and receives a token
|
||||
|
||||
- L1 requests the L0 to create an L2 vCPU with H_GUEST_CREATE_VCPU()
|
||||
|
||||
- L1 and L0 communicate the vCPU state using the H_GUEST_{G,S}ET() hcall
|
||||
|
||||
- L1 requests the L0 to run the vCPU using H_GUEST_RUN_VCPU() hcall
|
||||
|
||||
- L1 deletes L2 with H_GUEST_DELETE()
|
||||
|
||||
For more details, please refer:
|
||||
|
||||
[1] Linux Kernel documentation (upstream documentation commit):
|
||||
|
||||
commit 476652297f94a2e5e5ef29e734b0da37ade94110
|
||||
Author: Michael Neuling <mikey@neuling.org>
|
||||
Date: Thu Sep 14 13:06:00 2023 +1000
|
||||
|
||||
docs: powerpc: Document nested KVM on POWER
|
||||
|
||||
Document support for nested KVM on POWER using the existing API as well
|
||||
as the new PAPR API. This includes the new HCALL interface and how it
|
||||
used by KVM.
|
||||
|
||||
Signed-off-by: Michael Neuling <mikey@neuling.org>
|
||||
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
|
||||
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
|
||||
Link: https://msgid.link/20230914030600.16993-12-jniethe5@gmail.com
|
161
docs/system/ppc/amigang.rst
Normal file
161
docs/system/ppc/amigang.rst
Normal file
@ -0,0 +1,161 @@
|
||||
=========================================================
|
||||
AmigaNG boards (``amigaone``, ``pegasos2``, ``sam460ex``)
|
||||
=========================================================
|
||||
|
||||
These PowerPC machines emulate boards that are primarily used for
|
||||
running Amiga like OSes (AmigaOS 4, MorphOS and AROS) but these can
|
||||
also run Linux which is what this section documents.
|
||||
|
||||
Eyetech AmigaOne/Mai Logic Teron (``amigaone``)
|
||||
===============================================
|
||||
|
||||
The ``amigaone`` machine emulates an AmigaOne XE mainboard by Eyetech
|
||||
which is a rebranded Mai Logic Teron board with modified U-Boot
|
||||
firmware to support AmigaOS 4.
|
||||
|
||||
Emulated devices
|
||||
----------------
|
||||
|
||||
* PowerPC 7457 CPU (can also use``-cpu g3, 750cxe, 750fx`` or ``750gx``)
|
||||
* Articia S north bridge
|
||||
* VIA VT82C686B south bridge
|
||||
* PCI VGA compatible card (guests may need other card instead)
|
||||
* PS/2 keyboard and mouse
|
||||
|
||||
Firmware
|
||||
--------
|
||||
|
||||
A firmware binary is necessary for the boot process. It is a modified
|
||||
U-Boot under GPL but its source is lost so it cannot be included in
|
||||
QEMU. A binary is available at
|
||||
https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28.
|
||||
The ROM image is in the last 512kB which can be extracted with the
|
||||
following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ tail -c 524288 updater.image > u-boot-amigaone.bin
|
||||
|
||||
The BIOS emulator in the firmware is unable to run QEMU‘s standard
|
||||
vgabios so ``VGABIOS-lgpl-latest.bin`` is needed instead which can be
|
||||
downloaded from http://www.nongnu.org/vgabios.
|
||||
|
||||
Running Linux
|
||||
-------------
|
||||
|
||||
There are some Linux images under the following link that work on the
|
||||
``amigaone`` machine:
|
||||
https://sourceforge.net/projects/amigaone-linux/files/debian-installer/.
|
||||
To boot the system run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-ppc -machine amigaone -bios u-boot-amigaone.bin \
|
||||
-cdrom "A1 Linux Net Installer.iso" \
|
||||
-device ati-vga,model=rv100,romfile=VGABIOS-lgpl-latest.bin
|
||||
|
||||
From the firmware menu that appears select ``Boot sequence`` →
|
||||
``Amiga Multiboot Options`` and set ``Boot device 1`` to
|
||||
``Onboard VIA IDE CDROM``. Then hit escape until the main screen appears again,
|
||||
hit escape once more and from the exit menu that appears select either
|
||||
``Save settings and exit`` or ``Use settings for this session only``. It may
|
||||
take a long time loading the kernel into memory but eventually it boots and the
|
||||
installer becomes visible. The ``ati-vga`` RV100 emulation is not
|
||||
complete yet so only frame buffer works, DRM and 3D is not available.
|
||||
|
||||
Genesi/bPlan Pegasos II (``pegasos2``)
|
||||
======================================
|
||||
|
||||
The ``pegasos2`` machine emulates the Pegasos II sold by Genesi and
|
||||
designed by bPlan. Its schematics are available at
|
||||
https://www.powerdeveloper.org/platforms/pegasos/schematics.
|
||||
|
||||
Emulated devices
|
||||
----------------
|
||||
|
||||
* PowerPC 7457 CPU (can also use``-cpu g3`` or ``750cxe``)
|
||||
* Marvell MV64361 Discovery II north bridge
|
||||
* VIA VT8231 south bridge
|
||||
* PCI VGA compatible card (guests may need other card instead)
|
||||
* PS/2 keyboard and mouse
|
||||
|
||||
Firmware
|
||||
--------
|
||||
|
||||
The Pegasos II board has an Open Firmware compliant ROM based on
|
||||
SmartFirmware with some changes that are not open-sourced therefore
|
||||
the ROM binary cannot be included in QEMU. An updater was available
|
||||
from bPlan, it can be found in the `Internet Archive
|
||||
<http://web.archive.org/web/20071021223056/http://www.bplan-gmbh.de/up050404/up050404>`_.
|
||||
The ROM image can be extracted from it with the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ tail -c +85581 up050404 | head -c 524288 > pegasos2.rom
|
||||
|
||||
Running Linux
|
||||
-------------
|
||||
|
||||
The PowerPC version of Debian 8.11 supported Pegasos II. The BIOS
|
||||
emulator in the firmware binary is unable to run QEMU‘s standard
|
||||
vgabios so it needs to be disabled. To boot the system run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-ppc -machine pegasos2 -bios pegasos2.rom \
|
||||
-cdrom debian-8.11.0-powerpc-netinst.iso \
|
||||
-device VGA,romfile="" -serial stdio
|
||||
|
||||
At the firmware ``ok`` prompt enter ``boot cd install/pegasos``.
|
||||
|
||||
Alternatively, it is possible to boot the kernel directly without
|
||||
firmware ROM using the QEMU built-in minimal Virtual Open Firmware
|
||||
(VOF) emulation which is also supported on ``pegasos2``. For this,
|
||||
extract the kernel ``install/powerpc/vmlinuz-chrp.initrd`` from the CD
|
||||
image, then run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-ppc -machine pegasos2 -serial stdio \
|
||||
-kernel vmlinuz-chrp.initrd -append "---" \
|
||||
-cdrom debian-8.11.0-powerpc-netinst.iso
|
||||
|
||||
aCube Sam460ex (``sam460ex``)
|
||||
=============================
|
||||
|
||||
The ``sam460ex`` machine emulates the Sam460ex board by aCube which is
|
||||
based on the AMCC PowerPC 460EX SoC (that despite its name has a
|
||||
PPC440 CPU core).
|
||||
|
||||
Firmware
|
||||
--------
|
||||
|
||||
The board has a firmware based on an older U-Boot version with
|
||||
modifications to support booting AmigaOS 4. The firmware ROM is
|
||||
included with QEMU.
|
||||
|
||||
Emulated devices
|
||||
----------------
|
||||
|
||||
* PowerPC 460EX SoC
|
||||
* M41T80 serial RTC chip
|
||||
* Silicon Motion SM501 display parts (identical to SM502 on real board)
|
||||
* Silicon Image SiI3112 2 port SATA controller
|
||||
* USB keyboard and mouse
|
||||
|
||||
Running Linux
|
||||
-------------
|
||||
|
||||
The only Linux distro that supported Sam460ex out of box was CruxPPC
|
||||
2.x. It can be booted by running:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-ppc -machine sam460ex -serial stdio \
|
||||
-drive if=none,id=cd,format=raw,file=crux-ppc-2.7a.iso \
|
||||
-device ide-cd,drive=cd,bus=ide.1
|
||||
|
||||
There are some other kernels and instructions for booting other
|
||||
distros on aCube's product page at
|
||||
https://www.acube-systems.biz/index.php?page=hardware&pid=5
|
||||
but those are untested.
|
@ -17,6 +17,7 @@ help``.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ppc/amigang
|
||||
ppc/embedded
|
||||
ppc/powermac
|
||||
ppc/powernv
|
||||
|
175
hw/ppc/pnv.c
175
hw/ppc/pnv.c
@ -133,7 +133,7 @@ static int get_cpus_node(void *fdt)
|
||||
* device tree, used in XSCOM to address cores and in interrupt
|
||||
* servers.
|
||||
*/
|
||||
static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
|
||||
static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
|
||||
{
|
||||
PowerPCCPU *cpu = pc->threads[0];
|
||||
CPUState *cs = CPU(cpu);
|
||||
@ -141,32 +141,31 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
|
||||
int smt_threads = CPU_CORE(pc)->nr_threads;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||
PnvChipClass *pnv_cc = PNV_CHIP_GET_CLASS(chip);
|
||||
g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads);
|
||||
int i;
|
||||
uint32_t pir;
|
||||
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
||||
0xffffffff, 0xffffffff};
|
||||
uint32_t tbfreq = PNV_TIMEBASE_FREQ;
|
||||
uint32_t cpufreq = 1000000000;
|
||||
uint32_t page_sizes_prop[64];
|
||||
size_t page_sizes_prop_size;
|
||||
const uint8_t pa_features[] = { 24, 0,
|
||||
0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
|
||||
int offset;
|
||||
char *nodename;
|
||||
int cpus_offset = get_cpus_node(fdt);
|
||||
|
||||
nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
|
||||
pir = pnv_cc->chip_pir(chip, pc->hwid, 0);
|
||||
|
||||
nodename = g_strdup_printf("%s@%x", dc->fw_name, pir);
|
||||
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
|
||||
_FDT(offset);
|
||||
g_free(nodename);
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "reg", pir)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pir)));
|
||||
_FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
|
||||
@ -236,20 +235,21 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
|
||||
page_sizes_prop, page_sizes_prop_size)));
|
||||
}
|
||||
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||
pa_features, sizeof(pa_features))));
|
||||
|
||||
/* Build interrupt servers properties */
|
||||
for (i = 0; i < smt_threads; i++) {
|
||||
servers_prop[i] = cpu_to_be32(pc->pir + i);
|
||||
servers_prop[i] = cpu_to_be32(pnv_cc->chip_pir(chip, pc->hwid, i));
|
||||
}
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
|
||||
servers_prop, sizeof(*servers_prop) * smt_threads)));
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
|
||||
static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t hwid,
|
||||
uint32_t nr_threads)
|
||||
{
|
||||
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
|
||||
uint32_t pir = pcc->chip_pir(chip, hwid, 0);
|
||||
uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
|
||||
char *name;
|
||||
const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
|
||||
@ -263,6 +263,7 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
|
||||
rsize = sizeof(uint64_t) * 2 * nr_threads;
|
||||
reg = g_malloc(rsize);
|
||||
for (i = 0; i < nr_threads; i++) {
|
||||
/* We know P8 PIR is linear with thread id */
|
||||
reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
|
||||
reg[i * 2 + 1] = cpu_to_be64(0x1000);
|
||||
}
|
||||
@ -299,6 +300,17 @@ PnvChip *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb)
|
||||
return chip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as spapr pa_features_207 except pnv always enables CI largepages bit.
|
||||
* HTM is always enabled because TCG does implement HTM, it's just a
|
||||
* degenerate implementation.
|
||||
*/
|
||||
static const uint8_t pa_features_207[] = { 24, 0,
|
||||
0xf6, 0x3f, 0xc7, 0xc0, 0x00, 0xf0,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
|
||||
|
||||
static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
|
||||
{
|
||||
static const char compat[] = "ibm,power8-xscom\0ibm,xscom";
|
||||
@ -311,11 +323,15 @@ static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
|
||||
|
||||
for (i = 0; i < chip->nr_cores; i++) {
|
||||
PnvCore *pnv_core = chip->cores[i];
|
||||
int offset;
|
||||
|
||||
pnv_dt_core(chip, pnv_core, fdt);
|
||||
offset = pnv_dt_core(chip, pnv_core, fdt);
|
||||
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||
pa_features_207, sizeof(pa_features_207))));
|
||||
|
||||
/* Interrupt Control Presenters (ICP). One per core. */
|
||||
pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
|
||||
pnv_dt_icp(chip, fdt, pnv_core->hwid, CPU_CORE(pnv_core)->nr_threads);
|
||||
}
|
||||
|
||||
if (chip->ram_size) {
|
||||
@ -323,6 +339,35 @@ static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as spapr pa_features_300 except pnv always enables CI largepages bit.
|
||||
*/
|
||||
static const uint8_t pa_features_300[] = { 66, 0,
|
||||
/* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: CILRG|fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
|
||||
/* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */
|
||||
0xf6, 0x3f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */
|
||||
/* 6: DS207 */
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
|
||||
/* 16: Vector */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
|
||||
/* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 18 - 23 */
|
||||
/* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
|
||||
/* 32: LE atomic, 34: EBB + ext EBB */
|
||||
0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
|
||||
/* 40: Radix MMU */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */
|
||||
/* 42: PM, 44: PC RA, 46: SC vec'd */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
|
||||
/* 48: SIMD, 50: QP BFP, 52: String */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
|
||||
/* 54: DecFP, 56: DecI, 58: SHA */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
|
||||
/* 60: NM atomic, 62: RNG */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
|
||||
};
|
||||
|
||||
static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
|
||||
{
|
||||
static const char compat[] = "ibm,power9-xscom\0ibm,xscom";
|
||||
@ -335,8 +380,12 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
|
||||
|
||||
for (i = 0; i < chip->nr_cores; i++) {
|
||||
PnvCore *pnv_core = chip->cores[i];
|
||||
int offset;
|
||||
|
||||
pnv_dt_core(chip, pnv_core, fdt);
|
||||
offset = pnv_dt_core(chip, pnv_core, fdt);
|
||||
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||
pa_features_300, sizeof(pa_features_300))));
|
||||
}
|
||||
|
||||
if (chip->ram_size) {
|
||||
@ -346,6 +395,40 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
|
||||
pnv_dt_lpc(chip, fdt, 0, PNV9_LPCM_BASE(chip), PNV9_LPCM_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as spapr pa_features_31 except pnv always enables CI largepages bit,
|
||||
* always disables copy/paste.
|
||||
*/
|
||||
static const uint8_t pa_features_31[] = { 74, 0,
|
||||
/* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: CILRG|fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
|
||||
/* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */
|
||||
0xf6, 0x3f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */
|
||||
/* 6: DS207 */
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
|
||||
/* 16: Vector */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
|
||||
/* 18: Vec. Scalar, 20: Vec. XOR */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
|
||||
/* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
|
||||
/* 32: LE atomic, 34: EBB + ext EBB */
|
||||
0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
|
||||
/* 40: Radix MMU */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */
|
||||
/* 42: PM, 44: PC RA, 46: SC vec'd */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
|
||||
/* 48: SIMD, 50: QP BFP, 52: String */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
|
||||
/* 54: DecFP, 56: DecI, 58: SHA */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
|
||||
/* 60: NM atomic, 62: RNG */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
|
||||
/* 68: DEXCR[SBHE|IBRTPDUS|SRAPD|NPHIE|PHIE] */
|
||||
0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 66 - 71 */
|
||||
/* 72: [P]HASHST/[P]HASHCHK */
|
||||
0x80, 0x00, /* 72 - 73 */
|
||||
};
|
||||
|
||||
static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
|
||||
{
|
||||
static const char compat[] = "ibm,power10-xscom\0ibm,xscom";
|
||||
@ -358,8 +441,12 @@ static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
|
||||
|
||||
for (i = 0; i < chip->nr_cores; i++) {
|
||||
PnvCore *pnv_core = chip->cores[i];
|
||||
int offset;
|
||||
|
||||
pnv_dt_core(chip, pnv_core, fdt);
|
||||
offset = pnv_dt_core(chip, pnv_core, fdt);
|
||||
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||
pa_features_31, sizeof(pa_features_31))));
|
||||
}
|
||||
|
||||
if (chip->ram_size) {
|
||||
@ -995,9 +1082,10 @@ static void pnv_init(MachineState *machine)
|
||||
* 25:28 Core number
|
||||
* 29:31 Thread ID
|
||||
*/
|
||||
static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
|
||||
static uint32_t pnv_chip_pir_p8(PnvChip *chip, uint32_t core_id,
|
||||
uint32_t thread_id)
|
||||
{
|
||||
return (chip->chip_id << 7) | (core_id << 3);
|
||||
return (chip->chip_id << 7) | (core_id << 3) | thread_id;
|
||||
}
|
||||
|
||||
static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
|
||||
@ -1049,14 +1137,37 @@ static void pnv_chip_power8_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
||||
*
|
||||
* We only care about the lower bits. uint32_t is fine for the moment.
|
||||
*/
|
||||
static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
|
||||
static uint32_t pnv_chip_pir_p9(PnvChip *chip, uint32_t core_id,
|
||||
uint32_t thread_id)
|
||||
{
|
||||
return (chip->chip_id << 8) | (core_id << 2);
|
||||
if (chip->nr_threads == 8) {
|
||||
return (chip->chip_id << 8) | ((thread_id & 1) << 2) | (core_id << 3) |
|
||||
(thread_id >> 1);
|
||||
} else {
|
||||
return (chip->chip_id << 8) | (core_id << 2) | thread_id;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pnv_chip_core_pir_p10(PnvChip *chip, uint32_t core_id)
|
||||
/*
|
||||
* 0:48 Reserved - Read as zeroes
|
||||
* 49:52 Node ID
|
||||
* 53:55 Chip ID
|
||||
* 56 Reserved - Read as zero
|
||||
* 57:59 Quad ID
|
||||
* 60 Core Chiplet Pair ID
|
||||
* 61:63 Thread/Core Chiplet ID t0-t2
|
||||
*
|
||||
* We only care about the lower bits. uint32_t is fine for the moment.
|
||||
*/
|
||||
static uint32_t pnv_chip_pir_p10(PnvChip *chip, uint32_t core_id,
|
||||
uint32_t thread_id)
|
||||
{
|
||||
return (chip->chip_id << 8) | (core_id << 2);
|
||||
if (chip->nr_threads == 8) {
|
||||
return (chip->chip_id << 8) | ((core_id / 4) << 4) |
|
||||
((core_id % 2) << 3) | thread_id;
|
||||
} else {
|
||||
return (chip->chip_id << 8) | (core_id << 2) | thread_id;
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
|
||||
@ -1235,7 +1346,7 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
|
||||
int core_hwid = CPU_CORE(pnv_core)->core_id;
|
||||
|
||||
for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
|
||||
uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
|
||||
uint32_t pir = pcc->chip_pir(chip, core_hwid, j);
|
||||
PnvICPState *icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
|
||||
|
||||
memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
|
||||
@ -1348,7 +1459,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
|
||||
k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */
|
||||
k->cores_mask = POWER8E_CORE_MASK;
|
||||
k->num_phbs = 3;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->chip_pir = pnv_chip_pir_p8;
|
||||
k->intc_create = pnv_chip_power8_intc_create;
|
||||
k->intc_reset = pnv_chip_power8_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power8_intc_destroy;
|
||||
@ -1372,7 +1483,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
|
||||
k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
|
||||
k->cores_mask = POWER8_CORE_MASK;
|
||||
k->num_phbs = 3;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->chip_pir = pnv_chip_pir_p8;
|
||||
k->intc_create = pnv_chip_power8_intc_create;
|
||||
k->intc_reset = pnv_chip_power8_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power8_intc_destroy;
|
||||
@ -1396,7 +1507,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
|
||||
k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */
|
||||
k->cores_mask = POWER8_CORE_MASK;
|
||||
k->num_phbs = 4;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->chip_pir = pnv_chip_pir_p8;
|
||||
k->intc_create = pnv_chip_power8_intc_create;
|
||||
k->intc_reset = pnv_chip_power8_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power8_intc_destroy;
|
||||
@ -1669,7 +1780,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
|
||||
k->cores_mask = POWER9_CORE_MASK;
|
||||
k->core_pir = pnv_chip_core_pir_p9;
|
||||
k->chip_pir = pnv_chip_pir_p9;
|
||||
k->intc_create = pnv_chip_power9_intc_create;
|
||||
k->intc_reset = pnv_chip_power9_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power9_intc_destroy;
|
||||
@ -1981,7 +2092,7 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
|
||||
k->cores_mask = POWER10_CORE_MASK;
|
||||
k->core_pir = pnv_chip_core_pir_p10;
|
||||
k->chip_pir = pnv_chip_pir_p10;
|
||||
k->intc_create = pnv_chip_power10_intc_create;
|
||||
k->intc_reset = pnv_chip_power10_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power10_intc_destroy;
|
||||
@ -2071,8 +2182,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
|
||||
chip->nr_threads, &error_fatal);
|
||||
object_property_set_int(OBJECT(pnv_core), CPU_CORE_PROP_CORE_ID,
|
||||
core_hwid, &error_fatal);
|
||||
object_property_set_int(OBJECT(pnv_core), "pir",
|
||||
pcc->core_pir(chip, core_hwid), &error_fatal);
|
||||
object_property_set_int(OBJECT(pnv_core), "hwid", core_hwid,
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(pnv_core), "hrmor", pnv->fw_load_addr,
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
|
||||
|
@ -226,7 +226,7 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
|
||||
int thread_index)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int core_pir;
|
||||
int core_hwid;
|
||||
ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
|
||||
ppc_spr_t *tir = &env->spr_cb[SPR_TIR];
|
||||
Error *local_err = NULL;
|
||||
@ -242,10 +242,10 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
|
||||
return;
|
||||
}
|
||||
|
||||
core_pir = object_property_get_uint(OBJECT(pc), "pir", &error_abort);
|
||||
core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
|
||||
|
||||
tir->default_value = thread_index;
|
||||
pir->default_value = core_pir + thread_index;
|
||||
pir->default_value = pcc->chip_pir(pc->chip, core_hwid, thread_index);
|
||||
|
||||
/* Set time-base frequency to 512 MHz */
|
||||
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
|
||||
@ -342,7 +342,7 @@ static void pnv_core_unrealize(DeviceState *dev)
|
||||
}
|
||||
|
||||
static Property pnv_core_properties[] = {
|
||||
DEFINE_PROP_UINT32("pir", PnvCore, pir, 0),
|
||||
DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
|
||||
DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
|
||||
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
10
hw/ppc/ppc.c
10
hw/ppc/ppc.c
@ -633,6 +633,16 @@ void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
|
||||
((uint64_t)value << 32) | tb);
|
||||
}
|
||||
|
||||
void cpu_ppc_increase_tb_by_offset(CPUPPCState *env, int64_t offset)
|
||||
{
|
||||
env->tb_env->tb_offset += offset;
|
||||
}
|
||||
|
||||
void cpu_ppc_decrease_tb_by_offset(CPUPPCState *env, int64_t offset)
|
||||
{
|
||||
env->tb_env->tb_offset -= offset;
|
||||
}
|
||||
|
||||
uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
|
@ -233,29 +233,40 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
|
||||
PowerPCCPU *cpu,
|
||||
void *fdt, int offset)
|
||||
{
|
||||
/*
|
||||
* SSO (SAO) ordering is supported on KVM and thread=single hosts,
|
||||
* but not MTTCG, so disable it. To advertise it, a cap would have
|
||||
* to be added, or support implemented for MTTCG.
|
||||
*
|
||||
* Copy/paste is not supported by TCG, so it is not advertised. KVM
|
||||
* can execute them but it has no accelerator drivers which are usable,
|
||||
* so there isn't much need for it anyway.
|
||||
*/
|
||||
|
||||
/* These should be kept in sync with pnv */
|
||||
uint8_t pa_features_206[] = { 6, 0,
|
||||
0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
|
||||
0xf6, 0x1f, 0xc7, 0x00, 0x00, 0xc0 };
|
||||
uint8_t pa_features_207[] = { 24, 0,
|
||||
0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
|
||||
0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
|
||||
uint8_t pa_features_300[] = { 66, 0,
|
||||
/* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
|
||||
/* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
|
||||
0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
|
||||
/* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */
|
||||
0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */
|
||||
/* 6: DS207 */
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
|
||||
/* 16: Vector */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
|
||||
/* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
|
||||
/* 18: Vec. Scalar, 20: Vec. XOR */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
|
||||
/* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
|
||||
/* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
|
||||
0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
|
||||
/* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
|
||||
/* 32: LE atomic, 34: EBB + ext EBB */
|
||||
0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
|
||||
/* 40: Radix MMU */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */
|
||||
/* 42: PM, 44: PC RA, 46: SC vec'd */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
|
||||
/* 48: SIMD, 50: QP BFP, 52: String */
|
||||
@ -265,6 +276,36 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
|
||||
/* 60: NM atomic, 62: RNG */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
|
||||
};
|
||||
/* 3.1 removes SAO, HTM support */
|
||||
uint8_t pa_features_31[] = { 74, 0,
|
||||
/* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
|
||||
/* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, 5: LE|CFAR|EB|LSQ */
|
||||
0xf6, 0x1f, 0xc7, 0xc0, 0x00, 0xf0, /* 0 - 5 */
|
||||
/* 6: DS207 */
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
|
||||
/* 16: Vector */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
|
||||
/* 18: Vec. Scalar, 20: Vec. XOR */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
|
||||
/* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
|
||||
/* 32: LE atomic, 34: EBB + ext EBB */
|
||||
0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
|
||||
/* 40: Radix MMU */
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 36 - 41 */
|
||||
/* 42: PM, 44: PC RA, 46: SC vec'd */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
|
||||
/* 48: SIMD, 50: QP BFP, 52: String */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
|
||||
/* 54: DecFP, 56: DecI, 58: SHA */
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
|
||||
/* 60: NM atomic, 62: RNG */
|
||||
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
|
||||
/* 68: DEXCR[SBHE|IBRTPDUS|SRAPD|NPHIE|PHIE] */
|
||||
0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 66 - 71 */
|
||||
/* 72: [P]HASHST/[P]HASHCHK */
|
||||
0x80, 0x00, /* 72 - 73 */
|
||||
};
|
||||
uint8_t *pa_features = NULL;
|
||||
size_t pa_size;
|
||||
|
||||
@ -280,6 +321,10 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
|
||||
pa_features = pa_features_300;
|
||||
pa_size = sizeof(pa_features_300);
|
||||
}
|
||||
if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, cpu->compat_pvr)) {
|
||||
pa_features = pa_features_31;
|
||||
pa_size = sizeof(pa_features_31);
|
||||
}
|
||||
if (!pa_features) {
|
||||
return;
|
||||
}
|
||||
@ -1362,7 +1407,6 @@ void spapr_init_all_lpcrs(target_ulong value, target_ulong mask)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
|
||||
target_ulong lpid, ppc_v3_pate_t *entry)
|
||||
{
|
||||
@ -1375,33 +1419,16 @@ static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
|
||||
/* Copy PATE1:GR into PATE0:HR */
|
||||
entry->dw0 = spapr->patb_entry & PATE0_HR;
|
||||
entry->dw1 = spapr->patb_entry;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
uint64_t patb, pats;
|
||||
|
||||
assert(lpid != 0);
|
||||
|
||||
patb = spapr->nested_ptcr & PTCR_PATB;
|
||||
pats = spapr->nested_ptcr & PTCR_PATS;
|
||||
|
||||
/* Check if partition table is properly aligned */
|
||||
if (patb & MAKE_64BIT_MASK(0, pats + 12)) {
|
||||
return false;
|
||||
if (spapr_nested_api(spapr) == NESTED_API_KVM_HV) {
|
||||
return spapr_get_pate_nested_hv(spapr, cpu, lpid, entry);
|
||||
} else if (spapr_nested_api(spapr) == NESTED_API_PAPR) {
|
||||
return spapr_get_pate_nested_papr(spapr, cpu, lpid, entry);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/* Calculate number of entries */
|
||||
pats = 1ull << (pats + 12 - 4);
|
||||
if (pats <= lpid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Grab entry */
|
||||
patb += 16 * lpid;
|
||||
entry->dw0 = ldq_phys(CPU(cpu)->as, patb);
|
||||
entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
|
||||
@ -1689,6 +1716,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
|
||||
|
||||
pef_kvm_reset(machine->cgs, &error_fatal);
|
||||
spapr_caps_apply(spapr);
|
||||
spapr_nested_reset(spapr);
|
||||
|
||||
first_ppc_cpu = POWERPC_CPU(first_cpu);
|
||||
if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
|
||||
@ -2138,6 +2166,7 @@ static const VMStateDescription vmstate_spapr = {
|
||||
&vmstate_spapr_cap_fwnmi,
|
||||
&vmstate_spapr_fwnmi,
|
||||
&vmstate_spapr_cap_rpt_invalidate,
|
||||
&vmstate_spapr_cap_nested_papr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
@ -4702,6 +4731,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
|
||||
smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
|
||||
smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
|
||||
smc->default_caps.caps[SPAPR_CAP_NESTED_PAPR] = SPAPR_CAP_OFF;
|
||||
smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
|
||||
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
|
||||
smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
|
||||
|
@ -484,6 +484,50 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr,
|
||||
error_append_hint(errp, "Try appending -machine cap-nested-hv=off "
|
||||
"or use threads=1 with -smp\n");
|
||||
}
|
||||
if (spapr_nested_api(spapr) &&
|
||||
spapr_nested_api(spapr) != NESTED_API_KVM_HV) {
|
||||
error_setg(errp, "Nested-HV APIs are mutually exclusive");
|
||||
error_append_hint(errp, "Please use either cap-nested-hv or "
|
||||
"cap-nested-papr to proceed.\n");
|
||||
return;
|
||||
} else {
|
||||
spapr->nested.api = NESTED_API_KVM_HV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cap_nested_papr_apply(SpaprMachineState *spapr,
|
||||
uint8_t val, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if (!val) {
|
||||
/* capability disabled by default */
|
||||
return;
|
||||
}
|
||||
|
||||
if (tcg_enabled()) {
|
||||
if (!(env->insns_flags2 & PPC2_ISA300)) {
|
||||
error_setg(errp, "Nested-PAPR only supported on POWER9 and later");
|
||||
error_append_hint(errp,
|
||||
"Try appending -machine cap-nested-papr=off\n");
|
||||
return;
|
||||
}
|
||||
if (spapr_nested_api(spapr) &&
|
||||
spapr_nested_api(spapr) != NESTED_API_PAPR) {
|
||||
error_setg(errp, "Nested-HV APIs are mutually exclusive");
|
||||
error_append_hint(errp, "Please use either cap-nested-hv or "
|
||||
"cap-nested-papr to proceed.\n");
|
||||
return;
|
||||
} else {
|
||||
spapr->nested.api = NESTED_API_PAPR;
|
||||
}
|
||||
} else if (kvm_enabled()) {
|
||||
error_setg(errp, "KVM implementation does not support Nested-PAPR");
|
||||
error_append_hint(errp,
|
||||
"Try appending -machine cap-nested-papr=off\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -732,6 +776,15 @@ SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
|
||||
.type = "bool",
|
||||
.apply = cap_nested_kvm_hv_apply,
|
||||
},
|
||||
[SPAPR_CAP_NESTED_PAPR] = {
|
||||
.name = "nested-papr",
|
||||
.description = "Allow Nested HV (PAPR API)",
|
||||
.index = SPAPR_CAP_NESTED_PAPR,
|
||||
.get = spapr_cap_get_bool,
|
||||
.set = spapr_cap_set_bool,
|
||||
.type = "bool",
|
||||
.apply = cap_nested_papr_apply,
|
||||
},
|
||||
[SPAPR_CAP_LARGE_DECREMENTER] = {
|
||||
.name = "large-decr",
|
||||
.description = "Allow Large Decrementer",
|
||||
@ -916,6 +969,7 @@ SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC);
|
||||
SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS);
|
||||
SPAPR_CAP_MIG_STATE(hpt_maxpagesize, SPAPR_CAP_HPT_MAXPAGESIZE);
|
||||
SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV);
|
||||
SPAPR_CAP_MIG_STATE(nested_papr, SPAPR_CAP_NESTED_PAPR);
|
||||
SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER);
|
||||
SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
|
||||
SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI);
|
||||
|
@ -39,9 +39,13 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
|
||||
|
||||
/*
|
||||
* "PowerPC Processor binding to IEEE 1275" defines the initial MSR state
|
||||
* as 32bit (MSR_SF=0) in "8.2.1. Initial Register Values".
|
||||
* as 32bit (MSR_SF=0) with MSR_ME=1 and MSR_FP=1 in "8.2.1. Initial
|
||||
* Register Values". This can also be found in "LoPAPR 1.1" "C.9.2.1
|
||||
* Initial Register Values".
|
||||
*/
|
||||
env->msr &= ~(1ULL << MSR_SF);
|
||||
env->msr |= (1ULL << MSR_ME) | (1ULL << MSR_FP);
|
||||
|
||||
env->spr[SPR_HIOR] = 0;
|
||||
|
||||
lpcr = env->spr[SPR_LPCR];
|
||||
@ -394,10 +398,8 @@ static const TypeInfo spapr_cpu_core_type_infos[] = {
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power8_v2.0"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power8e_v2.1"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power8nvl_v1.0"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v1.0"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.2"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power10_v1.0"),
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("power10_v2.0"),
|
||||
#ifdef CONFIG_KVM
|
||||
DEFINE_SPAPR_CPU_CORE_TYPE("host"),
|
||||
|
@ -1525,6 +1525,28 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
|
||||
*slot = fn;
|
||||
}
|
||||
|
||||
void spapr_unregister_hypercall(target_ulong opcode)
|
||||
{
|
||||
spapr_hcall_fn *slot;
|
||||
|
||||
if (opcode <= MAX_HCALL_OPCODE) {
|
||||
assert((opcode & 0x3) == 0);
|
||||
|
||||
slot = &papr_hypercall_table[opcode / 4];
|
||||
} else if (opcode >= SVM_HCALL_BASE && opcode <= SVM_HCALL_MAX) {
|
||||
/* we only have SVM-related hcall numbers assigned in multiples of 4 */
|
||||
assert((opcode & 0x3) == 0);
|
||||
|
||||
slot = &svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4];
|
||||
} else {
|
||||
assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
|
||||
|
||||
slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
|
||||
}
|
||||
|
||||
*slot = NULL;
|
||||
}
|
||||
|
||||
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||
target_ulong *args)
|
||||
{
|
||||
@ -1638,8 +1660,6 @@ static void hypercall_register_types(void)
|
||||
spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support);
|
||||
|
||||
spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt);
|
||||
|
||||
spapr_register_nested();
|
||||
}
|
||||
|
||||
type_init(hypercall_register_types)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -147,7 +147,7 @@ struct PnvChipClass {
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
|
||||
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
|
||||
uint32_t (*chip_pir)(PnvChip *chip, uint32_t core_id, uint32_t thread_id);
|
||||
void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
|
||||
void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu);
|
||||
void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu);
|
||||
|
@ -36,6 +36,7 @@ struct PnvCore {
|
||||
/*< public >*/
|
||||
PowerPCCPU **threads;
|
||||
uint32_t pir;
|
||||
uint32_t hwid;
|
||||
uint64_t hrmor;
|
||||
PnvChip *chip;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "hw/ppc/spapr_xive.h" /* For SpaprXive */
|
||||
#include "hw/ppc/xics.h" /* For ICSState */
|
||||
#include "hw/ppc/spapr_tpm_proxy.h"
|
||||
#include "hw/ppc/spapr_nested.h" /* For SpaprMachineStateNested */
|
||||
|
||||
struct SpaprVioBus;
|
||||
struct SpaprPhbState;
|
||||
@ -80,8 +81,10 @@ typedef enum {
|
||||
#define SPAPR_CAP_RPT_INVALIDATE 0x0B
|
||||
/* Support for AIL modes */
|
||||
#define SPAPR_CAP_AIL_MODE_3 0x0C
|
||||
/* Nested PAPR */
|
||||
#define SPAPR_CAP_NESTED_PAPR 0x0D
|
||||
/* Num Caps */
|
||||
#define SPAPR_CAP_NUM (SPAPR_CAP_AIL_MODE_3 + 1)
|
||||
#define SPAPR_CAP_NUM (SPAPR_CAP_NESTED_PAPR + 1)
|
||||
|
||||
/*
|
||||
* Capability Values
|
||||
@ -213,7 +216,7 @@ struct SpaprMachineState {
|
||||
uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */
|
||||
|
||||
/* Nested HV support (TCG only) */
|
||||
uint64_t nested_ptcr;
|
||||
SpaprMachineStateNested nested;
|
||||
|
||||
Notifier epow_notifier;
|
||||
QTAILQ_HEAD(, SpaprEventLogEntry) pending_events;
|
||||
@ -363,6 +366,9 @@ struct SpaprMachineState {
|
||||
#define H_NOOP -63
|
||||
#define H_UNSUPPORTED -67
|
||||
#define H_OVERLAP -68
|
||||
#define H_STATE -75
|
||||
#define H_IN_USE -77
|
||||
#define H_INVALID_ELEMENT_VALUE -81
|
||||
#define H_UNSUPPORTED_FLAG -256
|
||||
#define H_MULTI_THREADS_ACTIVE -9005
|
||||
|
||||
@ -582,8 +588,16 @@ struct SpaprMachineState {
|
||||
#define H_RPT_INVALIDATE 0x448
|
||||
#define H_SCM_FLUSH 0x44C
|
||||
#define H_WATCHDOG 0x45C
|
||||
#define H_GUEST_GET_CAPABILITIES 0x460
|
||||
#define H_GUEST_SET_CAPABILITIES 0x464
|
||||
#define H_GUEST_CREATE 0x470
|
||||
#define H_GUEST_CREATE_VCPU 0x474
|
||||
#define H_GUEST_GET_STATE 0x478
|
||||
#define H_GUEST_SET_STATE 0x47C
|
||||
#define H_GUEST_RUN_VCPU 0x480
|
||||
#define H_GUEST_DELETE 0x488
|
||||
|
||||
#define MAX_HCALL_OPCODE H_WATCHDOG
|
||||
#define MAX_HCALL_OPCODE H_GUEST_DELETE
|
||||
|
||||
/* The hcalls above are standardized in PAPR and implemented by pHyp
|
||||
* as well.
|
||||
@ -631,6 +645,7 @@ typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
|
||||
target_ulong *args);
|
||||
|
||||
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
|
||||
void spapr_unregister_hypercall(target_ulong opcode);
|
||||
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||
target_ulong *args);
|
||||
|
||||
@ -984,6 +999,7 @@ extern const VMStateDescription vmstate_spapr_cap_sbbc;
|
||||
extern const VMStateDescription vmstate_spapr_cap_ibs;
|
||||
extern const VMStateDescription vmstate_spapr_cap_hpt_maxpagesize;
|
||||
extern const VMStateDescription vmstate_spapr_cap_nested_kvm_hv;
|
||||
extern const VMStateDescription vmstate_spapr_cap_nested_papr;
|
||||
extern const VMStateDescription vmstate_spapr_cap_large_decr;
|
||||
extern const VMStateDescription vmstate_spapr_cap_ccf_assist;
|
||||
extern const VMStateDescription vmstate_spapr_cap_fwnmi;
|
||||
@ -1028,5 +1044,10 @@ void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt);
|
||||
|
||||
/* H_WATCHDOG */
|
||||
void spapr_watchdog_init(SpaprMachineState *spapr);
|
||||
void spapr_register_nested_hv(void);
|
||||
void spapr_unregister_nested_hv(void);
|
||||
void spapr_nested_reset(SpaprMachineState *spapr);
|
||||
void spapr_register_nested_papr(void);
|
||||
void spapr_unregister_nested_papr(void);
|
||||
|
||||
#endif /* HW_SPAPR_H */
|
||||
|
@ -3,6 +3,348 @@
|
||||
|
||||
#include "target/ppc/cpu.h"
|
||||
|
||||
/* Guest State Buffer Element IDs */
|
||||
#define GSB_HV_VCPU_IGNORED_ID 0x0000 /* An element whose value is ignored */
|
||||
#define GSB_HV_VCPU_STATE_SIZE 0x0001 /* HV internal format VCPU state size */
|
||||
#define GSB_VCPU_OUT_BUF_MIN_SZ 0x0002 /* Min size of the Run VCPU o/p buffer */
|
||||
#define GSB_VCPU_LPVR 0x0003 /* Logical PVR */
|
||||
#define GSB_TB_OFFSET 0x0004 /* Timebase Offset */
|
||||
#define GSB_PART_SCOPED_PAGETBL 0x0005 /* Partition Scoped Page Table */
|
||||
#define GSB_PROCESS_TBL 0x0006 /* Process Table */
|
||||
/* RESERVED 0x0007 - 0x0BFF */
|
||||
#define GSB_VCPU_IN_BUFFER 0x0C00 /* Run VCPU Input Buffer */
|
||||
#define GSB_VCPU_OUT_BUFFER 0x0C01 /* Run VCPU Out Buffer */
|
||||
#define GSB_VCPU_VPA 0x0C02 /* HRA to Guest VCPU VPA */
|
||||
/* RESERVED 0x0C03 - 0x0FFF */
|
||||
#define GSB_VCPU_GPR0 0x1000
|
||||
#define GSB_VCPU_GPR1 0x1001
|
||||
#define GSB_VCPU_GPR2 0x1002
|
||||
#define GSB_VCPU_GPR3 0x1003
|
||||
#define GSB_VCPU_GPR4 0x1004
|
||||
#define GSB_VCPU_GPR5 0x1005
|
||||
#define GSB_VCPU_GPR6 0x1006
|
||||
#define GSB_VCPU_GPR7 0x1007
|
||||
#define GSB_VCPU_GPR8 0x1008
|
||||
#define GSB_VCPU_GPR9 0x1009
|
||||
#define GSB_VCPU_GPR10 0x100A
|
||||
#define GSB_VCPU_GPR11 0x100B
|
||||
#define GSB_VCPU_GPR12 0x100C
|
||||
#define GSB_VCPU_GPR13 0x100D
|
||||
#define GSB_VCPU_GPR14 0x100E
|
||||
#define GSB_VCPU_GPR15 0x100F
|
||||
#define GSB_VCPU_GPR16 0x1010
|
||||
#define GSB_VCPU_GPR17 0x1011
|
||||
#define GSB_VCPU_GPR18 0x1012
|
||||
#define GSB_VCPU_GPR19 0x1013
|
||||
#define GSB_VCPU_GPR20 0x1014
|
||||
#define GSB_VCPU_GPR21 0x1015
|
||||
#define GSB_VCPU_GPR22 0x1016
|
||||
#define GSB_VCPU_GPR23 0x1017
|
||||
#define GSB_VCPU_GPR24 0x1018
|
||||
#define GSB_VCPU_GPR25 0x1019
|
||||
#define GSB_VCPU_GPR26 0x101A
|
||||
#define GSB_VCPU_GPR27 0x101B
|
||||
#define GSB_VCPU_GPR28 0x101C
|
||||
#define GSB_VCPU_GPR29 0x101D
|
||||
#define GSB_VCPU_GPR30 0x101E
|
||||
#define GSB_VCPU_GPR31 0x101F
|
||||
#define GSB_VCPU_HDEC_EXPIRY_TB 0x1020
|
||||
#define GSB_VCPU_SPR_NIA 0x1021
|
||||
#define GSB_VCPU_SPR_MSR 0x1022
|
||||
#define GSB_VCPU_SPR_LR 0x1023
|
||||
#define GSB_VCPU_SPR_XER 0x1024
|
||||
#define GSB_VCPU_SPR_CTR 0x1025
|
||||
#define GSB_VCPU_SPR_CFAR 0x1026
|
||||
#define GSB_VCPU_SPR_SRR0 0x1027
|
||||
#define GSB_VCPU_SPR_SRR1 0x1028
|
||||
#define GSB_VCPU_SPR_DAR 0x1029
|
||||
#define GSB_VCPU_DEC_EXPIRE_TB 0x102A
|
||||
#define GSB_VCPU_SPR_VTB 0x102B
|
||||
#define GSB_VCPU_SPR_LPCR 0x102C
|
||||
#define GSB_VCPU_SPR_HFSCR 0x102D
|
||||
#define GSB_VCPU_SPR_FSCR 0x102E
|
||||
#define GSB_VCPU_SPR_FPSCR 0x102F
|
||||
#define GSB_VCPU_SPR_DAWR0 0x1030
|
||||
#define GSB_VCPU_SPR_DAWR1 0x1031
|
||||
#define GSB_VCPU_SPR_CIABR 0x1032
|
||||
#define GSB_VCPU_SPR_PURR 0x1033
|
||||
#define GSB_VCPU_SPR_SPURR 0x1034
|
||||
#define GSB_VCPU_SPR_IC 0x1035
|
||||
#define GSB_VCPU_SPR_SPRG0 0x1036
|
||||
#define GSB_VCPU_SPR_SPRG1 0x1037
|
||||
#define GSB_VCPU_SPR_SPRG2 0x1038
|
||||
#define GSB_VCPU_SPR_SPRG3 0x1039
|
||||
#define GSB_VCPU_SPR_PPR 0x103A
|
||||
#define GSB_VCPU_SPR_MMCR0 0x103B
|
||||
#define GSB_VCPU_SPR_MMCR1 0x103C
|
||||
#define GSB_VCPU_SPR_MMCR2 0x103D
|
||||
#define GSB_VCPU_SPR_MMCR3 0x103E
|
||||
#define GSB_VCPU_SPR_MMCRA 0x103F
|
||||
#define GSB_VCPU_SPR_SIER 0x1040
|
||||
#define GSB_VCPU_SPR_SIER2 0x1041
|
||||
#define GSB_VCPU_SPR_SIER3 0x1042
|
||||
#define GSB_VCPU_SPR_BESCR 0x1043
|
||||
#define GSB_VCPU_SPR_EBBHR 0x1044
|
||||
#define GSB_VCPU_SPR_EBBRR 0x1045
|
||||
#define GSB_VCPU_SPR_AMR 0x1046
|
||||
#define GSB_VCPU_SPR_IAMR 0x1047
|
||||
#define GSB_VCPU_SPR_AMOR 0x1048
|
||||
#define GSB_VCPU_SPR_UAMOR 0x1049
|
||||
#define GSB_VCPU_SPR_SDAR 0x104A
|
||||
#define GSB_VCPU_SPR_SIAR 0x104B
|
||||
#define GSB_VCPU_SPR_DSCR 0x104C
|
||||
#define GSB_VCPU_SPR_TAR 0x104D
|
||||
#define GSB_VCPU_SPR_DEXCR 0x104E
|
||||
#define GSB_VCPU_SPR_HDEXCR 0x104F
|
||||
#define GSB_VCPU_SPR_HASHKEYR 0x1050
|
||||
#define GSB_VCPU_SPR_HASHPKEYR 0x1051
|
||||
#define GSB_VCPU_SPR_CTRL 0x1052
|
||||
/* RESERVED 0x1053 - 0x1FFF */
|
||||
#define GSB_VCPU_SPR_CR 0x2000
|
||||
#define GSB_VCPU_SPR_PIDR 0x2001
|
||||
#define GSB_VCPU_SPR_DSISR 0x2002
|
||||
#define GSB_VCPU_SPR_VSCR 0x2003
|
||||
#define GSB_VCPU_SPR_VRSAVE 0x2004
|
||||
#define GSB_VCPU_SPR_DAWRX0 0x2005
|
||||
#define GSB_VCPU_SPR_DAWRX1 0x2006
|
||||
#define GSB_VCPU_SPR_PMC1 0x2007
|
||||
#define GSB_VCPU_SPR_PMC2 0x2008
|
||||
#define GSB_VCPU_SPR_PMC3 0x2009
|
||||
#define GSB_VCPU_SPR_PMC4 0x200A
|
||||
#define GSB_VCPU_SPR_PMC5 0x200B
|
||||
#define GSB_VCPU_SPR_PMC6 0x200C
|
||||
#define GSB_VCPU_SPR_WORT 0x200D
|
||||
#define GSB_VCPU_SPR_PSPB 0x200E
|
||||
/* RESERVED 0x200F - 0x2FFF */
|
||||
#define GSB_VCPU_SPR_VSR0 0x3000
|
||||
#define GSB_VCPU_SPR_VSR1 0x3001
|
||||
#define GSB_VCPU_SPR_VSR2 0x3002
|
||||
#define GSB_VCPU_SPR_VSR3 0x3003
|
||||
#define GSB_VCPU_SPR_VSR4 0x3004
|
||||
#define GSB_VCPU_SPR_VSR5 0x3005
|
||||
#define GSB_VCPU_SPR_VSR6 0x3006
|
||||
#define GSB_VCPU_SPR_VSR7 0x3007
|
||||
#define GSB_VCPU_SPR_VSR8 0x3008
|
||||
#define GSB_VCPU_SPR_VSR9 0x3009
|
||||
#define GSB_VCPU_SPR_VSR10 0x300A
|
||||
#define GSB_VCPU_SPR_VSR11 0x300B
|
||||
#define GSB_VCPU_SPR_VSR12 0x300C
|
||||
#define GSB_VCPU_SPR_VSR13 0x300D
|
||||
#define GSB_VCPU_SPR_VSR14 0x300E
|
||||
#define GSB_VCPU_SPR_VSR15 0x300F
|
||||
#define GSB_VCPU_SPR_VSR16 0x3010
|
||||
#define GSB_VCPU_SPR_VSR17 0x3011
|
||||
#define GSB_VCPU_SPR_VSR18 0x3012
|
||||
#define GSB_VCPU_SPR_VSR19 0x3013
|
||||
#define GSB_VCPU_SPR_VSR20 0x3014
|
||||
#define GSB_VCPU_SPR_VSR21 0x3015
|
||||
#define GSB_VCPU_SPR_VSR22 0x3016
|
||||
#define GSB_VCPU_SPR_VSR23 0x3017
|
||||
#define GSB_VCPU_SPR_VSR24 0x3018
|
||||
#define GSB_VCPU_SPR_VSR25 0x3019
|
||||
#define GSB_VCPU_SPR_VSR26 0x301A
|
||||
#define GSB_VCPU_SPR_VSR27 0x301B
|
||||
#define GSB_VCPU_SPR_VSR28 0x301C
|
||||
#define GSB_VCPU_SPR_VSR29 0x301D
|
||||
#define GSB_VCPU_SPR_VSR30 0x301E
|
||||
#define GSB_VCPU_SPR_VSR31 0x301F
|
||||
#define GSB_VCPU_SPR_VSR32 0x3020
|
||||
#define GSB_VCPU_SPR_VSR33 0x3021
|
||||
#define GSB_VCPU_SPR_VSR34 0x3022
|
||||
#define GSB_VCPU_SPR_VSR35 0x3023
|
||||
#define GSB_VCPU_SPR_VSR36 0x3024
|
||||
#define GSB_VCPU_SPR_VSR37 0x3025
|
||||
#define GSB_VCPU_SPR_VSR38 0x3026
|
||||
#define GSB_VCPU_SPR_VSR39 0x3027
|
||||
#define GSB_VCPU_SPR_VSR40 0x3028
|
||||
#define GSB_VCPU_SPR_VSR41 0x3029
|
||||
#define GSB_VCPU_SPR_VSR42 0x302A
|
||||
#define GSB_VCPU_SPR_VSR43 0x302B
|
||||
#define GSB_VCPU_SPR_VSR44 0x302C
|
||||
#define GSB_VCPU_SPR_VSR45 0x302D
|
||||
#define GSB_VCPU_SPR_VSR46 0x302E
|
||||
#define GSB_VCPU_SPR_VSR47 0x302F
|
||||
#define GSB_VCPU_SPR_VSR48 0x3030
|
||||
#define GSB_VCPU_SPR_VSR49 0x3031
|
||||
#define GSB_VCPU_SPR_VSR50 0x3032
|
||||
#define GSB_VCPU_SPR_VSR51 0x3033
|
||||
#define GSB_VCPU_SPR_VSR52 0x3034
|
||||
#define GSB_VCPU_SPR_VSR53 0x3035
|
||||
#define GSB_VCPU_SPR_VSR54 0x3036
|
||||
#define GSB_VCPU_SPR_VSR55 0x3037
|
||||
#define GSB_VCPU_SPR_VSR56 0x3038
|
||||
#define GSB_VCPU_SPR_VSR57 0x3039
|
||||
#define GSB_VCPU_SPR_VSR58 0x303A
|
||||
#define GSB_VCPU_SPR_VSR59 0x303B
|
||||
#define GSB_VCPU_SPR_VSR60 0x303C
|
||||
#define GSB_VCPU_SPR_VSR61 0x303D
|
||||
#define GSB_VCPU_SPR_VSR62 0x303E
|
||||
#define GSB_VCPU_SPR_VSR63 0x303F
|
||||
/* RESERVED 0x3040 - 0xEFFF */
|
||||
#define GSB_VCPU_SPR_HDAR 0xF000
|
||||
#define GSB_VCPU_SPR_HDSISR 0xF001
|
||||
#define GSB_VCPU_SPR_HEIR 0xF002
|
||||
#define GSB_VCPU_SPR_ASDR 0xF003
|
||||
/* End of list of Guest State Buffer Element IDs */
|
||||
#define GSB_LAST GSB_VCPU_SPR_ASDR
|
||||
|
||||
typedef struct SpaprMachineStateNested {
|
||||
uint64_t ptcr;
|
||||
uint8_t api;
|
||||
#define NESTED_API_KVM_HV 1
|
||||
#define NESTED_API_PAPR 2
|
||||
bool capabilities_set;
|
||||
uint32_t pvr_base;
|
||||
GHashTable *guests;
|
||||
} SpaprMachineStateNested;
|
||||
|
||||
typedef struct SpaprMachineStateNestedGuest {
|
||||
uint32_t pvr_logical;
|
||||
unsigned long nr_vcpus;
|
||||
uint64_t parttbl[2];
|
||||
uint64_t tb_offset;
|
||||
struct SpaprMachineStateNestedGuestVcpu *vcpus;
|
||||
} SpaprMachineStateNestedGuest;
|
||||
|
||||
/* Nested PAPR API related macros */
|
||||
#define H_GUEST_CAPABILITIES_COPY_MEM 0x8000000000000000
|
||||
#define H_GUEST_CAPABILITIES_P9_MODE 0x4000000000000000
|
||||
#define H_GUEST_CAPABILITIES_P10_MODE 0x2000000000000000
|
||||
#define H_GUEST_CAP_VALID_MASK (H_GUEST_CAPABILITIES_P10_MODE | \
|
||||
H_GUEST_CAPABILITIES_P9_MODE)
|
||||
#define H_GUEST_CAP_COPY_MEM_BMAP 0
|
||||
#define H_GUEST_CAP_P9_MODE_BMAP 1
|
||||
#define H_GUEST_CAP_P10_MODE_BMAP 2
|
||||
#define PAPR_NESTED_GUEST_MAX 4096
|
||||
#define H_GUEST_DELETE_ALL_FLAG 0x8000000000000000ULL
|
||||
#define PAPR_NESTED_GUEST_VCPU_MAX 2048
|
||||
#define VCPU_OUT_BUF_MIN_SZ 0x80ULL
|
||||
#define HVMASK_DEFAULT 0xffffffffffffffff
|
||||
#define HVMASK_LPCR 0x0070000003820800
|
||||
#define HVMASK_MSR 0xEBFFFFFFFFBFEFFF
|
||||
#define HVMASK_HDEXCR 0x00000000FFFFFFFF
|
||||
#define HVMASK_TB_OFFSET 0x000000FFFFFFFFFF
|
||||
#define GSB_MAX_BUF_SIZE (1024 * 1024)
|
||||
#define H_GUEST_GETSET_STATE_FLAG_GUEST_WIDE 0x8000000000000000
|
||||
#define GUEST_STATE_REQUEST_GUEST_WIDE 0x1
|
||||
#define GUEST_STATE_REQUEST_SET 0x2
|
||||
|
||||
/*
|
||||
* As per ISA v3.1B, following bits are reserved:
|
||||
* 0:2
|
||||
* 4:57 (ISA mentions bit 58 as well but it should be used for P10)
|
||||
* 61:63 (hence, haven't included PCR bits for v2.06 and v2.05
|
||||
* in LOW BITS)
|
||||
*/
|
||||
#define PCR_LOW_BITS (PCR_COMPAT_3_10 | PCR_COMPAT_3_00)
|
||||
#define HVMASK_PCR (~PCR_LOW_BITS)
|
||||
|
||||
#define GUEST_STATE_ELEMENT(i, sz, s, f, ptr, c) { \
|
||||
.id = (i), \
|
||||
.size = (sz), \
|
||||
.location = ptr, \
|
||||
.offset = offsetof(struct s, f), \
|
||||
.copy = (c) \
|
||||
}
|
||||
|
||||
#define GSBE_NESTED(i, sz, f, c) { \
|
||||
.id = (i), \
|
||||
.size = (sz), \
|
||||
.location = get_guest_ptr, \
|
||||
.offset = offsetof(struct SpaprMachineStateNestedGuest, f),\
|
||||
.copy = (c), \
|
||||
.mask = HVMASK_DEFAULT \
|
||||
}
|
||||
|
||||
#define GSBE_NESTED_MSK(i, sz, f, c, m) { \
|
||||
.id = (i), \
|
||||
.size = (sz), \
|
||||
.location = get_guest_ptr, \
|
||||
.offset = offsetof(struct SpaprMachineStateNestedGuest, f),\
|
||||
.copy = (c), \
|
||||
.mask = (m) \
|
||||
}
|
||||
|
||||
#define GSBE_NESTED_VCPU(i, sz, f, c) { \
|
||||
.id = (i), \
|
||||
.size = (sz), \
|
||||
.location = get_vcpu_ptr, \
|
||||
.offset = offsetof(struct SpaprMachineStateNestedGuestVcpu, f),\
|
||||
.copy = (c), \
|
||||
.mask = HVMASK_DEFAULT \
|
||||
}
|
||||
|
||||
#define GUEST_STATE_ELEMENT_NOP(i, sz) { \
|
||||
.id = (i), \
|
||||
.size = (sz), \
|
||||
.location = NULL, \
|
||||
.offset = 0, \
|
||||
.copy = NULL, \
|
||||
.mask = HVMASK_DEFAULT \
|
||||
}
|
||||
|
||||
#define GUEST_STATE_ELEMENT_NOP_DW(i) \
|
||||
GUEST_STATE_ELEMENT_NOP(i, 8)
|
||||
#define GUEST_STATE_ELEMENT_NOP_W(i) \
|
||||
GUEST_STATE_ELEMENT_NOP(i, 4)
|
||||
|
||||
#define GUEST_STATE_ELEMENT_BASE(i, s, c) { \
|
||||
.id = (i), \
|
||||
.size = (s), \
|
||||
.location = get_vcpu_state_ptr, \
|
||||
.offset = 0, \
|
||||
.copy = (c), \
|
||||
.mask = HVMASK_DEFAULT \
|
||||
}
|
||||
|
||||
#define GUEST_STATE_ELEMENT_OFF(i, s, f, c) { \
|
||||
.id = (i), \
|
||||
.size = (s), \
|
||||
.location = get_vcpu_state_ptr, \
|
||||
.offset = offsetof(struct nested_ppc_state, f), \
|
||||
.copy = (c), \
|
||||
.mask = HVMASK_DEFAULT \
|
||||
}
|
||||
|
||||
#define GUEST_STATE_ELEMENT_MSK(i, s, f, c, m) { \
|
||||
.id = (i), \
|
||||
.size = (s), \
|
||||
.location = get_vcpu_state_ptr, \
|
||||
.offset = offsetof(struct nested_ppc_state, f), \
|
||||
.copy = (c), \
|
||||
.mask = (m) \
|
||||
}
|
||||
|
||||
#define GUEST_STATE_ELEMENT_ENV_QW(i, f) \
|
||||
GUEST_STATE_ELEMENT_OFF(i, 16, f, copy_state_16to16)
|
||||
#define GUEST_STATE_ELEMENT_ENV_DW(i, f) \
|
||||
GUEST_STATE_ELEMENT_OFF(i, 8, f, copy_state_8to8)
|
||||
#define GUEST_STATE_ELEMENT_ENV_W(i, f) \
|
||||
GUEST_STATE_ELEMENT_OFF(i, 4, f, copy_state_4to8)
|
||||
#define GUEST_STATE_ELEMENT_ENV_WW(i, f) \
|
||||
GUEST_STATE_ELEMENT_OFF(i, 4, f, copy_state_4to4)
|
||||
#define GSE_ENV_DWM(i, f, m) \
|
||||
GUEST_STATE_ELEMENT_MSK(i, 8, f, copy_state_8to8, m)
|
||||
|
||||
struct guest_state_element {
|
||||
uint16_t id;
|
||||
uint16_t size;
|
||||
uint8_t value[];
|
||||
} QEMU_PACKED;
|
||||
|
||||
struct guest_state_buffer {
|
||||
uint32_t num_elements;
|
||||
struct guest_state_element elements[];
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* Actual buffer plus some metadata about the request */
|
||||
struct guest_state_request {
|
||||
struct guest_state_buffer *gsb;
|
||||
int64_t buf;
|
||||
int64_t len;
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Register state for entering a nested guest with H_ENTER_NESTED.
|
||||
* New member must be added at the end.
|
||||
@ -93,9 +435,90 @@ struct nested_ppc_state {
|
||||
uint64_t ppr;
|
||||
|
||||
int64_t tb_offset;
|
||||
/* Nested PAPR API */
|
||||
uint64_t amor;
|
||||
uint64_t dawr0;
|
||||
uint64_t dawrx0;
|
||||
uint64_t ciabr;
|
||||
uint64_t purr;
|
||||
uint64_t spurr;
|
||||
uint64_t ic;
|
||||
uint64_t vtb;
|
||||
uint64_t hdar;
|
||||
uint64_t hdsisr;
|
||||
uint64_t heir;
|
||||
uint64_t asdr;
|
||||
uint64_t dawr1;
|
||||
uint64_t dawrx1;
|
||||
uint64_t dexcr;
|
||||
uint64_t hdexcr;
|
||||
uint64_t hashkeyr;
|
||||
uint64_t hashpkeyr;
|
||||
ppc_vsr_t vsr[64] QEMU_ALIGNED(16);
|
||||
uint64_t ebbhr;
|
||||
uint64_t tar;
|
||||
uint64_t ebbrr;
|
||||
uint64_t bescr;
|
||||
uint64_t iamr;
|
||||
uint64_t amr;
|
||||
uint64_t uamor;
|
||||
uint64_t dscr;
|
||||
uint64_t fscr;
|
||||
uint64_t pspb;
|
||||
uint64_t ctrl;
|
||||
uint64_t vrsave;
|
||||
uint64_t dar;
|
||||
uint64_t dsisr;
|
||||
uint64_t pmc1;
|
||||
uint64_t pmc2;
|
||||
uint64_t pmc3;
|
||||
uint64_t pmc4;
|
||||
uint64_t pmc5;
|
||||
uint64_t pmc6;
|
||||
uint64_t mmcr0;
|
||||
uint64_t mmcr1;
|
||||
uint64_t mmcr2;
|
||||
uint64_t mmcra;
|
||||
uint64_t sdar;
|
||||
uint64_t siar;
|
||||
uint64_t sier;
|
||||
uint32_t vscr;
|
||||
uint64_t fpscr;
|
||||
int64_t dec_expiry_tb;
|
||||
};
|
||||
|
||||
void spapr_register_nested(void);
|
||||
void spapr_exit_nested(PowerPCCPU *cpu, int excp);
|
||||
struct SpaprMachineStateNestedGuestVcpuRunBuf {
|
||||
uint64_t addr;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
typedef struct SpaprMachineStateNestedGuestVcpu {
|
||||
bool enabled;
|
||||
struct nested_ppc_state state;
|
||||
struct SpaprMachineStateNestedGuestVcpuRunBuf runbufin;
|
||||
struct SpaprMachineStateNestedGuestVcpuRunBuf runbufout;
|
||||
int64_t tb_offset;
|
||||
uint64_t hdecr_expiry_tb;
|
||||
} SpaprMachineStateNestedGuestVcpu;
|
||||
|
||||
struct guest_state_element_type {
|
||||
uint16_t id;
|
||||
int size;
|
||||
#define GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE 0x1
|
||||
#define GUEST_STATE_ELEMENT_TYPE_FLAG_READ_ONLY 0x2
|
||||
uint16_t flags;
|
||||
void *(*location)(SpaprMachineStateNestedGuest *, target_ulong);
|
||||
size_t offset;
|
||||
void (*copy)(void *, void *, bool);
|
||||
uint64_t mask;
|
||||
};
|
||||
|
||||
void spapr_exit_nested(PowerPCCPU *cpu, int excp);
|
||||
typedef struct SpaprMachineState SpaprMachineState;
|
||||
bool spapr_get_pate_nested_hv(SpaprMachineState *spapr, PowerPCCPU *cpu,
|
||||
target_ulong lpid, ppc_v3_pate_t *entry);
|
||||
uint8_t spapr_nested_api(SpaprMachineState *spapr);
|
||||
void spapr_nested_gsb_init(void);
|
||||
bool spapr_get_pate_nested_papr(SpaprMachineState *spapr, PowerPCCPU *cpu,
|
||||
target_ulong lpid, ppc_v3_pate_t *entry);
|
||||
#endif /* HW_SPAPR_NESTED_H */
|
||||
|
@ -728,14 +728,10 @@
|
||||
"POWER8 v2.0")
|
||||
POWERPC_DEF("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8,
|
||||
"POWER8NVL v1.0")
|
||||
POWERPC_DEF("power9_v1.0", CPU_POWERPC_POWER9_DD1, POWER9,
|
||||
"POWER9 v1.0")
|
||||
POWERPC_DEF("power9_v2.0", CPU_POWERPC_POWER9_DD20, POWER9,
|
||||
"POWER9 v2.0")
|
||||
POWERPC_DEF("power9_v2.2", CPU_POWERPC_POWER9_DD22, POWER9,
|
||||
"POWER9 v2.2")
|
||||
POWERPC_DEF("power10_v1.0", CPU_POWERPC_POWER10_DD1, POWER10,
|
||||
"POWER10 v1.0")
|
||||
POWERPC_DEF("power10_v2.0", CPU_POWERPC_POWER10_DD20, POWER10,
|
||||
"POWER10 v2.0")
|
||||
#endif /* defined (TARGET_PPC64) */
|
||||
|
@ -1584,6 +1584,8 @@ uint64_t cpu_ppc_load_atbl(CPUPPCState *env);
|
||||
uint32_t cpu_ppc_load_atbu(CPUPPCState *env);
|
||||
void cpu_ppc_store_atbl(CPUPPCState *env, uint32_t value);
|
||||
void cpu_ppc_store_atbu(CPUPPCState *env, uint32_t value);
|
||||
void cpu_ppc_increase_tb_by_offset(CPUPPCState *env, int64_t offset);
|
||||
void cpu_ppc_decrease_tb_by_offset(CPUPPCState *env, int64_t offset);
|
||||
uint64_t cpu_ppc_load_vtb(CPUPPCState *env);
|
||||
void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value);
|
||||
bool ppc_decr_clear_on_delivery(CPUPPCState *env);
|
||||
@ -1755,9 +1757,11 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_PSPB (0x09F)
|
||||
#define SPR_DPDES (0x0B0)
|
||||
#define SPR_DAWR0 (0x0B4)
|
||||
#define SPR_DAWR1 (0x0B5)
|
||||
#define SPR_RPR (0x0BA)
|
||||
#define SPR_CIABR (0x0BB)
|
||||
#define SPR_DAWRX0 (0x0BC)
|
||||
#define SPR_DAWRX1 (0x0BD)
|
||||
#define SPR_HFSCR (0x0BE)
|
||||
#define SPR_VRSAVE (0x100)
|
||||
#define SPR_USPRG0 (0x100)
|
||||
@ -1951,6 +1955,12 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_BOOKE_TLB2CFG (0x2B2)
|
||||
#define SPR_BOOKE_TLB3CFG (0x2B3)
|
||||
#define SPR_BOOKE_EPR (0x2BE)
|
||||
#define SPR_POWER_USIER2 (0x2E0)
|
||||
#define SPR_POWER_USIER3 (0x2E1)
|
||||
#define SPR_POWER_UMMCR3 (0x2E2)
|
||||
#define SPR_POWER_SIER2 (0x2F0)
|
||||
#define SPR_POWER_SIER3 (0x2F1)
|
||||
#define SPR_POWER_MMCR3 (0x2F2)
|
||||
#define SPR_PERF0 (0x300)
|
||||
#define SPR_RCPU_MI_RBA0 (0x300)
|
||||
#define SPR_MPC_MI_CTR (0x300)
|
||||
@ -2948,6 +2958,7 @@ static inline bool ppc_has_spr(PowerPCCPU *cpu, int spr)
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Sort out endianness of interrupt. Depends on the CPU, HV mode, etc. */
|
||||
static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu, bool hv)
|
||||
{
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
|
@ -5308,6 +5308,38 @@ static void register_power8_pmu_user_sprs(CPUPPCState *env)
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
static void register_power10_pmu_sup_sprs(CPUPPCState *env)
|
||||
{
|
||||
spr_register_kvm(env, SPR_POWER_MMCR3, "MMCR3",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
KVM_REG_PPC_MMCR3, 0x00000000);
|
||||
spr_register_kvm(env, SPR_POWER_SIER2, "SIER2",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
KVM_REG_PPC_SIER2, 0x00000000);
|
||||
spr_register_kvm(env, SPR_POWER_SIER3, "SIER3",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
KVM_REG_PPC_SIER3, 0x00000000);
|
||||
}
|
||||
|
||||
static void register_power10_pmu_user_sprs(CPUPPCState *env)
|
||||
{
|
||||
spr_register(env, SPR_POWER_UMMCR3, "UMMCR3",
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_USIER2, "USIER2",
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_USIER3, "USIER3",
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
static void register_power5p_ear_sprs(CPUPPCState *env)
|
||||
{
|
||||
/* External access control */
|
||||
@ -6350,10 +6382,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((pvr & 0x0f00) == 0x100) {
|
||||
/* DD1.x always matches power9_v1.0 */
|
||||
return true;
|
||||
} else if ((pvr & 0x0f00) == 0x200) {
|
||||
if ((pvr & 0x0f00) == 0x200) {
|
||||
if ((pvr & 0xf) < 2) {
|
||||
/* DD2.0, DD2.1 match power9_v2.0 */
|
||||
if ((pcc->pvr & 0xf) == 0) {
|
||||
@ -6505,6 +6534,8 @@ static void init_proc_POWER10(CPUPPCState *env)
|
||||
register_power9_mmu_sprs(env);
|
||||
register_power10_hash_sprs(env);
|
||||
register_power10_dexcr_sprs(env);
|
||||
register_power10_pmu_sup_sprs(env);
|
||||
register_power10_pmu_user_sprs(env);
|
||||
|
||||
/* FIXME: Filter fields properly based on privilege level */
|
||||
spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL,
|
||||
@ -6536,7 +6567,7 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
|
||||
}
|
||||
|
||||
if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) {
|
||||
/* Major DD version matches to power10_v1.0 and power10_v2.0 */
|
||||
/* Major DD version matches power10_v2.0 */
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6576,11 +6607,10 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
||||
PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
|
||||
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
|
||||
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
|
||||
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310 |
|
||||
PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310 |
|
||||
PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206;
|
||||
pcc->msr_mask = (1ull << MSR_SF) |
|
||||
(1ull << MSR_HV) |
|
||||
(1ull << MSR_TM) |
|
||||
(1ull << MSR_VR) |
|
||||
(1ull << MSR_VSX) |
|
||||
(1ull << MSR_EE) |
|
||||
@ -6620,7 +6650,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
||||
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
||||
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
|
||||
POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV;
|
||||
POWERPC_FLAG_VSX | POWERPC_FLAG_SCV;
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x8000;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -320,6 +320,9 @@ static void gdb_gen_spr_feature(CPUState *cs)
|
||||
continue;
|
||||
}
|
||||
|
||||
gdb_feature_builder_append_reg(&builder, g_ascii_strdown(spr->name, -1),
|
||||
TARGET_LONG_BITS, num_regs,
|
||||
"int", "spr");
|
||||
/*
|
||||
* GDB identifies registers based on the order they are
|
||||
* presented in the XML. These ids will not match QEMU's
|
||||
@ -330,10 +333,6 @@ static void gdb_gen_spr_feature(CPUState *cs)
|
||||
*/
|
||||
spr->gdb_id = num_regs;
|
||||
num_regs++;
|
||||
|
||||
gdb_feature_builder_append_reg(&builder, g_ascii_strdown(spr->name, -1),
|
||||
TARGET_LONG_BITS, num_regs,
|
||||
"int", "spr");
|
||||
}
|
||||
|
||||
gdb_feature_builder_end(&builder);
|
||||
|
@ -264,6 +264,11 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
|
||||
value &= ~MSR_HVB;
|
||||
value |= env->msr & MSR_HVB;
|
||||
}
|
||||
/* Attempt to modify MSR[ME] in guest state is ignored */
|
||||
if (is_book3s_arch2x(env) && !(env->msr & MSR_HVB)) {
|
||||
value &= ~(1 << MSR_ME);
|
||||
value |= env->msr & (1 << MSR_ME);
|
||||
}
|
||||
if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) {
|
||||
cpu_interrupt_exittb(cs);
|
||||
}
|
||||
|
@ -187,6 +187,12 @@
|
||||
&X_a ra
|
||||
@X_a ...... ra:3 .. ..... ..... .......... . &X_a
|
||||
|
||||
&XO rt ra rb oe:bool rc:bool
|
||||
@XO ...... rt:5 ra:5 rb:5 oe:1 ......... rc:1 &XO
|
||||
|
||||
&XO_ta rt ra oe:bool rc:bool
|
||||
@XO_ta ...... rt:5 ra:5 ..... oe:1 ......... rc:1 &XO_ta
|
||||
|
||||
%xx_xt 0:1 21:5
|
||||
%xx_xb 1:1 11:5
|
||||
%xx_xa 2:1 16:5
|
||||
@ -322,10 +328,30 @@ CMPLI 001010 ... - . ..... ................ @D_bfu
|
||||
|
||||
### Fixed-Point Arithmetic Instructions
|
||||
|
||||
ADD 011111 ..... ..... ..... . 100001010 . @XO
|
||||
ADDC 011111 ..... ..... ..... . 000001010 . @XO
|
||||
ADDE 011111 ..... ..... ..... . 010001010 . @XO
|
||||
|
||||
# ADDEX is Z23-form, with CY=0; all other values for CY are reserved.
|
||||
# This works out the same as X-form.
|
||||
ADDEX 011111 ..... ..... ..... 00 10101010 - @X
|
||||
|
||||
ADDI 001110 ..... ..... ................ @D
|
||||
ADDIS 001111 ..... ..... ................ @D
|
||||
ADDIC 001100 ..... ..... ................ @D
|
||||
ADDIC_ 001101 ..... ..... ................ @D
|
||||
|
||||
ADDPCIS 010011 ..... ..... .......... 00010 . @DX
|
||||
ADDME 011111 ..... ..... ----- . 011101010 . @XO_ta
|
||||
ADDZE 011111 ..... ..... ----- . 011001010 . @XO_ta
|
||||
|
||||
SUBF 011111 ..... ..... ..... . 000101000 . @XO
|
||||
SUBFIC 001000 ..... ..... ................ @D
|
||||
SUBFC 011111 ..... ..... ..... . 000001000 . @XO
|
||||
SUBFE 011111 ..... ..... ..... . 010001000 . @XO
|
||||
|
||||
SUBFME 011111 ..... ..... ----- . 011101000 . @XO_ta
|
||||
SUBFZE 011111 ..... ..... ----- . 011001000 . @XO_ta
|
||||
|
||||
## Fixed-Point Logical Instructions
|
||||
|
||||
|
@ -2365,17 +2365,6 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
pcc->radix_page_info = kvmppc_get_radix_page_info();
|
||||
|
||||
if ((pcc->pvr & 0xffffff00) == CPU_POWERPC_POWER9_DD1) {
|
||||
/*
|
||||
* POWER9 DD1 has some bugs which make it not really ISA 3.00
|
||||
* compliant. More importantly, advertising ISA 3.00
|
||||
* architected mode may prevent guests from activating
|
||||
* necessary DD1 workarounds.
|
||||
*/
|
||||
pcc->pcr_supported &= ~(PCR_COMPAT_3_00 | PCR_COMPAT_2_07
|
||||
| PCR_COMPAT_2_06 | PCR_COMPAT_2_05);
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
}
|
||||
|
||||
|
@ -49,9 +49,6 @@ void helper_spr_core_write_generic(CPUPPCState *env, uint32_t sprn,
|
||||
CPUState *cs = env_cpu(env);
|
||||
CPUState *ccs;
|
||||
uint32_t nr_threads = cs->nr_threads;
|
||||
uint32_t core_id = env->spr[SPR_PIR] & ~(nr_threads - 1);
|
||||
|
||||
assert(core_id == env->spr[SPR_PIR] - env->spr[SPR_TIR]);
|
||||
|
||||
if (nr_threads == 1) {
|
||||
env->spr[sprn] = val;
|
||||
|
@ -296,33 +296,26 @@ static inline void gen_update_nip(DisasContext *ctx, target_ulong nip)
|
||||
tcg_gen_movi_tl(cpu_nip, nip);
|
||||
}
|
||||
|
||||
static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
|
||||
static void gen_exception_err_nip(DisasContext *ctx, uint32_t excp,
|
||||
uint32_t error, target_ulong nip)
|
||||
{
|
||||
TCGv_i32 t0, t1;
|
||||
|
||||
/*
|
||||
* These are all synchronous exceptions, we set the PC back to the
|
||||
* faulting instruction
|
||||
*/
|
||||
gen_update_nip(ctx, ctx->cia);
|
||||
gen_update_nip(ctx, nip);
|
||||
t0 = tcg_constant_i32(excp);
|
||||
t1 = tcg_constant_i32(error);
|
||||
gen_helper_raise_exception_err(tcg_env, t0, t1);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_exception(DisasContext *ctx, uint32_t excp)
|
||||
static inline void gen_exception_err(DisasContext *ctx, uint32_t excp,
|
||||
uint32_t error)
|
||||
{
|
||||
TCGv_i32 t0;
|
||||
|
||||
/*
|
||||
* These are all synchronous exceptions, we set the PC back to the
|
||||
* faulting instruction
|
||||
*/
|
||||
gen_update_nip(ctx, ctx->cia);
|
||||
t0 = tcg_constant_i32(excp);
|
||||
gen_helper_raise_exception(tcg_env, t0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
gen_exception_err_nip(ctx, excp, error, ctx->cia);
|
||||
}
|
||||
|
||||
static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
|
||||
@ -336,6 +329,15 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static inline void gen_exception(DisasContext *ctx, uint32_t excp)
|
||||
{
|
||||
/*
|
||||
* These are all synchronous exceptions, we set the PC back to the
|
||||
* faulting instruction
|
||||
*/
|
||||
gen_exception_nip(ctx, excp, ctx->cia);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static void gen_ppc_maybe_interrupt(DisasContext *ctx)
|
||||
{
|
||||
@ -1735,61 +1737,6 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
tcg_gen_mov_tl(ret, t0);
|
||||
}
|
||||
}
|
||||
/* Add functions with two operands */
|
||||
#define GEN_INT_ARITH_ADD(name, opc3, ca, add_ca, compute_ca, compute_ov) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
{ \
|
||||
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
|
||||
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
|
||||
ca, glue(ca, 32), \
|
||||
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
|
||||
}
|
||||
/* Add functions with one operand and one immediate */
|
||||
#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, ca, \
|
||||
add_ca, compute_ca, compute_ov) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
{ \
|
||||
TCGv t0 = tcg_constant_tl(const_val); \
|
||||
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
|
||||
cpu_gpr[rA(ctx->opcode)], t0, \
|
||||
ca, glue(ca, 32), \
|
||||
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
|
||||
}
|
||||
|
||||
/* add add. addo addo. */
|
||||
GEN_INT_ARITH_ADD(add, 0x08, cpu_ca, 0, 0, 0)
|
||||
GEN_INT_ARITH_ADD(addo, 0x18, cpu_ca, 0, 0, 1)
|
||||
/* addc addc. addco addco. */
|
||||
GEN_INT_ARITH_ADD(addc, 0x00, cpu_ca, 0, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addco, 0x10, cpu_ca, 0, 1, 1)
|
||||
/* adde adde. addeo addeo. */
|
||||
GEN_INT_ARITH_ADD(adde, 0x04, cpu_ca, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addeo, 0x14, cpu_ca, 1, 1, 1)
|
||||
/* addme addme. addmeo addmeo. */
|
||||
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, cpu_ca, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, cpu_ca, 1, 1, 1)
|
||||
/* addex */
|
||||
GEN_INT_ARITH_ADD(addex, 0x05, cpu_ov, 1, 1, 0);
|
||||
/* addze addze. addzeo addzeo.*/
|
||||
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, cpu_ca, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, cpu_ca, 1, 1, 1)
|
||||
/* addic addic.*/
|
||||
static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0)
|
||||
{
|
||||
TCGv c = tcg_constant_tl(SIMM(ctx->opcode));
|
||||
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
|
||||
c, cpu_ca, cpu_ca32, 0, 1, 0, compute_rc0);
|
||||
}
|
||||
|
||||
static void gen_addic(DisasContext *ctx)
|
||||
{
|
||||
gen_op_addic(ctx, 0);
|
||||
}
|
||||
|
||||
static void gen_addic_(DisasContext *ctx)
|
||||
{
|
||||
gen_op_addic(ctx, 1);
|
||||
}
|
||||
|
||||
static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
TCGv arg2, int sign, int compute_ov)
|
||||
@ -2210,47 +2157,6 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
tcg_gen_mov_tl(ret, t0);
|
||||
}
|
||||
}
|
||||
/* Sub functions with Two operands functions */
|
||||
#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
{ \
|
||||
gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \
|
||||
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
|
||||
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
|
||||
}
|
||||
/* Sub functions with one operand and one immediate */
|
||||
#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val, \
|
||||
add_ca, compute_ca, compute_ov) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
{ \
|
||||
TCGv t0 = tcg_constant_tl(const_val); \
|
||||
gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \
|
||||
cpu_gpr[rA(ctx->opcode)], t0, \
|
||||
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
|
||||
}
|
||||
/* subf subf. subfo subfo. */
|
||||
GEN_INT_ARITH_SUBF(subf, 0x01, 0, 0, 0)
|
||||
GEN_INT_ARITH_SUBF(subfo, 0x11, 0, 0, 1)
|
||||
/* subfc subfc. subfco subfco. */
|
||||
GEN_INT_ARITH_SUBF(subfc, 0x00, 0, 1, 0)
|
||||
GEN_INT_ARITH_SUBF(subfco, 0x10, 0, 1, 1)
|
||||
/* subfe subfe. subfeo subfo. */
|
||||
GEN_INT_ARITH_SUBF(subfe, 0x04, 1, 1, 0)
|
||||
GEN_INT_ARITH_SUBF(subfeo, 0x14, 1, 1, 1)
|
||||
/* subfme subfme. subfmeo subfmeo. */
|
||||
GEN_INT_ARITH_SUBF_CONST(subfme, 0x07, -1LL, 1, 1, 0)
|
||||
GEN_INT_ARITH_SUBF_CONST(subfmeo, 0x17, -1LL, 1, 1, 1)
|
||||
/* subfze subfze. subfzeo subfzeo.*/
|
||||
GEN_INT_ARITH_SUBF_CONST(subfze, 0x06, 0, 1, 1, 0)
|
||||
GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1)
|
||||
|
||||
/* subfic */
|
||||
static void gen_subfic(DisasContext *ctx)
|
||||
{
|
||||
TCGv c = tcg_constant_tl(SIMM(ctx->opcode));
|
||||
gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
|
||||
c, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
/* neg neg. nego nego. */
|
||||
static inline void gen_op_arith_neg(DisasContext *ctx, bool compute_ov)
|
||||
@ -6524,8 +6430,6 @@ GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300),
|
||||
GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205),
|
||||
GEN_HANDLER_E(cmprb, 0x1F, 0x00, 0x06, 0x00400001, PPC_NONE, PPC2_ISA300),
|
||||
GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL),
|
||||
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
|
||||
GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
|
||||
GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER),
|
||||
GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER),
|
||||
GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER),
|
||||
@ -6536,7 +6440,6 @@ GEN_HANDLER(mulld, 0x1F, 0x09, 0x07, 0x00000000, PPC_64B),
|
||||
#endif
|
||||
GEN_HANDLER(neg, 0x1F, 0x08, 0x03, 0x0000F800, PPC_INTEGER),
|
||||
GEN_HANDLER(nego, 0x1F, 0x08, 0x13, 0x0000F800, PPC_INTEGER),
|
||||
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
|
||||
GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
|
||||
GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
|
||||
GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER),
|
||||
@ -6747,25 +6650,6 @@ GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE,
|
||||
GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300),
|
||||
#endif
|
||||
|
||||
#undef GEN_INT_ARITH_ADD
|
||||
#undef GEN_INT_ARITH_ADD_CONST
|
||||
#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov) \
|
||||
GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x00000000, PPC_INTEGER),
|
||||
#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, \
|
||||
add_ca, compute_ca, compute_ov) \
|
||||
GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x0000F800, PPC_INTEGER),
|
||||
GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0)
|
||||
GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1)
|
||||
GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1)
|
||||
GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
|
||||
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
|
||||
GEN_HANDLER_E(addex, 0x1F, 0x0A, 0x05, 0x00000000, PPC_NONE, PPC2_ISA300),
|
||||
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
|
||||
|
||||
#undef GEN_INT_ARITH_DIVW
|
||||
#define GEN_INT_ARITH_DIVW(name, opc3, sign, compute_ov) \
|
||||
GEN_HANDLER(name, 0x1F, 0x0B, opc3, 0x00000000, PPC_INTEGER)
|
||||
@ -6804,24 +6688,6 @@ GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02),
|
||||
GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17),
|
||||
#endif
|
||||
|
||||
#undef GEN_INT_ARITH_SUBF
|
||||
#undef GEN_INT_ARITH_SUBF_CONST
|
||||
#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov) \
|
||||
GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x00000000, PPC_INTEGER),
|
||||
#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val, \
|
||||
add_ca, compute_ca, compute_ov) \
|
||||
GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x0000F800, PPC_INTEGER),
|
||||
GEN_INT_ARITH_SUBF(subf, 0x01, 0, 0, 0)
|
||||
GEN_INT_ARITH_SUBF(subfo, 0x11, 0, 0, 1)
|
||||
GEN_INT_ARITH_SUBF(subfc, 0x00, 0, 1, 0)
|
||||
GEN_INT_ARITH_SUBF(subfco, 0x10, 0, 1, 1)
|
||||
GEN_INT_ARITH_SUBF(subfe, 0x04, 1, 1, 0)
|
||||
GEN_INT_ARITH_SUBF(subfeo, 0x14, 1, 1, 1)
|
||||
GEN_INT_ARITH_SUBF_CONST(subfme, 0x07, -1LL, 1, 1, 0)
|
||||
GEN_INT_ARITH_SUBF_CONST(subfmeo, 0x17, -1LL, 1, 1, 1)
|
||||
GEN_INT_ARITH_SUBF_CONST(subfze, 0x06, 0, 1, 1, 0)
|
||||
GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1)
|
||||
|
||||
#undef GEN_LOGICAL1
|
||||
#undef GEN_LOGICAL2
|
||||
#define GEN_LOGICAL2(name, tcg_op, opc, type) \
|
||||
|
@ -325,6 +325,76 @@ static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ADDEX(DisasContext *ctx, arg_X *a)
|
||||
{
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
|
||||
cpu_ov, cpu_ov32, true, true, false, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_add_D(DisasContext *ctx, arg_D *a, bool add_ca, bool compute_ca,
|
||||
bool compute_ov, bool compute_rc0)
|
||||
{
|
||||
gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra],
|
||||
tcg_constant_tl(a->si), cpu_ca, cpu_ca32,
|
||||
add_ca, compute_ca, compute_ov, compute_rc0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_add_XO(DisasContext *ctx, arg_XO *a, bool add_ca,
|
||||
bool compute_ca)
|
||||
{
|
||||
gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
|
||||
cpu_ca, cpu_ca32, add_ca, compute_ca, a->oe, a->rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_add_const_XO(DisasContext *ctx, arg_XO_ta *a, TCGv const_val,
|
||||
bool add_ca, bool compute_ca)
|
||||
{
|
||||
gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], const_val,
|
||||
cpu_ca, cpu_ca32, add_ca, compute_ca, a->oe, a->rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(ADD, do_add_XO, false, false);
|
||||
TRANS(ADDC, do_add_XO, false, true);
|
||||
TRANS(ADDE, do_add_XO, true, true);
|
||||
TRANS(ADDME, do_add_const_XO, tcg_constant_tl(-1LL), true, true);
|
||||
TRANS(ADDZE, do_add_const_XO, tcg_constant_tl(0), true, true);
|
||||
TRANS(ADDIC, do_add_D, false, true, false, false);
|
||||
TRANS(ADDIC_, do_add_D, false, true, false, true);
|
||||
|
||||
static bool trans_SUBFIC(DisasContext *ctx, arg_D *a)
|
||||
{
|
||||
gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra],
|
||||
tcg_constant_tl(a->si), false, true, false, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_subf_XO(DisasContext *ctx, arg_XO *a, bool add_ca,
|
||||
bool compute_ca)
|
||||
{
|
||||
gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
|
||||
add_ca, compute_ca, a->oe, a->rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_subf_const_XO(DisasContext *ctx, arg_XO_ta *a, TCGv const_val,
|
||||
bool add_ca, bool compute_ca)
|
||||
{
|
||||
gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], const_val,
|
||||
add_ca, compute_ca, a->oe, a->rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(SUBF, do_subf_XO, false, false)
|
||||
TRANS(SUBFC, do_subf_XO, false, true)
|
||||
TRANS(SUBFE, do_subf_XO, true, true)
|
||||
TRANS(SUBFME, do_subf_const_XO, tcg_constant_tl(-1LL), true, true)
|
||||
TRANS(SUBFZE, do_subf_const_XO, tcg_constant_tl(0), true, true)
|
||||
|
||||
static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
|
||||
{
|
||||
gen_invalid(ctx);
|
||||
|
Loading…
Reference in New Issue
Block a user