xref: /aosp_15_r20/external/pigweed/targets/rp2040/device_handler.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #include "pw_system/device_handler.h"
15 
16 #include "hardware/watchdog.h"
17 #include "pw_cpu_exception/state.h"
18 #include "pw_cpu_exception_cortex_m/snapshot.h"
19 #include "pw_thread_freertos/snapshot.h"
20 
21 namespace pw::system::device_handler {
22 
23 namespace {
24 
25 // These symbols are added to the default pico_sdk linker script as part
26 // of the build process. If the build fails due to missing these symbols,
27 // it may be because a different linker script is configured and these
28 // symbols need added.
29 extern "C" uint32_t __pw_code_begin;
30 extern "C" uint32_t __pw_code_end;
31 
32 extern "C" uint32_t __StackBottom;
33 extern "C" uint32_t __StackTop;
34 
GetLinkerSymbolValue(const uint32_t & symbol)35 uintptr_t GetLinkerSymbolValue(const uint32_t& symbol) {
36   return reinterpret_cast<uintptr_t>(&symbol);
37 }
38 
IsAddressExecutable(uintptr_t address)39 bool IsAddressExecutable(uintptr_t address) {
40   const uintptr_t code_begin = GetLinkerSymbolValue(__pw_code_begin);
41   const uintptr_t code_end = GetLinkerSymbolValue(__pw_code_end);
42 
43   if ((address >= code_begin) && (address <= code_end)) {
44     return true;
45   }
46 
47   return false;
48 }
49 
AddressFilteredDumper(thread::proto::pwpb::Thread::StreamEncoder & encoder,ConstByteSpan stack)50 Status AddressFilteredDumper(
51     thread::proto::pwpb::Thread::StreamEncoder& encoder, ConstByteSpan stack) {
52   span<const uint32_t> addresses =
53       span<const uint32_t>(reinterpret_cast<const uint32_t*>(stack.data()),
54                            stack.size_bytes() / sizeof(uint32_t));
55   for (const uint32_t address : addresses) {
56     if (IsAddressExecutable(address)) {
57       auto status = encoder.WriteRawBacktrace(address);
58       if (status != OkStatus())
59         return status;
60     }
61   }
62   return OkStatus();
63 }
64 
65 }  // namespace
66 
RebootSystem()67 void RebootSystem() { watchdog_reboot(0, 0, 0); }
68 
CapturePlatformMetadata(snapshot::pwpb::Metadata::StreamEncoder & metadata_encoder)69 void CapturePlatformMetadata(
70     snapshot::pwpb::Metadata::StreamEncoder& metadata_encoder) {
71 // The device_handler is shared between rp2040 and 2350, so handle differences
72 // with the preprocessor.
73 #if _PW_ARCH_ARM_V6M
74   // TODO: https://pwbug.dev/357132837 - Review if IgnoreError is correct here.
75   metadata_encoder.WriteCpuArch(snapshot::pwpb::CpuArchitecture::Enum::ARMV6M)
76       .IgnoreError();
77 #elif _PW_ARCH_ARM_V8M_MAINLINE || _PW_ARCH_ARM_V8_1M_MAINLINE
78   // TODO: https://pwbug.dev/357132837 - Review if IgnoreError is correct here.
79   metadata_encoder.WriteCpuArch(snapshot::pwpb::CpuArchitecture::Enum::ARMV8M)
80       .IgnoreError();
81 #else
82 #error "Unknown CPU architecture."
83 #endif  // _PW_ARCH_ARM_V6M
84 }
85 
CaptureCpuState(const pw_cpu_exception_State & cpu_state,snapshot::pwpb::Snapshot::StreamEncoder & snapshot_encoder)86 Status CaptureCpuState(
87     const pw_cpu_exception_State& cpu_state,
88     snapshot::pwpb::Snapshot::StreamEncoder& snapshot_encoder) {
89   return cpu_exception::cortex_m::SnapshotCpuState(
90       cpu_state,
91       *static_cast<cpu_exception::cortex_m::pwpb::SnapshotCpuStateOverlay::
92                        StreamEncoder*>(
93           static_cast<protobuf::StreamEncoder*>(&snapshot_encoder)));
94 }
95 
CaptureMainStackThread(const pw_cpu_exception_State & cpu_state,thread::proto::pwpb::SnapshotThreadInfo::StreamEncoder & encoder)96 Status CaptureMainStackThread(
97     const pw_cpu_exception_State& cpu_state,
98     thread::proto::pwpb::SnapshotThreadInfo::StreamEncoder& encoder) {
99   uintptr_t stack_low_addr = GetLinkerSymbolValue(__StackBottom);
100   uintptr_t stack_high_addr = GetLinkerSymbolValue(__StackTop);
101   thread::ProcessThreadStackCallback stack_dumper =
102       device_handler::AddressFilteredDumper;
103 
104   return cpu_exception::cortex_m::SnapshotMainStackThread(
105       cpu_state, stack_low_addr, stack_high_addr, encoder, stack_dumper);
106 }
107 
CaptureThreads(uint32_t running_thread_stack_pointer,thread::proto::pwpb::SnapshotThreadInfo::StreamEncoder & encoder)108 Status CaptureThreads(
109     uint32_t running_thread_stack_pointer,
110     thread::proto::pwpb::SnapshotThreadInfo::StreamEncoder& encoder) {
111   thread::ProcessThreadStackCallback stack_dumper =
112       device_handler::AddressFilteredDumper;
113   return thread::freertos::SnapshotThreads(
114       reinterpret_cast<void*>(running_thread_stack_pointer),
115       encoder,
116       stack_dumper);
117 }
118 
119 }  // namespace pw::system::device_handler
120