Skip to content

Commit

Permalink
Merge pull request #489 from riscv-software-src/power_dance
Browse files Browse the repository at this point in the history
debug: Test OpenOCD behavior when harts become unavailable, using new spike mechanism
  • Loading branch information
timsifive authored Jul 17, 2023
2 parents 4d2b318 + 90691df commit cf5360f
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 55 deletions.
72 changes: 59 additions & 13 deletions debug/gdbserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from testlib import GdbTest, GdbSingleHartTest, TestFailed
from testlib import TestNotApplicable, CompileError
from testlib import UnknownThread
from testlib import CouldNotReadRegisters
from testlib import CouldNotReadRegisters, CommandException
from testlib import ThreadTerminated

MSTATUS_UIE = 0x00000001
MSTATUS_SIE = 0x00000002
Expand Down Expand Up @@ -1807,22 +1808,29 @@ def test(self):
output = self.gdb.c()
assertIn("_exit", output)

class CeaseMultiTest(GdbTest):
"""Test that we work correctly when a hart ceases to respond (e.g. because
class UnavailableMultiTest(GdbTest):
"""Test that we work correctly when a hart becomes unavailable (e.g. because
it's powered down)."""
compile_args = ("programs/counting_loop.c", "-DDEFINE_MALLOC",
"-DDEFINE_FREE")

def early_applicable(self):
return self.hart.support_cease and len(self.target.harts) > 1
return (self.hart.support_cease or
self.target.support_unavailable_control) \
and len(self.target.harts) > 1

def setup(self):
ProgramTest.setup(self)
self.parkOtherHarts("precease")
self.parkOtherHarts()

def test(self):
# Run all the way to the infinite loop in exit
self.gdb.c(wait=False)
self.gdb.c_all(wait=False)
# Other hart should have become unavailable.
if self.target.support_unavailable_control:
self.server.wait_until_running(self.target.harts)
self.server.command(
f"riscv dmi_write 0x1f 0x{(1<<self.hart.id)&0x3:x}")
self.gdb.expect(r"\S+ became unavailable.")
self.gdb.interrupt()

Expand All @@ -1834,7 +1842,7 @@ def test(self):
self.gdb.p("$misa")
assert False, \
"Shouldn't be able to access unavailable hart."
except UnknownThread:
except (UnknownThread, CommandException):
pass

# Check that the main hart can still be debugged.
Expand Down Expand Up @@ -1872,29 +1880,70 @@ def test(self):
except CouldNotReadRegisters:
pass

class CeaseRunTest(ProgramTest):
class UnavailableRunTest(ProgramTest):
"""Test that we work correctly when the hart we're debugging ceases to
respond."""
def early_applicable(self):
return self.hart.support_cease
return self.hart.support_cease or \
self.target.support_unavailable_control

def test(self):
self.gdb.b("main")
output = self.gdb.c()
assertIn("Breakpoint", output)
assertIn("main", output)

self.gdb.p("$pc=precease")
if self.target.support_unavailable_control:
self.gdb.p("$pc=loop_forever")
else:
self.gdb.p("$pc=cease")
self.gdb.c(wait=False)
if self.target.support_unavailable_control:
self.server.wait_until_running([self.hart])
self.server.command(
f"riscv dmi_write 0x1f 0x{(~(1<<self.hart.id))&0x3:x}")
self.gdb.expect(r"\S+ became unavailable.")
self.gdb.interrupt()
# gdb might automatically switch to the available hart.
try:
self.gdb.select_hart(self.hart)
except ThreadTerminated:
# GDB sees that the thread is gone. Count this as success.
return
try:
self.gdb.p("$pc")
assert False, ("Registers shouldn't be accessible when the hart is "
"unavailable.")
except CouldNotReadRegisters:
pass

class UnavailableCycleTest(ProgramTest):
"""Test that harts can be debugged after becoming temporarily
unavailable."""
def early_applicable(self):
return self.target.support_unavailable_control

def test(self):
self.gdb.b("main")
output = self.gdb.c()
assertIn("Breakpoint", output)
assertIn("main", output)

self.gdb.p("$pc=loop_forever")
self.gdb.c(wait=False)
self.server.wait_until_running([self.hart])
self.server.command(
f"riscv dmi_write 0x1f 0x{(~(1<<self.hart.id))&0x3:x}")
self.gdb.expect(r"\S+ became unavailable.")

# Now send a DMI command through OpenOCD to make the hart available
# again.

self.server.command("riscv dmi_write 0x1f 0x3")
self.gdb.expect(r"\S+ became available")
self.gdb.interrupt()
self.gdb.p("$pc")

class FreeRtosTest(GdbTest):
def early_applicable(self):
return self.target.freertos_binary
Expand Down Expand Up @@ -1989,7 +2038,6 @@ def setup(self):
self.gdb.b("handle_trap")

def test(self):
self.gdb.command(f"monitor targets {self.hart.id}")
# Set trigger on Load access fault
self.gdb.command("monitor riscv etrigger set m 0x20")
# Set fox to a null pointer so we'll get a load access exception later.
Expand All @@ -2009,7 +2057,6 @@ def setup(self):
DebugTest.setup(self)
self.gdb.b("main")
self.gdb.c()
self.gdb.command(f"monitor targets {self.hart.id}")

def test(self):
# Execute 2 instructions.
Expand Down Expand Up @@ -2039,7 +2086,6 @@ def setup(self):
self.gdb.load()

def test(self):
self.gdb.command(f"monitor targets {self.hart.id}")
output = self.gdb.command("monitor riscv itrigger set 0x80")
assertIn("Doesn't make sense", output)
output = self.gdb.command("monitor riscv itrigger set m 0")
Expand Down
3 changes: 3 additions & 0 deletions debug/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ class Target:
# in https://github.com/FreeRTOS/FreeRTOS.
freertos_binary = None

# Supports controlling hart availability through DMCUSTOM.
support_unavailable_control = False

# Internal variables:
directory = None
temporary_files = []
Expand Down
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike32-2-hwthread.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class spike32_2(targets.Target):
timeout_sec = 5
implements_custom_test = True
support_memory_sampling = False # not supported without sba
support_unavailable_control = True

def create(self):
return testlib.Spike(self, isa="RV32IMAFDV", support_hasel=True,
Expand Down
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike32-2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class spike32_2(targets.Target):
openocd_config_path = "spike-2.cfg"
timeout_sec = 30
implements_custom_test = True
support_unavailable_control = True

def create(self):
return testlib.Spike(self, isa="RV32IMAFC", progbufsize=0, dmi_rti=4,
Expand Down
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike32.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class spike32(targets.Target):
implements_custom_test = True
support_memory_sampling = False # Needs SBA
freertos_binary = "bin/RTOSDemo32.axf"
support_unavailable_control = True

def create(self):
# 64-bit FPRs on 32-bit target
Expand Down
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike64-2-hwthread.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class spike64_2(targets.Target):
implements_custom_test = True
support_hasel = False
support_memory_sampling = False # Needs SBA
support_unavailable_control = True

def create(self):
return testlib.Spike(self, isa="RV64IMAFDV", abstract_rti=30,
Expand Down
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike64-2-rtos.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class spike64_2_rtos(targets.Target):
test_semihosting = False
support_manual_hwbp = False # not supported with `-rtos riscv`
support_memory_sampling = False # not supported with `-rtos riscv`
support_unavailable_control = True

def create(self):
return testlib.Spike(self, abstract_rti=30, support_hasel=False,
Expand Down
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike64-2.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class spike64_2(targets.Target):
timeout_sec = 5
implements_custom_test = True
support_memory_sampling = False # Needs SBA
support_unavailable_control = True

def create(self):
return testlib.Spike(self)
1 change: 1 addition & 0 deletions debug/targets/RISC-V/spike64.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class spike64(targets.Target):
timeout_sec = 30
implements_custom_test = True
freertos_binary = "bin/RTOSDemo64.axf"
support_unavailable_control = True

def create(self):
# 32-bit FPRs only
Expand Down
Loading

0 comments on commit cf5360f

Please sign in to comment.