| From ab4782da6277e9cf0e6de37c772fa8526f3fd727 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 31 Mar 2021 11:38:41 +1100 |
| Subject: powerpc/pseries: Add key to flags in |
| pSeries_lpar_hpte_updateboltedpp() |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Michael Ellerman <mpe@ellerman.id.au> |
| |
| [ Upstream commit b56d55a5aa4aa9fc166595a7feb57f153ef7b555 ] |
| |
| The flags argument to plpar_pte_protect() (aka. H_PROTECT), includes |
| the key in bits 9-13, but currently we always set those bits to zero. |
| |
| In the past that hasn't been a problem because we always used key 0 |
| for the kernel, and updateboltedpp() is only used for kernel mappings. |
| |
| However since commit d94b827e89dc ("powerpc/book3s64/kuap: Use Key 3 |
| for kernel mapping with hash translation") we are now inadvertently |
| changing the key (to zero) when we call plpar_pte_protect(). |
| |
| That hasn't broken anything because updateboltedpp() is only used for |
| STRICT_KERNEL_RWX, which is currently disabled on 64s due to other |
| bugs. |
| |
| But we want to fix that, so first we need to pass the key correctly to |
| plpar_pte_protect(). We can't pass our newpp value directly in, we |
| have to convert it into the form expected by the hcall. |
| |
| The hcall we're using here is H_PROTECT, which is specified in section |
| 14.5.4.1.6 of LoPAPR v1.1. |
| |
| It takes a `flags` parameter, and the description for flags says: |
| |
| * flags: AVPN, pp0, pp1, pp2, key0-key4, n, and for the CMO |
| option: CMO Option flags as defined in Table 189‚ |
| |
| If you then go to the start of the parent section, 14.5.4.1, on page |
| 405, it says: |
| |
| Register Linkage (For hcall() tokens 0x04 - 0x18) |
| * On Call |
| * R3 function call token |
| * R4 flags (see Table 178‚ “Page Frame Table Access flags field |
| definition‚” on page 401) |
| |
| Then you have to go to section 14.5.3, and on page 394 there is a list |
| of hcalls and their tokens (table 176), and there you can see that |
| H_PROTECT == 0x18. |
| |
| Finally you can look at table 178, on page 401, where it specifies the |
| layout of the bits for the key: |
| |
| Bit Function |
| ----------------- |
| 50-54 | key0-key4 |
| |
| Those are big-endian bit numbers, converting to normal bit numbers you |
| get bits 9-13, or 0x3e00. |
| |
| In the kernel we have: |
| |
| #define HPTE_R_KEY_HI ASM_CONST(0x3000000000000000) |
| #define HPTE_R_KEY_LO ASM_CONST(0x0000000000000e00) |
| |
| So the LO bits of newpp are already in the right place, and the HI |
| bits need to be shifted down by 48. |
| |
| Fixes: d94b827e89dc ("powerpc/book3s64/kuap: Use Key 3 for kernel mapping with hash translation") |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Link: https://lore.kernel.org/r/20210331003845.216246-2-mpe@ellerman.id.au |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/powerpc/platforms/pseries/lpar.c | 4 +++- |
| 1 file changed, 3 insertions(+), 1 deletion(-) |
| |
| diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c |
| index 3805519a6469..cd38bd421f38 100644 |
| --- a/arch/powerpc/platforms/pseries/lpar.c |
| +++ b/arch/powerpc/platforms/pseries/lpar.c |
| @@ -977,11 +977,13 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, |
| slot = pSeries_lpar_hpte_find(vpn, psize, ssize); |
| BUG_ON(slot == -1); |
| |
| - flags = newpp & 7; |
| + flags = newpp & (HPTE_R_PP | HPTE_R_N); |
| if (mmu_has_feature(MMU_FTR_KERNEL_RO)) |
| /* Move pp0 into bit 8 (IBM 55) */ |
| flags |= (newpp & HPTE_R_PP0) >> 55; |
| |
| + flags |= ((newpp & HPTE_R_KEY_HI) >> 48) | (newpp & HPTE_R_KEY_LO); |
| + |
| lpar_rc = plpar_pte_protect(flags, slot, 0); |
| |
| BUG_ON(lpar_rc != H_SUCCESS); |
| -- |
| 2.30.2 |
| |