aboutsummaryrefslogtreecommitdiff
path: root/pw_cpu_exception_armv7m
diff options
context:
space:
mode:
Diffstat (limited to 'pw_cpu_exception_armv7m')
-rw-r--r--pw_cpu_exception_armv7m/BUILD2
-rw-r--r--pw_cpu_exception_armv7m/BUILD.gn26
-rw-r--r--pw_cpu_exception_armv7m/cpu_state.cc11
-rw-r--r--pw_cpu_exception_armv7m/docs.rst10
-rw-r--r--pw_cpu_exception_armv7m/entry.cc (renamed from pw_cpu_exception_armv7m/cpu_exception_entry.cc)29
-rw-r--r--pw_cpu_exception_armv7m/exception_entry_test.cc50
-rw-r--r--pw_cpu_exception_armv7m/public/pw_cpu_exception_armv7m/cpu_state.h10
7 files changed, 80 insertions, 58 deletions
diff --git a/pw_cpu_exception_armv7m/BUILD b/pw_cpu_exception_armv7m/BUILD
index dee7414d4..884433824 100644
--- a/pw_cpu_exception_armv7m/BUILD
+++ b/pw_cpu_exception_armv7m/BUILD
@@ -19,7 +19,7 @@ licenses(["notice"]) # Apache License 2.0
filegroup(
name = "pw_cpu_exception_armv7m",
srcs = [
- "cpu_exception_entry.cc",
+ "entry.cc",
"cpu_state.cc",
"public/pw_cpu_exception_armv7m/cpu_state.h",
],
diff --git a/pw_cpu_exception_armv7m/BUILD.gn b/pw_cpu_exception_armv7m/BUILD.gn
index 014824807..c1206f522 100644
--- a/pw_cpu_exception_armv7m/BUILD.gn
+++ b/pw_cpu_exception_armv7m/BUILD.gn
@@ -22,17 +22,26 @@ config("default_config") {
include_dirs = [ "public" ]
}
-pw_source_set("pw_cpu_exception_armv7m") {
+pw_source_set("support") {
public_configs = [ ":default_config" ]
- deps = [
- "$dir_pw_cpu_exception:facade",
+ public_deps = [
+ "$dir_pw_cpu_exception:support_facade",
"$dir_pw_preprocessor",
+ "$dir_pw_string",
]
public = [ "public/pw_cpu_exception_armv7m/cpu_state.h" ]
- sources = [
- "cpu_exception_entry.cc",
- "cpu_state.cc",
+ sources = [ "cpu_state.cc" ]
+}
+
+pw_source_set("pw_cpu_exception_armv7m") {
+ public_configs = [ ":default_config" ]
+ public_deps = [
+ ":support",
+ "$dir_pw_cpu_exception:entry_facade",
+ "$dir_pw_cpu_exception:handler",
+ "$dir_pw_preprocessor",
]
+ sources = [ "entry.cc" ]
}
pw_test_group("tests") {
@@ -40,10 +49,7 @@ pw_test_group("tests") {
}
pw_test("cpu_exception_entry_test") {
- deps = [
- ":pw_cpu_exception_armv7m",
- "$dir_pw_cpu_exception",
- ]
+ deps = [ ":pw_cpu_exception_armv7m" ]
sources = [ "exception_entry_test.cc" ]
}
diff --git a/pw_cpu_exception_armv7m/cpu_state.cc b/pw_cpu_exception_armv7m/cpu_state.cc
index d3245a4bc..466a216b5 100644
--- a/pw_cpu_exception_armv7m/cpu_state.cc
+++ b/pw_cpu_exception_armv7m/cpu_state.cc
@@ -18,23 +18,26 @@
#include <cstdint>
#include <span>
-#include "pw_cpu_exception/cpu_exception.h"
+#include "pw_cpu_exception/support.h"
#include "pw_string/string_builder.h"
namespace pw::cpu_exception {
-std::span<const uint8_t> RawFaultingCpuState(const CpuState& cpu_state) {
+std::span<const uint8_t> RawFaultingCpuState(
+ const pw_CpuExceptionState& cpu_state) {
return std::span(reinterpret_cast<const uint8_t*>(&cpu_state),
sizeof(cpu_state));
}
// Using this function adds approximately 100 bytes to binary size.
-void ToString(const CpuState& cpu_state, StringBuilder* builder) {
+void ToString(const pw_CpuExceptionState& cpu_state,
+ const std::span<char>& dest) {
+ StringBuilder builder(dest);
const ArmV7mFaultRegisters& base = cpu_state.base;
const ArmV7mExtraRegisters& extended = cpu_state.extended;
#define _PW_FORMAT_REGISTER(state_section, name) \
- builder->Format("%s=0x%08" PRIx32 "\n", #name, state_section.name)
+ builder.Format("%s=0x%08" PRIx32 "\n", #name, state_section.name)
// Other registers.
_PW_FORMAT_REGISTER(base, pc);
diff --git a/pw_cpu_exception_armv7m/docs.rst b/pw_cpu_exception_armv7m/docs.rst
index cf969961d..d55339f7d 100644
--- a/pw_cpu_exception_armv7m/docs.rst
+++ b/pw_cpu_exception_armv7m/docs.rst
@@ -78,11 +78,11 @@ architecture-specific registers, using the generic exception handler functions
is preferred.
However, some projects may need to explicitly access architecture-specific
-registers to attempt to recover from a CPU exception. ``CpuState`` provides
-access to the captured CPU state at the time of the fault. When the
-application-provided ``HandleCpuException()`` function returns, the CPU state is
-restored. This allows the exception handler to modify the captured state so that
-execution can safely continue.
+registers to attempt to recover from a CPU exception. ``pw_CpuExceptionState``
+provides access to the captured CPU state at the time of the fault. When the
+application-provided ``pw_CpuExceptionDefaultHandler()`` function returns, the
+CPU state is restored. This allows the exception handler to modify the captured
+state so that execution can safely continue.
Expected Behavior
-----------------
diff --git a/pw_cpu_exception_armv7m/cpu_exception_entry.cc b/pw_cpu_exception_armv7m/entry.cc
index 9f81789b4..a247dee59 100644
--- a/pw_cpu_exception_armv7m/cpu_exception_entry.cc
+++ b/pw_cpu_exception_armv7m/entry.cc
@@ -12,9 +12,12 @@
// License for the specific language governing permissions and limitations under
// the License.
+#include "pw_cpu_exception/entry.h"
+
#include <cstdint>
+#include <cstring>
-#include "pw_cpu_exception/cpu_exception.h"
+#include "pw_cpu_exception/handler.h"
#include "pw_cpu_exception_armv7m/cpu_state.h"
#include "pw_preprocessor/compiler.h"
@@ -57,13 +60,13 @@ constexpr uint32_t kInvalidRegisterValue = 0xFFFFFFFF;
// Checks exc_return in the captured CPU state to determine which stack pointer
// was in use prior to entering the exception handler.
-bool PspWasActive(const CpuState& cpu_state) {
+bool PspWasActive(const pw_CpuExceptionState& cpu_state) {
return cpu_state.extended.exc_return & kExcReturnStackMask;
}
// Checks exc_return to determine if FPU state was pushed to the stack in
// addition to the base CPU context frame.
-bool FpuStateWasPushed(const CpuState& cpu_state) {
+bool FpuStateWasPushed(const pw_CpuExceptionState& cpu_state) {
return !(cpu_state.extended.exc_return & kExcReturnBasicFrameMask);
}
@@ -71,7 +74,7 @@ bool FpuStateWasPushed(const CpuState& cpu_state) {
//
// For more information see (See ARMv7-M Section B1.5.11, derived exceptions
// on exception entry).
-void CloneBaseRegistersFromPsp(CpuState* cpu_state) {
+void CloneBaseRegistersFromPsp(pw_CpuExceptionState* cpu_state) {
// If CPU succeeded in pushing context to PSP, copy it to the MSP.
if (!(cpu_state->extended.cfsr & kStkErrMask) &&
!(cpu_state->extended.cfsr & kMStkErrMask)) {
@@ -97,7 +100,7 @@ void CloneBaseRegistersFromPsp(CpuState* cpu_state) {
//
// For more information see (See ARMv7-M Section B1.5.11, derived exceptions
// on exception entry).
-void RestoreBaseRegistersToPsp(CpuState* cpu_state) {
+void RestoreBaseRegistersToPsp(pw_CpuExceptionState* cpu_state) {
// If CPU succeeded in pushing context to PSP on exception entry, restore the
// contents of cpu_state to the CPU-pushed register frame so the CPU can
// continue. Otherwise, don't attempt as we'll likely end up in an escalated
@@ -111,7 +114,7 @@ void RestoreBaseRegistersToPsp(CpuState* cpu_state) {
}
// Determines the size of the CPU-pushed context frame.
-uint32_t CpuContextSize(const CpuState& cpu_state) {
+uint32_t CpuContextSize(const pw_CpuExceptionState& cpu_state) {
uint32_t cpu_context_size = sizeof(ArmV7mFaultRegisters);
if (FpuStateWasPushed(cpu_state)) {
cpu_context_size += sizeof(ArmV7mFaultRegistersFpu);
@@ -128,7 +131,7 @@ uint32_t CpuContextSize(const CpuState& cpu_state) {
// On exception entry, the Program Stack Pointer is patched to reflect the state
// at exception-time. On exception return, it is restored to the appropriate
// location. This calculates the delta that is used for these patch operations.
-uint32_t CalculatePspDelta(const CpuState& cpu_state) {
+uint32_t CalculatePspDelta(const pw_CpuExceptionState& cpu_state) {
// If CPU context was not pushed to program stack (because program stack
// wasn't in use, or an error occurred when pushing context), the PSP doesn't
// need to be shifted.
@@ -143,7 +146,7 @@ uint32_t CalculatePspDelta(const CpuState& cpu_state) {
// On exception entry, the Main Stack Pointer is patched to reflect the state
// at exception-time. On exception return, it is restored to the appropriate
// location. This calculates the delta that is used for these patch operations.
-uint32_t CalculateMspDelta(const CpuState& cpu_state) {
+uint32_t CalculateMspDelta(const pw_CpuExceptionState& cpu_state) {
if (PspWasActive(cpu_state)) {
// TODO(amontanez): Since FPU state isn't captured at this time, we ignore
// it when patching MSP. To add FPU capture support,
@@ -161,7 +164,7 @@ extern "C" {
// Collect remaining CPU state (memory mapped registers), populate memory mapped
// registers, and call application exception handler.
-PW_USED void pw_PackageAndHandleCpuException(CpuState* cpu_state) {
+PW_USED void pw_PackageAndHandleCpuException(pw_CpuExceptionState* cpu_state) {
// Capture memory mapped registers.
cpu_state->extended.cfsr = arm_v7m_cfsr;
cpu_state->extended.icsr = arm_v7m_icsr;
@@ -169,9 +172,9 @@ PW_USED void pw_PackageAndHandleCpuException(CpuState* cpu_state) {
cpu_state->extended.mmfar = arm_v7m_mmfar;
// CPU may have automatically pushed state to the program stack. If it did,
- // the values can be copied into in the CpuState struct that is passed
- // to HandleCpuException(). The cpu_state passed to the handler is ALWAYS
- // stored on the main stack (MSP).
+ // the values can be copied into in the pw_CpuExceptionState struct that is
+ // passed to HandleCpuException(). The cpu_state passed to the handler is
+ // ALWAYS stored on the main stack (MSP).
if (PspWasActive(*cpu_state)) {
CloneBaseRegistersFromPsp(cpu_state);
// If PSP wasn't active, this delta is 0.
@@ -182,7 +185,7 @@ PW_USED void pw_PackageAndHandleCpuException(CpuState* cpu_state) {
cpu_state->extended.msp += CalculateMspDelta(*cpu_state);
// Call application-level exception handler.
- HandleCpuException(cpu_state);
+ pw_HandleCpuException(cpu_state);
// Restore program stack pointer so exception return can restore state if
// needed.
diff --git a/pw_cpu_exception_armv7m/exception_entry_test.cc b/pw_cpu_exception_armv7m/exception_entry_test.cc
index fbd5fb36d..3000833cd 100644
--- a/pw_cpu_exception_armv7m/exception_entry_test.cc
+++ b/pw_cpu_exception_armv7m/exception_entry_test.cc
@@ -17,7 +17,9 @@
#include <type_traits>
#include "gtest/gtest.h"
-#include "pw_cpu_exception/cpu_exception.h"
+#include "pw_cpu_exception/entry.h"
+#include "pw_cpu_exception/handler.h"
+#include "pw_cpu_exception/support.h"
#include "pw_cpu_exception_armv7m/cpu_state.h"
namespace pw::cpu_exception {
@@ -132,10 +134,10 @@ constexpr size_t kMaxFaultDepth = 2;
// Variable to prevent more than kMaxFaultDepth nested crashes.
size_t current_fault_depth = 0;
-// Faulting CpuState is copied here so values can be validated after exiting
-// exception handler.
-CpuState captured_states[kMaxFaultDepth] = {};
-CpuState& captured_state = captured_states[0];
+// Faulting pw_CpuExceptionState is copied here so values can be validated after
+// exiting exception handler.
+pw_CpuExceptionState captured_states[kMaxFaultDepth] = {};
+pw_CpuExceptionState& captured_state = captured_states[0];
// Flag used to check if the contents of std::span matches the captured state.
bool span_matches = false;
@@ -147,10 +149,10 @@ bool span_matches = false;
// point support for double.
volatile float float_test_value;
-// Magic pattern to help identify if the exception handler's CpuState pointer
-// was pointing to captured CPU state that was pushed onto the stack when
-// the faulting context uses the VFP. Has to be computed at runtime
-// because it uses values only available at link time.
+// Magic pattern to help identify if the exception handler's
+// pw_CpuExceptionState pointer was pointing to captured CPU state that was
+// pushed onto the stack when the faulting context uses the VFP. Has to be
+// computed at runtime because it uses values only available at link time.
const float kFloatTestPattern = 12.345f * 67.89f;
volatile float fpu_lhs_val = 12.345f;
@@ -159,13 +161,14 @@ volatile float fpu_rhs_val = 67.89f;
// This macro provides a calculation that equals kFloatTestPattern.
#define _PW_TEST_FPU_OPERATION (fpu_lhs_val * fpu_rhs_val)
-// Magic pattern to help identify if the exception handler's CpuState pointer
-// was pointing to captured CPU state that was pushed onto the stack.
+// Magic pattern to help identify if the exception handler's
+// pw_CpuExceptionState pointer was pointing to captured CPU state that was
+// pushed onto the stack.
constexpr uint32_t kMagicPattern = 0xDEADBEEF;
// This pattern serves a purpose similar to kMagicPattern, but is used for
-// testing a nested fault to ensure both CpuState objects are correctly
-// captured.
+// testing a nested fault to ensure both pw_CpuExceptionState objects are
+// correctly captured.
constexpr uint32_t kNestedMagicPattern = 0x900DF00D;
// The manually captured PC won't be the exact same as the faulting PC. This is
@@ -176,6 +179,9 @@ constexpr int32_t kMaxPcDistance = 4;
using InterruptVectorTable = std::aligned_storage_t<512, 512>;
InterruptVectorTable ram_vector_table;
+// Forward declaration of the exception handler.
+void TestingExceptionHandler(pw_CpuExceptionState*);
+
// Populate the device's registers with testable values, then trigger exception.
void BeginBaseFaultTest() {
// Make sure divide by zero causes a fault.
@@ -337,7 +343,7 @@ void InstallVectorTableEntries() {
// Override exception handling vector table entries.
uint32_t* exception_entry_addr =
- reinterpret_cast<uint32_t*>(pw::cpu_exception::pw_CpuExceptionEntry);
+ reinterpret_cast<uint32_t*>(pw_CpuExceptionEntry);
uint32_t** interrupts = reinterpret_cast<uint32_t**>(&ram_vector_table);
interrupts[kHardFaultIsrNum] = exception_entry_addr;
interrupts[kMemFaultIsrNum] = exception_entry_addr;
@@ -364,6 +370,7 @@ void Setup(bool use_fpu) {
} else {
DisableFpu();
}
+ pw_CpuExceptionSetHandler(TestingExceptionHandler);
EnableAllFaultHandlers();
InstallVectorTableEntries();
exceptions_handled = 0;
@@ -546,9 +553,7 @@ TEST(FaultEntry, FloatUnalignedStackFault) {
#endif // defined(PW_ARMV7M_ENABLE_FPU) && PW_ARMV7M_ENABLE_FPU == 1
-} // namespace
-
-void HandleCpuException(CpuState* state) {
+void TestingExceptionHandler(pw_CpuExceptionState* state) {
if (++current_fault_depth > kMaxFaultDepth) {
volatile bool loop = true;
while (loop) {
@@ -571,7 +576,9 @@ void HandleCpuException(CpuState* state) {
if (arm_v7m_cfsr & kUnalignedFaultMask) {
// Copy captured state to check later.
- std::memcpy(&captured_states[exceptions_handled], state, sizeof(CpuState));
+ std::memcpy(&captured_states[exceptions_handled],
+ state,
+ sizeof(pw_CpuExceptionState));
// Disable unaligned read/write trapping to "handle" exception.
arm_v7m_ccr &= ~kUnalignedTrapEnableMask;
@@ -580,11 +587,13 @@ void HandleCpuException(CpuState* state) {
return;
} else if (arm_v7m_cfsr & kDivByZeroFaultMask) {
// Copy captured state to check later.
- std::memcpy(&captured_states[exceptions_handled], state, sizeof(CpuState));
+ std::memcpy(&captured_states[exceptions_handled],
+ state,
+ sizeof(pw_CpuExceptionState));
// Ensure std::span compares to be the same.
std::span<const uint8_t> state_span = RawFaultingCpuState(*state);
- EXPECT_EQ(state_span.size(), sizeof(CpuState));
+ EXPECT_EQ(state_span.size(), sizeof(pw_CpuExceptionState));
if (std::memcmp(state, state_span.data(), state_span.size()) == 0) {
span_matches = true;
} else {
@@ -603,4 +612,5 @@ void HandleCpuException(CpuState* state) {
}
}
+} // namespace
} // namespace pw::cpu_exception
diff --git a/pw_cpu_exception_armv7m/public/pw_cpu_exception_armv7m/cpu_state.h b/pw_cpu_exception_armv7m/public/pw_cpu_exception_armv7m/cpu_state.h
index 8646d9465..f38b949ba 100644
--- a/pw_cpu_exception_armv7m/public/pw_cpu_exception_armv7m/cpu_state.h
+++ b/pw_cpu_exception_armv7m/public/pw_cpu_exception_armv7m/cpu_state.h
@@ -84,12 +84,12 @@ PW_PACKED(struct) ArmV7mExtraRegisters {
uint32_t r11;
};
-PW_PACKED(struct) CpuState {
- ArmV7mExtraRegisters extended;
- ArmV7mFaultRegisters base;
+} // namespace pw::cpu_exception
+
+PW_PACKED(struct) pw_CpuExceptionState {
+ pw::cpu_exception::ArmV7mExtraRegisters extended;
+ pw::cpu_exception::ArmV7mFaultRegisters base;
// TODO(amontanez): FPU registers may or may not be here as well. Make the
// availability of the FPU registers a compile-time configuration when FPU
// register support is added.
};
-
-} // namespace pw::cpu_exception