1919from testlib import GdbTest , GdbSingleHartTest , TestFailed
2020from testlib import TestNotApplicable , CompileError
2121from testlib import UnknownThread
22- from testlib import CouldNotReadRegisters
22+ from testlib import CouldNotReadRegisters , CommandException
23+ from testlib import ThreadTerminated
2324
2425MSTATUS_UIE = 0x00000001
2526MSTATUS_SIE = 0x00000002
@@ -1807,22 +1808,29 @@ def test(self):
18071808 output = self .gdb .c ()
18081809 assertIn ("_exit" , output )
18091810
1810- class CeaseMultiTest (GdbTest ):
1811- """Test that we work correctly when a hart ceases to respond (e.g. because
1811+ class UnavailableMultiTest (GdbTest ):
1812+ """Test that we work correctly when a hart becomes unavailable (e.g. because
18121813 it's powered down)."""
18131814 compile_args = ("programs/counting_loop.c" , "-DDEFINE_MALLOC" ,
18141815 "-DDEFINE_FREE" )
18151816
18161817 def early_applicable (self ):
1817- return self .hart .support_cease and len (self .target .harts ) > 1
1818+ return (self .hart .support_cease or
1819+ self .target .support_unavailable_control ) \
1820+ and len (self .target .harts ) > 1
18181821
18191822 def setup (self ):
18201823 ProgramTest .setup (self )
1821- self .parkOtherHarts ("precease" )
1824+ self .parkOtherHarts ()
18221825
18231826 def test (self ):
18241827 # Run all the way to the infinite loop in exit
1825- self .gdb .c (wait = False )
1828+ self .gdb .c_all (wait = False )
1829+ # Other hart should have become unavailable.
1830+ if self .target .support_unavailable_control :
1831+ self .server .wait_until_running (self .target .harts )
1832+ self .server .command (
1833+ f"riscv dmi_write 0x1f 0x{ (1 << self .hart .id )& 0x3 :x} " )
18261834 self .gdb .expect (r"\S+ became unavailable." )
18271835 self .gdb .interrupt ()
18281836
@@ -1834,7 +1842,7 @@ def test(self):
18341842 self .gdb .p ("$misa" )
18351843 assert False , \
18361844 "Shouldn't be able to access unavailable hart."
1837- except UnknownThread :
1845+ except ( UnknownThread , CommandException ) :
18381846 pass
18391847
18401848 # Check that the main hart can still be debugged.
@@ -1872,29 +1880,70 @@ def test(self):
18721880 except CouldNotReadRegisters :
18731881 pass
18741882
1875- class CeaseRunTest (ProgramTest ):
1883+ class UnavailableRunTest (ProgramTest ):
18761884 """Test that we work correctly when the hart we're debugging ceases to
18771885 respond."""
18781886 def early_applicable (self ):
1879- return self .hart .support_cease
1887+ return self .hart .support_cease or \
1888+ self .target .support_unavailable_control
18801889
18811890 def test (self ):
18821891 self .gdb .b ("main" )
18831892 output = self .gdb .c ()
18841893 assertIn ("Breakpoint" , output )
18851894 assertIn ("main" , output )
18861895
1887- self .gdb .p ("$pc=precease" )
1896+ if self .target .support_unavailable_control :
1897+ self .gdb .p ("$pc=loop_forever" )
1898+ else :
1899+ self .gdb .p ("$pc=cease" )
18881900 self .gdb .c (wait = False )
1901+ if self .target .support_unavailable_control :
1902+ self .server .wait_until_running ([self .hart ])
1903+ self .server .command (
1904+ f"riscv dmi_write 0x1f 0x{ (~ (1 << self .hart .id ))& 0x3 :x} " )
18891905 self .gdb .expect (r"\S+ became unavailable." )
18901906 self .gdb .interrupt ()
1907+ # gdb might automatically switch to the available hart.
1908+ try :
1909+ self .gdb .select_hart (self .hart )
1910+ except ThreadTerminated :
1911+ # GDB sees that the thread is gone. Count this as success.
1912+ return
18911913 try :
18921914 self .gdb .p ("$pc" )
18931915 assert False , ("Registers shouldn't be accessible when the hart is "
18941916 "unavailable." )
18951917 except CouldNotReadRegisters :
18961918 pass
18971919
1920+ class UnavailableCycleTest (ProgramTest ):
1921+ """Test that harts can be debugged after becoming temporarily
1922+ unavailable."""
1923+ def early_applicable (self ):
1924+ return self .target .support_unavailable_control
1925+
1926+ def test (self ):
1927+ self .gdb .b ("main" )
1928+ output = self .gdb .c ()
1929+ assertIn ("Breakpoint" , output )
1930+ assertIn ("main" , output )
1931+
1932+ self .gdb .p ("$pc=loop_forever" )
1933+ self .gdb .c (wait = False )
1934+ self .server .wait_until_running ([self .hart ])
1935+ self .server .command (
1936+ f"riscv dmi_write 0x1f 0x{ (~ (1 << self .hart .id ))& 0x3 :x} " )
1937+ self .gdb .expect (r"\S+ became unavailable." )
1938+
1939+ # Now send a DMI command through OpenOCD to make the hart available
1940+ # again.
1941+
1942+ self .server .command ("riscv dmi_write 0x1f 0x3" )
1943+ self .gdb .expect (r"\S+ became available" )
1944+ self .gdb .interrupt ()
1945+ self .gdb .p ("$pc" )
1946+
18981947class FreeRtosTest (GdbTest ):
18991948 def early_applicable (self ):
19001949 return self .target .freertos_binary
@@ -1989,7 +2038,6 @@ def setup(self):
19892038 self .gdb .b ("handle_trap" )
19902039
19912040 def test (self ):
1992- self .gdb .command (f"monitor targets { self .hart .id } " )
19932041 # Set trigger on Load access fault
19942042 self .gdb .command ("monitor riscv etrigger set m 0x20" )
19952043 # Set fox to a null pointer so we'll get a load access exception later.
@@ -2009,7 +2057,6 @@ def setup(self):
20092057 DebugTest .setup (self )
20102058 self .gdb .b ("main" )
20112059 self .gdb .c ()
2012- self .gdb .command (f"monitor targets { self .hart .id } " )
20132060
20142061 def test (self ):
20152062 # Execute 2 instructions.
@@ -2039,7 +2086,6 @@ def setup(self):
20392086 self .gdb .load ()
20402087
20412088 def test (self ):
2042- self .gdb .command (f"monitor targets { self .hart .id } " )
20432089 output = self .gdb .command ("monitor riscv itrigger set 0x80" )
20442090 assertIn ("Doesn't make sense" , output )
20452091 output = self .gdb .command ("monitor riscv itrigger set m 0" )
0 commit comments