diff mbox series

mambo/mambo_utils.tcl: Inject an MCE at a specified address

Message ID 20180410112518.18604-1-bsingharora@gmail.com
State Superseded
Headers show
Series mambo/mambo_utils.tcl: Inject an MCE at a specified address | expand

Commit Message

Balbir Singh April 10, 2018, 11:25 a.m. UTC
Currently we don't support injecting an MCE on a specific address.
This is useful for testing functionality like memcpy_mcsafe()
(see https://patchwork.ozlabs.org/cover/893339/)

This patch refactors exc_mce into setup_mce and exc_mce. setup_mce
is generally useful to setup a MCE context with variables DSISR,
SRR1 and DAR. setup_mce supports setting up dsisr as a new
function argument. It's useful when we want to set up both the
cause and DSIR.

The core of the functionality is a routine called
inject_mce_ue_on_addr, which takes an addr argument and injects
an MCE (load/store with UE) when the specified address is accessed
by code. This functionality can easily be enhanced to cover
instruction UE's as well.

Signed-off-by: Balbir Singh <bsingharora@gmail.com>
---
 external/mambo/mambo_utils.tcl | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

Comments

Nicholas Piggin April 10, 2018, 1:14 p.m. UTC | #1
On Tue, 10 Apr 2018 21:25:18 +1000
Balbir Singh <bsingharora@gmail.com> wrote:

> Currently we don't support injecting an MCE on a specific address.
> This is useful for testing functionality like memcpy_mcsafe()
> (see https://patchwork.ozlabs.org/cover/893339/)
> 
> This patch refactors exc_mce into setup_mce and exc_mce. setup_mce
> is generally useful to setup a MCE context with variables DSISR,
> SRR1 and DAR. setup_mce supports setting up dsisr as a new
> function argument. It's useful when we want to set up both the
> cause and DSIR.

Hum, I actually have a patch sitting around that reworks this stuff
quite significantly for stop states (which mambo doesn't handle very
well). It doesn't look like there's a big conflict, but if I can send
it and get you to test and merge on top of it that would be good.

> 
> The core of the functionality is a routine called
> inject_mce_ue_on_addr, which takes an addr argument and injects
> an MCE (load/store with UE) when the specified address is accessed
> by code. This functionality can easily be enhanced to cover
> instruction UE's as well.
> 
> Signed-off-by: Balbir Singh <bsingharora@gmail.com>
> ---
>  external/mambo/mambo_utils.tcl | 29 ++++++++++++++++++++++++-----
>  1 file changed, 24 insertions(+), 5 deletions(-)
> 
> diff --git a/external/mambo/mambo_utils.tcl b/external/mambo/mambo_utils.tcl
> index 7a27f0f4..a9225e3e 100644
> --- a/external/mambo/mambo_utils.tcl
> +++ b/external/mambo/mambo_utils.tcl
> @@ -442,11 +442,12 @@ proc mce_trigger { args } {
>  #
>  # Default with no arguments is a recoverable i-side TLB multi-hit
>  # Other options:
> -# d_side=1 cause=0x80 - recoverable d-side SLB multi-hit
> +# d_side=1 dsisr=0x80 - recoverable d-side SLB multi-hit
> +# d_side=1 dsisr=0x8000, cause=0x1 - ue error on instruction fetch
>  # d_side=0 cause=0xd  - unrecoverable i-side async store timeout (POWER9 only)
>  # d_side=0 cause=0x1  - unrecoverable i-side ifetch
>  #
> -proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
> +proc setup_mce { { d_side 0 } {dsisr 0x5} { cause 0x5 } { recoverable 1 }} {
>      variable SRR1
>      variable DSISR
>      variable DAR
> @@ -466,11 +467,10 @@ proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
>          set msr_ri 0x0
>      }
>  
> -    # recoverable d-side SLB multihit
>      if { $d_side } {
>          set is_dside 1
> -        set SRR1_mc_cause 0x0
> -        set DSISR $cause
> +        set SRR1_mc_cause $cause
> +        set DSISR $dsisr
>          set DAR 0xdeadbeefdeadbeef
>      } else {
>          set is_dside 0

This doesn't seem right. ue error on ifetch is i-side which can not
set DSISR. I have the ifetch UE in the comment. What was wrong with
the original code here?

Thanks,
Nick
Balbir Singh April 10, 2018, 9 p.m. UTC | #2
On Tue, Apr 10, 2018 at 11:14 PM, Nicholas Piggin <npiggin@gmail.com> wrote:
> On Tue, 10 Apr 2018 21:25:18 +1000
> Balbir Singh <bsingharora@gmail.com> wrote:
>
>> Currently we don't support injecting an MCE on a specific address.
>> This is useful for testing functionality like memcpy_mcsafe()
>> (see https://patchwork.ozlabs.org/cover/893339/)
>>
>> This patch refactors exc_mce into setup_mce and exc_mce. setup_mce
>> is generally useful to setup a MCE context with variables DSISR,
>> SRR1 and DAR. setup_mce supports setting up dsisr as a new
>> function argument. It's useful when we want to set up both the
>> cause and DSIR.
>
> Hum, I actually have a patch sitting around that reworks this stuff
> quite significantly for stop states (which mambo doesn't handle very
> well). It doesn't look like there's a big conflict, but if I can send
> it and get you to test and merge on top of it that would be good.

Sure, send it across

>
>>
>> The core of the functionality is a routine called
>> inject_mce_ue_on_addr, which takes an addr argument and injects
>> an MCE (load/store with UE) when the specified address is accessed
>> by code. This functionality can easily be enhanced to cover
>> instruction UE's as well.
>>
>> Signed-off-by: Balbir Singh <bsingharora@gmail.com>
>> ---
>>  external/mambo/mambo_utils.tcl | 29 ++++++++++++++++++++++++-----
>>  1 file changed, 24 insertions(+), 5 deletions(-)
>>
>> diff --git a/external/mambo/mambo_utils.tcl b/external/mambo/mambo_utils.tcl
>> index 7a27f0f4..a9225e3e 100644
>> --- a/external/mambo/mambo_utils.tcl
>> +++ b/external/mambo/mambo_utils.tcl
>> @@ -442,11 +442,12 @@ proc mce_trigger { args } {
>>  #
>>  # Default with no arguments is a recoverable i-side TLB multi-hit
>>  # Other options:
>> -# d_side=1 cause=0x80 - recoverable d-side SLB multi-hit
>> +# d_side=1 dsisr=0x80 - recoverable d-side SLB multi-hit
>> +# d_side=1 dsisr=0x8000, cause=0x1 - ue error on instruction fetch
>>  # d_side=0 cause=0xd  - unrecoverable i-side async store timeout (POWER9 only)
>>  # d_side=0 cause=0x1  - unrecoverable i-side ifetch
>>  #
>> -proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
>> +proc setup_mce { { d_side 0 } {dsisr 0x5} { cause 0x5 } { recoverable 1 }} {
>>      variable SRR1
>>      variable DSISR
>>      variable DAR
>> @@ -466,11 +467,10 @@ proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
>>          set msr_ri 0x0
>>      }
>>
>> -    # recoverable d-side SLB multihit
>>      if { $d_side } {
>>          set is_dside 1
>> -        set SRR1_mc_cause 0x0
>> -        set DSISR $cause
>> +        set SRR1_mc_cause $cause
>> +        set DSISR $dsisr
>>          set DAR 0xdeadbeefdeadbeef
>>      } else {
>>          set is_dside 0
>
> This doesn't seem right. ue error on ifetch is i-side which can not
> set DSISR. I have the ifetch UE in the comment. What was wrong with
> the original code here?
>

This is called from a trigger on data access and sets up an MCE with
d_side set to 1.
So it's not an ifetch i-side change. Am I missing something?

Balbir Singh
Nicholas Piggin April 10, 2018, 10:19 p.m. UTC | #3
On Wed, 11 Apr 2018 07:00:06 +1000
Balbir Singh <bsingharora@gmail.com> wrote:

> On Tue, Apr 10, 2018 at 11:14 PM, Nicholas Piggin <npiggin@gmail.com> wrote:
> > On Tue, 10 Apr 2018 21:25:18 +1000
> > Balbir Singh <bsingharora@gmail.com> wrote:
> >  
> >> Currently we don't support injecting an MCE on a specific address.
> >> This is useful for testing functionality like memcpy_mcsafe()
> >> (see https://patchwork.ozlabs.org/cover/893339/)
> >>
> >> This patch refactors exc_mce into setup_mce and exc_mce. setup_mce
> >> is generally useful to setup a MCE context with variables DSISR,
> >> SRR1 and DAR. setup_mce supports setting up dsisr as a new
> >> function argument. It's useful when we want to set up both the
> >> cause and DSIR.  
> >
> > Hum, I actually have a patch sitting around that reworks this stuff
> > quite significantly for stop states (which mambo doesn't handle very
> > well). It doesn't look like there's a big conflict, but if I can send
> > it and get you to test and merge on top of it that would be good.  
> 
> Sure, send it across

I put it on the end of this email.

> >>
> >> The core of the functionality is a routine called
> >> inject_mce_ue_on_addr, which takes an addr argument and injects
> >> an MCE (load/store with UE) when the specified address is accessed
> >> by code. This functionality can easily be enhanced to cover
> >> instruction UE's as well.
> >>
> >> Signed-off-by: Balbir Singh <bsingharora@gmail.com>
> >> ---
> >>  external/mambo/mambo_utils.tcl | 29 ++++++++++++++++++++++++-----
> >>  1 file changed, 24 insertions(+), 5 deletions(-)
> >>
> >> diff --git a/external/mambo/mambo_utils.tcl b/external/mambo/mambo_utils.tcl
> >> index 7a27f0f4..a9225e3e 100644
> >> --- a/external/mambo/mambo_utils.tcl
> >> +++ b/external/mambo/mambo_utils.tcl
> >> @@ -442,11 +442,12 @@ proc mce_trigger { args } {
> >>  #
> >>  # Default with no arguments is a recoverable i-side TLB multi-hit
> >>  # Other options:
> >> -# d_side=1 cause=0x80 - recoverable d-side SLB multi-hit
> >> +# d_side=1 dsisr=0x80 - recoverable d-side SLB multi-hit
> >> +# d_side=1 dsisr=0x8000, cause=0x1 - ue error on instruction fetch
> >>  # d_side=0 cause=0xd  - unrecoverable i-side async store timeout (POWER9 only)
> >>  # d_side=0 cause=0x1  - unrecoverable i-side ifetch
> >>  #
> >> -proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
> >> +proc setup_mce { { d_side 0 } {dsisr 0x5} { cause 0x5 } { recoverable 1 }} {
> >>      variable SRR1
> >>      variable DSISR
> >>      variable DAR
> >> @@ -466,11 +467,10 @@ proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
> >>          set msr_ri 0x0
> >>      }
> >>
> >> -    # recoverable d-side SLB multihit
> >>      if { $d_side } {
> >>          set is_dside 1
> >> -        set SRR1_mc_cause 0x0
> >> -        set DSISR $cause
> >> +        set SRR1_mc_cause $cause
> >> +        set DSISR $dsisr
> >>          set DAR 0xdeadbeefdeadbeef
> >>      } else {
> >>          set is_dside 0  
> >
> > This doesn't seem right. ue error on ifetch is i-side which can not
> > set DSISR. I have the ifetch UE in the comment. What was wrong with
> > the original code here?
> >  
> 
> This is called from a trigger on data access and sets up an MCE with
> d_side set to 1.
> So it's not an ifetch i-side change. Am I missing something?

Oh I was talking about the previous hunk as well.

d-side MCEs don't get SRR1 set, which is why the cause is DSISR when
it's d-side, and SRR1 when it's i-side.

Thanks,
Nick

external/mambo: improve helper for machine checks

Improve workarounds for stop injection, because mambo often will
trigger on 0x104/204 when waking from stop.

This also adds a workaround to skip injecting on reservations to
avoid infinite loops when doing inject_mce_step.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 external/mambo/mambo_utils.tcl | 62 +++++++++++++++++++++++++++++-----
 1 file changed, 53 insertions(+), 9 deletions(-)

diff --git a/external/mambo/mambo_utils.tcl b/external/mambo/mambo_utils.tcl
index 7a27f0f4..6cbb222a 100644
--- a/external/mambo/mambo_utils.tcl
+++ b/external/mambo/mambo_utils.tcl
@@ -378,6 +378,7 @@ proc sreset_trigger { args } {
     variable SRR1
 
     mysim trigger clear pc 0x100
+    mysim trigger clear pc 0x104
     set s [expr [mysim cpu 0 display spr srr1] & ~0x00000000003c0002]
     set SRR1 [expr $SRR1 | $s]
     mysim cpu 0 set spr srr1 $SRR1
@@ -410,14 +411,23 @@ proc exc_sreset { } {
 
     if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } {
         # mambo has a quirk that interrupts from idle wake immediately
+        # and go over current instruction.
         mysim trigger set pc 0x100 "sreset_trigger"
-        mysim cpu 0 interrupt MachineCheck
-	# XXX: only trigger if pc is 0x100
-	sreset_trigger
+        mysim trigger set pc 0x104 "sreset_trigger"
+        mysim cpu 0 interrupt SystemReset
     } else {
         mysim trigger set pc 0x100 "sreset_trigger"
+        mysim trigger set pc 0x104 "sreset_trigger"
         mysim cpu 0 interrupt SystemReset
     }
+
+    # sleep and sometimes other types of interrupts do not trigger 0x100
+    if { [expr [mysim cpu 0 display spr pc] == 0x100 ] } {
+	sreset_trigger
+    }
+    if { [expr [mysim cpu 0 display spr pc] == 0x104 ] } {
+	sreset_trigger
+    }
 }
 
 proc mce_trigger { args } {
@@ -426,12 +436,13 @@ proc mce_trigger { args } {
     variable DAR
 
     mysim trigger clear pc 0x200
+    mysim trigger clear pc 0x204
 
     set s [expr [mysim cpu 0 display spr srr1] & ~0x00000000801f0002]
     set SRR1 [expr $SRR1 | $s]
     mysim cpu 0 set spr srr1 $SRR1
     mysim cpu 0 set spr dsisr $DSISR
-    mysim cpu 0 set spr dar $DAR
+    mysim cpu 0 set spr dar $DAR ; list
 }
 
 #
@@ -451,6 +462,8 @@ proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
     variable DSISR
     variable DAR
 
+#    puts "INJECTING MCE"
+
     # In case of recoverable MCE, idle wakeup always sets RI, others get
     # RI from current environment. For unrecoverable, RI would always be
     # clear by hardware.
@@ -466,7 +479,6 @@ proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
         set msr_ri 0x0
     }
 
-    # recoverable d-side SLB multihit
     if { $d_side } {
         set is_dside 1
         set SRR1_mc_cause 0x0
@@ -489,14 +501,23 @@ proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
 
     if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } {
         # mambo has a quirk that interrupts from idle wake immediately
+        # and go over current instruction.
         mysim trigger set pc 0x200 "mce_trigger"
+        mysim trigger set pc 0x204 "mce_trigger"
         mysim cpu 0 interrupt MachineCheck
-	# XXX: only trigger if pc is 0x200
-	mce_trigger
     } else {
         mysim trigger set pc 0x200 "mce_trigger"
+        mysim trigger set pc 0x204 "mce_trigger"
         mysim cpu 0 interrupt MachineCheck
     }
+
+    # sleep and sometimes other types of interrupts do not trigger 0x200
+    if { [expr [mysim cpu 0 display spr pc] == 0x200 ] } {
+	mce_trigger
+    }
+    if { [expr [mysim cpu 0 display spr pc] == 0x204 ] } {
+	mce_trigger
+    }
 }
 
 global R1
@@ -536,11 +557,34 @@ proc inject_mce_step { {nr 1} } {
 
 # inject if RI is set and step over one instruction, and repeat.
 proc inject_mce_step_ri { {nr 1} } {
+    set reserve_inject 1
+    set reserve_inject_skip 0
+    set reserve_counter 0
+
     for { set i 0 } { $i < $nr } { incr i 1 } {
         if { [expr [mysim cpu 0 display spr msr] & 0x2] } {
-            inject_mce
+            # inject_mce
+            if { [mysim cpu 0 display reservation] in { "none" } } {
+                inject_mce
+                mysim cpu 0 set reservation none
+                if { $reserve_inject_skip } {
+                    set reserve_inject 1
+                    set reserve_inject_skip 0
+                }
+            } else {
+                if { $reserve_inject } {
+                    inject_mce
+                    mysim cpu 0 set reservation none
+                    set reserve_inject 0
+                } else {
+                    set reserve_inject_skip 1
+                    set reserve_counter [ expr $reserve_counter + 1 ]
+                    if { $reserve_counter > 30 } {
+                        mysim cpu 0 set reservation none
+                    }
+                }
+            }
         }
         s
     }
 }
-
diff mbox series

Patch

diff --git a/external/mambo/mambo_utils.tcl b/external/mambo/mambo_utils.tcl
index 7a27f0f4..a9225e3e 100644
--- a/external/mambo/mambo_utils.tcl
+++ b/external/mambo/mambo_utils.tcl
@@ -442,11 +442,12 @@  proc mce_trigger { args } {
 #
 # Default with no arguments is a recoverable i-side TLB multi-hit
 # Other options:
-# d_side=1 cause=0x80 - recoverable d-side SLB multi-hit
+# d_side=1 dsisr=0x80 - recoverable d-side SLB multi-hit
+# d_side=1 dsisr=0x8000, cause=0x1 - ue error on instruction fetch
 # d_side=0 cause=0xd  - unrecoverable i-side async store timeout (POWER9 only)
 # d_side=0 cause=0x1  - unrecoverable i-side ifetch
 #
-proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
+proc setup_mce { { d_side 0 } {dsisr 0x5} { cause 0x5 } { recoverable 1 }} {
     variable SRR1
     variable DSISR
     variable DAR
@@ -466,11 +467,10 @@  proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
         set msr_ri 0x0
     }
 
-    # recoverable d-side SLB multihit
     if { $d_side } {
         set is_dside 1
-        set SRR1_mc_cause 0x0
-        set DSISR $cause
+        set SRR1_mc_cause $cause
+        set DSISR $dsisr
         set DAR 0xdeadbeefdeadbeef
     } else {
         set is_dside 0
@@ -486,7 +486,10 @@  proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } {
     set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 2) & 0x1) << (63-43))]
     set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 1) & 0x1) << (63-44))]
     set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 0) & 0x1) << (63-45))]
+}
 
+proc exc_mce { { d_side 0 } {dsisr 0x5} { cause 0x5 } { recoverable 1 }} {
+    setup_mce $d_side $dsisr $cause $recoverable
     if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } {
         # mambo has a quirk that interrupts from idle wake immediately
         mysim trigger set pc 0x200 "mce_trigger"
@@ -526,6 +529,22 @@  proc inject_mce { } {
     mysim trigger clear pc $pc ; list
 }
 
+#
+# We've stopped at addr and we need to inject the mce and continue
+#
+proc trigger_mce_ue_addr {args} {
+	set addr [lindex [lindex $args 0] 1]
+	mysim trigger clear memory system rw $addr $addr
+	setup_mce 0x1 0x8000 0x1 0x1
+	mysim trigger set pc 0x200 "mce_trigger"
+	mysim cpu 0 interrupt MachineCheck
+	mce_trigger
+}
+
+proc inject_mce_ue_on_addr {addr} {
+	mysim trigger set memory system rw $addr $addr 1 "trigger_mce_ue_addr"
+}
+
 # inject and step over one instruction, and repeat.
 proc inject_mce_step { {nr 1} } {
     for { set i 0 } { $i < $nr } { incr i 1 } {