aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/external/mambo/mambo_utils.tcl
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/external/mambo/mambo_utils.tcl
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/external/mambo/mambo_utils.tcl')
-rw-r--r--roms/skiboot/external/mambo/mambo_utils.tcl794
1 files changed, 794 insertions, 0 deletions
diff --git a/roms/skiboot/external/mambo/mambo_utils.tcl b/roms/skiboot/external/mambo/mambo_utils.tcl
new file mode 100644
index 000000000..96f8971ab
--- /dev/null
+++ b/roms/skiboot/external/mambo/mambo_utils.tcl
@@ -0,0 +1,794 @@
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Make Mambo behave a bit more like gdb
+#
+set target_t 0
+set target_c 0
+set target_p 0
+
+proc target { { t 0 } { c 0 } { p 0 } } {
+ global target_t
+ global target_c
+ global target_p
+
+ set target_t $t
+ set target_c $c
+ set target_p $p
+
+ return "targeting cpu $p:$c:$t"
+}
+
+proc p { reg { t -1 } { c -1 } { p -1 } } {
+ global target_t
+ global target_c
+ global target_p
+
+ if { $t == -1 } { set t $target_t }
+ if { $c == -1 } { set c $target_c }
+ if { $p == -1 } { set p $target_p }
+
+ switch -regexp $reg {
+ ^r$ {
+ set val [mysim cpu $p:$c:$t display gprs]
+ }
+ ^r[0-9]+$ {
+ regexp "r(\[0-9\]*)" $reg dummy num
+ set val [mysim cpu $p:$c:$t display gpr $num]
+ }
+ ^f[0-9]+$ {
+ regexp "f(\[0-9\]*)" $reg dummy num
+ set val [mysim cpu $p:$c:$t display fpr $num]
+ }
+ ^v[0-9]+$ {
+ regexp "v(\[0-9\]*)" $reg dummy num
+ set val [mysim cpu $p:$c:$t display vmxr $num]
+ }
+ default {
+ set val [mysim cpu $p:$c:$t display spr $reg]
+ }
+ }
+
+ return "$val"
+}
+
+#
+# behave like gdb
+#
+proc sr { reg val { t -1} { c -1 } { p -1 } } {
+ global target_t
+ global target_c
+ global target_p
+
+ if { $t == -1 } { set t $target_t }
+ if { $c == -1 } { set c $target_c }
+ if { $p == -1 } { set p $target_p }
+
+ switch -regexp $reg {
+ ^r[0-9]+$ {
+ regexp "r(\[0-9\]*)" $reg dummy num
+ mysim cpu $p:$c:$t set gpr $num $val
+ }
+ ^f[0-9]+$ {
+ regexp "f(\[0-9\]*)" $reg dummy num
+ mysim cpu $p:$c:$t set fpr $num $val
+ }
+ ^v[0-9]+$ {
+ regexp "v(\[0-9\]*)" $reg dummy num
+ mysim cpu $p:$c:$t set vmxr $num $val
+ }
+ default {
+ mysim cpu $p:$c:$t set spr $reg $val
+ }
+ }
+ p $reg $t
+}
+
+proc b { addr } {
+ mysim trigger set pc $addr "just_stop"
+ set at [i $addr]
+ puts "breakpoint set at $at"
+}
+
+# Run until $console_string appears on the Linux console
+#
+# eg.
+# break_on_console "Freeing unused kernel memory:"
+# break_on_console "buildroot login:"
+
+proc break_on_console { console_string } {
+ mysim trigger set console "$console_string" "just_stop"
+}
+
+proc clear_console_break { console_string } {
+ mysim trigger clear console "$console_string"
+}
+
+proc wr { start stop } {
+ mysim trigger set memory system w $start $stop 0 "just_stop"
+}
+
+proc c { } {
+ mysim go
+}
+
+proc i { pc { t -1 } { c -1 } { p -1 } } {
+ global target_t
+ global target_c
+ global target_p
+
+ if { $t == -1 } { set t $target_t }
+ if { $c == -1 } { set c $target_c }
+ if { $p == -1 } { set p $target_p }
+
+ set pc_laddr [mysim cpu $p:$c:$t util itranslate $pc]
+ set inst [mysim cpu $p:$c:$t memory display $pc_laddr 4]
+ set disasm [mysim cpu $p:$c:$t util ppc_disasm $inst $pc]
+ return "\[$p:$c:$t\]: $pc ($pc_laddr) Enc:$inst : $disasm"
+}
+
+proc ipc { { t -1 } { c -1 } { p -1 } } {
+ global target_t
+ global target_c
+ global target_p
+
+ if { $t == -1 } { set t $target_t }
+ if { $c == -1 } { set c $target_c }
+ if { $p == -1 } { set p $target_p }
+
+ set pc [mysim cpu $p:$c:$t display spr pc]
+ i $pc $t $c $p
+}
+
+proc ipca { } {
+ set cpus [myconf query cpus]
+ set threads [myconf query processor/number_of_threads]
+
+ for { set i 0 } { $i < $cpus } { incr i 1 } {
+ for { set j 0 } { $j < $threads } { incr j 1 } {
+ puts [ipc $j $i]
+ }
+ }
+}
+
+proc pa { spr } {
+ set cpus [myconf query cpus]
+ set threads [myconf query processor/number_of_threads]
+
+ for { set i 0 } { $i < $cpus } { incr i 1 } {
+ for { set j 0 } { $j < $threads } { incr j 1 } {
+ set val [mysim cpu $i thread $j display spr $spr]
+ puts "CPU: $i THREAD: $j SPR $spr = $val"
+ }
+ }
+}
+
+proc s { {nr 1} } {
+ for { set i 0 } { $i < $nr } { incr i 1 } {
+ mysim step 1
+ ipca
+ }
+}
+
+proc S { {nr 1} } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ for { set i 0 } { $i < $nr } { incr i 1 } {
+ mysim cpu $p:$c:$t step 1
+ puts [ipc]
+ }
+}
+
+proc z { count } {
+ while { $count > 0 } {
+ s
+ incr count -1
+ }
+}
+
+proc sample_pc { sample count } {
+ while { $count > 0 } {
+ mysim cycle $sample
+ ipc
+ incr count -1
+ }
+}
+
+proc e2p { ea } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set pa [ mysim cpu $p:$c:$t util dtranslate $ea ]
+ puts "$pa"
+}
+
+proc x { pa { size 8 } } {
+ set val [ mysim memory display $pa $size ]
+ puts "$pa : $val"
+}
+
+proc it { ea } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ mysim cpu $p:$c:$t util itranslate $ea
+}
+proc dt { ea } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ mysim cpu $p:$c:$t util dtranslate $ea
+}
+
+proc ex { ea { size 8 } } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set pa [ mysim cpu $p:$c:$t util dtranslate $ea ]
+ set val [ mysim memory display $pa $size ]
+ puts "$pa : $val"
+}
+
+proc di { location { count 16 } } {
+ set addr [expr $location & 0xfffffffffffffff0]
+ disasm_mem mysim $addr $count
+}
+
+proc hexdump { location count } {
+ set addr [expr $location & 0xfffffffffffffff0]
+ set top [expr $addr + ($count * 15)]
+ for { set i $addr } { $i < $top } { incr i 16 } {
+ set val [expr $i + (4 * 0)]
+ set val0 [format "%08x" [mysim memory display $val 4]]
+ set val [expr $i + (4 * 1)]
+ set val1 [format "%08x" [mysim memory display $val 4]]
+ set val [expr $i + (4 * 2)]
+ set val2 [format "%08x" [mysim memory display $val 4]]
+ set val [expr $i + (4 * 3)]
+ set val3 [format "%08x" [mysim memory display $val 4]]
+
+ set ascii ""
+ for { set j 0 } { $j < 16 } { incr j } {
+ set byte [get_char [expr $i + $j]]
+ if { $byte < 0x20 || $byte >= 127} {
+ set c "."
+ } else {
+ set c [format %c $byte]
+ }
+ set ascii [string cat "$ascii" "$c"]
+ }
+
+ set loc [format "0x%016x" $i]
+ puts "$loc: $val0 $val1 $val2 $val3 $ascii"
+ }
+}
+
+proc get_char { addr } {
+ return [expr [mysim memory display "$addr" 1]]
+}
+
+proc p_str { addr { limit 0 } } {
+ set addr_limit 0xfffffffffffffffff
+ if { $limit > 0 } { set addr_limit [expr $limit + $addr] }
+ set s ""
+
+ for {} { [get_char "$addr"] != 0} { incr addr 1 } {
+ # memory display returns hex values with a leading 0x
+ set c [format %c [get_char "$addr"]]
+ set s [string cat "$s" "$c"]
+ if { $addr == $addr_limit } { break }
+ }
+
+ puts "$s"
+}
+
+proc slbv {} {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ puts [mysim cpu $p:$c:$t display slb valid]
+}
+
+proc regs { { t -1 } { c -1 } { p -1 }} {
+ global target_t
+ global target_c
+ global target_p
+
+ if { $t == -1 } { set t $target_t }
+ if { $c == -1 } { set c $target_c }
+ if { $p == -1 } { set p $target_p }
+
+ puts "GPRS:"
+ puts [mysim cpu $p:$c:$t display gprs]
+}
+
+proc tlbv {} {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ puts "$p:$c:$t:TLB: ----------------------"
+ puts [mysim cpu $p:$c:$t display tlb valid]
+}
+
+proc exc { { i SystemReset } } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ puts "$p:$c:$t:EXCEPTION:$i"
+ puts [mysim cpu $p:$c:$t interrupt $i]
+}
+
+proc just_stop { args } {
+ simstop
+ ipca
+}
+
+proc st { count } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set sp [mysim cpu $p:$c:$t display gpr 1]
+ puts "SP: $sp"
+ ipc
+ set lr [mysim cpu $p:$c:$t display spr lr]
+ i $lr
+ while { $count > 0 } {
+ set sp [mysim cpu $p:$c:$t util itranslate $sp]
+ set lr [mysim memory display [expr $sp++16] 8]
+ i $lr
+ set sp [mysim memory display $sp 8]
+
+ incr count -1
+ }
+}
+
+proc mywatch { } {
+ while { [mysim memory display 0x700 8] != 0 } {
+ mysim cycle 1
+ }
+ puts "condition occurred "
+ ipc
+}
+
+#
+# force gdb to attach
+#
+proc gdb { { timeout 0 } } {
+ mysim set fast off
+ mysim debugger wait $timeout
+}
+
+proc egdb { { timeout 0 }} {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set srr0 [mysim cpu $p:$c:$t display spr srr0]
+ set srr1 [mysim cpu $p:$c:$t display spr srr1]
+ mysim cpu $p:$c:$t set spr pc $srr0
+ mysim cpu $p:$c:$t set spr msr $srr1
+ gdb $timeout
+}
+
+proc mem_display_64_le { addr } {
+ set data 0
+ for {set i 0} {$i < 8} {incr i} {
+ set data [ expr $data << 8 ]
+ set l [ mysim memory display [ expr $addr+7-$i ] 1 ]
+ set data [ expr $data | $l ]
+ }
+ return [format 0x%X $data]
+}
+
+proc mem_display_64 { addr le } {
+ if { $le } {
+ return [ mem_display_64_le $addr ]
+ }
+ # mysim memory display is big endian
+ return [ mysim memory display $addr 8 ]
+}
+
+proc bt { {sp 0} } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set lr [mysim cpu $p:$c:$t display spr pc]
+ set sym [addr2func $lr]
+ puts "pc:\t\t\t\t$lr\t$sym"
+ if { $sp == 0 } {
+ set sp [mysim cpu $p:$c:$t display gpr 1]
+ }
+ set lr [mysim cpu $p:$c:$t display spr lr]
+ set sym [addr2func $lr]
+ puts "lr:\t\t\t\t$lr\t$sym"
+
+ set msr [mysim cpu $p:$c:$t display spr msr]
+ set le [ expr $msr & 1 ]
+
+ # Limit to 200 in case of an infinite loop
+ for {set i 0} {$i < 200} {incr i} {
+ set pa [ mysim cpu $p:$c:$t util dtranslate $sp ]
+ set bc [ mem_display_64 $pa $le ]
+ set lr [ mem_display_64 [ expr $pa + 16 ] $le ]
+ set sym [addr2func $lr]
+ puts "stack:$pa \t$lr\t$sym"
+ if { $bc == 0 } { break }
+ set sp $bc
+ }
+ puts ""
+}
+
+proc ton { } {mysim mode turbo }
+proc toff { } {mysim mode simple }
+
+proc don { opt } {
+ simdebug set $opt 1
+}
+
+proc doff { opt } {
+ simdebug set $opt 0
+}
+
+# skisym and linsym return the address of a symbol, looked up from
+# the relevant System.map or skiboot.map file.
+proc linsym { name } {
+ global linux_symbol_map
+
+ # create a regexp that matches the symbol name
+ set base {([[:xdigit:]]*) (.)}
+ set exp [concat $base " $name\$"]
+ set ret ""
+
+ foreach {line addr type} [regexp -line -inline $exp $linux_symbol_map] {
+ set ret "0x$addr"
+ }
+
+ return $ret
+}
+
+# skisym factors in skiboot's load address
+proc skisym { name } {
+ global skiboot_symbol_map
+ global mconf
+
+ set base {([[:xdigit:]]*) (.)}
+ set exp [concat $base " $name\$"]
+ set ret ""
+
+ foreach {line addr type} [regexp -line -inline $exp $skiboot_symbol_map] {
+ set actual_addr [expr "0x$addr" + $mconf(boot_load)]
+ set ret [format "0x%.16x" $actual_addr]
+ }
+
+ return $ret
+}
+
+proc addr2func { addr } {
+ global skiboot_symbol_list
+ global linux_symbol_list
+ global user_symbol_list
+ global mconf
+
+ set prevname ""
+ set preva "0"
+
+ if { [ info exists linux_symbol_list ] && "$addr" >= 0xc000000000000000} {
+ foreach line $linux_symbol_list {
+ lassign $line a type name
+ if { "0x$a" > $addr } {
+ set o [format "0x%x" [expr $addr - "0x$preva"]]
+ return "$prevname+$o"
+ }
+ set prevname $name
+ set preva $a
+ }
+ }
+ # Assume skiboot is less that 4MB big
+ if { [ info exists skiboot_symbol_list ] &&
+ "$addr" > $mconf(boot_load) && "$addr" < [expr $mconf(boot_load) + 4194304] } {
+ set mapaddr [expr $addr - $mconf(boot_load)]
+
+ foreach line $skiboot_symbol_list {
+ lassign $line a type name
+ if { "0x$a" > $mapaddr } {
+ set o [format "0x%x" [expr $mapaddr - "0x$preva"]]
+ return "$prevname+$o"
+ }
+ set prevname $name
+ set preva $a
+ }
+ }
+ if { [ info exists user_symbol_list ] } {
+ foreach line $user_symbol_list {
+ lassign $line a type name
+ if { "0x$a" > $addr } {
+ set o [format "0x%x" [expr $addr - "0x$preva"]]
+ return "$prevname+$o"
+ }
+ set prevname $name
+ set preva $a
+ }
+ }
+ return "+$addr"
+}
+
+proc current_insn { { t -1 } { c -1 } { p -1 }} {
+ global target_t
+ global target_c
+ global target_p
+
+ if { $t == -1 } { set t $target_t }
+ if { $c == -1 } { set c $target_c }
+ if { $p == -1 } { set p $target_p }
+
+ set pc [mysim cpu $p:$c:$t display spr pc]
+ set pc_laddr [mysim cpu $p:$c:$t util itranslate $pc]
+ set inst [mysim cpu $p:$c:$t memory display $pc_laddr 4]
+ set disasm [mysim cpu $p:$c:$t util ppc_disasm $inst $pc]
+ return $disasm
+}
+
+set SRR1 0
+set DSISR 0
+set DAR 0
+
+proc sreset_trigger { args } {
+ global SRR1
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ mysim trigger clear pc 0x100
+ mysim trigger clear pc 0x104
+ set s [expr [mysim cpu $p:$c:$t display spr srr1] & ~0x00000000003c0002]
+ set SRR1 [expr $SRR1 | $s]
+ mysim cpu $p:$c:$t set spr srr1 $SRR1
+}
+
+proc exc_sreset { } {
+ global SRR1
+ global DSISR
+ global DAR
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ # 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.
+ if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } {
+ set msr_ri 0x2
+ set SRR1_powersave [expr (0x2 << (63-47))]
+ } else {
+ set msr_ri [expr [mysim cpu $p:$c:$t display spr msr] & 0x2]
+ set SRR1_powersave 0
+ }
+
+ # reason system reset
+ set SRR1_reason 0x4
+
+ set SRR1 [expr 0x0 | $msr_ri | $SRR1_powersave]
+ set SRR1 [expr $SRR1 | ((($SRR1_reason >> 3) & 0x1) << (63-42))]
+ set SRR1 [expr $SRR1 | ((($SRR1_reason >> 2) & 0x1) << (63-43))]
+ set SRR1 [expr $SRR1 | ((($SRR1_reason >> 1) & 0x1) << (63-44))]
+ set SRR1 [expr $SRR1 | ((($SRR1_reason >> 0) & 0x1) << (63-45))]
+
+ 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 trigger set pc 0x104 "sreset_trigger"
+ mysim cpu $p:$c:$t interrupt SystemReset
+ } else {
+ mysim trigger set pc 0x100 "sreset_trigger"
+ mysim trigger set pc 0x104 "sreset_trigger"
+ mysim cpu $p:$c:$t interrupt SystemReset
+ }
+
+ # sleep and sometimes other types of interrupts do not trigger 0x100
+ if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x100 ] } {
+ sreset_trigger
+ }
+ if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x104 ] } {
+ sreset_trigger
+ }
+}
+
+proc mce_trigger { args } {
+ global SRR1
+ global DSISR
+ global DAR
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ 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 $p:$c:$t set spr srr1 $SRR1
+ mysim cpu $p:$c:$t set spr dsisr $DSISR
+ mysim cpu $p:$c:$t set spr dar $DAR ; list
+}
+
+#
+# Inject a machine check. Recoverable MCE types can be forced to unrecoverable
+# by clearing MSR_RI bit from SRR1 (which hardware may do).
+# If d_side is 0, then cause goes into SRR1. Otherwise it gets put into DSISR.
+# DAR is hardcoded to always 0xdeadbeefdeadbeef
+#
+# Default with no arguments is a recoverable i-side TLB multi-hit
+# Other options:
+# d_side=1 dsisr=0x80 - recoverable d-side SLB multi-hit
+# d_side=1 dsisr=0x8000 - 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 } } {
+ global SRR1
+ global DSISR
+ global DAR
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+# 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.
+ if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } {
+ set msr_ri 0x2
+ set SRR1_powersave [expr (0x2 << (63-47))]
+ } else {
+ set msr_ri [expr [mysim cpu $p:$c:$t display spr msr] & 0x2]
+ set SRR1_powersave 0
+ }
+
+ if { !$recoverable } {
+ set msr_ri 0x0
+ }
+
+ if { $d_side } {
+ set is_dside 1
+ set SRR1_mc_cause 0x0
+ set DSISR $cause
+ set DAR 0xdeadbeefdeadbeef
+ } else {
+ set is_dside 0
+ set SRR1_mc_cause $cause
+ set DSISR 0x0
+ set DAR 0x0
+ }
+
+ set SRR1 [expr 0x0 | $msr_ri | $SRR1_powersave]
+
+ set SRR1 [expr $SRR1 | ($is_dside << (63-42))]
+ set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 3) & 0x1) << (63-36))]
+ 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))]
+
+ 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 $p:$c:$t interrupt MachineCheck
+ } else {
+ mysim trigger set pc 0x200 "mce_trigger"
+ mysim trigger set pc 0x204 "mce_trigger"
+ mysim cpu $p:$c:$t interrupt MachineCheck
+ }
+
+ # sleep and sometimes other types of interrupts do not trigger 0x200
+ if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x200 ] } {
+ mce_trigger
+ }
+ if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x204 ] } {
+ mce_trigger
+ }
+}
+
+set R1 0
+
+# Avoid stopping if we re-enter the same code. Wait until r1 matches.
+# This helps stepping over exceptions or function calls etc.
+proc stop_stack_match { args } {
+ global R1
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set r1 [mysim cpu $p:$c:$t display gpr 1]
+ if { $R1 == $r1 } {
+ simstop
+ ipca
+ }
+}
+
+# inject default recoverable MCE and step over it. Useful for testing whether
+# code copes with taking an interleaving MCE.
+proc inject_mce { } {
+ global R1
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ set R1 [mysim cpu $p:$c:$t display gpr 1]
+ set pc [mysim cpu $p:$c:$t display spr pc]
+ mysim trigger set pc $pc "stop_stack_match"
+ exc_mce
+ c
+ 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
+ exc_mce 0x1 0x8000 0x1
+}
+
+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 } {
+ inject_mce
+ s
+ }
+}
+
+# inject if RI is set and step over one instruction, and repeat.
+proc inject_mce_step_ri { {nr 1} } {
+ upvar #0 target_t t
+ upvar #0 target_c c
+ upvar #0 target_p p
+
+ 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 $p:$c:$t display spr msr] & 0x2] } {
+ # inject_mce
+ if { [mysim cpu $p:$c:$t display reservation] in { "none" } } {
+ inject_mce
+ mysim cpu $p:$c:$t set reservation none
+ if { $reserve_inject_skip } {
+ set reserve_inject 1
+ set reserve_inject_skip 0
+ }
+ } else {
+ if { $reserve_inject } {
+ inject_mce
+ mysim cpu $p:$c:$t 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 $p:$c:$t set reservation none
+ }
+ }
+ }
+ }
+ s
+ }
+}