* Re: [PATCH v2 3/3] powerpc: machine check interrupt is a non-maskable interrupt
From: Christophe LEROY @ 2018-10-08 15:39 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: Mahesh Jagannath Salgaonkar
In-Reply-To: <20170719065912.19183-4-npiggin@gmail.com>
Hi Nick,
Le 19/07/2017 à 08:59, Nicholas Piggin a écrit :
> Use nmi_enter similarly to system reset interrupts. This uses NMI
> printk NMI buffers and turns off various debugging facilities that
> helps avoid tripping on ourselves or other CPUs.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
> arch/powerpc/kernel/traps.c | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index 2849c4f50324..6d31f9d7c333 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -789,8 +789,10 @@ int machine_check_generic(struct pt_regs *regs)
>
> void machine_check_exception(struct pt_regs *regs)
> {
> - enum ctx_state prev_state = exception_enter();
> int recover = 0;
> + bool nested = in_nmi();
> + if (!nested)
> + nmi_enter();
This alters preempt_count, then when die() is called
in_interrupt() returns true allthough the trap didn't happen in
interrupt, so oops_end() panics for "fatal exception in interrupt"
instead of gently sending SIGBUS the faulting app.
Any idea on how to fix this ?
Christophe
>
> __this_cpu_inc(irq_stat.mce_exceptions);
>
> @@ -820,10 +822,11 @@ void machine_check_exception(struct pt_regs *regs)
>
> /* Must die if the interrupt is not recoverable */
> if (!(regs->msr & MSR_RI))
> - panic("Unrecoverable Machine check");
> + nmi_panic(regs, "Unrecoverable Machine check");
>
> bail:
> - exception_exit(prev_state);
> + if (!nested)
> + nmi_exit();
> }
>
> void SMIException(struct pt_regs *regs)
>
^ permalink raw reply
* Re: Looking for architecture papers
From: Raz @ 2018-10-08 16:44 UTC (permalink / raw)
To: segher; +Cc: linuxppc-dev
In-Reply-To: <20181006122750.GF29268@gate.crashing.org>
Both systemsim and my powerpc server boots with MSR_HV=1, i.e, hypervisor state.
Is there away to fix that ? writing to the MSR cannot work according
the documentation ( and reality ).
On Sat, Oct 6, 2018 at 3:27 PM Segher Boessenkool
<segher@kernel.crashing.org> wrote:
>
> On Sat, Oct 06, 2018 at 12:19:45PM +0300, Raz wrote:
> > Hey
> > How does HVSC works ?
> > I looked in the code and LoPAR documentation. It looks like there is
> > vector called
> > system_call_pSeries ( at 0xc00 ) that is supposed to be called when we
> > invoke HVSC from kernel
> > mode.
> > Now, I wrote a NULL call HSVC and patched the exceptions-64s.S to
> > return RFID immediately.
> > This does not work.
> > Would you be so kind to explain how HVSC works ?
> > thank you
>
> If your kernel is not running in hypervisor mode, sc 1 does not call the
> kernel (but the hypervisor, instead). If your kernel _is_ running in
> hypervisor mode, sc 1 does the same as sc 0, a normal system call.
>
> I don't know which it is for you; you didn't say.
>
> I have no idea what "a NULL call HSVC" means. If you make exception c00
> return immediately (as you suggest) then you have made all system calls
> non-functional, which indeed is unlikely to work as you want.
>
>
> Segher
^ permalink raw reply
* Re: [PATCH 29/36] dt-bindings: arm: Convert Renesas board/soc bindings to json-schema
From: Rob Herring @ 2018-10-08 16:54 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Mark Rutland, devicetree, Kumar Gala, Grant Likely, Arnd Bergmann,
Tom Rini, Simon Horman, Frank Rowand, Linus Walleij,
Pantelis Antoniou, linux-kernel@vger.kernel.org, Bjorn Andersson,
open list:MEDIA DRIVERS FOR RENESAS - FCP, Mark Brown,
Jonathan Cameron, Olof Johansson, linuxppc-dev,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <CAMuHMdVtuKkytpHxJfWHw=-R09_AMZ8Tn=ixjPSSRydQL6qK2g@mail.gmail.com>
On Mon, Oct 8, 2018 at 10:13 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Rob,
>
> On Mon, Oct 8, 2018 at 4:57 PM Rob Herring <robh@kernel.org> wrote:
> > On Mon, Oct 8, 2018 at 2:47 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > > On Fri, Oct 5, 2018 at 6:59 PM Rob Herring <robh@kernel.org> wrote:
> > > > Convert Renesas SoC bindings to DT schema format using json-schema.
>
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/arm/shmobile.yaml
> > > > @@ -0,0 +1,205 @@
>
> > > > + - description: Kingfisher (SBEV-RCAR-KF-M03)
> > > > + items:
> > > > + - const: shimafuji,kingfisher
> > > > + - enum:
> > > > + - renesas,h3ulcb
> > > > + - renesas,m3ulcb
> > > > + - enum:
> > > > + - renesas,r8a7795
> > > > + - renesas,r8a7796
> > >
> > > This looks a bit funny: all other entries have the "const" last, and
> > > use it for the
> > > SoC number. May be correct, though.
> > > To clarify, this is an extension board that can fit both the [HM]3ULCB
> > > boards (actually also the new M3NULCB, I think).
> >
> > This being Kingfisher?
>
> Correct.
>
> > I wrote this based on dts files in the tree. There's 2 combinations that I see:
> >
> > "shimafuji,kingfisher", "renesas,h3ulcb", "renesas,r8a7795"
> > "shimafuji,kingfisher", "renesas,m3ulcb", "renesas,r8a7796"
> >
> > The schema allows 4 combinations (1 * 2 * 2). I have no idea if the
> > other combinations are possible. If not, then we could rewrite this as
> > 2 entries with 3 const values each.
>
> I expect there will soon be a third one:
>
> "shimafuji,kingfisher", "renesas,m3nulcb", "renesas,r8a77965"
>
> Technically, {h3,m3,m3n}ulcb are the same board (although there may be
> minor revision differences), with a different SiP mounted.
> But they are called/marketed depending on which SiP is mounted.
>
> And on top of that, you can plug in a Kingfisher daughterboard. Could be an
> overlay ;-)
We probably shouldn't have put kingfisher as a top-level compatible
then. But we did, so not really much point to discuss that now.
As to whether there's a better way to express it in the schema, I'm
not sure. I don't think there's a way with json-schema to express a
list, but the 1st item is optional.
Rob
^ permalink raw reply
* Re: [PATCH 0/8] add generic builtin command line
From: Maksym Kokhan @ 2018-10-08 18:01 UTC (permalink / raw)
To: Daniel Walker
Cc: linux-mips, linux-efi, Ruslan Bilovol, Will Deacon,
Paul Mackerras, H. Peter Anvin, Frank Rowand, x86, Russell King,
Ingo Molnar, Catalin Marinas, James Hogan, Daniel Walker,
devicetree, Rob Herring, Borislav Petkov, Thomas Gleixner,
Andrii Bordunov, Ard Biesheuvel, linux-kernel, Ralf Baechle,
Paul Burton, Andrew Morton, linuxppc-dev
In-Reply-To: <20180929181725.GB27441@fifo99.com>
Hi, Daniel
On Sat, Sep 29, 2018 at 9:17 PM <dwalker@fifo99.com> wrote:
>
> On Thu, Sep 27, 2018 at 07:55:08PM +0300, Maksym Kokhan wrote:
> > Daniel Walker (7):
> > add generic builtin command line
> > drivers: of: ifdef out cmdline section
> > x86: convert to generic builtin command line
> > arm: convert to generic builtin command line
> > arm64: convert to generic builtin command line
> > mips: convert to generic builtin command line
> > powerpc: convert to generic builtin command line
> >
>
> When I originally submitted these I had a very good conversion with Rob Herring
> on the device tree changes. It seemed fairly clear that my approach in these
> changes could be done better. It effected specifically arm64, but a lot of other
> platforms use the device tree integrally. With arm64 you can reduce the changes
> down to only Kconfig changes, and that would likely be the case for many of the
> other architecture. I made patches to do this a while back, but have not had
> time to test them and push them out.
Can you please share this patches? I could test them and use to improve this
generic command line implementation.
> In terms of mips I think there's a fair amount of work needed to pull out their
> architecture specific mangling into something generic. Part of my motivation for
> these was to take the architecture specific feature and open that up for all the
> architecture. So it makes sense that the mips changes should become part of
> that.
This is really makes sense, and we have intentions to implement it
afterward. It would be easier to initially merge this simple
implementation and then develop it step by step.
> The only changes which have no comments are the generic changes, x86, and
> powerpc. Those patches have been used at Cisco for years with no issues.
> I added those changes into my -next tree for a round of testing. Assuming there
> are no issues I can work out the merging with the architecture maintainers.
> As for the other changes I think they can be done in time, as long as the
> generic parts of upstream the rest can be worked on by any of the architecture
> developers.
Thanks,
Maksym
^ permalink raw reply
* Re: [PATCH 09/16] of: overlay: validate overlay properties #address-cells and #size-cells
From: Alan Tull @ 2018-10-08 18:46 UTC (permalink / raw)
To: Frank Rowand
Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-fpga, Pantelis Antoniou, linux-kernel, Rob Herring,
Moritz Fischer, Paul Mackerras, linuxppc-dev
In-Reply-To: <CANk1AXQFTfdwy9n+WH2k98w6oyqLj3wLDRfaMmtTGk66sJjqUw@mail.gmail.com>
On Mon, Oct 8, 2018 at 10:57 AM Alan Tull <atull@kernel.org> wrote:
>
> On Thu, Oct 4, 2018 at 11:14 PM <frowand.list@gmail.com> wrote:
> >
> > From: Frank Rowand <frank.rowand@sony.com>
> >
> > If overlay properties #address-cells or #size-cells are already in
> > the live devicetree for any given node, then the values in the
> > overlay must match the values in the live tree.
>
> Hi Frank,
>
> I'm starting some FPGA testing on this patchset applied to v4.19-rc7.
> That applied cleanly; if that's not the best base to test against,
> please let me know.
>
> On a very simple overlay, I'm seeing this patch's warning catching
> things other than #address-cells or #size-cells.
What it's warning about are new properties being added to an existing
node. So !prop is true and !of_node_check_flag(target->np,
OF_OVERLAY) also is true. Is that a potential memory leak as you are
warning? If so, your code is working as planned and you'll just need
to document that also in the header.
> I'm just getting
> started looking at this, will spend time understanding this better and
> I'll test other overlays. The warnings were:
>
> Applying dtbo: socfpga_overlay.dtb
> [ 33.117881] fpga_manager fpga0: writing soc_system.rbf to Altera
> SOCFPGA FPGA Manager
> [ 33.575223] OF: overlay: WARNING: add_changeset_property(), memory
> leak will occur if overlay removed. Property:
> /soc/base-fpga-region/firmware-name
> [ 33.588584] OF: overlay: WARNING: add_changeset_property(), memory
> leak will occur if overlay removed. Property:
> /soc/base-fpga-region/fpga-bridges
> [ 33.601856] OF: overlay: WARNING: add_changeset_property(), memory
> leak will occur if overlay removed. Property:
> /soc/base-fpga-region/ranges
>
> Here's part of that overlay including the properties it's complaining about:
>
> /dts-v1/;
> /plugin/;
> / {
> fragment@0 {
> target = <&base_fpga_region>;
> #address-cells = <1>;
> #size-cells = <1>;
> __overlay__ {
> #address-cells = <1>;
> #size-cells = <1>;
>
> firmware-name = "soc_system.rbf";
> fpga-bridges = <&fpga_bridge1>;
> ranges = <0x20000 0xff200000 0x100000>,
> <0x0 0xc0000000 0x20000000>;
>
> gpio@10040 {
> so on...
>
> By the way, I didn't get any warnings when I subsequently removed this overlay.
>
> Alan
>
> >
> > If the properties are already in the live tree then there is no
> > need to create a changeset entry to add them since they must
> > have the same value. This reduces the memory used by the
> > changeset and eliminates a possible memory leak. This is
> > verified by 12 fewer warnings during the devicetree unittest,
> > as the possible memory leak warnings about #address-cells and
> >
> > Signed-off-by: Frank Rowand <frank.rowand@sony.com>
> > ---
> > drivers/of/overlay.c | 38 +++++++++++++++++++++++++++++++++++---
> > 1 file changed, 35 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
> > index 29c33a5c533f..e6fb3ffe9d93 100644
> > --- a/drivers/of/overlay.c
> > +++ b/drivers/of/overlay.c
> > @@ -287,7 +287,12 @@ static struct property *dup_and_fixup_symbol_prop(
> > * @target may be either in the live devicetree or in a new subtree that
> > * is contained in the changeset.
> > *
> > - * Some special properties are not updated (no error returned).
> > + * Some special properties are not added or updated (no error returned):
> > + * "name", "phandle", "linux,phandle".
> > + *
> > + * Properties "#address-cells" and "#size-cells" are not updated if they
> > + * are already in the live tree, but if present in the live tree, the values
> > + * in the overlay must match the values in the live tree.
> > *
> > * Update of property in symbols node is not allowed.
> > *
> > @@ -300,6 +305,7 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
> > {
> > struct property *new_prop = NULL, *prop;
> > int ret = 0;
> > + bool check_for_non_overlay_node = false;
> >
> > if (!of_prop_cmp(overlay_prop->name, "name") ||
> > !of_prop_cmp(overlay_prop->name, "phandle") ||
> > @@ -322,13 +328,39 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
> > if (!new_prop)
> > return -ENOMEM;
> >
> > - if (!prop)
> > + if (!prop) {
> > +
> > + check_for_non_overlay_node = true;
> > ret = of_changeset_add_property(&ovcs->cset, target->np,
> > new_prop);
> > - else
> > +
> > + } else if (!of_prop_cmp(prop->name, "#address-cells")) {
> > +
> > + if (prop->length != 4 || new_prop->length != 4 ||
> > + *(u32 *)prop->value != *(u32 *)new_prop->value)
> > + pr_err("ERROR: overlay and/or live tree #address-cells invalid in node %pOF\n",
> > + target->np);
> > +
> > + } else if (!of_prop_cmp(prop->name, "#size-cells")) {
> > +
> > + if (prop->length != 4 || new_prop->length != 4 ||
> > + *(u32 *)prop->value != *(u32 *)new_prop->value)
> > + pr_err("ERROR: overlay and/or live tree #size-cells invalid in node %pOF\n",
> > + target->np);
> > +
> > + } else {
> > +
> > + check_for_non_overlay_node = true;
> > ret = of_changeset_update_property(&ovcs->cset, target->np,
> > new_prop);
> >
> > + }
> > +
> > + if (check_for_non_overlay_node &&
> > + !of_node_check_flag(target->np, OF_OVERLAY))
> > + pr_err("WARNING: %s(), memory leak will occur if overlay removed. Property: %pOF/%s\n",
> > + __func__, target->np, new_prop->name);
> > +
> > if (ret) {
> > kfree(new_prop->name);
> > kfree(new_prop->value);
> > --
> > Frank Rowand <frank.rowand@sony.com>
> >
^ permalink raw reply
* [PATCH 4.18 125/168] sched/topology: Set correct NUMA topology type
From: Greg Kroah-Hartman @ 2018-10-08 18:31 UTC (permalink / raw)
To: linux-kernel
Cc: Srikar Dronamraju, Rik van Riel, Peter Zijlstra (Intel),
Greg Kroah-Hartman, linuxppc-dev, Heiko Carstens, Mel Gorman,
stable, Sasha Levin, Suravee Suthikulpanit, Andre Wild,
Thomas Gleixner, Linus Torvalds, Ingo Molnar
In-Reply-To: <20181008175620.043587728@linuxfoundation.org>
4.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
[ Upstream commit e5e96fafd9028b1478b165db78c52d981c14f471 ]
With the following commit:
051f3ca02e46 ("sched/topology: Introduce NUMA identity node sched domain")
the scheduler introduced a new NUMA level. However this leads to the NUMA topology
on 2 node systems to not be marked as NUMA_DIRECT anymore.
After this commit, it gets reported as NUMA_BACKPLANE, because
sched_domains_numa_level is now 2 on 2 node systems.
Fix this by allowing setting systems that have up to 2 NUMA levels as
NUMA_DIRECT.
While here remove code that assumes that level can be 0.
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andre Wild <wild@linux.vnet.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linuxppc-dev <linuxppc-dev@lists.ozlabs.org>
Fixes: 051f3ca02e46 "Introduce NUMA identity node sched domain"
Link: http://lkml.kernel.org/r/1533920419-17410-1-git-send-email-srikar@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
kernel/sched/topology.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -1295,7 +1295,7 @@ static void init_numa_topology_type(void
n = sched_max_numa_distance;
- if (sched_domains_numa_levels <= 1) {
+ if (sched_domains_numa_levels <= 2) {
sched_numa_topology_type = NUMA_DIRECT;
return;
}
@@ -1380,9 +1380,6 @@ void sched_init_numa(void)
break;
}
- if (!level)
- return;
-
/*
* 'level' contains the number of unique distances
*
^ permalink raw reply
* Re: Looking for architecture papers
From: Segher Boessenkool @ 2018-10-08 19:29 UTC (permalink / raw)
To: Raz; +Cc: linuxppc-dev
In-Reply-To: <CAPB=Z-qC+Xgwyb=WAD-r_TYWWRRrpLJT6jFzCfKLtkNVn_FDUg@mail.gmail.com>
On Mon, Oct 08, 2018 at 07:44:12PM +0300, Raz wrote:
> Both systemsim and my powerpc server boots with MSR_HV=1, i.e, hypervisor state.
> Is there away to fix that ? writing to the MSR cannot work according
> the documentation ( and reality ).
But that is what you do: you write HV=0 in MSR. After doing other setup,
of course.
On some hardware you cannot set HV=0. You cannot do logical partitioning
on such hardware. PowerMac G5 comes to mind.
Segher
^ permalink raw reply
* Re: Looking for architecture papers
From: Gustavo Romero @ 2018-10-08 19:59 UTC (permalink / raw)
To: Raz; +Cc: linuxppc-dev
In-Reply-To: <CAPB=Z-pLCkXcsAXD5YWt5pwPzFzJrdZsdDye_bZjE0-ea-Ur6A@mail.gmail.com>
Hi Raz,
On 10/04/2018 04:41 AM, Raz wrote:
> Frankly, the more I read the more perplexed I get. For example,
> according to BOOK III-S, chapter 3,
> the MSR bits are differ from the ones described in
> arch/powerpc/include/asm/reg.h.
> Bit zero, is LE, but in the book it is 64-bit mode.
>
> Would someone be kind to explain what I do not understand?
Yes, I know that can be confusing at the first sight when one is used to, for
instance, x86.
x86 documents use LSB 0 notation, which means (as others already pointed out)
that the least significant bit of a value is marked as being bit 0.
On the other hand Power documents use MSB 0 notation, which means that the most
significant bit of a value is marked as being bit 0 and as a consequence the
least significant bit in that notation in a 64-bit platform is bit 63, not bit
0. MSB 0 notation is also known as IBM bit notation/bit numbering.
Historically LSB 0 notation tend to be used on docs about little-endian
architectures (for instance, x86), whilst MSB 0 notation tend to be used on docs
about big-endian architectures (for instance, Power - Power is actually a little
different because it's now bi-endian actually).
However LSB 0 and MSB 0 are only different notations, so LSB 0 can be employed
on a big-endian architecture documentation, and vice versa.
It happens that kernel code is written in C and for shifts, etc, it's convenient
the LSB 0 notation, not the MSB 0 notation, so it's convenient to use LSB 0
notation when creating a mask, like in arch/powerpc/include/asm/reg.h), i.e.
it's convenient to employ bit positions as '63 - <bit position in PowerISA>'.
So, as another example, in the following gcc macro '_TEXASR_EXTRACT_BITS' takes
a bit position 'BITNUM' as found in the PowerISA documentation but then for the
shift right it uses '63 - BITNUM':
https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000/htmintrin.h#L44-L45
I think it's also important to mention that on PowerISA the elements also follow
the MSB 0 notation. So byte, word, and dword elements in a register found in the
instruction descriptions when referred to 0 are the element "at the left tip",
i.e. "the most significant elements", so to speak. For instance, take
instruction "vperm": doc says 'index' takes bits 3:7 of a byte from [byte]
element 'i'. So for a byte element i=0 it means the most significant byte
("on the left tip") of vector register operand 'VRC'. Moreover, specified bits
in that byte element, i.e. bits 3:7, also follow the MSB 0, so for the
little-endian addicted thought they are bits 4:0 (LSB 0 notation).
Now, if bits 4:0 = 0b00011 (decimal 3), we grab byte element 3 from 'src'
(256-bit). However byte element 3 is also in MSB 0 notation, so it means third
byte of 'src' but starting counting bytes from 0 from the left to the right
(which in IMO looks indeed more natural since we count, for instance, Natural
Numbers on the 'x' axis similarly).
Hence, it's like to say that 'vperm' instruction in a certain sense has a
"big-endian semantics" for the byte indices. The 'vpermr' instruction introduced
by PowerISA v3.0 is meant to cope with that, so 'vpermr' byte indices have a
"little-endian semantics", so for bits 3:7 MSB 0 (or bits 4:0 in LSB 0 notation) =
0b00011 (decimal 3), on the 'vpermr' instruction it really means we must count
bytes starting from right to left as in the LSB 0 notation and grab the third byte
element from right to left.
So, for instance:
vr0 uint128 = 0x00000000000000000000000000000000
vr1 uint128 = 0x00102030405060708090a0b0c0d0e0f0
vr2 uint128 = 0x01112233445566779999aabbccddeeff
vr3 uint128 = 0x03000000000000000000000000000000
we have 'src' as:
MSB 0: v--- byte 0, 1, 2, 3, ...
LSB 0: ... 3, 2, 1, byte 0 ---v
src = vr1 || vr2 = 00 10 20 30 40 50 60 70 80 90 A0 B0 C0 D0 E0 F0 01 11 22 33 44 55 66 77 99 99 AA BB CC DD EE FF
vperm vr0, vr1, vr2, vr3 result is:
vr0 uint128 = 0x30000000000000000000000000000000
byte 3 in MSB 0 = 0x30 ---^ and 0x00 (byte 0 in MSB 0) copied to the remaining bytes
whilst with vpermr (PowerISA v3.0 / POWER9):
vpermr vr0, vr1, vr2, vr3 result is:
vr0 uint128 = 0xccffffffffffffffffffffffffffffff
byte 3 in LSB 0 = 0xCC----^ and 0xFF (byte 0 in LSB 0) copied to the remaining bytes
Anyway, vperm/vpermr was just an example about notation not being restricted to
bits on Power ISA. So read the docs carefully :) GDB is always useful for checking
if one's understanding about a given Power instruction is correct.
HTH.
Regards,
Gustavo
^ permalink raw reply
* Re: [PATCH 09/16] of: overlay: validate overlay properties #address-cells and #size-cells
From: Frank Rowand @ 2018-10-09 0:02 UTC (permalink / raw)
To: Alan Tull
Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-fpga, Pantelis Antoniou, linux-kernel, Rob Herring,
Moritz Fischer, Paul Mackerras, linuxppc-dev
In-Reply-To: <CANk1AXRi90nFNTji+7RVPC-hb9NFX5+gJo6OpCKvyuVx8eX3Fw@mail.gmail.com>
On 10/08/18 11:46, Alan Tull wrote:
> On Mon, Oct 8, 2018 at 10:57 AM Alan Tull <atull@kernel.org> wrote:
>>
>> On Thu, Oct 4, 2018 at 11:14 PM <frowand.list@gmail.com> wrote:
>>>
>>> From: Frank Rowand <frank.rowand@sony.com>
>>>
>>> If overlay properties #address-cells or #size-cells are already in
>>> the live devicetree for any given node, then the values in the
>>> overlay must match the values in the live tree.
>>
>> Hi Frank,
>>
>> I'm starting some FPGA testing on this patchset applied to v4.19-rc7.
>> That applied cleanly; if that's not the best base to test against,
>> please let me know.
I would expect -rc7 to be ok to test against. I'm doing the development
of it on -rc1.
Thanks for the testing.
>> On a very simple overlay, I'm seeing this patch's warning catching
>> things other than #address-cells or #size-cells.
#address-cells and #size-cells escape the warning for properties on an
existing (non-overlay) node if the existing node already contains them
as a special case. Those two properties are needed in the overlay to
avoid dtc compiler warnings. If the same properties already exist in
the base devicetree and have the same values as in the overlay then
there is no need to add property update changeset entries in the overlay
changeset. Since there will not be changeset entries for those two
properties, there will be no memory leak when the changeset is removed.
The special casing of #address-cells and #size-cells is part of the
fix patches that are a result of the validation patches. Thus a little
bit less memory leaking than we have today.
> What it's warning about are new properties being added to an existing
> node. So !prop is true and !of_node_check_flag(target->np,
> OF_OVERLAY) also is true. Is that a potential memory leak as you are
> warning? If so, your code is working as planned and you'll just need
> to document that also in the header.
Yes, you are accurately describing what the check is catching.
The memory leak (on release) is because the memory allocated for overlay
properties is released when the reference count of the node they are
attached is decremented to zero, but only if the node is a dynamic flagged
node (as overlays are). The memory allocated for the overlay properties
will not be freed in this case because the node is not a dynamic node.
>> I'm just getting
>> started looking at this, will spend time understanding this better and
>> I'll test other overlays. The warnings were:
>>
>> Applying dtbo: socfpga_overlay.dtb
>> [ 33.117881] fpga_manager fpga0: writing soc_system.rbf to Altera
>> SOCFPGA FPGA Manager
>> [ 33.575223] OF: overlay: WARNING: add_changeset_property(), memory
>> leak will occur if overlay removed. Property:
>> /soc/base-fpga-region/firmware-name
>> [ 33.588584] OF: overlay: WARNING: add_changeset_property(), memory
>> leak will occur if overlay removed. Property:
>> /soc/base-fpga-region/fpga-bridges
>> [ 33.601856] OF: overlay: WARNING: add_changeset_property(), memory
>> leak will occur if overlay removed. Property:
>> /soc/base-fpga-region/ranges
Are there properties in /soc/base-fpga-region/ in the base devicetree?
If not, then that node could be removed from the base devicetree and first created
in an overlay.
If so, is it possible to add an additional level of node, /soc/base-fpga-region/foo,
which would contain the properties that are warned about above? Then the properties
would be children of an overlay node and the memory would be freed on overlay
release.
This is not actually a suggestion that should be implemented right now, just trying
to understand the possible alternatives, because this would result in an arbitrary
fake level in the tree (which I don't like).
My intent is to leave these validation checks as warnings while we figure out the
best way to solve the underlying memory leak issue. Note that some of the
validation checks result in errors and cause an overlay apply to fail. If I
did those checks correctly, they should only catch cases where the live tree
after applying the overlay was a "corrupt" tree instead of the desired changes.
I expect that Plumbers will be a good place to explore these things.
>> Here's part of that overlay including the properties it's complaining about:
>>
>> /dts-v1/;
>> /plugin/;
>> / {
>> fragment@0 {
>> target = <&base_fpga_region>;
>> #address-cells = <1>;
>> #size-cells = <1>;
>> __overlay__ {
>> #address-cells = <1>;
>> #size-cells = <1>;
>>
>> firmware-name = "soc_system.rbf";
>> fpga-bridges = <&fpga_bridge1>;
>> ranges = <0x20000 0xff200000 0x100000>,
>> <0x0 0xc0000000 0x20000000>;
>>
>> gpio@10040 {
>> so on...
>>
>> By the way, I didn't get any warnings when I subsequently removed this overlay.
Yes, I did not add any check that could catch this at release time.
-Frank
>> Alan
>>
>>>
>>> If the properties are already in the live tree then there is no
>>> need to create a changeset entry to add them since they must
>>> have the same value. This reduces the memory used by the
>>> changeset and eliminates a possible memory leak. This is
>>> verified by 12 fewer warnings during the devicetree unittest,
>>> as the possible memory leak warnings about #address-cells and
>>>
>>> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
>>> ---
>>> drivers/of/overlay.c | 38 +++++++++++++++++++++++++++++++++++---
>>> 1 file changed, 35 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
>>> index 29c33a5c533f..e6fb3ffe9d93 100644
>>> --- a/drivers/of/overlay.c
>>> +++ b/drivers/of/overlay.c
>>> @@ -287,7 +287,12 @@ static struct property *dup_and_fixup_symbol_prop(
>>> * @target may be either in the live devicetree or in a new subtree that
>>> * is contained in the changeset.
>>> *
>>> - * Some special properties are not updated (no error returned).
>>> + * Some special properties are not added or updated (no error returned):
>>> + * "name", "phandle", "linux,phandle".
>>> + *
>>> + * Properties "#address-cells" and "#size-cells" are not updated if they
>>> + * are already in the live tree, but if present in the live tree, the values
>>> + * in the overlay must match the values in the live tree.
>>> *
>>> * Update of property in symbols node is not allowed.
>>> *
>>> @@ -300,6 +305,7 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
>>> {
>>> struct property *new_prop = NULL, *prop;
>>> int ret = 0;
>>> + bool check_for_non_overlay_node = false;
>>>
>>> if (!of_prop_cmp(overlay_prop->name, "name") ||
>>> !of_prop_cmp(overlay_prop->name, "phandle") ||
>>> @@ -322,13 +328,39 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
>>> if (!new_prop)
>>> return -ENOMEM;
>>>
>>> - if (!prop)
>>> + if (!prop) {
>>> +
>>> + check_for_non_overlay_node = true;
>>> ret = of_changeset_add_property(&ovcs->cset, target->np,
>>> new_prop);
>>> - else
>>> +
>>> + } else if (!of_prop_cmp(prop->name, "#address-cells")) {
>>> +
>>> + if (prop->length != 4 || new_prop->length != 4 ||
>>> + *(u32 *)prop->value != *(u32 *)new_prop->value)
>>> + pr_err("ERROR: overlay and/or live tree #address-cells invalid in node %pOF\n",
>>> + target->np);
>>> +
>>> + } else if (!of_prop_cmp(prop->name, "#size-cells")) {
>>> +
>>> + if (prop->length != 4 || new_prop->length != 4 ||
>>> + *(u32 *)prop->value != *(u32 *)new_prop->value)
>>> + pr_err("ERROR: overlay and/or live tree #size-cells invalid in node %pOF\n",
>>> + target->np);
>>> +
>>> + } else {
>>> +
>>> + check_for_non_overlay_node = true;
>>> ret = of_changeset_update_property(&ovcs->cset, target->np,
>>> new_prop);
>>>
>>> + }
>>> +
>>> + if (check_for_non_overlay_node &&
>>> + !of_node_check_flag(target->np, OF_OVERLAY))
>>> + pr_err("WARNING: %s(), memory leak will occur if overlay removed. Property: %pOF/%s\n",
>>> + __func__, target->np, new_prop->name);
>>> +
>>> if (ret) {
>>> kfree(new_prop->name);
>>> kfree(new_prop->value);
>>> --
>>> Frank Rowand <frank.rowand@sony.com>
>>>
>
^ permalink raw reply
* Re: [PATCH v5 30/33] KVM: PPC: Book3S HV: Allow HV module to load without hypervisor mode
From: David Gibson @ 2018-10-08 23:31 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-31-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 2788 bytes --]
On Mon, Oct 08, 2018 at 04:31:16PM +1100, Paul Mackerras wrote:
> With this, the KVM-HV module can be loaded in a guest running under
> KVM-HV, and if the hypervisor supports nested virtualization, this
> guest can now act as a nested hypervisor and run nested guests.
>
> This also adds some checks to inform userspace that HPT guests are not
> supported by nested hypervisors (by returning false for the
> KVM_CAP_PPC_MMU_HASH_V3 capability), and to prevent userspace from
> configuring a guest to use HPT mode.
>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> arch/powerpc/kvm/book3s_hv.c | 16 ++++++++++++----
> arch/powerpc/kvm/powerpc.c | 3 ++-
> 2 files changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 127bb5f..152bf75 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -4807,11 +4807,15 @@ static int kvmppc_core_emulate_mfspr_hv(struct kvm_vcpu *vcpu, int sprn,
>
> static int kvmppc_core_check_processor_compat_hv(void)
> {
> - if (!cpu_has_feature(CPU_FTR_HVMODE) ||
> - !cpu_has_feature(CPU_FTR_ARCH_206))
> - return -EIO;
> + if (cpu_has_feature(CPU_FTR_HVMODE) &&
> + cpu_has_feature(CPU_FTR_ARCH_206))
> + return 0;
>
> - return 0;
> + /* POWER9 in radix mode is capable of being a nested hypervisor. */
> + if (cpu_has_feature(CPU_FTR_ARCH_300) && radix_enabled())
> + return 0;
> +
> + return -EIO;
> }
>
> #ifdef CONFIG_KVM_XICS
> @@ -5129,6 +5133,10 @@ static int kvmhv_configure_mmu(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg)
> if (radix && !radix_enabled())
> return -EINVAL;
>
> + /* If we're a nested hypervisor, we currently only support radix */
> + if (kvmhv_on_pseries() && !radix)
> + return -EINVAL;
> +
> mutex_lock(&kvm->lock);
> if (radix != kvm_is_radix(kvm)) {
> if (kvm->arch.mmu_ready) {
> diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
> index eba5756..1f4b128 100644
> --- a/arch/powerpc/kvm/powerpc.c
> +++ b/arch/powerpc/kvm/powerpc.c
> @@ -594,7 +594,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> r = !!(hv_enabled && radix_enabled());
> break;
> case KVM_CAP_PPC_MMU_HASH_V3:
> - r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300));
> + r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300) &&
> + cpu_has_feature(CPU_FTR_HVMODE));
> break;
> #endif
> case KVM_CAP_SYNC_MMU:
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v5 32/33] KVM: PPC: Book3S HV: Add a VM capability to enable nested virtualization
From: David Gibson @ 2018-10-08 23:34 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-33-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 7729 bytes --]
On Mon, Oct 08, 2018 at 04:31:18PM +1100, Paul Mackerras wrote:
> With this, userspace can enable a KVM-HV guest to run nested guests
> under it.
>
> The administrator can control whether any nested guests can be run;
> setting the "nested" module parameter to false prevents any guests
> becoming nested hypervisors (that is, any attempt to enable the nested
> capability on a guest will fail). Guests which are already nested
> hypervisors will continue to be so.
>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> Documentation/virtual/kvm/api.txt | 14 ++++++++++++++
> arch/powerpc/include/asm/kvm_ppc.h | 1 +
> arch/powerpc/kvm/book3s_hv.c | 39 +++++++++++++++++++++++++++++---------
> arch/powerpc/kvm/powerpc.c | 12 ++++++++++++
> include/uapi/linux/kvm.h | 1 +
> 5 files changed, 58 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 2f5f9b7..fde48b6 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -4532,6 +4532,20 @@ With this capability, a guest may read the MSR_PLATFORM_INFO MSR. Otherwise,
> a #GP would be raised when the guest tries to access. Currently, this
> capability does not enable write permissions of this MSR for the guest.
>
> +7.16 KVM_CAP_PPC_NESTED_HV
> +
> +Architectures: ppc
> +Parameters: none
> +Returns: 0 on success, -EINVAL when the implementation doesn't support
> + nested-HV virtualization.
> +
> +HV-KVM on POWER9 and later systems allows for "nested-HV"
> +virtualization, which provides a way for a guest VM to run guests that
> +can run using the CPU's supervisor mode (privileged non-hypervisor
> +state). Enabling this capability on a VM depends on the CPU having
> +the necessary functionality and on the facility being enabled with a
> +kvm-hv module parameter.
> +
> 8. Other capabilities.
> ----------------------
>
> diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
> index 245e564..b3796bd 100644
> --- a/arch/powerpc/include/asm/kvm_ppc.h
> +++ b/arch/powerpc/include/asm/kvm_ppc.h
> @@ -327,6 +327,7 @@ struct kvmppc_ops {
> int (*set_smt_mode)(struct kvm *kvm, unsigned long mode,
> unsigned long flags);
> void (*giveup_ext)(struct kvm_vcpu *vcpu, ulong msr);
> + int (*enable_nested)(struct kvm *kvm);
> };
>
> extern struct kvmppc_ops *kvmppc_hv_ops;
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 152bf75..fa61647 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -118,6 +118,16 @@ module_param_cb(h_ipi_redirect, &module_param_ops, &h_ipi_redirect, 0644);
> MODULE_PARM_DESC(h_ipi_redirect, "Redirect H_IPI wakeup to a free host core");
> #endif
>
> +/* If set, guests are allowed to create and control nested guests */
> +static bool nested = true;
> +module_param(nested, bool, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(nested, "Enable nested virtualization (only on POWER9)");
> +
> +static inline bool nesting_enabled(struct kvm *kvm)
> +{
> + return kvm->arch.nested_enable && kvm_is_radix(kvm);
> +}
> +
> /* If set, the threads on each CPU core have to be in the same MMU mode */
> static bool no_mixing_hpt_and_radix;
>
> @@ -959,12 +969,12 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
>
> case H_SET_PARTITION_TABLE:
> ret = H_FUNCTION;
> - if (vcpu->kvm->arch.nested_enable)
> + if (nesting_enabled(vcpu->kvm))
> ret = kvmhv_set_partition_table(vcpu);
> break;
> case H_ENTER_NESTED:
> ret = H_FUNCTION;
> - if (!vcpu->kvm->arch.nested_enable)
> + if (!nesting_enabled(vcpu->kvm))
> break;
> ret = kvmhv_enter_nested_guest(vcpu);
> if (ret == H_INTERRUPT) {
> @@ -974,9 +984,8 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
> break;
> case H_TLB_INVALIDATE:
> ret = H_FUNCTION;
> - if (!vcpu->kvm->arch.nested_enable)
> - break;
> - ret = kvmhv_do_nested_tlbie(vcpu);
> + if (nesting_enabled(vcpu->kvm))
> + ret = kvmhv_do_nested_tlbie(vcpu);
> break;
>
> default:
> @@ -4496,10 +4505,8 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
> /* Must be called with kvm->lock held and mmu_ready = 0 and no vcpus running */
> int kvmppc_switch_mmu_to_hpt(struct kvm *kvm)
> {
> - if (kvm->arch.nested_enable) {
> - kvm->arch.nested_enable = false;
> + if (nesting_enabled(kvm))
> kvmhv_release_all_nested(kvm);
> - }
> kvmppc_free_radix(kvm);
> kvmppc_update_lpcr(kvm, LPCR_VPM1,
> LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR);
> @@ -4776,7 +4783,7 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
>
> /* Perform global invalidation and return lpid to the pool */
> if (cpu_has_feature(CPU_FTR_ARCH_300)) {
> - if (kvm->arch.nested_enable)
> + if (nesting_enabled(kvm))
> kvmhv_release_all_nested(kvm);
> kvm->arch.process_table = 0;
> kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
> @@ -5169,6 +5176,19 @@ static int kvmhv_configure_mmu(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg)
> return err;
> }
>
> +static int kvmhv_enable_nested(struct kvm *kvm)
> +{
> + if (!nested)
> + return -EPERM;
> + if (!cpu_has_feature(CPU_FTR_ARCH_300))
> + return -ENODEV;
> +
> + /* kvm == NULL means the caller is testing if the capability exists */
> + if (kvm)
> + kvm->arch.nested_enable = true;
> + return 0;
> +}
> +
> static struct kvmppc_ops kvm_ops_hv = {
> .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
> .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
> @@ -5208,6 +5228,7 @@ static struct kvmppc_ops kvm_ops_hv = {
> .configure_mmu = kvmhv_configure_mmu,
> .get_rmmu_info = kvmhv_get_rmmu_info,
> .set_smt_mode = kvmhv_set_smt_mode,
> + .enable_nested = kvmhv_enable_nested,
> };
>
> static int kvm_init_subcore_bitmap(void)
> diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
> index 1f4b128..2869a29 100644
> --- a/arch/powerpc/kvm/powerpc.c
> +++ b/arch/powerpc/kvm/powerpc.c
> @@ -597,6 +597,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300) &&
> cpu_has_feature(CPU_FTR_HVMODE));
> break;
> + case KVM_CAP_PPC_NESTED_HV:
> + r = !!(hv_enabled && kvmppc_hv_ops->enable_nested &&
> + !kvmppc_hv_ops->enable_nested(NULL));
> + break;
> #endif
> case KVM_CAP_SYNC_MMU:
> #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
> @@ -2115,6 +2119,14 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
> r = kvm->arch.kvm_ops->set_smt_mode(kvm, mode, flags);
> break;
> }
> +
> + case KVM_CAP_PPC_NESTED_HV:
> + r = -EINVAL;
> + if (!is_kvmppc_hv_enabled(kvm) ||
> + !kvm->arch.kvm_ops->enable_nested)
> + break;
> + r = kvm->arch.kvm_ops->enable_nested(kvm);
> + break;
> #endif
> default:
> r = -EINVAL;
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 251be35..d9cec6b 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -953,6 +953,7 @@ struct kvm_ppc_resize_hpt {
> #define KVM_CAP_NESTED_STATE 157
> #define KVM_CAP_ARM_INJECT_SERROR_ESR 158
> #define KVM_CAP_MSR_PLATFORM_INFO 159
> +#define KVM_CAP_PPC_NESTED_HV 160
>
> #ifdef KVM_CAP_IRQ_ROUTING
>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v5 09/33] KVM: PPC: Book3S HV: Streamlined guest entry/exit path on P9 for radix guests
From: David Gibson @ 2018-10-09 0:20 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-10-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 24730 bytes --]
On Mon, Oct 08, 2018 at 04:30:55PM +1100, Paul Mackerras wrote:
> This creates an alternative guest entry/exit path which is used for
> radix guests on POWER9 systems when we have indep_threads_mode=Y. In
> these circumstances there is exactly one vcpu per vcore and there is
> no coordination required between vcpus or vcores; the vcpu can enter
> the guest without needing to synchronize with anything else.
>
> The new fast path is implemented almost entirely in C in book3s_hv.c
> and runs with the MMU on until the guest is entered. On guest exit
> we use the existing path until the point where we are committed to
> exiting the guest (as distinct from handling an interrupt in the
> low-level code and returning to the guest) and we have pulled the
> guest context from the XIVE. At that point we check a flag in the
> stack frame to see whether we came in via the old path and the new
> path; if we came in via the new path then we go back to C code to do
> the rest of the process of saving the guest context and restoring the
> host context.
>
> The C code is split into separate functions for handling the
> OS-accessible state and the hypervisor state, with the idea that the
> latter can be replaced by a hypercall when we implement nested
> virtualization.
>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> arch/powerpc/include/asm/asm-prototypes.h | 2 +
> arch/powerpc/include/asm/kvm_ppc.h | 2 +
> arch/powerpc/kvm/book3s_hv.c | 429 +++++++++++++++++++++++++++++-
> arch/powerpc/kvm/book3s_hv_ras.c | 2 +
> arch/powerpc/kvm/book3s_hv_rmhandlers.S | 95 ++++++-
> arch/powerpc/kvm/book3s_xive.c | 63 +++++
> 6 files changed, 589 insertions(+), 4 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h
> index 0c1a2b0..5c9b00c 100644
> --- a/arch/powerpc/include/asm/asm-prototypes.h
> +++ b/arch/powerpc/include/asm/asm-prototypes.h
> @@ -165,4 +165,6 @@ void kvmhv_load_host_pmu(void);
> void kvmhv_save_guest_pmu(struct kvm_vcpu *vcpu, bool pmu_in_use);
> void kvmhv_load_guest_pmu(struct kvm_vcpu *vcpu);
>
> +int __kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu);
> +
> #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
> diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
> index 83d61b8..245e564 100644
> --- a/arch/powerpc/include/asm/kvm_ppc.h
> +++ b/arch/powerpc/include/asm/kvm_ppc.h
> @@ -585,6 +585,7 @@ extern int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
>
> extern int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
> int level, bool line_status);
> +extern void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu);
> #else
> static inline int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server,
> u32 priority) { return -1; }
> @@ -607,6 +608,7 @@ static inline int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) { retur
>
> static inline int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
> int level, bool line_status) { return -ENODEV; }
> +static inline void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) { }
> #endif /* CONFIG_KVM_XIVE */
>
> /*
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 0e17593..0c1dd76 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -3080,6 +3080,269 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
> }
>
> /*
> + * Load up hypervisor-mode registers on P9.
> + */
> +static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit)
> +{
> + struct kvmppc_vcore *vc = vcpu->arch.vcore;
> + s64 hdec;
> + u64 tb, purr, spurr;
> + int trap;
> + unsigned long host_hfscr = mfspr(SPRN_HFSCR);
> + unsigned long host_ciabr = mfspr(SPRN_CIABR);
> + unsigned long host_dawr = mfspr(SPRN_DAWR);
> + unsigned long host_dawrx = mfspr(SPRN_DAWRX);
> + unsigned long host_psscr = mfspr(SPRN_PSSCR);
> + unsigned long host_pidr = mfspr(SPRN_PID);
> +
> + hdec = time_limit - mftb();
> + if (hdec < 0)
> + return BOOK3S_INTERRUPT_HV_DECREMENTER;
> + mtspr(SPRN_HDEC, hdec);
> +
> + if (vc->tb_offset) {
> + u64 new_tb = mftb() + vc->tb_offset;
> + mtspr(SPRN_TBU40, new_tb);
> + tb = mftb();
> + if ((tb & 0xffffff) < (new_tb & 0xffffff))
> + mtspr(SPRN_TBU40, new_tb + 0x1000000);
> + vc->tb_offset_applied = vc->tb_offset;
> + }
> +
> + if (vc->pcr)
> + mtspr(SPRN_PCR, vc->pcr);
> + mtspr(SPRN_DPDES, vc->dpdes);
> + mtspr(SPRN_VTB, vc->vtb);
> +
> + local_paca->kvm_hstate.host_purr = mfspr(SPRN_PURR);
> + local_paca->kvm_hstate.host_spurr = mfspr(SPRN_SPURR);
> + mtspr(SPRN_PURR, vcpu->arch.purr);
> + mtspr(SPRN_SPURR, vcpu->arch.spurr);
> +
> + if (cpu_has_feature(CPU_FTR_DAWR)) {
> + mtspr(SPRN_DAWR, vcpu->arch.dawr);
> + mtspr(SPRN_DAWRX, vcpu->arch.dawrx);
> + }
> + mtspr(SPRN_CIABR, vcpu->arch.ciabr);
> + mtspr(SPRN_IC, vcpu->arch.ic);
> + mtspr(SPRN_PID, vcpu->arch.pid);
> +
> + mtspr(SPRN_PSSCR, vcpu->arch.psscr | PSSCR_EC |
> + (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
> +
> + mtspr(SPRN_HFSCR, vcpu->arch.hfscr);
> +
> + mtspr(SPRN_SPRG0, vcpu->arch.shregs.sprg0);
> + mtspr(SPRN_SPRG1, vcpu->arch.shregs.sprg1);
> + mtspr(SPRN_SPRG2, vcpu->arch.shregs.sprg2);
> + mtspr(SPRN_SPRG3, vcpu->arch.shregs.sprg3);
> +
> + mtspr(SPRN_AMOR, ~0UL);
> +
> + mtspr(SPRN_LPCR, vc->lpcr);
> + isync();
> +
> + kvmppc_xive_push_vcpu(vcpu);
> +
> + mtspr(SPRN_SRR0, vcpu->arch.shregs.srr0);
> + mtspr(SPRN_SRR1, vcpu->arch.shregs.srr1);
> +
> + trap = __kvmhv_vcpu_entry_p9(vcpu);
> +
> + /* Advance host PURR/SPURR by the amount used by guest */
> + purr = mfspr(SPRN_PURR);
> + spurr = mfspr(SPRN_SPURR);
> + mtspr(SPRN_PURR, local_paca->kvm_hstate.host_purr +
> + purr - vcpu->arch.purr);
> + mtspr(SPRN_SPURR, local_paca->kvm_hstate.host_spurr +
> + spurr - vcpu->arch.spurr);
> + vcpu->arch.purr = purr;
> + vcpu->arch.spurr = spurr;
> +
> + vcpu->arch.ic = mfspr(SPRN_IC);
> + vcpu->arch.pid = mfspr(SPRN_PID);
> + vcpu->arch.psscr = mfspr(SPRN_PSSCR) & PSSCR_GUEST_VIS;
> +
> + vcpu->arch.shregs.sprg0 = mfspr(SPRN_SPRG0);
> + vcpu->arch.shregs.sprg1 = mfspr(SPRN_SPRG1);
> + vcpu->arch.shregs.sprg2 = mfspr(SPRN_SPRG2);
> + vcpu->arch.shregs.sprg3 = mfspr(SPRN_SPRG3);
> +
> + mtspr(SPRN_PSSCR, host_psscr);
> + mtspr(SPRN_HFSCR, host_hfscr);
> + mtspr(SPRN_CIABR, host_ciabr);
> + mtspr(SPRN_DAWR, host_dawr);
> + mtspr(SPRN_DAWRX, host_dawrx);
> + mtspr(SPRN_PID, host_pidr);
> +
> + /*
> + * Since this is radix, do a eieio; tlbsync; ptesync sequence in
> + * case we interrupted the guest between a tlbie and a ptesync.
> + */
> + asm volatile("eieio; tlbsync; ptesync");
> +
> + mtspr(SPRN_LPID, vcpu->kvm->arch.host_lpid); /* restore host LPID */
> + isync();
> +
> + vc->dpdes = mfspr(SPRN_DPDES);
> + vc->vtb = mfspr(SPRN_VTB);
> + mtspr(SPRN_DPDES, 0);
> + if (vc->pcr)
> + mtspr(SPRN_PCR, 0);
> +
> + if (vc->tb_offset_applied) {
> + u64 new_tb = mftb() - vc->tb_offset_applied;
> + mtspr(SPRN_TBU40, new_tb);
> + tb = mftb();
> + if ((tb & 0xffffff) < (new_tb & 0xffffff))
> + mtspr(SPRN_TBU40, new_tb + 0x1000000);
> + vc->tb_offset_applied = 0;
> + }
> +
> + mtspr(SPRN_HDEC, 0x7fffffff);
> + mtspr(SPRN_LPCR, vcpu->kvm->arch.host_lpcr);
> +
> + return trap;
> +}
> +
> +/*
> + * Virtual-mode guest entry for POWER9 and later when the host and
> + * guest are both using the radix MMU. The LPIDR has already been set.
> + */
> +int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit)
> +{
> + struct kvmppc_vcore *vc = vcpu->arch.vcore;
> + unsigned long host_dscr = mfspr(SPRN_DSCR);
> + unsigned long host_tidr = mfspr(SPRN_TIDR);
> + unsigned long host_iamr = mfspr(SPRN_IAMR);
> + s64 dec;
> + u64 tb;
> + int trap, save_pmu;
> +
> + dec = mfspr(SPRN_DEC);
> + tb = mftb();
> + if (dec < 512)
> + return BOOK3S_INTERRUPT_HV_DECREMENTER;
> + local_paca->kvm_hstate.dec_expires = dec + tb;
> + if (local_paca->kvm_hstate.dec_expires < time_limit)
> + time_limit = local_paca->kvm_hstate.dec_expires;
> +
> + vcpu->arch.ceded = 0;
> +
> + kvmhv_save_host_pmu(); /* saves it to PACA kvm_hstate */
> +
> + kvmppc_subcore_enter_guest();
> +
> + vc->entry_exit_map = 1;
> + vc->in_guest = 1;
> +
> + if (vcpu->arch.vpa.pinned_addr) {
> + struct lppaca *lp = vcpu->arch.vpa.pinned_addr;
> + u32 yield_count = be32_to_cpu(lp->yield_count) + 1;
> + lp->yield_count = cpu_to_be32(yield_count);
> + vcpu->arch.vpa.dirty = 1;
> + }
> +
> + if (cpu_has_feature(CPU_FTR_TM) ||
> + cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
> + kvmppc_restore_tm_hv(vcpu, vcpu->arch.shregs.msr, true);
> +
> + kvmhv_load_guest_pmu(vcpu);
> +
> + msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX);
> + load_fp_state(&vcpu->arch.fp);
> + load_vr_state(&vcpu->arch.vr);
> +
> + mtspr(SPRN_DSCR, vcpu->arch.dscr);
> + mtspr(SPRN_IAMR, vcpu->arch.iamr);
> + mtspr(SPRN_PSPB, vcpu->arch.pspb);
> + mtspr(SPRN_FSCR, vcpu->arch.fscr);
> + mtspr(SPRN_TAR, vcpu->arch.tar);
> + mtspr(SPRN_EBBHR, vcpu->arch.ebbhr);
> + mtspr(SPRN_EBBRR, vcpu->arch.ebbrr);
> + mtspr(SPRN_BESCR, vcpu->arch.bescr);
> + mtspr(SPRN_WORT, vcpu->arch.wort);
> + mtspr(SPRN_TIDR, vcpu->arch.tid);
> + mtspr(SPRN_DAR, vcpu->arch.shregs.dar);
> + mtspr(SPRN_DSISR, vcpu->arch.shregs.dsisr);
> + mtspr(SPRN_AMR, vcpu->arch.amr);
> + mtspr(SPRN_UAMOR, vcpu->arch.uamor);
> +
> + if (!(vcpu->arch.ctrl & 1))
> + mtspr(SPRN_CTRLT, mfspr(SPRN_CTRLF) & ~1);
> +
> + mtspr(SPRN_DEC, vcpu->arch.dec_expires - mftb());
> +
> + if (vcpu->arch.doorbell_request) {
> + vc->dpdes = 1;
> + smp_wmb();
> + vcpu->arch.doorbell_request = 0;
> + }
> +
> + trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit);
> +
> + vcpu->arch.slb_max = 0;
> + dec = mfspr(SPRN_DEC);
> + tb = mftb();
> + vcpu->arch.dec_expires = dec + tb;
> + vcpu->cpu = -1;
> + vcpu->arch.thread_cpu = -1;
> + vcpu->arch.ctrl = mfspr(SPRN_CTRLF);
> +
> + vcpu->arch.iamr = mfspr(SPRN_IAMR);
> + vcpu->arch.pspb = mfspr(SPRN_PSPB);
> + vcpu->arch.fscr = mfspr(SPRN_FSCR);
> + vcpu->arch.tar = mfspr(SPRN_TAR);
> + vcpu->arch.ebbhr = mfspr(SPRN_EBBHR);
> + vcpu->arch.ebbrr = mfspr(SPRN_EBBRR);
> + vcpu->arch.bescr = mfspr(SPRN_BESCR);
> + vcpu->arch.wort = mfspr(SPRN_WORT);
> + vcpu->arch.tid = mfspr(SPRN_TIDR);
> + vcpu->arch.amr = mfspr(SPRN_AMR);
> + vcpu->arch.uamor = mfspr(SPRN_UAMOR);
> + vcpu->arch.dscr = mfspr(SPRN_DSCR);
> +
> + mtspr(SPRN_PSPB, 0);
> + mtspr(SPRN_WORT, 0);
> + mtspr(SPRN_AMR, 0);
> + mtspr(SPRN_UAMOR, 0);
> + mtspr(SPRN_DSCR, host_dscr);
> + mtspr(SPRN_TIDR, host_tidr);
> + mtspr(SPRN_IAMR, host_iamr);
> + mtspr(SPRN_PSPB, 0);
> +
> + msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX);
> + store_fp_state(&vcpu->arch.fp);
> + store_vr_state(&vcpu->arch.vr);
> +
> + if (cpu_has_feature(CPU_FTR_TM) ||
> + cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
> + kvmppc_save_tm_hv(vcpu, vcpu->arch.shregs.msr, true);
> +
> + save_pmu = 1;
> + if (vcpu->arch.vpa.pinned_addr) {
> + struct lppaca *lp = vcpu->arch.vpa.pinned_addr;
> + u32 yield_count = be32_to_cpu(lp->yield_count) + 1;
> + lp->yield_count = cpu_to_be32(yield_count);
> + vcpu->arch.vpa.dirty = 1;
> + save_pmu = lp->pmcregs_in_use;
> + }
> +
> + kvmhv_save_guest_pmu(vcpu, save_pmu);
> +
> + vc->entry_exit_map = 0x101;
> + vc->in_guest = 0;
> +
> + mtspr(SPRN_DEC, local_paca->kvm_hstate.dec_expires - mftb());
> +
> + kvmhv_load_host_pmu();
> +
> + kvmppc_subcore_exit_guest();
> +
> + return trap;
> +}
> +
> +/*
> * Wait for some other vcpu thread to execute us, and
> * wake us up when we need to handle something in the host.
> */
> @@ -3405,6 +3668,167 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
> return vcpu->arch.ret;
> }
>
> +static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run,
> + struct kvm_vcpu *vcpu, u64 time_limit)
> +{
> + int trap, r, pcpu, pcpu0;
> + int srcu_idx;
> + struct kvmppc_vcore *vc;
> + struct kvm *kvm = vcpu->kvm;
> +
> + trace_kvmppc_run_vcpu_enter(vcpu);
> +
> + kvm_run->exit_reason = 0;
> + vcpu->arch.ret = RESUME_GUEST;
> + vcpu->arch.trap = 0;
> +
> + vc = vcpu->arch.vcore;
> + vcpu->arch.ceded = 0;
> + vcpu->arch.run_task = current;
> + vcpu->arch.kvm_run = kvm_run;
> + vcpu->arch.stolen_logged = vcore_stolen_time(vc, mftb());
> + vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
> + vcpu->arch.busy_preempt = TB_NIL;
> + vcpu->arch.last_inst = KVM_INST_FETCH_FAILED;
> + vc->runnable_threads[0] = vcpu;
> + vc->n_runnable = 1;
> + vc->runner = vcpu;
> +
> + /* See if the MMU is ready to go */
> + if (!kvm->arch.mmu_ready) {
> + r = kvmhv_setup_mmu(vcpu);
> + if (r) {
> + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
> + kvm_run->fail_entry.
> + hardware_entry_failure_reason = 0;
> + vcpu->arch.ret = r;
> + goto out;
> + }
> + }
> +
> + if (need_resched())
> + cond_resched();
> +
> + kvmppc_update_vpas(vcpu);
> +
> + init_vcore_to_run(vc);
> + vc->preempt_tb = TB_NIL;
> +
> + preempt_disable();
> + pcpu = smp_processor_id();
> + vc->pcpu = pcpu;
> + kvmppc_prepare_radix_vcpu(vcpu, pcpu);
> +
> + local_irq_disable();
> + hard_irq_disable();
> + if (signal_pending(current))
> + goto sigpend;
> + if (lazy_irq_pending() || need_resched() || !kvm->arch.mmu_ready)
> + goto out;
> +
> + kvmppc_core_prepare_to_enter(vcpu);
> +
> + kvmppc_clear_host_core(pcpu);
> +
> + local_paca->kvm_hstate.tid = 0;
> + local_paca->kvm_hstate.napping = 0;
> + local_paca->kvm_hstate.kvm_split_mode = NULL;
> + kvmppc_start_thread(vcpu, vc);
> + kvmppc_create_dtl_entry(vcpu, vc);
> + trace_kvm_guest_enter(vcpu);
> +
> + vc->vcore_state = VCORE_RUNNING;
> + trace_kvmppc_run_core(vc, 0);
> +
> + mtspr(SPRN_LPID, vc->kvm->arch.lpid);
> + isync();
> +
> + /* See comment above in kvmppc_run_core() about this */
> + pcpu0 = pcpu;
> + if (cpu_has_feature(CPU_FTR_ARCH_300))
> + pcpu0 &= ~0x3UL;
> +
> + if (cpumask_test_cpu(pcpu0, &kvm->arch.need_tlb_flush)) {
> + radix__local_flush_tlb_lpid_guest(kvm->arch.lpid);
> + /* Clear the bit after the TLB flush */
> + cpumask_clear_cpu(pcpu0, &kvm->arch.need_tlb_flush);
> + }
> +
> + trace_hardirqs_on();
> + guest_enter_irqoff();
> +
> + srcu_idx = srcu_read_lock(&kvm->srcu);
> +
> + this_cpu_disable_ftrace();
> +
> + trap = kvmhv_p9_guest_entry(vcpu, time_limit);
> + vcpu->arch.trap = trap;
> +
> + this_cpu_enable_ftrace();
> +
> + srcu_read_unlock(&kvm->srcu, srcu_idx);
> +
> + mtspr(SPRN_LPID, kvm->arch.host_lpid);
> + isync();
> +
> + trace_hardirqs_off();
> + set_irq_happened(trap);
> +
> + kvmppc_set_host_core(pcpu);
> +
> + local_irq_enable();
> + guest_exit();
> +
> + cpumask_clear_cpu(pcpu, &kvm->arch.cpu_in_guest);
> +
> + preempt_enable();
> +
> + /* cancel pending decrementer exception if DEC is now positive */
> + if (get_tb() < vcpu->arch.dec_expires && kvmppc_core_pending_dec(vcpu))
> + kvmppc_core_dequeue_dec(vcpu);
> +
> + trace_kvm_guest_exit(vcpu);
> + r = RESUME_GUEST;
> + if (trap)
> + r = kvmppc_handle_exit_hv(kvm_run, vcpu, current);
> + vcpu->arch.ret = r;
> +
> + if (is_kvmppc_resume_guest(r) && vcpu->arch.ceded &&
> + !kvmppc_vcpu_woken(vcpu)) {
> + kvmppc_set_timer(vcpu);
> + while (vcpu->arch.ceded && !kvmppc_vcpu_woken(vcpu)) {
> + if (signal_pending(current)) {
> + vcpu->stat.signal_exits++;
> + kvm_run->exit_reason = KVM_EXIT_INTR;
> + vcpu->arch.ret = -EINTR;
> + break;
> + }
> + spin_lock(&vc->lock);
> + kvmppc_vcore_blocked(vc);
> + spin_unlock(&vc->lock);
> + }
> + }
> + vcpu->arch.ceded = 0;
> +
> + vc->vcore_state = VCORE_INACTIVE;
> + trace_kvmppc_run_core(vc, 1);
> +
> + done:
> + kvmppc_remove_runnable(vc, vcpu);
> + trace_kvmppc_run_vcpu_exit(vcpu, kvm_run);
> +
> + return vcpu->arch.ret;
> +
> + sigpend:
> + vcpu->stat.signal_exits++;
> + kvm_run->exit_reason = KVM_EXIT_INTR;
> + vcpu->arch.ret = -EINTR;
> + out:
> + local_irq_enable();
> + preempt_enable();
> + goto done;
> +}
> +
> static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
> {
> int r;
> @@ -3480,7 +3904,10 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
> vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
>
> do {
> - r = kvmppc_run_vcpu(run, vcpu);
> + if (kvm->arch.threads_indep && kvm_is_radix(kvm))
> + r = kvmhv_run_single_vcpu(run, vcpu, ~(u64)0);
> + else
> + r = kvmppc_run_vcpu(run, vcpu);
>
> if (run->exit_reason == KVM_EXIT_PAPR_HCALL &&
> !(vcpu->arch.shregs.msr & MSR_PR)) {
> diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c
> index ee564b6..0787f12 100644
> --- a/arch/powerpc/kvm/book3s_hv_ras.c
> +++ b/arch/powerpc/kvm/book3s_hv_ras.c
> @@ -177,6 +177,7 @@ void kvmppc_subcore_enter_guest(void)
>
> local_paca->sibling_subcore_state->in_guest[subcore_id] = 1;
> }
> +EXPORT_SYMBOL_GPL(kvmppc_subcore_enter_guest);
>
> void kvmppc_subcore_exit_guest(void)
> {
> @@ -187,6 +188,7 @@ void kvmppc_subcore_exit_guest(void)
>
> local_paca->sibling_subcore_state->in_guest[subcore_id] = 0;
> }
> +EXPORT_SYMBOL_GPL(kvmppc_subcore_exit_guest);
>
> static bool kvmppc_tb_resync_required(void)
> {
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index 45dd637..ea84696 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -47,8 +47,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> #define NAPPING_NOVCPU 2
>
> /* Stack frame offsets for kvmppc_hv_entry */
> -#define SFS 160
> +#define SFS 208
> #define STACK_SLOT_TRAP (SFS-4)
> +#define STACK_SLOT_SHORT_PATH (SFS-8)
> #define STACK_SLOT_TID (SFS-16)
> #define STACK_SLOT_PSSCR (SFS-24)
> #define STACK_SLOT_PID (SFS-32)
> @@ -57,6 +58,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> #define STACK_SLOT_DAWR (SFS-56)
> #define STACK_SLOT_DAWRX (SFS-64)
> #define STACK_SLOT_HFSCR (SFS-72)
> +/* the following is used by the P9 short path */
> +#define STACK_SLOT_NVGPRS (SFS-152) /* 18 gprs */
>
> /*
> * Call kvmppc_hv_entry in real mode.
> @@ -1020,6 +1023,9 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
> no_xive:
> #endif /* CONFIG_KVM_XICS */
>
> + li r0, 0
> + stw r0, STACK_SLOT_SHORT_PATH(r1)
> +
> deliver_guest_interrupt: /* r4 = vcpu, r13 = paca */
> /* Check if we can deliver an external or decrementer interrupt now */
> ld r0, VCPU_PENDING_EXC(r4)
> @@ -1034,13 +1040,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> bl kvmppc_guest_entry_inject_int
> ld r4, HSTATE_KVM_VCPU(r13)
> 71:
> - ld r10, VCPU_PC(r4)
> - ld r11, VCPU_MSR(r4)
> ld r6, VCPU_SRR0(r4)
> ld r7, VCPU_SRR1(r4)
> mtspr SPRN_SRR0, r6
> mtspr SPRN_SRR1, r7
>
> +fast_guest_entry_c:
> + ld r10, VCPU_PC(r4)
> + ld r11, VCPU_MSR(r4)
> /* r11 = vcpu->arch.msr & ~MSR_HV */
> rldicl r11, r11, 63 - MSR_HV_LG, 1
> rotldi r11, r11, 1 + MSR_HV_LG
> @@ -1117,6 +1124,83 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> HRFI_TO_GUEST
> b .
>
> +/*
> + * Enter the guest on a P9 or later system where we have exactly
> + * one vcpu per vcore and we don't need to go to real mode
> + * (which implies that host and guest are both using radix MMU mode).
> + * r3 = vcpu pointer
> + * Most SPRs and all the VSRs have been loaded already.
> + */
> +_GLOBAL(__kvmhv_vcpu_entry_p9)
> +EXPORT_SYMBOL_GPL(__kvmhv_vcpu_entry_p9)
> + mflr r0
> + std r0, PPC_LR_STKOFF(r1)
> + stdu r1, -SFS(r1)
> +
> + li r0, 1
> + stw r0, STACK_SLOT_SHORT_PATH(r1)
> +
> + std r3, HSTATE_KVM_VCPU(r13)
> + mfcr r4
> + stw r4, SFS+8(r1)
> +
> + std r1, HSTATE_HOST_R1(r13)
> +
> + reg = 14
> + .rept 18
> + std reg, STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
> + reg = reg + 1
> + .endr
> +
> + reg = 14
> + .rept 18
> + ld reg, __VCPU_GPR(reg)(r3)
> + reg = reg + 1
> + .endr
> +
> + mfmsr r10
> + std r10, HSTATE_HOST_MSR(r13)
> +
> + mr r4, r3
> + b fast_guest_entry_c
> +guest_exit_short_path:
> +
> + li r0, KVM_GUEST_MODE_NONE
> + stb r0, HSTATE_IN_GUEST(r13)
> +
> + reg = 14
> + .rept 18
> + std reg, __VCPU_GPR(reg)(r9)
> + reg = reg + 1
> + .endr
> +
> + reg = 14
> + .rept 18
> + ld reg, STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
> + reg = reg + 1
> + .endr
> +
> + lwz r4, SFS+8(r1)
> + mtcr r4
> +
> + mr r3, r12 /* trap number */
> +
> + addi r1, r1, SFS
> + ld r0, PPC_LR_STKOFF(r1)
> + mtlr r0
> +
> + /* If we are in real mode, do a rfid to get back to the caller */
> + mfmsr r4
> + andi. r5, r4, MSR_IR
> + bnelr
> + rldicl r5, r4, 64 - MSR_TS_S_LG, 62 /* extract TS field */
> + mtspr SPRN_SRR0, r0
> + ld r10, HSTATE_HOST_MSR(r13)
> + rldimi r10, r5, MSR_TS_S_LG, 63 - MSR_TS_T_LG
> + mtspr SPRN_SRR1, r10
> + RFI_TO_KERNEL
> + b .
> +
> secondary_too_late:
> li r12, 0
> stw r12, STACK_SLOT_TRAP(r1)
> @@ -1377,6 +1461,11 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
> 1:
> #endif /* CONFIG_KVM_XICS */
>
> + /* If we came in through the P9 short path, go back out to C now */
> + lwz r0, STACK_SLOT_SHORT_PATH(r1)
> + cmpwi r0, 0
> + bne guest_exit_short_path
> +
> /* For hash guest, read the guest SLB and save it away */
> ld r5, VCPU_KVM(r9)
> lbz r0, KVM_RADIX(r5)
> diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c
> index 30c2eb7..ad4a370 100644
> --- a/arch/powerpc/kvm/book3s_xive.c
> +++ b/arch/powerpc/kvm/book3s_xive.c
> @@ -62,6 +62,69 @@
> #define XIVE_Q_GAP 2
>
> /*
> + * Push a vcpu's context to the XIVE on guest entry.
> + * This assumes we are in virtual mode (MMU on)
> + */
> +void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu)
> +{
> + void __iomem *tima = local_paca->kvm_hstate.xive_tima_virt;
> + u64 pq;
> +
> + if (!tima)
> + return;
> + eieio();
> + __raw_writeq(vcpu->arch.xive_saved_state.w01, tima + TM_QW1_OS);
> + __raw_writel(vcpu->arch.xive_cam_word, tima + TM_QW1_OS + TM_WORD2);
> + vcpu->arch.xive_pushed = 1;
> + eieio();
> +
> + /*
> + * We clear the irq_pending flag. There is a small chance of a
> + * race vs. the escalation interrupt happening on another
> + * processor setting it again, but the only consequence is to
> + * cause a spurious wakeup on the next H_CEDE, which is not an
> + * issue.
> + */
> + vcpu->arch.irq_pending = 0;
> +
> + /*
> + * In single escalation mode, if the escalation interrupt is
> + * on, we mask it.
> + */
> + if (vcpu->arch.xive_esc_on) {
> + pq = __raw_readq((void __iomem *)(vcpu->arch.xive_esc_vaddr +
> + XIVE_ESB_SET_PQ_01));
> + mb();
> +
> + /*
> + * We have a possible subtle race here: The escalation
> + * interrupt might have fired and be on its way to the
> + * host queue while we mask it, and if we unmask it
> + * early enough (re-cede right away), there is a
> + * theorical possibility that it fires again, thus
> + * landing in the target queue more than once which is
> + * a big no-no.
> + *
> + * Fortunately, solving this is rather easy. If the
> + * above load setting PQ to 01 returns a previous
> + * value where P is set, then we know the escalation
> + * interrupt is somewhere on its way to the host. In
> + * that case we simply don't clear the xive_esc_on
> + * flag below. It will be eventually cleared by the
> + * handler for the escalation interrupt.
> + *
> + * Then, when doing a cede, we check that flag again
> + * before re-enabling the escalation interrupt, and if
> + * set, we abort the cede.
> + */
> + if (!(pq & XIVE_ESB_VAL_P))
> + /* Now P is 0, we can clear the flag */
> + vcpu->arch.xive_esc_on = 0;
> + }
> +}
> +EXPORT_SYMBOL_GPL(kvmppc_xive_push_vcpu);
> +
> +/*
> * This is a simple trigger for a generic XIVE IRQ. This must
> * only be called for interrupts that support a trigger page
> */
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v5 33/33] KVM: PPC: Book3S HV: Add NO_HASH flag to GET_SMMU_INFO ioctl result
From: David Gibson @ 2018-10-08 23:34 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-34-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 2672 bytes --]
On Mon, Oct 08, 2018 at 04:31:19PM +1100, Paul Mackerras wrote:
> This adds a KVM_PPC_NO_HASH flag to the flags field of the
> kvm_ppc_smmu_info struct, and arranges for it to be set when
> running as a nested hypervisor, as an unambiguous indication
> to userspace that HPT guests are not supported. Reporting the
> KVM_CAP_PPC_MMU_HASH_V3 capability as false could be taken as
> indicating only that the new HPT features in ISA V3.0 are not
> supported, leaving it ambiguous whether pre-V3.0 HPT features
> are supported.
>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> Documentation/virtual/kvm/api.txt | 4 ++++
> arch/powerpc/kvm/book3s_hv.c | 4 ++++
> include/uapi/linux/kvm.h | 1 +
> 3 files changed, 9 insertions(+)
>
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index fde48b6..df98b63 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2270,6 +2270,10 @@ The supported flags are:
> The emulated MMU supports 1T segments in addition to the
> standard 256M ones.
>
> + - KVM_PPC_NO_HASH
> + This flag indicates that HPT guests are not supported by KVM,
> + thus all guests must use radix MMU mode.
> +
> The "slb_size" field indicates how many SLB entries are supported
>
> The "sps" array contains 8 entries indicating the supported base
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index fa61647..f565403 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -4245,6 +4245,10 @@ static int kvm_vm_ioctl_get_smmu_info_hv(struct kvm *kvm,
> kvmppc_add_seg_page_size(&sps, 16, SLB_VSID_L | SLB_VSID_LP_01);
> kvmppc_add_seg_page_size(&sps, 24, SLB_VSID_L);
>
> + /* If running as a nested hypervisor, we don't support HPT guests */
> + if (kvmhv_on_pseries())
> + info->flags |= KVM_PPC_NO_HASH;
> +
> return 0;
> }
>
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index d9cec6b..7f2ff3a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -719,6 +719,7 @@ struct kvm_ppc_one_seg_page_size {
>
> #define KVM_PPC_PAGE_SIZES_REAL 0x00000001
> #define KVM_PPC_1T_SEGMENTS 0x00000002
> +#define KVM_PPC_NO_HASH 0x00000004
>
> struct kvm_ppc_smmu_info {
> __u64 flags;
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v5 17/33] KVM: PPC: Book3S HV: Framework and hcall stubs for nested virtualization
From: David Gibson @ 2018-10-08 23:30 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-18-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 19096 bytes --]
On Mon, Oct 08, 2018 at 04:31:03PM +1100, Paul Mackerras wrote:
> This starts the process of adding the code to support nested HV-style
> virtualization. It defines a new H_SET_PARTITION_TABLE hypercall which
> a nested hypervisor can use to set the base address and size of a
> partition table in its memory (analogous to the PTCR register).
> On the host (level 0 hypervisor) side, the H_SET_PARTITION_TABLE
> hypercall from the guest is handled by code that saves the virtual
> PTCR value for the guest.
>
> This also adds code for creating and destroying nested guests and for
> reading the partition table entry for a nested guest from L1 memory.
> Each nested guest has its own shadow LPID value, different in general
> from the LPID value used by the nested hypervisor to refer to it. The
> shadow LPID value is allocated at nested guest creation time.
>
> Nested hypervisor functionality is only available for a radix guest,
> which therefore means a radix host on a POWER9 (or later) processor.
>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> arch/powerpc/include/asm/hvcall.h | 5 +
> arch/powerpc/include/asm/kvm_book3s.h | 10 +-
> arch/powerpc/include/asm/kvm_book3s_64.h | 33 ++++
> arch/powerpc/include/asm/kvm_book3s_asm.h | 3 +
> arch/powerpc/include/asm/kvm_host.h | 5 +
> arch/powerpc/kvm/Makefile | 3 +-
> arch/powerpc/kvm/book3s_hv.c | 31 ++-
> arch/powerpc/kvm/book3s_hv_nested.c | 301 ++++++++++++++++++++++++++++++
> 8 files changed, 384 insertions(+), 7 deletions(-)
> create mode 100644 arch/powerpc/kvm/book3s_hv_nested.c
>
> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
> index a0b17f9..c95c651 100644
> --- a/arch/powerpc/include/asm/hvcall.h
> +++ b/arch/powerpc/include/asm/hvcall.h
> @@ -322,6 +322,11 @@
> #define H_GET_24X7_DATA 0xF07C
> #define H_GET_PERF_COUNTER_INFO 0xF080
>
> +/* Platform-specific hcalls used for nested HV KVM */
> +#define H_SET_PARTITION_TABLE 0xF800
> +#define H_ENTER_NESTED 0xF804
> +#define H_TLB_INVALIDATE 0xF808
> +
> /* Values for 2nd argument to H_SET_MODE */
> #define H_SET_MODE_RESOURCE_SET_CIABR 1
> #define H_SET_MODE_RESOURCE_SET_DAWR 2
> diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
> index 91c9779..43f212e 100644
> --- a/arch/powerpc/include/asm/kvm_book3s.h
> +++ b/arch/powerpc/include/asm/kvm_book3s.h
> @@ -274,6 +274,13 @@ static inline void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu) {}
> static inline void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu) {}
> #endif
>
> +long kvmhv_nested_init(void);
> +void kvmhv_nested_exit(void);
> +void kvmhv_vm_nested_init(struct kvm *kvm);
> +long kvmhv_set_partition_table(struct kvm_vcpu *vcpu);
> +void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1);
> +void kvmhv_release_all_nested(struct kvm *kvm);
> +
> void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac);
>
> extern int kvm_irq_bypass;
> @@ -387,9 +394,6 @@ extern int kvmppc_h_logical_ci_store(struct kvm_vcpu *vcpu);
> /* TO = 31 for unconditional trap */
> #define INS_TW 0x7fe00008
>
> -/* LPIDs we support with this build -- runtime limit may be lower */
> -#define KVMPPC_NR_LPIDS (LPID_RSVD + 1)
> -
> #define SPLIT_HACK_MASK 0xff000000
> #define SPLIT_HACK_OFFS 0xfb000000
>
> diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
> index 5c0e2d9..6d67b6a 100644
> --- a/arch/powerpc/include/asm/kvm_book3s_64.h
> +++ b/arch/powerpc/include/asm/kvm_book3s_64.h
> @@ -23,6 +23,39 @@
> #include <linux/string.h>
> #include <asm/bitops.h>
> #include <asm/book3s/64/mmu-hash.h>
> +#include <asm/cpu_has_feature.h>
> +
> +#ifdef CONFIG_PPC_PSERIES
> +static inline bool kvmhv_on_pseries(void)
> +{
> + return !cpu_has_feature(CPU_FTR_HVMODE);
> +}
> +#else
> +static inline bool kvmhv_on_pseries(void)
> +{
> + return false;
> +}
> +#endif
> +
> +/*
> + * Structure for a nested guest, that is, for a guest that is managed by
> + * one of our guests.
> + */
> +struct kvm_nested_guest {
> + struct kvm *l1_host; /* L1 VM that owns this nested guest */
> + int l1_lpid; /* lpid L1 guest thinks this guest is */
> + int shadow_lpid; /* real lpid of this nested guest */
> + pgd_t *shadow_pgtable; /* our page table for this guest */
> + u64 l1_gr_to_hr; /* L1's addr of part'n-scoped table */
> + u64 process_table; /* process table entry for this guest */
> + long refcnt; /* number of pointers to this struct */
> + struct mutex tlb_lock; /* serialize page faults and tlbies */
> + struct kvm_nested_guest *next;
> +};
> +
> +struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid,
> + bool create);
> +void kvmhv_put_nested(struct kvm_nested_guest *gp);
>
> /* Power architecture requires HPT is at least 256kiB, at most 64TiB */
> #define PPC_MIN_HPT_ORDER 18
> diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h
> index d978fdf..eb3ba63 100644
> --- a/arch/powerpc/include/asm/kvm_book3s_asm.h
> +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
> @@ -25,6 +25,9 @@
> #define XICS_MFRR 0xc
> #define XICS_IPI 2 /* interrupt source # for IPIs */
>
> +/* LPIDs we support with this build -- runtime limit may be lower */
> +#define KVMPPC_NR_LPIDS (LPID_RSVD + 1)
> +
> /* Maximum number of threads per physical core */
> #define MAX_SMT_THREADS 8
>
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index c9cc42f..c35d4f2 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -46,6 +46,7 @@
> #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
> #include <asm/kvm_book3s_asm.h> /* for MAX_SMT_THREADS */
> #define KVM_MAX_VCPU_ID (MAX_SMT_THREADS * KVM_MAX_VCORES)
> +#define KVM_MAX_NESTED_GUESTS KVMPPC_NR_LPIDS
>
> #else
> #define KVM_MAX_VCPU_ID KVM_MAX_VCPUS
> @@ -287,6 +288,7 @@ struct kvm_arch {
> u8 radix;
> u8 fwnmi_enabled;
> bool threads_indep;
> + bool nested_enable;
> pgd_t *pgtable;
> u64 process_table;
> struct dentry *debugfs_dir;
> @@ -312,6 +314,9 @@ struct kvm_arch {
> #endif
> struct kvmppc_ops *kvm_ops;
> #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
> + u64 l1_ptcr;
> + int max_nested_lpid;
> + struct kvm_nested_guest *nested_guests[KVM_MAX_NESTED_GUESTS];
> /* This array can grow quite large, keep it at the end */
> struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
> #endif
> diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
> index f872c04..e814f40 100644
> --- a/arch/powerpc/kvm/Makefile
> +++ b/arch/powerpc/kvm/Makefile
> @@ -75,7 +75,8 @@ kvm-hv-y += \
> book3s_hv.o \
> book3s_hv_interrupts.o \
> book3s_64_mmu_hv.o \
> - book3s_64_mmu_radix.o
> + book3s_64_mmu_radix.o \
> + book3s_hv_nested.o
>
> kvm-hv-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
> book3s_hv_tm.o
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 8425d72..4c72f2f 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -934,6 +934,19 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
> if (ret == H_TOO_HARD)
> return RESUME_HOST;
> break;
> +
> + case H_SET_PARTITION_TABLE:
> + ret = H_FUNCTION;
> + if (vcpu->kvm->arch.nested_enable)
> + ret = kvmhv_set_partition_table(vcpu);
> + break;
> + case H_ENTER_NESTED:
> + ret = H_FUNCTION;
> + break;
> + case H_TLB_INVALIDATE:
> + ret = H_FUNCTION;
> + break;
> +
> default:
> return RESUME_HOST;
> }
> @@ -4153,8 +4166,7 @@ void kvmppc_setup_partition_table(struct kvm *kvm)
> __pa(kvm->arch.pgtable) | RADIX_PGD_INDEX_SIZE;
> dw1 = PATB_GR | kvm->arch.process_table;
> }
> -
> - mmu_partition_table_set_entry(kvm->arch.lpid, dw0, dw1);
> + kvmhv_set_ptbl_entry(kvm->arch.lpid, dw0, dw1);
> }
>
> /*
> @@ -4250,6 +4262,10 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
> /* Must be called with kvm->lock held and mmu_ready = 0 and no vcpus running */
> int kvmppc_switch_mmu_to_hpt(struct kvm *kvm)
> {
> + if (kvm->arch.nested_enable) {
> + kvm->arch.nested_enable = false;
> + kvmhv_release_all_nested(kvm);
> + }
> kvmppc_free_radix(kvm);
> kvmppc_update_lpcr(kvm, LPCR_VPM1,
> LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR);
> @@ -4370,6 +4386,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
>
> kvmppc_alloc_host_rm_ops();
>
> + kvmhv_vm_nested_init(kvm);
> +
> /*
> * Since we don't flush the TLB when tearing down a VM,
> * and this lpid might have previously been used,
> @@ -4513,8 +4531,10 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
>
> /* Perform global invalidation and return lpid to the pool */
> if (cpu_has_feature(CPU_FTR_ARCH_300)) {
> + if (kvm->arch.nested_enable)
> + kvmhv_release_all_nested(kvm);
> kvm->arch.process_table = 0;
> - kvmppc_setup_partition_table(kvm);
> + kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
> }
> kvmppc_free_lpid(kvm->arch.lpid);
>
> @@ -4985,6 +5005,10 @@ static int kvmppc_book3s_init_hv(void)
> if (r < 0)
> return -ENODEV;
>
> + r = kvmhv_nested_init();
> + if (r)
> + return r;
> +
> r = kvm_init_subcore_bitmap();
> if (r)
> return r;
> @@ -5043,6 +5067,7 @@ static void kvmppc_book3s_exit_hv(void)
> if (kvmppc_radix_possible())
> kvmppc_radix_exit();
> kvmppc_hv_ops = NULL;
> + kvmhv_nested_exit();
> }
>
> module_init(kvmppc_book3s_init_hv);
> diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c
> new file mode 100644
> index 0000000..32782624
> --- /dev/null
> +++ b/arch/powerpc/kvm/book3s_hv_nested.c
> @@ -0,0 +1,301 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright IBM Corporation, 2018
> + * Authors Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> + * Paul Mackerras <paulus@ozlabs.org>
> + *
> + * Description: KVM functions specific to running nested KVM-HV guests
> + * on Book3S processors (specifically POWER9 and later).
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/kvm_host.h>
> +
> +#include <asm/kvm_ppc.h>
> +#include <asm/mmu.h>
> +#include <asm/pgtable.h>
> +#include <asm/pgalloc.h>
> +
> +static struct patb_entry *pseries_partition_tb;
> +
> +static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp);
> +
> +long kvmhv_nested_init(void)
> +{
> + long int ptb_order;
> + unsigned long ptcr;
> + long rc;
> +
> + if (!kvmhv_on_pseries())
> + return 0;
> + if (!radix_enabled())
> + return -ENODEV;
> +
> + /* find log base 2 of KVMPPC_NR_LPIDS, rounding up */
> + ptb_order = __ilog2(KVMPPC_NR_LPIDS - 1) + 1;
> + if (ptb_order < 8)
> + ptb_order = 8;
> + pseries_partition_tb = kmalloc(sizeof(struct patb_entry) << ptb_order,
> + GFP_KERNEL);
> + if (!pseries_partition_tb) {
> + pr_err("kvm-hv: failed to allocated nested partition table\n");
> + return -ENOMEM;
> + }
> +
> + ptcr = __pa(pseries_partition_tb) | (ptb_order - 8);
> + rc = plpar_hcall_norets(H_SET_PARTITION_TABLE, ptcr);
> + if (rc != H_SUCCESS) {
> + pr_err("kvm-hv: Parent hypervisor does not support nesting (rc=%ld)\n",
> + rc);
> + kfree(pseries_partition_tb);
> + pseries_partition_tb = NULL;
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +void kvmhv_nested_exit(void)
> +{
> + /*
> + * N.B. the kvmhv_on_pseries() test is there because it enables
> + * the compiler to remove the call to plpar_hcall_norets()
> + * when CONFIG_PPC_PSERIES=n.
> + */
> + if (kvmhv_on_pseries() && pseries_partition_tb) {
> + plpar_hcall_norets(H_SET_PARTITION_TABLE, 0);
> + kfree(pseries_partition_tb);
> + pseries_partition_tb = NULL;
> + }
> +}
> +
> +void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1)
> +{
> + if (cpu_has_feature(CPU_FTR_HVMODE)) {
> + mmu_partition_table_set_entry(lpid, dw0, dw1);
> + } else {
> + pseries_partition_tb[lpid].patb0 = cpu_to_be64(dw0);
> + pseries_partition_tb[lpid].patb1 = cpu_to_be64(dw1);
To double check my understanding: we don't need any locking on pseries
on pseries_partition_tb, because the allocation of lpids is properly
synchronized, so we assume that code which knows about an lpid "owns"
that slot in the table. Is that right?
> + }
> +}
> +
> +static void kvmhv_set_nested_ptbl(struct kvm_nested_guest *gp)
> +{
> + unsigned long dw0;
> +
> + dw0 = PATB_HR | radix__get_tree_size() |
> + __pa(gp->shadow_pgtable) | RADIX_PGD_INDEX_SIZE;
> + kvmhv_set_ptbl_entry(gp->shadow_lpid, dw0, gp->process_table);
> +}
> +
> +void kvmhv_vm_nested_init(struct kvm *kvm)
> +{
> + kvm->arch.max_nested_lpid = -1;
> +}
> +
> +/*
> + * Handle the H_SET_PARTITION_TABLE hcall.
> + * r4 = guest real address of partition table + log_2(size) - 12
> + * (formatted as for the PTCR).
> + */
> +long kvmhv_set_partition_table(struct kvm_vcpu *vcpu)
> +{
> + struct kvm *kvm = vcpu->kvm;
> + unsigned long ptcr = kvmppc_get_gpr(vcpu, 4);
> + int srcu_idx;
> + long ret = H_SUCCESS;
> +
> + srcu_idx = srcu_read_lock(&kvm->srcu);
> + /*
> + * Limit the partition table to 4096 entries (because that's what
> + * hardware supports), and check the base address.
> + */
> + if ((ptcr & PRTS_MASK) > 12 - 8 ||
> + !kvm_is_visible_gfn(vcpu->kvm, (ptcr & PRTB_MASK) >> PAGE_SHIFT))
> + ret = H_PARAMETER;
Note there's a subtle dependency on 64k page size here, since you only
validate the table's base address.
> + srcu_read_unlock(&kvm->srcu, srcu_idx);
> + if (ret == H_SUCCESS)
> + kvm->arch.l1_ptcr = ptcr;
> + return ret;
> +}
> +
> +/*
> + * Reload the partition table entry for a guest.
> + * Caller must hold gp->tlb_lock.
> + */
> +static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp)
> +{
> + int ret;
> + struct patb_entry ptbl_entry;
> + unsigned long ptbl_addr;
> + struct kvm *kvm = gp->l1_host;
> +
> + ret = -EFAULT;
> + ptbl_addr = (kvm->arch.l1_ptcr & PRTB_MASK) + (gp->l1_lpid << 4);
> + if (gp->l1_lpid < (1ul << ((kvm->arch.l1_ptcr & PRTS_MASK) + 8)))
> + ret = kvm_read_guest(kvm, ptbl_addr,
> + &ptbl_entry, sizeof(ptbl_entry));
> + if (ret) {
> + gp->l1_gr_to_hr = 0;
> + gp->process_table = 0;
> + } else {
> + gp->l1_gr_to_hr = be64_to_cpu(ptbl_entry.patb0);
> + gp->process_table = be64_to_cpu(ptbl_entry.patb1);
> + }
> + kvmhv_set_nested_ptbl(gp);
> +}
> +
> +struct kvm_nested_guest *kvmhv_alloc_nested(struct kvm *kvm, unsigned int lpid)
> +{
> + struct kvm_nested_guest *gp;
> + long shadow_lpid;
> +
> + gp = kzalloc(sizeof(*gp), GFP_KERNEL);
> + if (!gp)
> + return NULL;
> + gp->l1_host = kvm;
> + gp->l1_lpid = lpid;
> + mutex_init(&gp->tlb_lock);
> + gp->shadow_pgtable = pgd_alloc(kvm->mm);
> + if (!gp->shadow_pgtable)
> + goto out_free;
> + shadow_lpid = kvmppc_alloc_lpid();
> + if (shadow_lpid < 0)
> + goto out_free2;
> + gp->shadow_lpid = shadow_lpid;
> +
> + return gp;
> +
> + out_free2:
> + pgd_free(kvm->mm, gp->shadow_pgtable);
> + out_free:
> + kfree(gp);
> + return NULL;
> +}
> +
> +/*
> + * Free up any resources allocated for a nested guest.
> + */
> +static void kvmhv_release_nested(struct kvm_nested_guest *gp)
> +{
> + kvmhv_set_ptbl_entry(gp->shadow_lpid, 0, 0);
> + kvmppc_free_lpid(gp->shadow_lpid);
> + if (gp->shadow_pgtable)
> + pgd_free(gp->l1_host->mm, gp->shadow_pgtable);
> + kfree(gp);
> +}
> +
> +static void kvmhv_remove_nested(struct kvm_nested_guest *gp)
> +{
> + struct kvm *kvm = gp->l1_host;
> + int lpid = gp->l1_lpid;
> + long ref;
> +
> + spin_lock(&kvm->mmu_lock);
> + if (gp == kvm->arch.nested_guests[lpid]) {
> + kvm->arch.nested_guests[lpid] = NULL;
> + if (lpid == kvm->arch.max_nested_lpid) {
> + while (--lpid >= 0 && !kvm->arch.nested_guests[lpid])
> + ;
> + kvm->arch.max_nested_lpid = lpid;
> + }
> + --gp->refcnt;
> + }
> + ref = gp->refcnt;
> + spin_unlock(&kvm->mmu_lock);
> + if (ref == 0)
> + kvmhv_release_nested(gp);
> +}
> +
> +/*
> + * Free up all nested resources allocated for this guest.
> + * This is called with no vcpus of the guest running, when
> + * switching the guest to HPT mode or when destroying the
> + * guest.
> + */
> +void kvmhv_release_all_nested(struct kvm *kvm)
> +{
> + int i;
> + struct kvm_nested_guest *gp;
> + struct kvm_nested_guest *freelist = NULL;
> +
> + spin_lock(&kvm->mmu_lock);
> + for (i = 0; i <= kvm->arch.max_nested_lpid; i++) {
> + gp = kvm->arch.nested_guests[i];
> + if (!gp)
> + continue;
> + kvm->arch.nested_guests[i] = NULL;
> + if (--gp->refcnt == 0) {
> + gp->next = freelist;
> + freelist = gp;
> + }
> + }
> + kvm->arch.max_nested_lpid = -1;
> + spin_unlock(&kvm->mmu_lock);
> + while ((gp = freelist) != NULL) {
> + freelist = gp->next;
> + kvmhv_release_nested(gp);
> + }
> +}
> +
> +/* caller must hold gp->tlb_lock */
> +void kvmhv_flush_nested(struct kvm_nested_guest *gp)
> +{
> + kvmhv_update_ptbl_cache(gp);
> + if (gp->l1_gr_to_hr == 0)
> + kvmhv_remove_nested(gp);
> +}
> +
> +struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid,
> + bool create)
> +{
> + struct kvm_nested_guest *gp, *newgp;
> +
> + if (l1_lpid >= KVM_MAX_NESTED_GUESTS ||
> + l1_lpid >= (1ul << ((kvm->arch.l1_ptcr & PRTS_MASK) + 12 - 4)))
> + return NULL;
> +
> + spin_lock(&kvm->mmu_lock);
> + gp = kvm->arch.nested_guests[l1_lpid];
> + if (gp)
> + ++gp->refcnt;
> + spin_unlock(&kvm->mmu_lock);
> +
> + if (gp || !create)
> + return gp;
> +
> + newgp = kvmhv_alloc_nested(kvm, l1_lpid);
> + if (!newgp)
> + return NULL;
> + spin_lock(&kvm->mmu_lock);
> + if (kvm->arch.nested_guests[l1_lpid]) {
> + /* someone else beat us to it */
> + gp = kvm->arch.nested_guests[l1_lpid];
> + } else {
> + kvm->arch.nested_guests[l1_lpid] = newgp;
> + ++newgp->refcnt;
> + gp = newgp;
> + newgp = NULL;
> + if (l1_lpid > kvm->arch.max_nested_lpid)
> + kvm->arch.max_nested_lpid = l1_lpid;
> + }
> + ++gp->refcnt;
> + spin_unlock(&kvm->mmu_lock);
> +
> + if (newgp)
> + kvmhv_release_nested(newgp);
> +
> + return gp;
> +}
> +
> +void kvmhv_put_nested(struct kvm_nested_guest *gp)
> +{
> + struct kvm *kvm = gp->l1_host;
> + long ref;
> +
> + spin_lock(&kvm->mmu_lock);
> + ref = --gp->refcnt;
> + spin_unlock(&kvm->mmu_lock);
> + if (ref == 0)
> + kvmhv_release_nested(gp);
> +}
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v5 22/33] KVM: PPC: Book3S HV: Introduce rmap to track nested guest mappings
From: David Gibson @ 2018-10-09 0:26 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-23-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 18756 bytes --]
On Mon, Oct 08, 2018 at 04:31:08PM +1100, Paul Mackerras wrote:
> From: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
>
> When a host (L0) page which is mapped into a (L1) guest is in turn
> mapped through to a nested (L2) guest we keep a reverse mapping (rmap)
> so that these mappings can be retrieved later.
>
> Whenever we create an entry in a shadow_pgtable for a nested guest we
> create a corresponding rmap entry and add it to the list for the
> L1 guest memslot at the index of the L1 guest page it maps. This means
> at the L1 guest memslot we end up with lists of rmaps.
>
> When we are notified of a host page being invalidated which has been
> mapped through to a (L1) guest, we can then walk the rmap list for that
> guest page, and find and invalidate all of the corresponding
> shadow_pgtable entries.
>
> In order to reduce memory consumption, we compress the information for
> each rmap entry down to 52 bits -- 12 bits for the LPID and 40 bits
> for the guest real page frame number -- which will fit in a single
> unsigned long. To avoid a scenario where a guest can trigger
> unbounded memory allocations, we scan the list when adding an entry to
> see if there is already an entry with the contents we need. This can
> occur, because we don't ever remove entries from the middle of a list.
>
> A struct nested guest rmap is a list pointer and an rmap entry;
> ----------------
> | next pointer |
> ----------------
> | rmap entry |
> ----------------
>
> Thus the rmap pointer for each guest frame number in the memslot can be
> either NULL, a single entry, or a pointer to a list of nested rmap entries.
>
> gfn memslot rmap array
> -------------------------
> 0 | NULL | (no rmap entry)
> -------------------------
> 1 | single rmap entry | (rmap entry with low bit set)
> -------------------------
> 2 | list head pointer | (list of rmap entries)
> -------------------------
>
> The final entry always has the lowest bit set and is stored in the next
> pointer of the last list entry, or as a single rmap entry.
> With a list of rmap entries looking like;
>
> ----------------- ----------------- -------------------------
> | list head ptr | ----> | next pointer | ----> | single rmap entry |
> ----------------- ----------------- -------------------------
> | rmap entry | | rmap entry |
> ----------------- -------------------------
>
> Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> arch/powerpc/include/asm/kvm_book3s.h | 3 +
> arch/powerpc/include/asm/kvm_book3s_64.h | 69 +++++++++++++++-
> arch/powerpc/kvm/book3s_64_mmu_radix.c | 44 +++++++---
> arch/powerpc/kvm/book3s_hv.c | 1 +
> arch/powerpc/kvm/book3s_hv_nested.c | 138 ++++++++++++++++++++++++++++++-
> 5 files changed, 240 insertions(+), 15 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
> index 63f7ccf..d7aeb6f 100644
> --- a/arch/powerpc/include/asm/kvm_book3s.h
> +++ b/arch/powerpc/include/asm/kvm_book3s.h
> @@ -196,6 +196,9 @@ extern int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr,
> int table_index, u64 *pte_ret_p);
> extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
> struct kvmppc_pte *gpte, bool data, bool iswrite);
> +extern void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa,
> + unsigned int shift, struct kvm_memory_slot *memslot,
> + unsigned int lpid);
> extern bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable,
> bool writing, unsigned long gpa,
> unsigned int lpid);
> diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
> index 5496152..c2a9146 100644
> --- a/arch/powerpc/include/asm/kvm_book3s_64.h
> +++ b/arch/powerpc/include/asm/kvm_book3s_64.h
> @@ -53,6 +53,66 @@ struct kvm_nested_guest {
> struct kvm_nested_guest *next;
> };
>
> +/*
> + * We define a nested rmap entry as a single 64-bit quantity
> + * 0xFFF0000000000000 12-bit lpid field
> + * 0x000FFFFFFFFFF000 40-bit guest 4k page frame number
> + * 0x0000000000000001 1-bit single entry flag
> + */
> +#define RMAP_NESTED_LPID_MASK 0xFFF0000000000000UL
> +#define RMAP_NESTED_LPID_SHIFT (52)
> +#define RMAP_NESTED_GPA_MASK 0x000FFFFFFFFFF000UL
> +#define RMAP_NESTED_IS_SINGLE_ENTRY 0x0000000000000001UL
> +
> +/* Structure for a nested guest rmap entry */
> +struct rmap_nested {
> + struct llist_node list;
> + u64 rmap;
> +};
> +
> +/*
> + * for_each_nest_rmap_safe - iterate over the list of nested rmap entries
> + * safe against removal of the list entry or NULL list
> + * @pos: a (struct rmap_nested *) to use as a loop cursor
> + * @node: pointer to the first entry
> + * NOTE: this can be NULL
> + * @rmapp: an (unsigned long *) in which to return the rmap entries on each
> + * iteration
> + * NOTE: this must point to already allocated memory
> + *
> + * The nested_rmap is a llist of (struct rmap_nested) entries pointed to by the
> + * rmap entry in the memslot. The list is always terminated by a "single entry"
> + * stored in the list element of the final entry of the llist. If there is ONLY
> + * a single entry then this is itself in the rmap entry of the memslot, not a
> + * llist head pointer.
> + *
> + * Note that the iterator below assumes that a nested rmap entry is always
> + * non-zero. This is true for our usage because the LPID field is always
> + * non-zero (zero is reserved for the host).
> + *
> + * This should be used to iterate over the list of rmap_nested entries with
> + * processing done on the u64 rmap value given by each iteration. This is safe
> + * against removal of list entries and it is always safe to call free on (pos).
> + *
> + * e.g.
> + * struct rmap_nested *cursor;
> + * struct llist_node *first;
> + * unsigned long rmap;
> + * for_each_nest_rmap_safe(cursor, first, &rmap) {
> + * do_something(rmap);
> + * free(cursor);
> + * }
> + */
> +#define for_each_nest_rmap_safe(pos, node, rmapp) \
> + for ((pos) = llist_entry((node), typeof(*(pos)), list); \
> + (node) && \
> + (*(rmapp) = ((RMAP_NESTED_IS_SINGLE_ENTRY & ((u64) (node))) ? \
> + ((u64) (node)) : ((pos)->rmap))) && \
> + (((node) = ((RMAP_NESTED_IS_SINGLE_ENTRY & ((u64) (node))) ? \
> + ((struct llist_node *) ((pos) = NULL)) : \
> + (pos)->list.next)), true); \
> + (pos) = llist_entry((node), typeof(*(pos)), list))
> +
> struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid,
> bool create);
> void kvmhv_put_nested(struct kvm_nested_guest *gp);
> @@ -551,7 +611,14 @@ static inline void copy_to_checkpoint(struct kvm_vcpu *vcpu)
>
> extern int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
> unsigned long gpa, unsigned int level,
> - unsigned long mmu_seq, unsigned int lpid);
> + unsigned long mmu_seq, unsigned int lpid,
> + unsigned long *rmapp, struct rmap_nested **n_rmap);
> +extern void kvmhv_insert_nest_rmap(struct kvm *kvm, unsigned long *rmapp,
> + struct rmap_nested **n_rmap);
> +extern void kvmhv_remove_nest_rmap_range(struct kvm *kvm,
> + struct kvm_memory_slot *memslot,
> + unsigned long gpa, unsigned long hpa,
> + unsigned long nbytes);
>
> #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
>
> diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
> index c4b1a9e..4c1eccb 100644
> --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
> +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
> @@ -256,27 +256,38 @@ static void kvmppc_pmd_free(pmd_t *pmdp)
> kmem_cache_free(kvm_pmd_cache, pmdp);
> }
>
> -void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte,
> - unsigned long gpa, unsigned int shift,
> - struct kvm_memory_slot *memslot,
> +/* Called with kvm->mmu_lock held */
> +void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa,
> + unsigned int shift, struct kvm_memory_slot *memslot,
> unsigned int lpid)
>
> {
> unsigned long old;
> + unsigned long gfn = gpa >> PAGE_SHIFT;
> + unsigned long page_size = PAGE_SIZE;
> + unsigned long hpa;
>
> old = kvmppc_radix_update_pte(kvm, pte, ~0UL, 0, gpa, shift);
> kvmppc_radix_tlbie_page(kvm, gpa, shift, lpid);
> - if ((old & _PAGE_DIRTY) && (lpid == kvm->arch.lpid)) {
> - unsigned long gfn = gpa >> PAGE_SHIFT;
> - unsigned long page_size = PAGE_SIZE;
>
> - if (shift)
> - page_size = 1ul << shift;
> + /* The following only applies to L1 entries */
> + if (lpid != kvm->arch.lpid)
> + return;
> +
> + if (!memslot) {
> + memslot = gfn_to_memslot(kvm, gfn);
> if (!memslot)
> - memslot = gfn_to_memslot(kvm, gfn);
> - if (memslot && memslot->dirty_bitmap)
> - kvmppc_update_dirty_map(memslot, gfn, page_size);
> + return;
> }
> + if (shift)
> + page_size = 1ul << shift;
> +
> + gpa &= ~(page_size - 1);
> + hpa = old & PTE_RPN_MASK;
> + kvmhv_remove_nest_rmap_range(kvm, memslot, gpa, hpa, page_size);
> +
> + if ((old & _PAGE_DIRTY) && memslot->dirty_bitmap)
> + kvmppc_update_dirty_map(memslot, gfn, page_size);
> }
>
> /*
> @@ -430,7 +441,8 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud,
>
> int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
> unsigned long gpa, unsigned int level,
> - unsigned long mmu_seq, unsigned int lpid)
> + unsigned long mmu_seq, unsigned int lpid,
> + unsigned long *rmapp, struct rmap_nested **n_rmap)
> {
> pgd_t *pgd;
> pud_t *pud, *new_pud = NULL;
> @@ -509,6 +521,8 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
> kvmppc_unmap_free_pud_entry_table(kvm, pud, gpa, lpid);
> }
> kvmppc_radix_set_pte_at(kvm, gpa, (pte_t *)pud, pte);
> + if (rmapp && n_rmap)
> + kvmhv_insert_nest_rmap(kvm, rmapp, n_rmap);
> ret = 0;
> goto out_unlock;
> }
> @@ -559,6 +573,8 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
> kvmppc_unmap_free_pmd_entry_table(kvm, pmd, gpa, lpid);
> }
> kvmppc_radix_set_pte_at(kvm, gpa, pmdp_ptep(pmd), pte);
> + if (rmapp && n_rmap)
> + kvmhv_insert_nest_rmap(kvm, rmapp, n_rmap);
> ret = 0;
> goto out_unlock;
> }
> @@ -583,6 +599,8 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
> goto out_unlock;
> }
> kvmppc_radix_set_pte_at(kvm, gpa, ptep, pte);
> + if (rmapp && n_rmap)
> + kvmhv_insert_nest_rmap(kvm, rmapp, n_rmap);
> ret = 0;
>
> out_unlock:
> @@ -710,7 +728,7 @@ int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu,
>
> /* Allocate space in the tree and write the PTE */
> ret = kvmppc_create_pte(kvm, kvm->arch.pgtable, pte, gpa, level,
> - mmu_seq, kvm->arch.lpid);
> + mmu_seq, kvm->arch.lpid, NULL, NULL);
> if (inserted_pte)
> *inserted_pte = pte;
> if (levelp)
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index dc25461..cb9e738 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -4482,6 +4482,7 @@ int kvmppc_switch_mmu_to_radix(struct kvm *kvm)
> kvmppc_free_hpt(&kvm->arch.hpt);
> kvmppc_update_lpcr(kvm, LPCR_UPRT | LPCR_GTSE | LPCR_HR,
> LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR);
> + kvmppc_rmap_reset(kvm);
> kvm->arch.radix = 1;
> return 0;
> }
> diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c
> index 21a210c..3fa676b 100644
> --- a/arch/powerpc/kvm/book3s_hv_nested.c
> +++ b/arch/powerpc/kvm/book3s_hv_nested.c
> @@ -10,6 +10,7 @@
>
> #include <linux/kernel.h>
> #include <linux/kvm_host.h>
> +#include <linux/llist.h>
>
> #include <asm/kvm_ppc.h>
> #include <asm/kvm_book3s.h>
> @@ -22,6 +23,7 @@
> static struct patb_entry *pseries_partition_tb;
>
> static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp);
> +static void kvmhv_free_memslot_nest_rmap(struct kvm_memory_slot *free);
>
> void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr)
> {
> @@ -456,6 +458,8 @@ void kvmhv_release_all_nested(struct kvm *kvm)
> int i;
> struct kvm_nested_guest *gp;
> struct kvm_nested_guest *freelist = NULL;
> + struct kvm_memory_slot *memslot;
> + int srcu_idx;
>
> spin_lock(&kvm->mmu_lock);
> for (i = 0; i <= kvm->arch.max_nested_lpid; i++) {
> @@ -474,6 +478,11 @@ void kvmhv_release_all_nested(struct kvm *kvm)
> freelist = gp->next;
> kvmhv_release_nested(gp);
> }
> +
> + srcu_idx = srcu_read_lock(&kvm->srcu);
> + kvm_for_each_memslot(memslot, kvm_memslots(kvm))
> + kvmhv_free_memslot_nest_rmap(memslot);
> + srcu_read_unlock(&kvm->srcu, srcu_idx);
> }
>
> /* caller must hold gp->tlb_lock */
> @@ -544,6 +553,123 @@ void kvmhv_put_nested(struct kvm_nested_guest *gp)
> kvmhv_release_nested(gp);
> }
>
> +static struct kvm_nested_guest *kvmhv_find_nested(struct kvm *kvm, int lpid)
> +{
> + if (lpid > kvm->arch.max_nested_lpid)
> + return NULL;
> + return kvm->arch.nested_guests[lpid];
> +}
> +
> +static inline bool kvmhv_n_rmap_is_equal(u64 rmap_1, u64 rmap_2)
> +{
> + return !((rmap_1 ^ rmap_2) & (RMAP_NESTED_LPID_MASK |
> + RMAP_NESTED_GPA_MASK));
> +}
> +
> +void kvmhv_insert_nest_rmap(struct kvm *kvm, unsigned long *rmapp,
> + struct rmap_nested **n_rmap)
> +{
> + struct llist_node *entry = ((struct llist_head *) rmapp)->first;
> + struct rmap_nested *cursor;
> + u64 rmap, new_rmap = (*n_rmap)->rmap;
> +
> + /* Are there any existing entries? */
> + if (!(*rmapp)) {
> + /* No -> use the rmap as a single entry */
> + *rmapp = new_rmap | RMAP_NESTED_IS_SINGLE_ENTRY;
> + return;
> + }
> +
> + /* Do any entries match what we're trying to insert? */
> + for_each_nest_rmap_safe(cursor, entry, &rmap) {
> + if (kvmhv_n_rmap_is_equal(rmap, new_rmap))
> + return;
> + }
> +
> + /* Do we need to create a list or just add the new entry? */
> + rmap = *rmapp;
> + if (rmap & RMAP_NESTED_IS_SINGLE_ENTRY) /* Not previously a list */
> + *rmapp = 0UL;
> + llist_add(&((*n_rmap)->list), (struct llist_head *) rmapp);
> + if (rmap & RMAP_NESTED_IS_SINGLE_ENTRY) /* Not previously a list */
> + (*n_rmap)->list.next = (struct llist_node *) rmap;
> +
> + /* Set NULL so not freed by caller */
> + *n_rmap = NULL;
> +}
> +
> +static void kvmhv_remove_nest_rmap(struct kvm *kvm, u64 n_rmap,
> + unsigned long hpa, unsigned long mask)
> +{
> + struct kvm_nested_guest *gp;
> + unsigned long gpa;
> + unsigned int shift, lpid;
> + pte_t *ptep;
> +
> + gpa = n_rmap & RMAP_NESTED_GPA_MASK;
> + lpid = (n_rmap & RMAP_NESTED_LPID_MASK) >> RMAP_NESTED_LPID_SHIFT;
> + gp = kvmhv_find_nested(kvm, lpid);
> + if (!gp)
> + return;
> +
> + /* Find and invalidate the pte */
> + ptep = __find_linux_pte(gp->shadow_pgtable, gpa, NULL, &shift);
> + /* Don't spuriously invalidate ptes if the pfn has changed */
> + if (ptep && pte_present(*ptep) && ((pte_val(*ptep) & mask) == hpa))
> + kvmppc_unmap_pte(kvm, ptep, gpa, shift, NULL, gp->shadow_lpid);
> +}
> +
> +static void kvmhv_remove_nest_rmap_list(struct kvm *kvm, unsigned long *rmapp,
> + unsigned long hpa, unsigned long mask)
> +{
> + struct llist_node *entry = llist_del_all((struct llist_head *) rmapp);
> + struct rmap_nested *cursor;
> + unsigned long rmap;
> +
> + for_each_nest_rmap_safe(cursor, entry, &rmap) {
> + kvmhv_remove_nest_rmap(kvm, rmap, hpa, mask);
> + kfree(cursor);
> + }
> +}
> +
> +/* called with kvm->mmu_lock held */
> +void kvmhv_remove_nest_rmap_range(struct kvm *kvm,
> + struct kvm_memory_slot *memslot,
> + unsigned long gpa, unsigned long hpa,
> + unsigned long nbytes)
> +{
> + unsigned long gfn, end_gfn;
> + unsigned long addr_mask;
> +
> + if (!memslot)
> + return;
> + gfn = (gpa >> PAGE_SHIFT) - memslot->base_gfn;
> + end_gfn = gfn + (nbytes >> PAGE_SHIFT);
> +
> + addr_mask = PTE_RPN_MASK & ~(nbytes - 1);
> + hpa &= addr_mask;
> +
> + for (; gfn < end_gfn; gfn++) {
> + unsigned long *rmap = &memslot->arch.rmap[gfn];
> + kvmhv_remove_nest_rmap_list(kvm, rmap, hpa, addr_mask);
> + }
> +}
> +
> +static void kvmhv_free_memslot_nest_rmap(struct kvm_memory_slot *free)
> +{
> + unsigned long page;
> +
> + for (page = 0; page < free->npages; page++) {
> + unsigned long rmap, *rmapp = &free->arch.rmap[page];
> + struct rmap_nested *cursor;
> + struct llist_node *entry;
> +
> + entry = llist_del_all((struct llist_head *) rmapp);
> + for_each_nest_rmap_safe(cursor, entry, &rmap)
> + kfree(cursor);
> + }
> +}
> +
> static bool kvmhv_invalidate_shadow_pte(struct kvm_vcpu *vcpu,
> struct kvm_nested_guest *gp,
> long gpa, int *shift_ret)
> @@ -695,11 +821,13 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu,
> {
> struct kvm *kvm = vcpu->kvm;
> struct kvm_memory_slot *memslot;
> + struct rmap_nested *n_rmap;
> struct kvmppc_pte gpte;
> pte_t pte, *pte_p;
> unsigned long mmu_seq;
> unsigned long dsisr = vcpu->arch.fault_dsisr;
> unsigned long ea = vcpu->arch.fault_dar;
> + unsigned long *rmapp;
> unsigned long n_gpa, gpa, gfn, perm = 0UL;
> unsigned int shift, l1_shift, level;
> bool writing = !!(dsisr & DSISR_ISSTORE);
> @@ -833,8 +961,16 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu,
>
> /* 4. Insert the pte into our shadow_pgtable */
>
> + n_rmap = kzalloc(sizeof(*n_rmap), GFP_KERNEL);
> + if (!n_rmap)
> + return RESUME_GUEST; /* Let the guest try again */
> + n_rmap->rmap = (n_gpa & RMAP_NESTED_GPA_MASK) |
> + (((unsigned long) gp->l1_lpid) << RMAP_NESTED_LPID_SHIFT);
> + rmapp = &memslot->arch.rmap[gfn - memslot->base_gfn];
> ret = kvmppc_create_pte(kvm, gp->shadow_pgtable, pte, n_gpa, level,
> - mmu_seq, gp->shadow_lpid);
> + mmu_seq, gp->shadow_lpid, rmapp, &n_rmap);
> + if (n_rmap)
> + kfree(n_rmap);
> if (ret == -EAGAIN)
> ret = RESUME_GUEST; /* Let the guest try again */
>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v5 06/33] KVM: PPC: Book3S HV: Simplify real-mode interrupt handling
From: David Gibson @ 2018-10-09 0:05 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev, kvm-ppc, kvm
In-Reply-To: <1538976679-1363-7-git-send-email-paulus@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 12008 bytes --]
On Mon, Oct 08, 2018 at 04:30:52PM +1100, Paul Mackerras wrote:
> This streamlines the first part of the code that handles a hypervisor
> interrupt that occurred in the guest. With this, all of the real-mode
> handling that occurs is done before the "guest_exit_cont" label; once
> we get to that label we are committed to exiting to host virtual mode.
> Thus the machine check and HMI real-mode handling is moved before that
> label.
>
> Also, the code to handle external interrupts is moved out of line, as
> is the code that calls kvmppc_realmode_hmi_handler().
>
> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> arch/powerpc/kvm/book3s_hv_ras.c | 8 ++
> arch/powerpc/kvm/book3s_hv_rmhandlers.S | 220 ++++++++++++++++----------------
> 2 files changed, 119 insertions(+), 109 deletions(-)
>
> diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c
> index b11043b..ee564b6 100644
> --- a/arch/powerpc/kvm/book3s_hv_ras.c
> +++ b/arch/powerpc/kvm/book3s_hv_ras.c
> @@ -331,5 +331,13 @@ long kvmppc_realmode_hmi_handler(void)
> } else {
> wait_for_tb_resync();
> }
> +
> + /*
> + * Reset tb_offset_applied so the guest exit code won't try
> + * to subtract the previous timebase offset from the timebase.
> + */
> + if (local_paca->kvm_hstate.kvm_vcore)
> + local_paca->kvm_hstate.kvm_vcore->tb_offset_applied = 0;
> +
> return 0;
> }
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index 5b2ae34..fc360b5 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -1018,8 +1018,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
> no_xive:
> #endif /* CONFIG_KVM_XICS */
>
> -deliver_guest_interrupt:
> -kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
> +deliver_guest_interrupt: /* r4 = vcpu, r13 = paca */
> /* Check if we can deliver an external or decrementer interrupt now */
> ld r0, VCPU_PENDING_EXC(r4)
> BEGIN_FTR_SECTION
> @@ -1269,18 +1268,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
> std r3, VCPU_CTR(r9)
> std r4, VCPU_XER(r9)
>
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> - /* For softpatch interrupt, go off and do TM instruction emulation */
> - cmpwi r12, BOOK3S_INTERRUPT_HV_SOFTPATCH
> - beq kvmppc_tm_emul
> -#endif
> + /* Save more register state */
> + mfdar r3
> + mfdsisr r4
> + std r3, VCPU_DAR(r9)
> + stw r4, VCPU_DSISR(r9)
>
> /* If this is a page table miss then see if it's theirs or ours */
> cmpwi r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
> beq kvmppc_hdsi
> + std r3, VCPU_FAULT_DAR(r9)
> + stw r4, VCPU_FAULT_DSISR(r9)
> cmpwi r12, BOOK3S_INTERRUPT_H_INST_STORAGE
> beq kvmppc_hisi
>
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> + /* For softpatch interrupt, go off and do TM instruction emulation */
> + cmpwi r12, BOOK3S_INTERRUPT_HV_SOFTPATCH
> + beq kvmppc_tm_emul
> +#endif
> +
> /* See if this is a leftover HDEC interrupt */
> cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER
> bne 2f
> @@ -1303,7 +1310,7 @@ BEGIN_FTR_SECTION
> END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> lbz r0, HSTATE_HOST_IPI(r13)
> cmpwi r0, 0
> - beq 4f
> + beq maybe_reenter_guest
> b guest_exit_cont
> 3:
> /* If it's a hypervisor facility unavailable interrupt, save HFSCR */
> @@ -1315,82 +1322,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> 14:
> /* External interrupt ? */
> cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL
> - bne+ guest_exit_cont
> -
> - /* External interrupt, first check for host_ipi. If this is
> - * set, we know the host wants us out so let's do it now
> - */
> - bl kvmppc_read_intr
> -
> - /*
> - * Restore the active volatile registers after returning from
> - * a C function.
> - */
> - ld r9, HSTATE_KVM_VCPU(r13)
> - li r12, BOOK3S_INTERRUPT_EXTERNAL
> -
> - /*
> - * kvmppc_read_intr return codes:
> - *
> - * Exit to host (r3 > 0)
> - * 1 An interrupt is pending that needs to be handled by the host
> - * Exit guest and return to host by branching to guest_exit_cont
> - *
> - * 2 Passthrough that needs completion in the host
> - * Exit guest and return to host by branching to guest_exit_cont
> - * However, we also set r12 to BOOK3S_INTERRUPT_HV_RM_HARD
> - * to indicate to the host to complete handling the interrupt
> - *
> - * Before returning to guest, we check if any CPU is heading out
> - * to the host and if so, we head out also. If no CPUs are heading
> - * check return values <= 0.
> - *
> - * Return to guest (r3 <= 0)
> - * 0 No external interrupt is pending
> - * -1 A guest wakeup IPI (which has now been cleared)
> - * In either case, we return to guest to deliver any pending
> - * guest interrupts.
> - *
> - * -2 A PCI passthrough external interrupt was handled
> - * (interrupt was delivered directly to guest)
> - * Return to guest to deliver any pending guest interrupts.
> - */
> -
> - cmpdi r3, 1
> - ble 1f
> -
> - /* Return code = 2 */
> - li r12, BOOK3S_INTERRUPT_HV_RM_HARD
> - stw r12, VCPU_TRAP(r9)
> - b guest_exit_cont
> -
> -1: /* Return code <= 1 */
> - cmpdi r3, 0
> - bgt guest_exit_cont
> -
> - /* Return code <= 0 */
> -4: ld r5, HSTATE_KVM_VCORE(r13)
> - lwz r0, VCORE_ENTRY_EXIT(r5)
> - cmpwi r0, 0x100
> - mr r4, r9
> - blt deliver_guest_interrupt
> -
> -guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
> - /* Save more register state */
> - mfdar r6
> - mfdsisr r7
> - std r6, VCPU_DAR(r9)
> - stw r7, VCPU_DSISR(r9)
> - /* don't overwrite fault_dar/fault_dsisr if HDSI */
> - cmpwi r12,BOOK3S_INTERRUPT_H_DATA_STORAGE
> - beq mc_cont
> - std r6, VCPU_FAULT_DAR(r9)
> - stw r7, VCPU_FAULT_DSISR(r9)
> -
> + beq kvmppc_guest_external
> /* See if it is a machine check */
> cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK
> beq machine_check_realmode
> -mc_cont:
> + /* Or a hypervisor maintenance interrupt */
> + cmpwi r12, BOOK3S_INTERRUPT_HMI
> + beq hmi_realmode
> +
> +guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
> +
> #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
> addi r3, r9, VCPU_TB_RMEXIT
> mr r4, r9
> @@ -1821,24 +1762,6 @@ BEGIN_FTR_SECTION
> mtspr SPRN_DPDES, r8
> END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
>
> - /* If HMI, call kvmppc_realmode_hmi_handler() */
> - lwz r12, STACK_SLOT_TRAP(r1)
> - cmpwi r12, BOOK3S_INTERRUPT_HMI
> - bne 27f
> - bl kvmppc_realmode_hmi_handler
> - nop
> - cmpdi r3, 0
> - /*
> - * At this point kvmppc_realmode_hmi_handler may have resync-ed
> - * the TB, and if it has, we must not subtract the guest timebase
> - * offset from the timebase. So, skip it.
> - *
> - * Also, do not call kvmppc_subcore_exit_guest() because it has
> - * been invoked as part of kvmppc_realmode_hmi_handler().
> - */
> - beq 30f
> -
> -27:
> /* Subtract timebase offset from timebase */
> ld r8, VCORE_TB_OFFSET_APPL(r5)
> cmpdi r8,0
> @@ -1856,7 +1779,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
> addis r8,r8,0x100 /* if so, increment upper 40 bits */
> mtspr SPRN_TBU40,r8
>
> -17: bl kvmppc_subcore_exit_guest
> +17:
> + /*
> + * If this is an HMI, we called kvmppc_realmode_hmi_handler
> + * above, which may or may not have already called
> + * kvmppc_subcore_exit_guest. Fortunately, all that
> + * kvmppc_subcore_exit_guest does is clear a flag, so calling
> + * it again here is benign even if kvmppc_realmode_hmi_handler
> + * has already called it.
> + */
> + bl kvmppc_subcore_exit_guest
> nop
> 30: ld r5,HSTATE_KVM_VCORE(r13)
> ld r4,VCORE_KVM(r5) /* pointer to struct kvm */
> @@ -1910,6 +1842,67 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
> mtlr r0
> blr
>
> +kvmppc_guest_external:
> + /* External interrupt, first check for host_ipi. If this is
> + * set, we know the host wants us out so let's do it now
> + */
> + bl kvmppc_read_intr
> +
> + /*
> + * Restore the active volatile registers after returning from
> + * a C function.
> + */
> + ld r9, HSTATE_KVM_VCPU(r13)
> + li r12, BOOK3S_INTERRUPT_EXTERNAL
> +
> + /*
> + * kvmppc_read_intr return codes:
> + *
> + * Exit to host (r3 > 0)
> + * 1 An interrupt is pending that needs to be handled by the host
> + * Exit guest and return to host by branching to guest_exit_cont
> + *
> + * 2 Passthrough that needs completion in the host
> + * Exit guest and return to host by branching to guest_exit_cont
> + * However, we also set r12 to BOOK3S_INTERRUPT_HV_RM_HARD
> + * to indicate to the host to complete handling the interrupt
> + *
> + * Before returning to guest, we check if any CPU is heading out
> + * to the host and if so, we head out also. If no CPUs are heading
> + * check return values <= 0.
> + *
> + * Return to guest (r3 <= 0)
> + * 0 No external interrupt is pending
> + * -1 A guest wakeup IPI (which has now been cleared)
> + * In either case, we return to guest to deliver any pending
> + * guest interrupts.
> + *
> + * -2 A PCI passthrough external interrupt was handled
> + * (interrupt was delivered directly to guest)
> + * Return to guest to deliver any pending guest interrupts.
> + */
> +
> + cmpdi r3, 1
> + ble 1f
> +
> + /* Return code = 2 */
> + li r12, BOOK3S_INTERRUPT_HV_RM_HARD
> + stw r12, VCPU_TRAP(r9)
> + b guest_exit_cont
> +
> +1: /* Return code <= 1 */
> + cmpdi r3, 0
> + bgt guest_exit_cont
> +
> + /* Return code <= 0 */
> +maybe_reenter_guest:
> + ld r5, HSTATE_KVM_VCORE(r13)
> + lwz r0, VCORE_ENTRY_EXIT(r5)
> + cmpwi r0, 0x100
> + mr r4, r9
> + blt deliver_guest_interrupt
> + b guest_exit_cont
> +
> #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> /*
> * Softpatch interrupt for transactional memory emulation cases
> @@ -2685,13 +2678,7 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
> mr r9, r4
> cmpdi r3, 0
> bgt guest_exit_cont
> -
> - /* see if any other thread is already exiting */
> - lwz r0,VCORE_ENTRY_EXIT(r5)
> - cmpwi r0,0x100
> - bge guest_exit_cont
> -
> - b kvmppc_cede_reentry /* if not go back to guest */
> + b maybe_reenter_guest
>
> /* cede when already previously prodded case */
> kvm_cede_prodded:
> @@ -2758,12 +2745,12 @@ machine_check_realmode:
> */
> ld r11, VCPU_MSR(r9)
> rldicl. r0, r11, 64-MSR_HV_LG, 63 /* check if it happened in HV mode */
> - bne mc_cont /* if so, exit to host */
> + bne guest_exit_cont /* if so, exit to host */
> /* Check if guest is capable of handling NMI exit */
> ld r10, VCPU_KVM(r9)
> lbz r10, KVM_FWNMI(r10)
> cmpdi r10, 1 /* FWNMI capable? */
> - beq mc_cont /* if so, exit with KVM_EXIT_NMI. */
> + beq guest_exit_cont /* if so, exit with KVM_EXIT_NMI. */
>
> /* if not, fall through for backward compatibility. */
> andi. r10, r11, MSR_RI /* check for unrecoverable exception */
> @@ -2777,6 +2764,21 @@ machine_check_realmode:
> 2: b fast_interrupt_c_return
>
> /*
> + * Call C code to handle a HMI in real mode.
> + * Only the primary thread does the call, secondary threads are handled
> + * by calling hmi_exception_realmode() after kvmppc_hv_entry returns.
> + * r9 points to the vcpu on entry
> + */
> +hmi_realmode:
> + lbz r0, HSTATE_PTID(r13)
> + cmpwi r0, 0
> + bne guest_exit_cont
> + bl kvmppc_realmode_hmi_handler
> + ld r9, HSTATE_KVM_VCPU(r13)
> + li r12, BOOK3S_INTERRUPT_HMI
> + b guest_exit_cont
> +
> +/*
> * Check the reason we woke from nap, and take appropriate action.
> * Returns (in r3):
> * 0 if nothing needs to be done
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] powerpc/xmon/ppc-opc: Use ARRAY_SIZE macro
From: Joe Perches @ 2018-10-09 2:27 UTC (permalink / raw)
To: Gustavo A. R. Silva, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20181004171036.GA1907@embeddedor.com>
On Thu, 2018-10-04 at 19:10 +0200, Gustavo A. R. Silva wrote:
> Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element.
[]
> diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c
[]
> @@ -966,8 +966,7 @@ const struct powerpc_operand powerpc_operands[] =
> { 0xff, 11, NULL, NULL, PPC_OPERAND_SIGNOPT },
> };
>
> -const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
> - / sizeof (powerpc_operands[0]));
> +const unsigned int num_powerpc_operands = ARRAY_SIZE(powerpc_operands);
It seems this is unused and could be deleted.
> /* The functions used to insert and extract complicated operands. */
>
> @@ -6980,8 +6979,7 @@ const struct powerpc_opcode powerpc_opcodes[] = {
> {"fcfidu.", XRC(63,974,1), XRA_MASK, POWER7|PPCA2, PPCVLE, {FRT, FRB}},
> };
>
> -const int powerpc_num_opcodes =
> - sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
> +const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes);
This is used once and should probably be replaced where
it is used with ARRAY_SIZE
> /* The VLE opcode table.
>
> @@ -7219,8 +7217,7 @@ const struct powerpc_opcode vle_opcodes[] = {
> {"se_bl", BD8(58,0,1), BD8_MASK, PPCVLE, 0, {B8}},
> };
>
> -const int vle_num_opcodes =
> - sizeof (vle_opcodes) / sizeof (vle_opcodes[0]);
> +const int vle_num_opcodes = ARRAY_SIZE(vle_opcodes);
Also apparently unused and could be deleted.
>
> /* The macro table. This is only used by the assembler. */
>
> @@ -7288,5 +7285,4 @@ const struct powerpc_macro powerpc_macros[] = {
> {"e_clrlslwi",4, PPCVLE, "e_rlwinm %0,%1,%3,(%2)-(%3),31-(%3)"},
> };
> ld
> -const int powerpc_num_macros =
> - sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
> +const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros);
Also apparently unused and could be deleted.
^ permalink raw reply
* Re: [PATCH] powerpc/xmon/ppc-opc: Use ARRAY_SIZE macro
From: Michael Ellerman @ 2018-10-09 3:43 UTC (permalink / raw)
To: Joe Perches, Gustavo A. R. Silva, Benjamin Herrenschmidt,
Paul Mackerras
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <8e2f906a85c3cfe0715982370a6d96f08a37987c.camel@perches.com>
Joe Perches <joe@perches.com> writes:
> On Thu, 2018-10-04 at 19:10 +0200, Gustavo A. R. Silva wrote:
>> Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element.
> []
>> diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c
> []
>> @@ -966,8 +966,7 @@ const struct powerpc_operand powerpc_operands[] =
>> { 0xff, 11, NULL, NULL, PPC_OPERAND_SIGNOPT },
>> };
>>
>> -const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
>> - / sizeof (powerpc_operands[0]));
>> +const unsigned int num_powerpc_operands = ARRAY_SIZE(powerpc_operands);
>
> It seems this is unused and could be deleted.
The code in this file is copied from binutils.
We don't want to needlessly diverge it.
I've said this before:
https://lore.kernel.org/linuxppc-dev/874lfxjnzl.fsf@concordia.ellerman.id.au/
Is there some way we can blacklist this file from checkpatch, Coccinelle
etc?
cheers
^ permalink raw reply
* Re: [PATCH v2 3/3] powerpc: machine check interrupt is a non-maskable interrupt
From: Nicholas Piggin @ 2018-10-09 4:32 UTC (permalink / raw)
To: Christophe LEROY; +Cc: Mahesh Jagannath Salgaonkar, linuxppc-dev
In-Reply-To: <30487984-752a-960d-6aae-6571c55c7ba5@c-s.fr>
On Mon, 8 Oct 2018 17:39:11 +0200
Christophe LEROY <christophe.leroy@c-s.fr> wrote:
> Hi Nick,
>
> Le 19/07/2017 à 08:59, Nicholas Piggin a écrit :
> > Use nmi_enter similarly to system reset interrupts. This uses NMI
> > printk NMI buffers and turns off various debugging facilities that
> > helps avoid tripping on ourselves or other CPUs.
> >
> > Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> > ---
> > arch/powerpc/kernel/traps.c | 9 ++++++---
> > 1 file changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> > index 2849c4f50324..6d31f9d7c333 100644
> > --- a/arch/powerpc/kernel/traps.c
> > +++ b/arch/powerpc/kernel/traps.c
> > @@ -789,8 +789,10 @@ int machine_check_generic(struct pt_regs *regs)
> >
> > void machine_check_exception(struct pt_regs *regs)
> > {
> > - enum ctx_state prev_state = exception_enter();
> > int recover = 0;
> > + bool nested = in_nmi();
> > + if (!nested)
> > + nmi_enter();
>
> This alters preempt_count, then when die() is called
> in_interrupt() returns true allthough the trap didn't happen in
> interrupt, so oops_end() panics for "fatal exception in interrupt"
> instead of gently sending SIGBUS the faulting app.
Thanks for tracking that down.
> Any idea on how to fix this ?
I would say we have to deliver the sigbus by hand.
if ((user_mode(regs)))
_exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
else
die("Machine check", regs, SIGBUS);
^ permalink raw reply
* Re: [PATCH] powerpc/xmon/ppc-opc: Use ARRAY_SIZE macro
From: Joe Perches @ 2018-10-09 4:38 UTC (permalink / raw)
To: Michael Ellerman, Gustavo A. R. Silva, Benjamin Herrenschmidt,
Paul Mackerras
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <874ldv3hty.fsf@concordia.ellerman.id.au>
On Tue, 2018-10-09 at 14:43 +1100, Michael Ellerman wrote:
> Joe Perches <joe@perches.com> writes:
>
> > On Thu, 2018-10-04 at 19:10 +0200, Gustavo A. R. Silva wrote:
> > > Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element.
> > []
> > > diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c
> > []
> > > @@ -966,8 +966,7 @@ const struct powerpc_operand powerpc_operands[] =
> > > { 0xff, 11, NULL, NULL, PPC_OPERAND_SIGNOPT },
> > > };
> > >
> > > -const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
> > > - / sizeof (powerpc_operands[0]));
> > > +const unsigned int num_powerpc_operands = ARRAY_SIZE(powerpc_operands);
> >
> > It seems this is unused and could be deleted.
>
> The code in this file is copied from binutils.
>
> We don't want to needlessly diverge it.
>
> I've said this before:
>
> https://lore.kernel.org/linuxppc-dev/874lfxjnzl.fsf@concordia.ellerman.id.au/
Don't expect people to remember this.
> Is there some way we can blacklist this file from checkpatch, Coccinelle
> etc?
Modify both to look for some specific tag
in a file and then update the scripts to
read the file when looking at patches too.
Otherwise, no.
^ permalink raw reply
* Re: [PATCH v2 3/3] powerpc: machine check interrupt is a non-maskable interrupt
From: Christophe LEROY @ 2018-10-09 4:46 UTC (permalink / raw)
To: Nicholas Piggin; +Cc: Mahesh Jagannath Salgaonkar, linuxppc-dev
In-Reply-To: <20181009143241.026f3e7f@roar.ozlabs.ibm.com>
Le 09/10/2018 à 06:32, Nicholas Piggin a écrit :
> On Mon, 8 Oct 2018 17:39:11 +0200
> Christophe LEROY <christophe.leroy@c-s.fr> wrote:
>
>> Hi Nick,
>>
>> Le 19/07/2017 à 08:59, Nicholas Piggin a écrit :
>>> Use nmi_enter similarly to system reset interrupts. This uses NMI
>>> printk NMI buffers and turns off various debugging facilities that
>>> helps avoid tripping on ourselves or other CPUs.
>>>
>>> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
>>> ---
>>> arch/powerpc/kernel/traps.c | 9 ++++++---
>>> 1 file changed, 6 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
>>> index 2849c4f50324..6d31f9d7c333 100644
>>> --- a/arch/powerpc/kernel/traps.c
>>> +++ b/arch/powerpc/kernel/traps.c
>>> @@ -789,8 +789,10 @@ int machine_check_generic(struct pt_regs *regs)
>>>
>>> void machine_check_exception(struct pt_regs *regs)
>>> {
>>> - enum ctx_state prev_state = exception_enter();
>>> int recover = 0;
>>> + bool nested = in_nmi();
>>> + if (!nested)
>>> + nmi_enter();
>>
>> This alters preempt_count, then when die() is called
>> in_interrupt() returns true allthough the trap didn't happen in
>> interrupt, so oops_end() panics for "fatal exception in interrupt"
>> instead of gently sending SIGBUS the faulting app.
>
> Thanks for tracking that down.
>
>> Any idea on how to fix this ?
>
> I would say we have to deliver the sigbus by hand.
>
> if ((user_mode(regs)))
> _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
> else
> die("Machine check", regs, SIGBUS);
>
And what about all the other things done by 'die()' ?
And what if it is a kernel thread ?
In one of my boards, I have a kernel thread regularly checking the HW,
and if it gets a machine check I expect it to gently stop and the die
notification to be delivered to all registered notifiers.
Until before this patch, it was working well.
Christophe
^ permalink raw reply
* [PATCH v7 0/9] powerpc: Switch to CONFIG_THREAD_INFO_IN_TASK
From: Christophe Leroy @ 2018-10-09 4:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
The purpose of this serie is to activate CONFIG_THREAD_INFO_IN_TASK which
moves the thread_info into task_struct.
Moving thread_info into task_struct has the following advantages:
- It protects thread_info from corruption in the case of stack
overflows.
- Its address is harder to determine if stack addresses are
leaked, making a number of attacks more difficult.
Changes since v6:
- Fixed validate_sp() to exclude NULL sp in 'regain entire stack space' patch (early crash with CONFIG_KMEMLEAK)
Changes since v5:
- Fixed livepatch_sp setup by using end_of_stack() instead of hardcoding
- Fixed PPC_BPF_LOAD_CPU() macro
Changes since v4:
- Fixed a build failure on 32bits SMP when include/generated/asm-offsets.h is not
already existing, was due to spaces instead of a tab in the Makefile
Changes since RFC v3: (based on Nick's review)
- Renamed task_size.h to task_size_user64.h to better relate to what it contains.
- Handling of the isolation of thread_info cpu field inside CONFIG_SMP #ifdefs moved to a separate patch.
- Removed CURRENT_THREAD_INFO macro completely.
- Added a guard in asm/smp.h to avoid build failure before _TASK_CPU is defined.
- Added a patch at the end to rename 'tp' pointers to 'sp' pointers
- Renamed 'tp' into 'sp' pointers in preparation patch when relevant
- Fixed a few commit logs
- Fixed checkpatch report.
Changes since RFC v2:
- Removed the modification of names in asm-offsets
- Created a rule in arch/powerpc/Makefile to append the offset of current->cpu in CFLAGS
- Modified asm/smp.h to use the offset set in CFLAGS
- Squashed the renaming of THREAD_INFO to TASK_STACK in the preparation patch
- Moved the modification of current_pt_regs in the patch activating CONFIG_THREAD_INFO_IN_TASK
Changes since RFC v1:
- Removed the first patch which was modifying header inclusion order in timer
- Modified some names in asm-offsets to avoid conflicts when including asm-offsets in C files
- Modified asm/smp.h to avoid having to include linux/sched.h (using asm-offsets instead)
- Moved some changes from the activation patch to the preparation patch.
Christophe Leroy (9):
book3s/64: avoid circular header inclusion in mmu-hash.h
powerpc: Only use task_struct 'cpu' field on SMP
powerpc: Prepare for moving thread_info into task_struct
powerpc: Activate CONFIG_THREAD_INFO_IN_TASK
powerpc: regain entire stack space
powerpc: 'current_set' is now a table of task_struct pointers
powerpc/32: Remove CURRENT_THREAD_INFO and rename TI_CPU
powerpc/64: Remove CURRENT_THREAD_INFO
powerpc: clean stack pointers naming
Christophe Leroy (9):
book3s/64: avoid circular header inclusion in mmu-hash.h
powerpc: Only use task_struct 'cpu' field on SMP
powerpc: Prepare for moving thread_info into task_struct
powerpc: Activate CONFIG_THREAD_INFO_IN_TASK
powerpc: regain entire stack space
powerpc: 'current_set' is now a table of task_struct pointers
powerpc/32: Remove CURRENT_THREAD_INFO and rename TI_CPU
powerpc/64: Remove CURRENT_THREAD_INFO
powerpc: clean stack pointers naming
arch/powerpc/Kconfig | 1 +
arch/powerpc/Makefile | 8 ++-
arch/powerpc/include/asm/asm-prototypes.h | 4 +-
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
arch/powerpc/include/asm/exception-64s.h | 4 +-
arch/powerpc/include/asm/irq.h | 14 ++---
arch/powerpc/include/asm/livepatch.h | 7 ++-
arch/powerpc/include/asm/processor.h | 39 +------------
arch/powerpc/include/asm/ptrace.h | 2 +-
arch/powerpc/include/asm/reg.h | 2 +-
arch/powerpc/include/asm/smp.h | 17 +++++-
arch/powerpc/include/asm/task_size_user64.h | 42 ++++++++++++++
arch/powerpc/include/asm/thread_info.h | 19 -------
arch/powerpc/kernel/asm-offsets.c | 10 ++--
arch/powerpc/kernel/entry_32.S | 66 ++++++++--------------
arch/powerpc/kernel/entry_64.S | 12 ++--
arch/powerpc/kernel/epapr_hcalls.S | 5 +-
arch/powerpc/kernel/exceptions-64e.S | 13 +----
arch/powerpc/kernel/exceptions-64s.S | 2 +-
arch/powerpc/kernel/head_32.S | 14 ++---
arch/powerpc/kernel/head_40x.S | 4 +-
arch/powerpc/kernel/head_44x.S | 8 +--
arch/powerpc/kernel/head_64.S | 1 +
arch/powerpc/kernel/head_8xx.S | 2 +-
arch/powerpc/kernel/head_booke.h | 12 +---
arch/powerpc/kernel/head_fsl_booke.S | 16 +++---
arch/powerpc/kernel/idle_6xx.S | 8 +--
arch/powerpc/kernel/idle_book3e.S | 2 +-
arch/powerpc/kernel/idle_e500.S | 8 +--
arch/powerpc/kernel/idle_power4.S | 2 +-
arch/powerpc/kernel/irq.c | 77 +++++---------------------
arch/powerpc/kernel/kgdb.c | 28 ----------
arch/powerpc/kernel/machine_kexec_64.c | 6 +-
arch/powerpc/kernel/misc_32.S | 17 +++---
arch/powerpc/kernel/process.c | 40 ++++++-------
arch/powerpc/kernel/setup-common.c | 2 +-
arch/powerpc/kernel/setup_32.c | 15 ++---
arch/powerpc/kernel/setup_64.c | 41 ++++----------
arch/powerpc/kernel/smp.c | 16 +++---
arch/powerpc/kernel/trace/ftrace_64_mprofile.S | 6 +-
arch/powerpc/kvm/book3s_hv_hmi.c | 1 +
arch/powerpc/mm/hash_low_32.S | 14 ++---
arch/powerpc/net/bpf_jit32.h | 5 +-
arch/powerpc/sysdev/6xx-suspend.S | 5 +-
arch/powerpc/xmon/xmon.c | 2 +-
45 files changed, 240 insertions(+), 381 deletions(-)
create mode 100644 arch/powerpc/include/asm/task_size_user64.h
--
2.13.3
^ permalink raw reply
* [PATCH v7 1/9] book3s/64: avoid circular header inclusion in mmu-hash.h
From: Christophe Leroy @ 2018-10-09 4:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1539040628.git.christophe.leroy@c-s.fr>
When activating CONFIG_THREAD_INFO_IN_TASK, linux/sched.h
includes asm/current.h. This generates a circular dependency.
To avoid that, asm/processor.h shall not be included in mmu-hash.h
In order to do that, this patch moves into a new header called
asm/task_size_user64.h the information from asm/processor.h required
by mmu-hash.h
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
arch/powerpc/include/asm/processor.h | 34 +---------------------
arch/powerpc/include/asm/task_size_user64.h | 42 +++++++++++++++++++++++++++
arch/powerpc/kvm/book3s_hv_hmi.c | 1 +
4 files changed, 45 insertions(+), 34 deletions(-)
create mode 100644 arch/powerpc/include/asm/task_size_user64.h
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index e0e4ce8f77d6..02955d867067 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -23,7 +23,7 @@
*/
#include <asm/book3s/64/pgtable.h>
#include <asm/bug.h>
-#include <asm/processor.h>
+#include <asm/task_size_user64.h>
#include <asm/cpu_has_feature.h>
/*
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 52fadded5c1e..13589274fe9b 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -101,40 +101,8 @@ void release_thread(struct task_struct *);
#endif
#ifdef CONFIG_PPC64
-/*
- * 64-bit user address space can have multiple limits
- * For now supported values are:
- */
-#define TASK_SIZE_64TB (0x0000400000000000UL)
-#define TASK_SIZE_128TB (0x0000800000000000UL)
-#define TASK_SIZE_512TB (0x0002000000000000UL)
-#define TASK_SIZE_1PB (0x0004000000000000UL)
-#define TASK_SIZE_2PB (0x0008000000000000UL)
-/*
- * With 52 bits in the address we can support
- * upto 4PB of range.
- */
-#define TASK_SIZE_4PB (0x0010000000000000UL)
-/*
- * For now 512TB is only supported with book3s and 64K linux page size.
- */
-#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_64K_PAGES)
-/*
- * Max value currently used:
- */
-#define TASK_SIZE_USER64 TASK_SIZE_4PB
-#define DEFAULT_MAP_WINDOW_USER64 TASK_SIZE_128TB
-#define TASK_CONTEXT_SIZE TASK_SIZE_512TB
-#else
-#define TASK_SIZE_USER64 TASK_SIZE_64TB
-#define DEFAULT_MAP_WINDOW_USER64 TASK_SIZE_64TB
-/*
- * We don't need to allocate extended context ids for 4K page size, because
- * we limit the max effective address on this config to 64TB.
- */
-#define TASK_CONTEXT_SIZE TASK_SIZE_64TB
-#endif
+#include <asm/task_size_user64.h>
/*
* 32-bit user address space is 4GB - 1 page
diff --git a/arch/powerpc/include/asm/task_size_user64.h b/arch/powerpc/include/asm/task_size_user64.h
new file mode 100644
index 000000000000..a4043075864b
--- /dev/null
+++ b/arch/powerpc/include/asm/task_size_user64.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_TASK_SIZE_USER64_H
+#define _ASM_POWERPC_TASK_SIZE_USER64_H
+
+#ifdef CONFIG_PPC64
+/*
+ * 64-bit user address space can have multiple limits
+ * For now supported values are:
+ */
+#define TASK_SIZE_64TB (0x0000400000000000UL)
+#define TASK_SIZE_128TB (0x0000800000000000UL)
+#define TASK_SIZE_512TB (0x0002000000000000UL)
+#define TASK_SIZE_1PB (0x0004000000000000UL)
+#define TASK_SIZE_2PB (0x0008000000000000UL)
+/*
+ * With 52 bits in the address we can support
+ * upto 4PB of range.
+ */
+#define TASK_SIZE_4PB (0x0010000000000000UL)
+
+/*
+ * For now 512TB is only supported with book3s and 64K linux page size.
+ */
+#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_64K_PAGES)
+/*
+ * Max value currently used:
+ */
+#define TASK_SIZE_USER64 TASK_SIZE_4PB
+#define DEFAULT_MAP_WINDOW_USER64 TASK_SIZE_128TB
+#define TASK_CONTEXT_SIZE TASK_SIZE_512TB
+#else
+#define TASK_SIZE_USER64 TASK_SIZE_64TB
+#define DEFAULT_MAP_WINDOW_USER64 TASK_SIZE_64TB
+/*
+ * We don't need to allocate extended context ids for 4K page size, because
+ * we limit the max effective address on this config to 64TB.
+ */
+#define TASK_CONTEXT_SIZE TASK_SIZE_64TB
+#endif
+
+#endif /* CONFIG_PPC64 */
+#endif /* _ASM_POWERPC_TASK_SIZE_USER64_H */
diff --git a/arch/powerpc/kvm/book3s_hv_hmi.c b/arch/powerpc/kvm/book3s_hv_hmi.c
index e3f738eb1cac..64b5011475c7 100644
--- a/arch/powerpc/kvm/book3s_hv_hmi.c
+++ b/arch/powerpc/kvm/book3s_hv_hmi.c
@@ -24,6 +24,7 @@
#include <linux/compiler.h>
#include <asm/paca.h>
#include <asm/hmi.h>
+#include <asm/processor.h>
void wait_for_subcore_guest_exit(void)
{
--
2.13.3
^ permalink raw reply related
* [PATCH v7 2/9] powerpc: Only use task_struct 'cpu' field on SMP
From: Christophe Leroy @ 2018-10-09 4:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1539040628.git.christophe.leroy@c-s.fr>
When moving to CONFIG_THREAD_INFO_IN_TASK, the thread_info 'cpu' field
gets moved into task_struct and only defined when CONFIG_SMP is set.
This patch ensures that TI_CPU is only used when CONFIG_SMP is set and
that task_struct 'cpu' field is not used directly out of SMP code.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/head_fsl_booke.S | 2 ++
arch/powerpc/kernel/misc_32.S | 4 ++++
arch/powerpc/xmon/xmon.c | 2 +-
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index e2750b856c8f..05b574f416b3 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -243,8 +243,10 @@ set_ivor:
li r0,0
stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
+#ifdef CONFIG_SMP
CURRENT_THREAD_INFO(r22, r1)
stw r24, TI_CPU(r22)
+#endif
bl early_init
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 695b24a2d954..2f0fe8bfc078 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -183,10 +183,14 @@ _GLOBAL(low_choose_750fx_pll)
or r4,r4,r5
mtspr SPRN_HID1,r4
+#ifdef CONFIG_SMP
/* Store new HID1 image */
CURRENT_THREAD_INFO(r6, r1)
lwz r6,TI_CPU(r6)
slwi r6,r6,2
+#else
+ li r6, 0
+#endif
addis r6,r6,nap_save_hid1@ha
stw r4,nap_save_hid1@l(r6)
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index c70d17c9a6ba..1731793e1277 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2986,7 +2986,7 @@ static void show_task(struct task_struct *tsk)
printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
tsk->thread.ksp,
tsk->pid, tsk->parent->pid,
- state, task_thread_info(tsk)->cpu,
+ state, task_cpu(tsk),
tsk->comm);
}
--
2.13.3
^ permalink raw reply related
* [PATCH v7 3/9] powerpc: Prepare for moving thread_info into task_struct
From: Christophe Leroy @ 2018-10-09 4:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1539040628.git.christophe.leroy@c-s.fr>
This patch cleans the powerpc kernel before activating
CONFIG_THREAD_INFO_IN_TASK:
- The purpose of the pointer given to call_do_softirq() and
call_do_irq() is to point the new stack ==> change it to void* and
rename it 'sp'
- Don't use CURRENT_THREAD_INFO() to locate the stack.
- Fix a few comments.
- Replace current_thread_info()->task by current
- Remove unnecessary casts to thread_info, as they'll become invalid
once thread_info is not in stack anymore.
- Rename THREAD_INFO to TASK_STASK: as it is in fact the offset of the
pointer to the stack in task_struct, this pointer will not be impacted
by the move of THREAD_INFO.
- Makes TASK_STACK available to PPC64. PPC64 will need it to get the
stack pointer from current once the thread_info have been moved.
- Modifies klp_init_thread_info() to take task_struct pointer argument.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/irq.h | 4 ++--
arch/powerpc/include/asm/livepatch.h | 7 ++++---
arch/powerpc/include/asm/processor.h | 4 ++--
arch/powerpc/include/asm/reg.h | 2 +-
arch/powerpc/kernel/asm-offsets.c | 2 +-
arch/powerpc/kernel/entry_32.S | 2 +-
arch/powerpc/kernel/entry_64.S | 2 +-
arch/powerpc/kernel/head_32.S | 4 ++--
arch/powerpc/kernel/head_40x.S | 4 ++--
arch/powerpc/kernel/head_44x.S | 2 +-
arch/powerpc/kernel/head_8xx.S | 2 +-
arch/powerpc/kernel/head_booke.h | 4 ++--
arch/powerpc/kernel/head_fsl_booke.S | 4 ++--
arch/powerpc/kernel/irq.c | 2 +-
arch/powerpc/kernel/misc_32.S | 4 ++--
arch/powerpc/kernel/process.c | 8 ++++----
arch/powerpc/kernel/setup-common.c | 2 +-
arch/powerpc/kernel/setup_32.c | 15 +++++----------
arch/powerpc/kernel/smp.c | 4 +++-
19 files changed, 38 insertions(+), 40 deletions(-)
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index ee39ce56b2a2..2efbae8d93be 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -63,8 +63,8 @@ extern struct thread_info *hardirq_ctx[NR_CPUS];
extern struct thread_info *softirq_ctx[NR_CPUS];
extern void irq_ctx_init(void);
-extern void call_do_softirq(struct thread_info *tp);
-extern void call_do_irq(struct pt_regs *regs, struct thread_info *tp);
+void call_do_softirq(void *sp);
+void call_do_irq(struct pt_regs *regs, void *sp);
extern void do_IRQ(struct pt_regs *regs);
extern void __init init_IRQ(void);
extern void __do_irq(struct pt_regs *regs);
diff --git a/arch/powerpc/include/asm/livepatch.h b/arch/powerpc/include/asm/livepatch.h
index 47a03b9b528b..8a81d10ccc82 100644
--- a/arch/powerpc/include/asm/livepatch.h
+++ b/arch/powerpc/include/asm/livepatch.h
@@ -43,13 +43,14 @@ static inline unsigned long klp_get_ftrace_location(unsigned long faddr)
return ftrace_location_range(faddr, faddr + 16);
}
-static inline void klp_init_thread_info(struct thread_info *ti)
+static inline void klp_init_thread_info(struct task_struct *p)
{
+ struct thread_info *ti = task_thread_info(p);
/* + 1 to account for STACK_END_MAGIC */
- ti->livepatch_sp = (unsigned long *)(ti + 1) + 1;
+ ti->livepatch_sp = end_of_stack(p) + 1;
}
#else
-static void klp_init_thread_info(struct thread_info *ti) { }
+static inline void klp_init_thread_info(struct task_struct *p) { }
#endif /* CONFIG_LIVEPATCH */
#endif /* _ASM_POWERPC_LIVEPATCH_H */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 13589274fe9b..b225c7f7c5a4 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -40,7 +40,7 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
-#include <asm/thread_info.h>
+#include <linux/thread_info.h>
#include <asm/ptrace.h>
#include <asm/hw_breakpoint.h>
@@ -332,7 +332,7 @@ struct thread_struct {
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
#define INIT_SP_LIMIT \
- (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack)
+ (_ALIGN_UP(sizeof(struct thread_info), 16) + (unsigned long)&init_stack)
#ifdef CONFIG_SPE
#define SPEFSCR_INIT \
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 640a4d818772..d2528a0b2f5b 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1058,7 +1058,7 @@
* - SPRG9 debug exception scratch
*
* All 32-bit:
- * - SPRG3 current thread_info pointer
+ * - SPRG3 current thread_struct physical addr pointer
* (virtual on BookE, physical on others)
*
* 32-bit classic:
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index a6d70fd2e499..c583a02e5a21 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -91,10 +91,10 @@ int main(void)
DEFINE(NMI_MASK, NMI_MASK);
OFFSET(TASKTHREADPPR, task_struct, thread.ppr);
#else
- OFFSET(THREAD_INFO, task_struct, stack);
DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16));
OFFSET(KSP_LIMIT, thread_struct, ksp_limit);
#endif /* CONFIG_PPC64 */
+ OFFSET(TASK_STACK, task_struct, stack);
#ifdef CONFIG_LIVEPATCH
OFFSET(TI_livepatch_sp, thread_info, livepatch_sp);
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 77decded1175..7ea1d71f4546 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -1166,7 +1166,7 @@ ret_from_debug_exc:
mfspr r9,SPRN_SPRG_THREAD
lwz r10,SAVED_KSP_LIMIT(r1)
stw r10,KSP_LIMIT(r9)
- lwz r9,THREAD_INFO-THREAD(r9)
+ lwz r9,TASK_STACK-THREAD(r9)
CURRENT_THREAD_INFO(r10, r1)
lwz r10,TI_PREEMPT(r10)
stw r10,TI_PREEMPT(r9)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index ed6f6c7f4264..6fce0f8fd8c4 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -684,7 +684,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
2:
#endif /* CONFIG_PPC_BOOK3S_64 */
- CURRENT_THREAD_INFO(r7, r8) /* base of new stack */
+ clrrdi r7, r8, THREAD_SHIFT /* base of new stack */
/* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE
because we don't need to leave the 288-byte ABI gap at the
top of the kernel stack. */
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 61ca27929355..dce6f2ff07e5 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -261,7 +261,7 @@ __secondary_hold_acknowledge:
tophys(r11,r1); /* use tophys(r1) if kernel */ \
beq 1f; \
mfspr r11,SPRN_SPRG_THREAD; \
- lwz r11,THREAD_INFO-THREAD(r11); \
+ lwz r11,TASK_STACK-THREAD(r11); \
addi r11,r11,THREAD_SIZE; \
tophys(r11,r11); \
1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */
@@ -841,7 +841,7 @@ __secondary_start:
bl init_idle_6xx
#endif /* CONFIG_6xx */
- /* get current_thread_info and current */
+ /* get current's stack and current */
lis r1,secondary_ti@ha
tophys(r1,r1)
lwz r1,secondary_ti@l(r1)
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index b19d78410511..3088c9f29f5e 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -115,7 +115,7 @@ _ENTRY(saved_ksp_limit)
andi. r11,r11,MSR_PR; \
beq 1f; \
mfspr r1,SPRN_SPRG_THREAD; /* if from user, start at top of */\
- lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\
+ lwz r1,TASK_STACK-THREAD(r1); /* this thread's kernel stack */\
addi r1,r1,THREAD_SIZE; \
1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\
tophys(r11,r1); \
@@ -158,7 +158,7 @@ _ENTRY(saved_ksp_limit)
beq 1f; \
/* COMING FROM USER MODE */ \
mfspr r11,SPRN_SPRG_THREAD; /* if from user, start at top of */\
- lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+ lwz r11,TASK_STACK-THREAD(r11); /* this thread's kernel stack */\
1: addi r11,r11,THREAD_SIZE-INT_FRAME_SIZE; /* Alloc an excpt frm */\
tophys(r11,r11); \
stw r10,_CCR(r11); /* save various registers */\
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 37e4a7cf0065..15d39b2499de 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -1020,7 +1020,7 @@ _GLOBAL(start_secondary_47x)
/* Now we can get our task struct and real stack pointer */
- /* Get current_thread_info and current */
+ /* Get current's stack and current */
lis r1,secondary_ti@ha
lwz r1,secondary_ti@l(r1)
lwz r2,TI_TASK(r1)
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 6582f824d620..e56e36aa2b3d 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -124,7 +124,7 @@ turn_on_mmu:
tophys(r11,r1); /* use tophys(r1) if kernel */ \
beq 1f; \
mfspr r11,SPRN_SPRG_THREAD; \
- lwz r11,THREAD_INFO-THREAD(r11); \
+ lwz r11,TASK_STACK-THREAD(r11); \
addi r11,r11,THREAD_SIZE; \
tophys(r11,r11); \
1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index d0862a100d29..175f812066dc 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -44,7 +44,7 @@
mr r11, r1; \
beq 1f; \
/* if from user, start at top of this thread's kernel stack */ \
- lwz r11, THREAD_INFO-THREAD(r10); \
+ lwz r11, TASK_STACK - THREAD(r10); \
ALLOC_STACK_FRAME(r11, THREAD_SIZE); \
1 : subi r11, r11, INT_FRAME_SIZE; /* Allocate exception frame */ \
stw r13, _CCR(r11); /* save various registers */ \
@@ -130,7 +130,7 @@
DO_KVM BOOKE_INTERRUPT_##intno exc_level_srr1; \
andi. r11,r11,MSR_PR; \
mfspr r11,SPRN_SPRG_THREAD; /* if from user, start at top of */\
- lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+ lwz r11, TASK_STACK - THREAD(r11); /* this thread's kernel stack */\
addi r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame */\
beq 1f; \
/* COMING FROM USER MODE */ \
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 05b574f416b3..239ad8a4754e 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -704,7 +704,7 @@ finish_tlb_load:
/* Get the next_tlbcam_idx percpu var */
#ifdef CONFIG_SMP
- lwz r12, THREAD_INFO-THREAD(r12)
+ lwz r12, TASK_STACK-THREAD(r12)
lwz r15, TI_CPU(r12)
lis r14, __per_cpu_offset@h
ori r14, r14, __per_cpu_offset@l
@@ -1076,7 +1076,7 @@ __secondary_start:
mr r4,r24 /* Why? */
bl call_setup_cpu
- /* get current_thread_info and current */
+ /* get current's stack and current */
lis r1,secondary_ti@ha
lwz r1,secondary_ti@l(r1)
lwz r2,TI_TASK(r1)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 916ddc4aac44..9e7dc4468c8c 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -663,7 +663,7 @@ void do_IRQ(struct pt_regs *regs)
struct thread_info *curtp, *irqtp, *sirqtp;
/* Switch to the irq stack to handle this */
- curtp = current_thread_info();
+ curtp = (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1));
irqtp = hardirq_ctx[raw_smp_processor_id()];
sirqtp = softirq_ctx[raw_smp_processor_id()];
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 2f0fe8bfc078..32762f4c3458 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -60,7 +60,7 @@ _GLOBAL(call_do_softirq)
blr
/*
- * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp);
+ * void call_do_irq(struct pt_regs *regs, void *sp);
*/
_GLOBAL(call_do_irq)
mflr r0
@@ -603,7 +603,7 @@ EXPORT_SYMBOL(__bswapdi2)
#ifdef CONFIG_SMP
_GLOBAL(start_secondary_resume)
/* Reset stack */
- CURRENT_THREAD_INFO(r1, r1)
+ rlwinm r1, r1, 0, 0, 31 - THREAD_SHIFT
addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
li r3,0
stw r3,0(r1) /* Zero the stack frame pointer */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index d9d4eb2ea6c9..a12307ebb7ef 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1237,8 +1237,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
batch->active = 1;
}
- if (current_thread_info()->task->thread.regs) {
- restore_math(current_thread_info()->task->thread.regs);
+ if (current->thread.regs) {
+ restore_math(current->thread.regs);
/*
* The copy-paste buffer can only store into foreign real
@@ -1248,7 +1248,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
* mappings, we must issue a cp_abort to clear any state and
* prevent snooping, corruption or a covert channel.
*/
- if (current_thread_info()->task->thread.used_vas)
+ if (current->thread.used_vas)
asm volatile(PPC_CP_ABORT);
}
#endif /* CONFIG_PPC_BOOK3S_64 */
@@ -1632,7 +1632,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
struct thread_info *ti = task_thread_info(p);
- klp_init_thread_info(ti);
+ klp_init_thread_info(p);
/* Copy registers */
sp -= sizeof(struct pt_regs);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 9ca9db707bcb..8054a7b9e026 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -940,7 +940,7 @@ void __init setup_arch(char **cmdline_p)
/* Reserve large chunks of memory for use by CMA for KVM. */
kvm_cma_reserve();
- klp_init_thread_info(&init_thread_info);
+ klp_init_thread_info(&init_task);
init_mm.start_code = (unsigned long)_stext;
init_mm.end_code = (unsigned long) _etext;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 8c507be12c3c..81ebf7d6f526 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -205,10 +205,8 @@ void __init irqstack_early_init(void)
/* interrupt stacks must be in lowmem, we get that for free on ppc32
* as the memblock is limited to lowmem by default */
for_each_possible_cpu(i) {
- softirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- hardirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ softirq_ctx[i] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ hardirq_ctx[i] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
}
}
@@ -226,13 +224,10 @@ void __init exc_lvl_early_init(void)
hw_cpu = 0;
#endif
- critirq_ctx[hw_cpu] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ critirq_ctx[hw_cpu] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
#ifdef CONFIG_BOOKE
- dbgirq_ctx[hw_cpu] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- mcheckirq_ctx[hw_cpu] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ dbgirq_ctx[hw_cpu] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ mcheckirq_ctx[hw_cpu] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
#endif
}
}
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 61c1fadbc644..19dd0ea55714 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/sched/mm.h>
+#include <linux/sched/task_stack.h>
#include <linux/sched/topology.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
@@ -812,7 +813,8 @@ static void cpu_idle_thread_init(unsigned int cpu, struct task_struct *idle)
#ifdef CONFIG_PPC64
paca_ptrs[cpu]->__current = idle;
- paca_ptrs[cpu]->kstack = (unsigned long)ti + THREAD_SIZE - STACK_FRAME_OVERHEAD;
+ paca_ptrs[cpu]->kstack = (unsigned long)task_stack_page(idle) +
+ THREAD_SIZE - STACK_FRAME_OVERHEAD;
#endif
ti->cpu = cpu;
secondary_ti = current_set[cpu] = ti;
--
2.13.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox