diff options
author | Tim Newsome <tim@sifive.com> | 2021-04-13 14:41:45 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-13 14:41:45 -0700 |
commit | 1b05661baa79f03830f5ddefa999dc7aaf7b1ce1 (patch) | |
tree | c3b934eea5e0522888edc7a4cf742d09afaa7512 | |
parent | 1ce128fa78c24bb0ed399c647e7139322b5353a7 (diff) | |
download | riscv-tests-1b05661baa79f03830f5ddefa999dc7aaf7b1ce1.zip riscv-tests-1b05661baa79f03830f5ddefa999dc7aaf7b1ce1.tar.gz riscv-tests-1b05661baa79f03830f5ddefa999dc7aaf7b1ce1.tar.bz2 |
Add FreeRTOS smoke tests. (#333)
* Add FreeRTOS smoke tests.
Make sure that OpenOCD can access all threads in a FreeRTOS binary on
single-hart RV32 and RV64.
* Also test `-rtos FreeRTOS`.
-rw-r--r-- | debug/bin/README.md | 7 | ||||
-rw-r--r-- | debug/bin/RTOSDemo32.axf | bin | 0 -> 131616 bytes | |||
-rw-r--r-- | debug/bin/RTOSDemo64.axf | bin | 0 -> 147328 bytes | |||
-rwxr-xr-x | debug/gdbserver.py | 54 | ||||
-rw-r--r-- | debug/targets.py | 9 | ||||
-rw-r--r-- | debug/targets/RISC-V/spike-1.cfg | 7 | ||||
-rw-r--r-- | debug/targets/RISC-V/spike32.py | 3 | ||||
-rw-r--r-- | debug/targets/RISC-V/spike64.py | 3 | ||||
-rw-r--r-- | debug/testlib.py | 35 |
9 files changed, 103 insertions, 15 deletions
diff --git a/debug/bin/README.md b/debug/bin/README.md new file mode 100644 index 0000000..7e81515 --- /dev/null +++ b/debug/bin/README.md @@ -0,0 +1,7 @@ +This directory contains binaries that are not easy to compile. + +RTOSDemo32.axf and RTOSDemo64.axf are created by checking out +https://github.com/FreeRTOS/FreeRTOS, following the instructions in +`FreeRTOS/Demo/RISC-V-spike-htif_GCC/README.md`, and building: +* `make XLEN=32 BASE_ADDRESS=0x10000000` +* `make XLEN=64 BASE_ADDRESS=0x1212340000` diff --git a/debug/bin/RTOSDemo32.axf b/debug/bin/RTOSDemo32.axf Binary files differnew file mode 100644 index 0000000..5fa3fe7 --- /dev/null +++ b/debug/bin/RTOSDemo32.axf diff --git a/debug/bin/RTOSDemo64.axf b/debug/bin/RTOSDemo64.axf Binary files differnew file mode 100644 index 0000000..bfa2a2a --- /dev/null +++ b/debug/bin/RTOSDemo64.axf diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 0a174d3..bcac02c 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -1700,6 +1700,60 @@ class VectorTest(GdbSingleHartTest): assertIn("_exit", output) assertEqual(self.gdb.p("status"), 0) +class FreeRtosTest(GdbTest): + def early_applicable(self): + return self.target.freertos_binary + + def freertos(self): + return True + + def test(self): + self.gdb.command("file %s" % self.target.freertos_binary) + self.gdb.load() + + output = self.gdb.command("monitor riscv_freertos_stacking mainline") + + # Turn off htif, which doesn't work when the file is loaded into spike + # through gdb. It only works when spike loads the ELF file itself. + bp = self.gdb.b("main") + self.gdb.c() + self.gdb.command("delete %d" % bp) + self.gdb.p("*((int*) &use_htif) = 0") + # Need this, otherwise gdb complains that there is no current active + # thread. + self.gdb.threads() + + bp = self.gdb.b("prvQueueReceiveTask") + + self.gdb.c() + self.gdb.command("delete %d" % bp) + + bp = self.gdb.b("prvQueueSendTask") + self.gdb.c() + self.gdb.command("delete %d" % bp) + + # Now we know for sure at least 2 threads have executed. + + threads = self.gdb.threads() + assertGreater(len(threads), 1) + + values = {} + for thread in threads: + assertNotIn("No Name", thread[1]) + self.gdb.thread(thread) + assertEqual(self.gdb.p("$zero"), 0) + output = self.gdb.command("info reg sp") + assertIn("ucHeap", output) + self.gdb.command("info reg mstatus") + values[thread.id] = self.gdb.p("$s11") + self.gdb.p("$s11=0x%x" % (values[thread.id] ^ int(thread.id))) + + # Test that writing worked + self.gdb.stepi() + for thread in self.gdb.threads(): + self.gdb.thread(thread) + assertEqual(self.gdb.p("$s11"), values[thread.id] ^ int(thread.id)) + parsed = None def main(): parser = argparse.ArgumentParser( diff --git a/debug/targets.py b/debug/targets.py index f8f7b6f..0890465 100644 --- a/debug/targets.py +++ b/debug/targets.py @@ -108,6 +108,10 @@ class Target: # limitation/hardware support. support_memory_sampling = True + # Relative path to a FreeRTOS binary compiled from the spike demo project + # in https://github.com/FreeRTOS/FreeRTOS. + freertos_binary = None + # Internal variables: directory = None temporary_files = [] @@ -143,11 +147,12 @@ class Target: def create(self): """Create the target out of thin air, eg. start a simulator.""" - def server(self): + def server(self, test): """Start the debug server that gdb connects to, eg. OpenOCD.""" return testlib.Openocd(server_cmd=self.server_cmd, config=self.openocd_config_path, - timeout=self.server_timeout_sec) + timeout=self.server_timeout_sec, + freertos=test.freertos()) def do_compile(self, hart, *sources): binary_name = "%s_%s-%d" % ( diff --git a/debug/targets/RISC-V/spike-1.cfg b/debug/targets/RISC-V/spike-1.cfg index 3bc32d1..5f11b08 100644 --- a/debug/targets/RISC-V/spike-1.cfg +++ b/debug/targets/RISC-V/spike-1.cfg @@ -8,10 +8,13 @@ set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME +if {$::env(USE_FREERTOS)} { + target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos FreeRTOS +} else { + target create $_TARGETNAME riscv -chain-position $_TARGETNAME +} $_TARGETNAME configure -work-area-phys $::env(WORK_AREA) -work-area-size 8096 -work-area-backup 1 - gdb_report_data_abort enable gdb_report_register_access_error enable diff --git a/debug/targets/RISC-V/spike32.py b/debug/targets/RISC-V/spike32.py index 463e7cf..381aea7 100644 --- a/debug/targets/RISC-V/spike32.py +++ b/debug/targets/RISC-V/spike32.py @@ -5,7 +5,7 @@ class spike32_hart(targets.Hart): xlen = 32 ram = 0x10000000 ram_size = 0x10000000 - bad_address = 0x10000000 - 8 + bad_address = ram - 8 instruction_hardware_breakpoint_count = 4 reset_vectors = [0x1000] link_script_path = "spike32.lds" @@ -19,6 +19,7 @@ class spike32(targets.Target): timeout_sec = 30 implements_custom_test = True support_memory_sampling = False # Needs SBA + freertos_binary = "bin/RTOSDemo32.axf" def create(self): # 64-bit FPRs on 32-bit target diff --git a/debug/targets/RISC-V/spike64.py b/debug/targets/RISC-V/spike64.py index cdb67f7..c4c66c8 100644 --- a/debug/targets/RISC-V/spike64.py +++ b/debug/targets/RISC-V/spike64.py @@ -5,7 +5,7 @@ class spike64_hart(targets.Hart): xlen = 64 ram = 0x1212340000 ram_size = 0x10000000 - bad_address = 0x1212340000 - 8 + bad_address = ram - 8 instruction_hardware_breakpoint_count = 4 reset_vectors = [0x1000] link_script_path = "spike64.lds" @@ -18,6 +18,7 @@ class spike64(targets.Target): openocd_config_path = "spike-1.cfg" timeout_sec = 30 implements_custom_test = True + freertos_binary = "bin/RTOSDemo64.axf" def create(self): # 32-bit FPRs only diff --git a/debug/testlib.py b/debug/testlib.py index d8fc891..501e0e6 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -245,7 +245,8 @@ class Openocd: logfile = tempfile.NamedTemporaryFile(prefix='openocd', suffix='.log') logname = logfile.name - def __init__(self, server_cmd=None, config=None, debug=False, timeout=60): + def __init__(self, server_cmd=None, config=None, debug=False, timeout=60, + freertos=False): self.timeout = timeout if server_cmd: @@ -280,6 +281,12 @@ class Openocd: if debug: cmd.append("-d") + extra_env = {} + if freertos: + extra_env['USE_FREERTOS'] = "1" + else: + extra_env['USE_FREERTOS'] = "0" + raw_logfile = open(Openocd.logname, "wb") try: spike_dasm = subprocess.Popen("spike-dasm", stdin=subprocess.PIPE, @@ -292,17 +299,21 @@ class Openocd: env_entries = ("REMOTE_BITBANG_HOST", "REMOTE_BITBANG_PORT", "WORK_AREA") env_entries = [key for key in env_entries if key in os.environ] - logfile.write(("+ %s%s\n" % ( - "".join("%s=%s " % (key, os.environ[key]) for key in env_entries), - " ".join(map(pipes.quote, cmd)))).encode()) + parts = [ + " ".join("%s=%s" % (key, os.environ[key]) for key in env_entries), + " ".join("%s=%s" % (k, v) for k, v in extra_env.items()), + " ".join(map(pipes.quote, cmd)) + ] + logfile.write(("+ %s\n" % " ".join(parts)).encode()) logfile.flush() self.gdb_ports = [] - self.process = self.start(cmd, logfile) + self.process = self.start(cmd, logfile, extra_env) - def start(self, cmd, logfile): + def start(self, cmd, logfile, extra_env): + combined_env = {**os.environ, **extra_env} process = subprocess.Popen(cmd, stdin=subprocess.PIPE, - stdout=logfile, stderr=logfile) + stdout=logfile, stderr=logfile, env=combined_env) try: # Wait for OpenOCD to have made it through riscv_examine(). When @@ -710,7 +721,7 @@ class Gdb: value = shlex.split(output.split('=')[-1].strip())[1] return value - def info_registers(self, group): + def info_registers(self, group=""): output = self.command("info registers %s" % group, ops=5) result = {} for line in output.splitlines(): @@ -954,6 +965,12 @@ class BaseTest: # pylint: disable=no-self-use return True + def freertos(self): + """Return a true value if the test is running a FreeRTOS binary where + the debugger should expose FreeRTOS threads to gdb.""" + # pylint: disable=no-self-use + return False + def setup(self): pass @@ -971,7 +988,7 @@ class BaseTest: if self.target_process: self.logs.append(self.target_process.logname) try: - self.server = self.target.server() + self.server = self.target.server(self) self.logs.append(self.server.logname) except Exception: for log in self.logs: |