Skip to contentSkip to conversation

s390x/tcg: LAP support using immediate TLB invalidation

RFC PATCH Applied David Hildenbrand 4 participants 21 messages Sep 27, 2017 – Oct 16, 2017

lore
Share & tools
lore
#0 lore raw

cover s390x/tcg: LAP support using immediate TLB invalidation

Details about Low-Address Protection can be found in description of patch 1 and 2. It is basically a subpage protection of the first two pages of every address space (for which it is enabled).

We can achieve this by simply directly invalidating the TLB entry and therefore forcing every write accesses onto these two pages into the slow path.

With this patch, I can boot Linux just fine (which uses LAP). This also makes all related kvm-unit-tests that we have pass.

The checks are working that good, that I discovered a STFL bug. STFL stores into the low addresses but low-address protection does explicitly not apply. The Linux kernel calls STFL while LAP is active. So without patch nr 3, booting Linux will fail. (this change is also part of a patch of my SMP series).

Based on: https://github.com/cohuck/qemu.git s390-next Available on: https://github.com/dhildenb/qemu.git s390x_lap

David Hildenbrand (3):
accel/tcg: allow to invalidate a write TLB entry immediately s390x/tcg: low-address protection support s390x/tcg: make STFL store into the lowcore

 accel/tcg/cputlb.c           |  5 ++-
 accel/tcg/softmmu_template.h |  4 +-
 include/exec/cpu-all.h       |  3 ++
 target/s390x/excp_helper.c   |  3 +-
 target/s390x/helper.h        |  2 +-
 target/s390x/mem_helper.c    |  8 ----
 target/s390x/misc_helper.c   |  7 +++-
 target/s390x/mmu_helper.c    | 96 ++++++++++++++++++++++++++++----------------
 8 files changed, 78 insertions(+), 50 deletions(-)
Signature · 1 line
2.13.5
#1 lore raw

RFC PATCH 1/3 accel/tcg: allow to invalidate a write TLB entry immediately

Background: s390x implements Low-Address Protection (LAP). If LAP is enabled, writing to effective addresses (before any transaltion) 0-511 and 4096-4607 triggers a protection exception.

So we have subpage protection on the first two pages of every address space (where the lowcore - the CPU private data resides).

By immediately invalidating the write entry but allowing the caller to continue, we force every write access onto these first two pages into the slow path. we will get a tlb fault with the specific accessed addresses and can then evaluate if protection applies or not.

We have to make sure to ignore the invalid bit if tlb_fill() succeeds.

---
 accel/tcg/cputlb.c           | 5 ++++-
 accel/tcg/softmmu_template.h | 4 ++--
 include/exec/cpu-all.h       | 3 +++
 3 files changed, 9 insertions(+), 3 deletions(-)
accel/tcg/cputlb.c +4 -1
index bcbcc4db6c..5bc4233961 100644
@@ -683,6 +683,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
         } else {
             tn.addr_write = address;
         }
+        if (prot & PAGE_WRITE_INV) {
+            tn.addr_write |= TLB_INVALID_MASK;
+        }
     }
 
     /* Pairs with flag setting in tlb_reset_dirty_range */
@@ -967,7 +970,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
         }
-        tlb_addr = tlbe->addr_write;
+        tlb_addr = tlbe->addr_write & ~TLB_INVALID_MASK;
     }
 
     /* Check notdirty */
accel/tcg/softmmu_template.h +2 -2
index d7563292a5..3fc5144316 100644
@@ -285,7 +285,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
         }
-        tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+        tlb_addr = env->tlb_table[mmu_idx][index].addr_write & ~TLB_INVALID_MASK;
     }
 
     /* Handle an IO access.  */
@@ -361,7 +361,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
         }
-        tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+        tlb_addr = env->tlb_table[mmu_idx][index].addr_write & ~TLB_INVALID_MASK;
     }
 
     /* Handle an IO access.  */
include/exec/cpu-all.h +3 -0
index ffe43d5654..24b9509604 100644
@@ -247,6 +247,9 @@ extern intptr_t qemu_host_page_mask;
 /* original state of the write flag (used when tracking self-modifying
    code */
 #define PAGE_WRITE_ORG 0x0010
+/* Invalidate the TLB entry immediately, helpful for s390x
+ * Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs() */
+#define PAGE_WRITE_INV 0x0040
 #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
 /* FIXME: Code that sets/uses this is broken and needs to go away.  */
 #define PAGE_RESERVED  0x0020
Signature · 1 line
2.13.5
#2 lore raw

Re: [Qemu-devel] [PATCH RFC 1/3] accel/tcg: allow to invalidate a write TLB entry immediately

Quoted 7 lines · David Hildenbrand

Background: s390x implements Low-Address Protection (LAP). If LAP is enabled, writing to effective addresses (before any transaltion) 0-511 and 4096-4607 triggers a protection exception.

So we have subpage protection on the first two pages of every address space (where the lowcore - the CPU private data resides).

Quoted 6 lines

By immediately invalidating the write entry but allowing the caller to continue, we force every write access onto these first two pages into the slow path. we will get a tlb fault with the specific accessed addresses and can then evaluate if protection applies or not.

We have to make sure to ignore the invalid bit if tlb_fill() succeeds.

This is similar to a scheme I proposed to PMM wrt handling ARM v8M translation.
Reusing TLB_INVALID_MASK would appear to work, but I wonder if it wouldn't be
clearer to use another bit. I believe I had proposed a TLB_FORCE_SLOW_MASK.

Thoughts, Peter?

r~

#3 lore raw

Re: [Qemu-devel] [PATCH RFC 1/3] accel/tcg: allow to invalidate a write TLB entry immediately

Quoted 13 lines · Richard Henderson
Quoted 12 lines · David Hildenbrand

Background: s390x implements Low-Address Protection (LAP). If LAP is enabled, writing to effective addresses (before any transaltion) 0-511 and 4096-4607 triggers a protection exception.

So we have subpage protection on the first two pages of every address space (where the lowcore - the CPU private data resides).

By immediately invalidating the write entry but allowing the caller to continue, we force every write access onto these first two pages into the slow path. we will get a tlb fault with the specific accessed addresses and can then evaluate if protection applies or not.

Quoted 5 lines
Quoted 1 line

We have to make sure to ignore the invalid bit if tlb_fill() succeeds.

This is similar to a scheme I proposed to PMM wrt handling ARM v8M translation.
Reusing TLB_INVALID_MASK would appear to work, but I wonder if it wouldn't be
clearer to use another bit. I believe I had proposed a TLB_FORCE_SLOW_MASK.

The only downside of another bit is that we have to duplicate all checks. Using TLB_INVALID_MASK avoids this change (because it simply works).

Of course, we could come up with something as simple as

#define TLB_INVALID_MASK (TLB_INVALID | TLB_FORCE_SLOW)

and fixup the few places where TLB_INVALID_MASK really just has to be TLB_INVALID.

Have no strong opinion on this. This way requires minimal changes.

Quoted 6 lines

Thoughts, Peter?

r~

Signature · 3 lines
Thanks,

David
#4 lore raw

Re: [Qemu-devel] [PATCH RFC 1/3] accel/tcg: allow to invalidate a write TLB entry immediately

In reply to Richard Henderson
Quoted 13 lines · Richard Henderson
Quoted 12 lines · David Hildenbrand

Background: s390x implements Low-Address Protection (LAP). If LAP is enabled, writing to effective addresses (before any transaltion) 0-511 and 4096-4607 triggers a protection exception.

So we have subpage protection on the first two pages of every address space (where the lowcore - the CPU private data resides).

By immediately invalidating the write entry but allowing the caller to continue, we force every write access onto these first two pages into the slow path. we will get a tlb fault with the specific accessed addresses and can then evaluate if protection applies or not.

Quoted 7 lines
Quoted 1 line

We have to make sure to ignore the invalid bit if tlb_fill() succeeds.

This is similar to a scheme I proposed to PMM wrt handling ARM v8M translation.
Reusing TLB_INVALID_MASK would appear to work, but I wonder if it wouldn't be
clearer to use another bit. I believe I had proposed a TLB_FORCE_SLOW_MASK.

Thoughts, Peter?

As two weeks have passed:

Any further opinions? Richard, how do you want me to continue with this?

Thanks!

Signature · 3 lines
Thanks,

David
#5 lore raw

Re: [Qemu-devel] [PATCH RFC 1/3] accel/tcg: allow to invalidate a write TLB entry immediately

Quoted 20 lines · David Hildenbrand
Quoted 19 lines · Richard Henderson
Quoted 7 lines · David Hildenbrand

Background: s390x implements Low-Address Protection (LAP). If LAP is enabled, writing to effective addresses (before any transaltion) 0-511 and 4096-4607 triggers a protection exception.

So we have subpage protection on the first two pages of every address space (where the lowcore - the CPU private data resides).

Quoted 6 lines

By immediately invalidating the write entry but allowing the caller to continue, we force every write access onto these first two pages into the slow path. we will get a tlb fault with the specific accessed addresses and can then evaluate if protection applies or not.

We have to make sure to ignore the invalid bit if tlb_fill() succeeds.

This is similar to a scheme I proposed to PMM wrt handling ARM v8M translation.
Reusing TLB_INVALID_MASK would appear to work, but I wonder if it wouldn't be
clearer to use another bit. I believe I had proposed a TLB_FORCE_SLOW_MASK.

Quoted 5 lines
Quoted 1 line

Thoughts, Peter?

As two weeks have passed:

Any further opinions? Richard, how do you want me to continue with this?

Let's just go ahead with TLB_INVALID_MASK; we'll revisit if it gets to be confusing.

r~

#6 lore raw

RFC PATCH 2/3 s390x/tcg: low-address protection support

In reply to David Hildenbrand

This is a neat way to implement low address protection, whereby only the first 512 bytes of the first two pages (each 4096 bytes) of every address space are protected.

Store a tec of 0 for the access exception, this is what is defined by Enhanced Suppression on Protection in case of a low address protection (Bit 61 set to 0, rest undefined).

We have to make sure to to pass the access address, not the masked page address into mmu_translate*().

Drop the check from testblock. So we can properly test this via kvm-unit-tests.

This will check every access going through one of the MMUs.

---
 target/s390x/excp_helper.c |  3 +-
 target/s390x/mem_helper.c  |  8 ----
 target/s390x/mmu_helper.c  | 96 +++++++++++++++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 45 deletions(-)
target/s390x/excp_helper.c +1 -2
index 3e4349d00b..aa0cbf67ac 100644
@@ -95,7 +95,6 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
     DPRINTF("%s: address 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
             __func__, orig_vaddr, rw, mmu_idx);
 
-    orig_vaddr &= TARGET_PAGE_MASK;
     vaddr = orig_vaddr;
 
     if (mmu_idx < MMU_REAL_IDX) {
@@ -127,7 +126,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
     qemu_log_mask(CPU_LOG_MMU, "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
             __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
 
-    tlb_set_page(cs, orig_vaddr, raddr, prot,
+    tlb_set_page(cs, orig_vaddr & TARGET_PAGE_MASK, raddr, prot,
                  mmu_idx, TARGET_PAGE_SIZE);
 
     return 0;
target/s390x/mem_helper.c +0 -8
index bbbe1c62b3..69a16867d4 100644
@@ -1687,18 +1687,10 @@ void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
 {
     uintptr_t ra = GETPC();
-    CPUState *cs = CPU(s390_env_get_cpu(env));
     int i;
 
     real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
 
-    /* Check low-address protection */
-    if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) {
-        cpu_restore_state(cs, ra);
-        program_interrupt(env, PGM_PROTECTION, 4);
-        return 1;
-    }
-
     for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
         cpu_stq_real_ra(env, real_addr + i, 0, ra);
     }
target/s390x/mmu_helper.c +61 -35

132 lines not on this page · raw message

Signature · 1 line
2.13.5
Reviewed-by on v1 2/3
#7 lore raw

Re: [Qemu-devel] [PATCH RFC 2/3] s390x/tcg: low-address protection support

target/s390x/mmu_helper.c static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, · line 136

Quoted 6 lines · David Hildenbrand
target/s390x/mmu_helper.c +6 -0
+    case PSW_ASC_HOME:
+        return !(env->cregs[13] & _ASCE_PRIVATE_SPACE);
+    default:
+        /* We don't support access register mode */
+        error_report("unsupported addressing mode");
+        exit(1);

I think g_assert_not_reached() is sufficient for cases like this.

Oh, it's just code movement. Nevermind, perhaps.
Modulo the outcome of discussion on patch 1,

r~

#8 lore raw

Re: [Qemu-devel] [PATCH RFC 2/3] s390x/tcg: low-address protection support

In reply to David Hildenbrand
Quoted 22 lines · David Hildenbrand

This is a neat way to implement low address protection, whereby only the first 512 bytes of the first two pages (each 4096 bytes) of every address space are protected.

Store a tec of 0 for the access exception, this is what is defined by Enhanced Suppression on Protection in case of a low address protection (Bit 61 set to 0, rest undefined).

We have to make sure to to pass the access address, not the masked page address into mmu_translate*().

Drop the check from testblock. So we can properly test this via kvm-unit-tests.

This will check every access going through one of the MMUs.

---
 target/s390x/excp_helper.c |  3 +-
 target/s390x/mem_helper.c  |  8 ----
 target/s390x/mmu_helper.c  | 96 +++++++++++++++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 45 deletions(-)

[...]

target/s390x/mmu_helper.c static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, · line 113

Quoted 13 lines
target/s390x/mmu_helper.c +5 -0
index 9daa0fd8e2..44a15449d2 100644
@@ -106,6 +106,37 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
     trigger_access_exception(env, type, ilen, tec);
 }
 
+/* check whether the address would be proteted by Low-Address Protection */
+static bool is_low_address(uint64_t addr)
+{
+    return addr < 512 || (addr >= 4096 && addr < 4607);
+}

I like the check from the kernel sources better:

static inline int is_low_address(unsigned long ga)

{
    /* Check for address ranges 0..511 and 4096..4607 */
    return (ga & ~0x11fful) == 0;
}

... that might result in slightly faster code (depending on the compiler, of course).

Thomas

#9 lore raw

Re: [Qemu-devel] [PATCH RFC 2/3] s390x/tcg: low-address protection support

Quoted 40 lines · Thomas Huth
Quoted 22 lines · David Hildenbrand

This is a neat way to implement low address protection, whereby only the first 512 bytes of the first two pages (each 4096 bytes) of every address space are protected.

Store a tec of 0 for the access exception, this is what is defined by Enhanced Suppression on Protection in case of a low address protection (Bit 61 set to 0, rest undefined).

We have to make sure to to pass the access address, not the masked page address into mmu_translate*().

Drop the check from testblock. So we can properly test this via kvm-unit-tests.

This will check every access going through one of the MMUs.

---
 target/s390x/excp_helper.c |  3 +-
 target/s390x/mem_helper.c  |  8 ----
 target/s390x/mmu_helper.c  | 96 +++++++++++++++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 45 deletions(-)

[...]

target/s390x/mmu_helper.c static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, · line 113

Quoted 13 lines
target/s390x/mmu_helper.c +5 -0
index 9daa0fd8e2..44a15449d2 100644
@@ -106,6 +106,37 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
     trigger_access_exception(env, type, ilen, tec);
 }
 
+/* check whether the address would be proteted by Low-Address Protection */
+static bool is_low_address(uint64_t addr)
+{
+    return addr < 512 || (addr >= 4096 && addr < 4607);
+}

I like the check from the kernel sources better:

Quoted 8 lines

static inline int is_low_address(unsigned long ga)

{
    /* Check for address ranges 0..511 and 4096..4607 */
    return (ga & ~0x11fful) == 0;
}

... that might result in slightly faster code (depending on the compiler, of course).

I think that lim (readability) -> 0. Without that comment you're at first sight really clueless what this is about.

My check exactly corresponds to the wording in the PoP (and smart compilers should be able to optimize).

But I don't have a strong opinion on this micro optimization.

Thanks

Quoted 3 lines

Thomas

Signature · 3 lines
Thanks,

David
#10 lore raw

Re: [Qemu-devel] [PATCH RFC 2/3] s390x/tcg: low-address protection support

Quoted 50 lines · On Thu, 28 Sep 2017 15:08:11 +0200 David Hildenbrand <[email protected]> wrote:
Quoted 40 lines · Thomas Huth
Quoted 22 lines · David Hildenbrand

This is a neat way to implement low address protection, whereby only the first 512 bytes of the first two pages (each 4096 bytes) of every address space are protected.

Store a tec of 0 for the access exception, this is what is defined by Enhanced Suppression on Protection in case of a low address protection (Bit 61 set to 0, rest undefined).

We have to make sure to to pass the access address, not the masked page address into mmu_translate*().

Drop the check from testblock. So we can properly test this via kvm-unit-tests.

This will check every access going through one of the MMUs.

---
 target/s390x/excp_helper.c |  3 +-
 target/s390x/mem_helper.c  |  8 ----
 target/s390x/mmu_helper.c  | 96 +++++++++++++++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 45 deletions(-)  

[...]

target/s390x/mmu_helper.c static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, · line 113

Quoted 13 lines
target/s390x/mmu_helper.c +5 -0
index 9daa0fd8e2..44a15449d2 100644
@@ -106,6 +106,37 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
     trigger_access_exception(env, type, ilen, tec);
 }
 
+/* check whether the address would be proteted by Low-Address Protection */
+static bool is_low_address(uint64_t addr)
+{
+    return addr < 512 || (addr >= 4096 && addr < 4607);
+}  

I like the check from the kernel sources better:

Quoted 8 lines

static inline int is_low_address(unsigned long ga)

{
    /* Check for address ranges 0..511 and 4096..4607 */
    return (ga & ~0x11fful) == 0;
}

... that might result in slightly faster code (depending on the compiler, of course).

Quoted 7 lines

I think that lim (readability) -> 0. Without that comment you're at first sight really clueless what this is about.

My check exactly corresponds to the wording in the PoP (and smart compilers should be able to optimize).

But I don't have a strong opinion on this micro optimization.

FWIW, I'd be happy with both, but has anyone actually looked at the generated code?

#11 lore raw

Re: [Qemu-devel] [PATCH RFC 2/3] s390x/tcg: low-address protection support

Quoted 56 lines · Cornelia Huck
Quoted 53 lines · On Thu, 28 Sep 2017 15:08:11 +0200 David Hildenbrand <[email protected]> wrote:
Quoted 40 lines · Thomas Huth
Quoted 22 lines · David Hildenbrand

This is a neat way to implement low address protection, whereby only the first 512 bytes of the first two pages (each 4096 bytes) of every address space are protected.

Store a tec of 0 for the access exception, this is what is defined by Enhanced Suppression on Protection in case of a low address protection (Bit 61 set to 0, rest undefined).

We have to make sure to to pass the access address, not the masked page address into mmu_translate*().

Drop the check from testblock. So we can properly test this via kvm-unit-tests.

This will check every access going through one of the MMUs.

---
 target/s390x/excp_helper.c |  3 +-
 target/s390x/mem_helper.c  |  8 ----
 target/s390x/mmu_helper.c  | 96 +++++++++++++++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 45 deletions(-)  

[...]

target/s390x/mmu_helper.c static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, · line 113

Quoted 13 lines
target/s390x/mmu_helper.c +5 -0
index 9daa0fd8e2..44a15449d2 100644
@@ -106,6 +106,37 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
     trigger_access_exception(env, type, ilen, tec);
 }
 
+/* check whether the address would be proteted by Low-Address Protection */
+static bool is_low_address(uint64_t addr)
+{
+    return addr < 512 || (addr >= 4096 && addr < 4607);
+}  

I like the check from the kernel sources better:

Quoted 8 lines

static inline int is_low_address(unsigned long ga)

{
    /* Check for address ranges 0..511 and 4096..4607 */
    return (ga & ~0x11fful) == 0;
}

... that might result in slightly faster code (depending on the compiler, of course).

I think that lim (readability) -> 0. Without that comment you're at first sight really clueless what this is about.

Quoted 7 lines
Quoted 4 lines

My check exactly corresponds to the wording in the PoP (and smart compilers should be able to optimize).

But I don't have a strong opinion on this micro optimization.

FWIW, I'd be happy with both, but has anyone actually looked at the generated code?

This is what I get for David's original code:

    80000510:   c4 18 00 00 0d a4       lgrl    %r1,80002058 <x1>
    80000516:   a7 29 01 ff             lghi    %r2,511
    8000051a:   ec 12 00 4f c0 65       clgrjnh %r1,%r2,800005b8 <main+0xd8>
    80000520:   a7 1b f0 00             aghi    %r1,-4096
    80000524:   c2 1e 00 00 01 fe       clgfi   %r1,510
    8000052a:   a7 18 00 00             lhi     %r1,0
    8000052e:   b9 99 00 11             slbr    %r1,%r1
    80000532:   13 11                   lcr     %r1,%r1
    80000534:   c4 1f 00 00 0d 96       strl    %r1,80002060 <b1>

And this is the optimized kernel version:

    8000054a:   c4 18 00 00 0d 7f       lgrl    %r1,80002048 <x2>
    80000550:   a5 17 ee 00             nill    %r1,60928
    80000554:   b9 00 00 11             lpgr    %r1,%r1
    80000558:   a7 1b ff ff             aghi    %r1,-1
    8000055c:   eb 11 00 3f 00 0c       srlg    %r1,%r1,63
    80000562:   c4 1f 00 00 0d 77       strl    %r1,80002050 <b2>

So that's indeed a little bit better :-)
(I was using GCC 4.8.5 from RHEL7, with -O2)

By the way, I think there's a bug in David's code: It should either be "addr <= 4607" or "addr < 4608" instead of "addr < 4607".

With that bug fixed, David's version get's optimized even more:

    80000510:   c4 18 00 00 0d a4       lgrl    %r1,80002058 <x1>
    80000516:   a5 17 ef ff             nill    %r1,61439
    8000051a:   c2 1e 00 00 01 ff       clgfi   %r1,511
    80000520:   a7 18 00 00             lhi     %r1,0
    80000524:   b9 99 00 11             slbr    %r1,%r1
    80000528:   13 11                   lcr     %r1,%r1
    8000052a:   c4 1f 00 00 0d 9b       strl    %r1,80002060 <b1>

... so the difference is really very minimal in that case --> We could really use the more readable version, I think.

Thomas

#12 lore raw

Re: [Qemu-devel] [PATCH RFC 2/3] s390x/tcg: low-address protection support

Quoted 102 lines · Thomas Huth
Quoted 56 lines · Cornelia Huck
Quoted 53 lines · On Thu, 28 Sep 2017 15:08:11 +0200 David Hildenbrand <[email protected]> wrote:
Quoted 40 lines · Thomas Huth
Quoted 22 lines · David Hildenbrand

This is a neat way to implement low address protection, whereby only the first 512 bytes of the first two pages (each 4096 bytes) of every address space are protected.

Store a tec of 0 for the access exception, this is what is defined by Enhanced Suppression on Protection in case of a low address protection (Bit 61 set to 0, rest undefined).

We have to make sure to to pass the access address, not the masked page address into mmu_translate*().

Drop the check from testblock. So we can properly test this via kvm-unit-tests.

This will check every access going through one of the MMUs.

---
 target/s390x/excp_helper.c |  3 +-
 target/s390x/mem_helper.c  |  8 ----
 target/s390x/mmu_helper.c  | 96 +++++++++++++++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 45 deletions(-)  

[...]

target/s390x/mmu_helper.c static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, · line 113

Quoted 13 lines
target/s390x/mmu_helper.c +5 -0
index 9daa0fd8e2..44a15449d2 100644
@@ -106,6 +106,37 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
     trigger_access_exception(env, type, ilen, tec);
 }
 
+/* check whether the address would be proteted by Low-Address Protection */
+static bool is_low_address(uint64_t addr)
+{
+    return addr < 512 || (addr >= 4096 && addr < 4607);
+}  

I like the check from the kernel sources better:

Quoted 8 lines

static inline int is_low_address(unsigned long ga)

{
    /* Check for address ranges 0..511 and 4096..4607 */
    return (ga & ~0x11fful) == 0;
}

... that might result in slightly faster code (depending on the compiler, of course).

I think that lim (readability) -> 0. Without that comment you're at first sight really clueless what this is about.

Quoted 7 lines
Quoted 4 lines

My check exactly corresponds to the wording in the PoP (and smart compilers should be able to optimize).

But I don't have a strong opinion on this micro optimization.

FWIW, I'd be happy with both, but has anyone actually looked at the generated code?

This is what I get for David's original code:

    80000510:   c4 18 00 00 0d a4       lgrl    %r1,80002058 <x1>
    80000516:   a7 29 01 ff             lghi    %r2,511
    8000051a:   ec 12 00 4f c0 65       clgrjnh %r1,%r2,800005b8 <main+0xd8>
    80000520:   a7 1b f0 00             aghi    %r1,-4096
    80000524:   c2 1e 00 00 01 fe       clgfi   %r1,510
    8000052a:   a7 18 00 00             lhi     %r1,0
    8000052e:   b9 99 00 11             slbr    %r1,%r1
    80000532:   13 11                   lcr     %r1,%r1
    80000534:   c4 1f 00 00 0d 96       strl    %r1,80002060 <b1>

And this is the optimized kernel version:

    8000054a:   c4 18 00 00 0d 7f       lgrl    %r1,80002048 <x2>
    80000550:   a5 17 ee 00             nill    %r1,60928
    80000554:   b9 00 00 11             lpgr    %r1,%r1
    80000558:   a7 1b ff ff             aghi    %r1,-1
    8000055c:   eb 11 00 3f 00 0c       srlg    %r1,%r1,63
    80000562:   c4 1f 00 00 0d 77       strl    %r1,80002050 <b2>

So that's indeed a little bit better :-)
(I was using GCC 4.8.5 from RHEL7, with -O2)

By the way, I think there's a bug in David's code: It should either be "addr <= 4607" or "addr < 4608" instead of "addr < 4607".

With that bug fixed, David's version get's optimized even more:

    80000510:   c4 18 00 00 0d a4       lgrl    %r1,80002058 <x1>
    80000516:   a5 17 ef ff             nill    %r1,61439
    8000051a:   c2 1e 00 00 01 ff       clgfi   %r1,511
    80000520:   a7 18 00 00             lhi     %r1,0
    80000524:   b9 99 00 11             slbr    %r1,%r1
    80000528:   13 11                   lcr     %r1,%r1
    8000052a:   c4 1f 00 00 0d 9b       strl    %r1,80002060 <b1>
Quoted 5 lines

... so the difference is really very minimal in that case --> We could really use the more readable version, I think.

Thomas

Very right, I'll fix that.

Nice way to find BUGs - comparing generated code :)

Thanks!

Signature · 3 lines
Thanks,

David
#13 lore raw

RFC PATCH 3/3 s390x/tcg: make STFL store into the lowcore

In reply to David Hildenbrand

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

This was originally part of a bigger STFL(E) refactoring.

---
 target/s390x/helper.h      | 2 +-
 target/s390x/misc_helper.c | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)
target/s390x/helper.h +1 -1
index 75ba04fc15..52c2963baa 100644
@@ -104,7 +104,6 @@ DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64)
 DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64)
 DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64)
 DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)
-DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_2(stfle, i32, env, i64)
 DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64)
@@ -153,6 +152,7 @@ DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_1(per_check_exception, void, env)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 
 DEF_HELPER_2(xsch, void, env, i64)
 DEF_HELPER_2(csch, void, env, i64)
target/s390x/misc_helper.c +6 -1
index 293fc8428a..0b93381188 100644
@@ -541,13 +541,18 @@ static unsigned do_stfle(CPUS390XState *env, uint64_t words[MAX_STFL_WORDS])
     return max_bit / 64;
 }
 
+#ifndef CONFIG_USER_ONLY
 void HELPER(stfl)(CPUS390XState *env)
 {
     uint64_t words[MAX_STFL_WORDS];
+    LowCore *lowcore;
 
+    lowcore = cpu_map_lowcore(env);
     do_stfle(env, words);
-    cpu_stl_data(env, 200, words[0] >> 32);
+    lowcore->stfl_fac_list = cpu_to_be32(words[0] >> 32);
+    cpu_unmap_lowcore(lowcore);
 }
+#endif
 
 uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
 {
Signature · 1 line
2.13.5
Reviewed-by on v1 3/3
#14 lore raw

Re: [Qemu-devel] [PATCH RFC 3/3] s390x/tcg: make STFL store into the lowcore

Quoted 10 lines · David Hildenbrand

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

This was originally part of a bigger STFL(E) refactoring.

---
 target/s390x/helper.h      | 2 +-
 target/s390x/misc_helper.c | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

Need to sort this patch first, so that the series is bisectable.

target/s390x/helper.h DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64) · line 156

Quoted 13 lines

DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)

target/s390x/helper.h +1 -1
-DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_2(stfle, i32, env, i64)
 DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64)
@@ -153,6 +152,7 @@ DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_1(per_check_exception, void, env)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 

Why? Otherwise,

r~

#15 lore raw

Re: [Qemu-devel] [PATCH RFC 3/3] s390x/tcg: make STFL store into the lowcore

Quoted 6 lines · Richard Henderson
Quoted 5 lines · David Hildenbrand

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

This was originally part of a bigger STFL(E) refactoring.

Quoted 7 lines
Quoted 5 lines
---
 target/s390x/helper.h      | 2 +-
 target/s390x/misc_helper.c | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

Need to sort this patch first, so that the series is bisectable.

Right, this should become #2.

Quoted 16 lines
Quoted 9 lines

DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)

target/s390x/helper.h +0 -1
-DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_2(stfle, i32, env, i64)
 DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64)

target/s390x/helper.h DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64) · line 156

Quoted 5 lines
target/s390x/helper.h +1 -0
@@ -153,6 +152,7 @@ DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_1(per_check_exception, void, env)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 

Why? Otherwise,

struct LowCore is only available for !CONFIG_USER_ONLY. Therefore I also have to move the helper declaration into !CONFIG_USER_ONLY.

Thanks!

Quoted 6 lines

r~

Signature · 3 lines
Thanks,

David
Reviewed-by
#16 lore raw

Re: [Qemu-devel] [PATCH RFC 3/3] s390x/tcg: make STFL store into the lowcore

Quoted 34 lines · David Hildenbrand
Quoted 6 lines · Richard Henderson
Quoted 5 lines · David Hildenbrand

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

This was originally part of a bigger STFL(E) refactoring.

Quoted 7 lines
Quoted 5 lines
---
 target/s390x/helper.h      | 2 +-
 target/s390x/misc_helper.c | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

Need to sort this patch first, so that the series is bisectable.

Right, this should become #2.

Quoted 16 lines
Quoted 9 lines

DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)

target/s390x/helper.h +0 -1
-DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_2(stfle, i32, env, i64)
 DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64)

target/s390x/helper.h DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64) · line 156

Quoted 5 lines
target/s390x/helper.h +1 -0
@@ -153,6 +152,7 @@ DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_1(per_check_exception, void, env)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 

Why? Otherwise,

Quoted 2 lines

struct LowCore is only available for !CONFIG_USER_ONLY. Therefore I also have to move the helper declaration into !CONFIG_USER_ONLY.

You should mention that in the patch description, that it is a privileged instruction and thus you also mark it here accordingly.

With that update:

#17 lore raw

Re: [Qemu-devel] [PATCH RFC 3/3] s390x/tcg: make STFL store into the lowcore

In reply to David Hildenbrand
Quoted 10 lines · On Wed, 27 Sep 2017 19:00:27 +0200 David Hildenbrand <[email protected]> wrote:

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

This was originally part of a bigger STFL(E) refactoring.

---
 target/s390x/helper.h      | 2 +-
 target/s390x/misc_helper.c | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

Thanks, applied (with updated patch description).

#18 lore raw
In reply to David Hildenbrand
Quoted 8 lines · On Wed, 27 Sep 2017 19:00:24 +0200 David Hildenbrand <[email protected]> wrote:

Details about Low-Address Protection can be found in description of patch 1 and 2. It is basically a subpage protection of the first two pages of every address space (for which it is enabled).

We can achieve this by simply directly invalidating the TLB entry and therefore forcing every write accesses onto these two pages into the slow path.

Quoted 8 lines

With this patch, I can boot Linux just fine (which uses LAP). This also makes all related kvm-unit-tests that we have pass.

The checks are working that good, that I discovered a STFL bug. STFL stores into the low addresses but low-address protection does explicitly not apply. The Linux kernel calls STFL while LAP is active. So without patch nr 3, booting Linux will fail. (this change is also part of a patch of my SMP series).

I fear I have lost track a bit with all those patches floating around. IIUC, patch 3 fixes a real bug that is only exposed by your LAP changes. It used to be part of the stfl changes in v1 of your smp series but is no longer in v2. So, is this a patch that can be applied to current s390-next?

Quoted 20 lines

Based on: https://github.com/cohuck/qemu.git s390-next Available on: https://github.com/dhildenb/qemu.git s390x_lap

David Hildenbrand (3):
accel/tcg: allow to invalidate a write TLB entry immediately s390x/tcg: low-address protection support s390x/tcg: make STFL store into the lowcore

 accel/tcg/cputlb.c           |  5 ++-
 accel/tcg/softmmu_template.h |  4 +-
 include/exec/cpu-all.h       |  3 ++
 target/s390x/excp_helper.c   |  3 +-
 target/s390x/helper.h        |  2 +-
 target/s390x/mem_helper.c    |  8 ----
 target/s390x/misc_helper.c   |  7 +++-
 target/s390x/mmu_helper.c    | 96 ++++++++++++++++++++++++++++----------------
 8 files changed, 78 insertions(+), 50 deletions(-)
author Reviewed-by Richard Henderson Reviewed-by Thomas Huth
#19 lore raw
Quoted 20 lines · Cornelia Huck
Quoted 8 lines · On Wed, 27 Sep 2017 19:00:24 +0200 David Hildenbrand <[email protected]> wrote:

Details about Low-Address Protection can be found in description of patch 1 and 2. It is basically a subpage protection of the first two pages of every address space (for which it is enabled).

We can achieve this by simply directly invalidating the TLB entry and therefore forcing every write accesses onto these two pages into the slow path.

Quoted 8 lines

With this patch, I can boot Linux just fine (which uses LAP). This also makes all related kvm-unit-tests that we have pass.

The checks are working that good, that I discovered a STFL bug. STFL stores into the low addresses but low-address protection does explicitly not apply. The Linux kernel calls STFL while LAP is active. So without patch nr 3, booting Linux will fail. (this change is also part of a patch of my SMP series).

Quoted 6 lines

I fear I have lost track a bit with all those patches floating around. IIUC, patch 3 fixes a real bug that is only exposed by your LAP changes. It used to be part of the stfl changes in v1 of your smp series but is no longer in v2. So, is this a patch that can be applied to current s390-next?

The SMP series is based on both, this series and the CPU cleanup series you already picked up.

You can apply Patch 3 with the following modified description (requested by Thomas):

s390x/tcg: make STFL store into the lowcore

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

STFL is a privileged instruction and using LowCore requires !CONFIG_USER_ONLY, so add the ifdef and move the declaration to the right place.

This was originally part of a bigger STFL(E) refactoring.

The other two patches, I will resend once we know how to handle the TLB invalidation.

Quoted 21 lines
Quoted 20 lines

Based on: https://github.com/cohuck/qemu.git s390-next Available on: https://github.com/dhildenb/qemu.git s390x_lap

David Hildenbrand (3):
accel/tcg: allow to invalidate a write TLB entry immediately s390x/tcg: low-address protection support s390x/tcg: make STFL store into the lowcore

 accel/tcg/cputlb.c           |  5 ++-
 accel/tcg/softmmu_template.h |  4 +-
 include/exec/cpu-all.h       |  3 ++
 target/s390x/excp_helper.c   |  3 +-
 target/s390x/helper.h        |  2 +-
 target/s390x/mem_helper.c    |  8 ----
 target/s390x/misc_helper.c   |  7 +++-
 target/s390x/mmu_helper.c    | 96 ++++++++++++++++++++++++++++----------------
 8 files changed, 78 insertions(+), 50 deletions(-)
Signature · 3 lines
Thanks,

David
#20 lore raw
Quoted 46 lines · On Fri, 29 Sep 2017 14:09:04 +0200 David Hildenbrand <[email protected]> wrote:
Quoted 20 lines · Cornelia Huck
Quoted 8 lines · On Wed, 27 Sep 2017 19:00:24 +0200 David Hildenbrand <[email protected]> wrote:

Details about Low-Address Protection can be found in description of patch 1 and 2. It is basically a subpage protection of the first two pages of every address space (for which it is enabled).

We can achieve this by simply directly invalidating the TLB entry and therefore forcing every write accesses onto these two pages into the slow path.

Quoted 8 lines

With this patch, I can boot Linux just fine (which uses LAP). This also makes all related kvm-unit-tests that we have pass.

The checks are working that good, that I discovered a STFL bug. STFL stores into the low addresses but low-address protection does explicitly not apply. The Linux kernel calls STFL while LAP is active. So without patch nr 3, booting Linux will fail. (this change is also part of a patch of my SMP series).

Quoted 6 lines

I fear I have lost track a bit with all those patches floating around. IIUC, patch 3 fixes a real bug that is only exposed by your LAP changes. It used to be part of the stfl changes in v1 of your smp series but is no longer in v2. So, is this a patch that can be applied to current s390-next?

The SMP series is based on both, this series and the CPU cleanup series you already picked up.

You can apply Patch 3 with the following modified description (requested by Thomas):

s390x/tcg: make STFL store into the lowcore

Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL.

STFL is a privileged instruction and using LowCore requires !CONFIG_USER_ONLY, so add the ifdef and move the declaration to the right place.

This was originally part of a bigger STFL(E) refactoring.

Quoted 7 lines

The other two patches, I will resend once we know how to handle the TLB invalidation.

OK, thanks for the clarification!