Skip to content

Commit cc1ae68

Browse files
rtos: add handling for banked PSP registers (#1841)
1 parent 555dbfe commit cc1ae68

File tree

6 files changed

+105
-46
lines changed

6 files changed

+105
-46
lines changed

pyocd/rtos/argon.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pyOCD debugger
2-
# Copyright (c) 2016-2020 Arm Limited
2+
# Copyright (c) 2016-2020,2025 Arm Limited
33
# SPDX-License-Identifier: Apache-2.0
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -197,8 +197,10 @@ def read_core_registers_raw(self, reg_list):
197197
swStacked = 0x60
198198

199199
for reg in reg_list:
200-
# Must handle stack pointer specially.
201-
if reg == 13:
200+
201+
# Must handle stack pointer(s) specially.
202+
if (reg == index_for_reg('sp') or
203+
reg == index_for_reg('psp')):
202204
if inException:
203205
reg_vals.append(sp + hwStacked)
204206
else:
@@ -537,4 +539,3 @@ def name(self):
537539
@property
538540
def description(self):
539541
return "Argon RTOS"
540-

pyocd/rtos/common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
# on the frame. The bit is 0 if the frame is extended.
2727
EXC_RETURN_EXT_FRAME_MASK = (1 << 4)
2828

29+
## Mask on EXC_RETURN indicating whether a Secure or Non-secure stack is used
30+
# to restore stack frame on exception return. The bit is 0 if the Non-secure
31+
# stack is used or 1 if the Secure stack is used.
32+
EXC_RETURN_SECURE_STACK_MASK = (1 << 6)
33+
2934
def read_c_string(context, ptr):
3035
"""@brief Reads a null-terminated C string from the target."""
3136
if ptr == 0:

pyocd/rtos/freertos.py

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pyOCD debugger
2-
# Copyright (c) 2016-2020 Arm Limited
2+
# Copyright (c) 2016-2020,2025 Arm Limited
33
# SPDX-License-Identifier: Apache-2.0
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
1515
# limitations under the License.
1616

1717
from .provider import (TargetThread, ThreadProvider)
18-
from .common import (read_c_string, HandlerModeThread, EXC_RETURN_EXT_FRAME_MASK)
18+
from .common import (read_c_string, HandlerModeThread, EXC_RETURN_EXT_FRAME_MASK, EXC_RETURN_SECURE_STACK_MASK)
1919
from ..core import exceptions
2020
from ..core.target import Target
2121
from ..core.plugin import Plugin
@@ -157,6 +157,7 @@ def __init__(self, parent, thread):
157157
super(FreeRTOSThreadContext, self).__init__(parent)
158158
self._thread = thread
159159
self._has_fpu = self.core.has_fpu
160+
self._has_security_extension = Target.SecurityState.SECURE in self.core.supported_security_states
160161

161162
def read_core_registers_raw(self, reg_list):
162163
reg_list = [index_for_reg(reg) for reg in reg_list]
@@ -179,11 +180,10 @@ def read_core_registers_raw(self, reg_list):
179180
else:
180181
sp = self._thread.get_stack_pointer()
181182

182-
# Determine which register offset table to use and the offsets past the saved state.
183-
hwStacked = 0x20
184-
swStacked = 0x20
185-
table = self.NOFPU_REGISTER_OFFSETS
186-
if self._has_fpu:
183+
# Read exception LR (holds EXC_RETURN) to determine stacking info.
184+
hasExtendedFrame = False
185+
hasSecureStack = False
186+
if self._has_fpu or self._has_security_extension:
187187
try:
188188
if inException and self.core.is_vector_catch():
189189
# Vector catch has just occurred, take live LR
@@ -193,20 +193,39 @@ def read_core_registers_raw(self, reg_list):
193193
offset = self.FPU_BASIC_REGISTER_OFFSETS[-1]
194194
exceptionLR = self._parent.read32(sp + offset)
195195

196-
# Check bit 4 of the saved exception LR to determine if FPU registers were stacked.
197-
if (exceptionLR & EXC_RETURN_EXT_FRAME_MASK) != 0:
198-
table = self.FPU_BASIC_REGISTER_OFFSETS
199-
swStacked = 0x24
200-
else:
201-
table = self.FPU_EXTENDED_REGISTER_OFFSETS
202-
hwStacked = 0x68
203-
swStacked = 0x64
196+
# Check bit 4 of the exception LR to determine if FPU registers were stacked.
197+
if (exceptionLR & EXC_RETURN_EXT_FRAME_MASK) == 0:
198+
hasExtendedFrame = True
199+
200+
# Check bit 6 of the exception LR to determine if Secure stack is used.
201+
if (exceptionLR & EXC_RETURN_SECURE_STACK_MASK) != 0:
202+
hasSecureStack = True
203+
204204
except exceptions.TransferError:
205205
LOG.debug("Transfer error while reading thread's saved LR")
206206

207+
# Determine which register offset table to use and the offsets past the saved state.
208+
if self._has_fpu:
209+
if hasExtendedFrame:
210+
table = self.FPU_EXTENDED_REGISTER_OFFSETS
211+
hwStacked = 0x68
212+
swStacked = 0x64
213+
else:
214+
table = self.FPU_BASIC_REGISTER_OFFSETS
215+
hwStacked = 0x20
216+
swStacked = 0x24
217+
else:
218+
table = self.NOFPU_REGISTER_OFFSETS
219+
hwStacked = 0x20
220+
swStacked = 0x20
221+
207222
for reg in reg_list:
208-
# Must handle stack pointer specially.
209-
if reg == 13:
223+
224+
# Must handle stack pointer(s) specially.
225+
if (reg == index_for_reg('sp') or
226+
reg == index_for_reg('psp') or
227+
(reg == index_for_reg('psp_s') and hasSecureStack) or
228+
(reg == index_for_reg('psp_ns') and not hasSecureStack)):
210229
if inException:
211230
reg_vals.append(sp + hwStacked)
212231
else:

pyocd/rtos/rtx5.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616
from .provider import (TargetThread, ThreadProvider)
17-
from .common import (read_c_string, HandlerModeThread, EXC_RETURN_EXT_FRAME_MASK)
17+
from .common import (read_c_string, HandlerModeThread, EXC_RETURN_EXT_FRAME_MASK, EXC_RETURN_SECURE_STACK_MASK)
1818
from ..core import exceptions
1919
from ..core.target import Target
2020
from ..core.plugin import Plugin
@@ -135,6 +135,7 @@ def __init__(self, parent, thread):
135135
super(RTXThreadContext, self).__init__(parent)
136136
self._thread = thread
137137
self._has_fpu = self.core.has_fpu
138+
self._has_security_extension = Target.SecurityState.SECURE in self.core.supported_security_states
138139

139140
def read_core_registers_raw(self, reg_list):
140141
reg_list = [index_for_reg(reg) for reg in reg_list]
@@ -157,11 +158,10 @@ def read_core_registers_raw(self, reg_list):
157158
else:
158159
sp = self._thread.get_stack_pointer()
159160

160-
# Determine which register offset table to use and the offsets past the saved state.
161-
hwStacked = 0x20
162-
swStacked = 0x20
163-
table = self.NOFPU_REGISTER_OFFSETS
164-
if self._has_fpu:
161+
# Read exception LR (holds EXC_RETURN) to determine stacking info.
162+
hasExtendedFrame = False
163+
hasSecureStack = False
164+
if self._has_fpu or self._has_security_extension:
165165
try:
166166
if inException and self.core.is_vector_catch():
167167
# Vector catch has just occurred, take live LR
@@ -174,16 +174,32 @@ def read_core_registers_raw(self, reg_list):
174174

175175
# Check bit 4 of the exception LR to determine if FPU registers were stacked.
176176
if (exceptionLR & EXC_RETURN_EXT_FRAME_MASK) == 0:
177-
table = self.FPU_REGISTER_OFFSETS
178-
hwStacked = 0x68
179-
swStacked = 0x60
177+
hasExtendedFrame = True
178+
179+
# Check bit 6 of the exception LR to determine if Secure stack is used.
180+
if (exceptionLR & EXC_RETURN_SECURE_STACK_MASK) != 0:
181+
hasSecureStack = True
182+
180183
except exceptions.TransferError:
181184
LOG.debug("Transfer error while reading thread's saved LR")
182185

186+
# Determine which register offset table to use and the offsets past the saved state.
187+
if hasExtendedFrame:
188+
table = self.FPU_REGISTER_OFFSETS
189+
hwStacked = 0x68
190+
swStacked = 0x60
191+
else:
192+
table = self.NOFPU_REGISTER_OFFSETS
193+
hwStacked = 0x20
194+
swStacked = 0x20
195+
183196
for reg in reg_list:
184197

185-
# Must handle stack pointer specially.
186-
if reg == 13:
198+
# Must handle stack pointer(s) specially.
199+
if (reg == index_for_reg('sp') or
200+
reg == index_for_reg('psp') or
201+
(reg == index_for_reg('psp_s') and hasSecureStack) or
202+
(reg == index_for_reg('psp_ns') and not hasSecureStack)):
187203
if inException:
188204
reg_vals.append(sp + hwStacked)
189205
else:
@@ -244,7 +260,6 @@ def __init__(self, targetContext, provider, base):
244260
self._state = 0
245261
self._priority = 0
246262
self._thread_context = RTXThreadContext(self._target_context, self)
247-
self._has_fpu = self._thread_context.core.has_fpu
248263
try:
249264
name_ptr = self._target_context.read32(self._base + RTXTargetThread.NAME_OFFSET)
250265
self._name = read_c_string(self._target_context, name_ptr)

pyocd/rtos/threadx.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# pyOCD debugger
2+
# Copyright (c) 2025 Arm Limited
23
# Copyright (c) 2020-2021 Federico Zuccardi Merli
34
# SPDX-License-Identifier: Apache-2.0
45
#
@@ -16,7 +17,8 @@
1617

1718
from .provider import (TargetThread, ThreadProvider)
1819
from .common import (read_c_string, HandlerModeThread,
19-
EXC_RETURN_EXT_FRAME_MASK)
20+
EXC_RETURN_EXT_FRAME_MASK,
21+
EXC_RETURN_SECURE_STACK_MASK)
2022
from ..core import exceptions
2123
from ..core.target import Target
2224
from ..core.plugin import Plugin
@@ -175,6 +177,7 @@ def __init__(self, parent, thread):
175177
super(ThreadXThreadContext, self).__init__(parent)
176178
self._thread = thread
177179
self._has_fpu = self.core.has_fpu
180+
self._has_security_extension = Target.SecurityState.SECURE in self.core.supported_security_states
178181
if self.core.architecture != CoreArchitecture.ARMv6M:
179182
# Use the default offsets for this istance
180183
self._nofpu_register_offsets = self.NOFPU_REGISTER_OFFSETS
@@ -205,11 +208,10 @@ def read_core_registers_raw(self, reg_list):
205208
else:
206209
sp = self._thread.get_stack_pointer()
207210

208-
# Determine which register offset table to use and the offsets past the saved state.
209-
hwStacked = 0x20
210-
swStacked = 0x24
211-
table = self._nofpu_register_offsets
212-
if self._has_fpu:
211+
# Read exception LR (holds EXC_RETURN) to determine stacking info.
212+
hasExtendedFrame = False
213+
hasSecureStack = False
214+
if self._has_fpu or self._has_security_extension:
213215
try:
214216
if inException and self.core.is_vector_catch():
215217
# Vector catch has just occurred, take live LR
@@ -221,16 +223,32 @@ def read_core_registers_raw(self, reg_list):
221223

222224
# Check bit 4 of the exception LR to determine if FPU registers were stacked.
223225
if (exceptionLR & EXC_RETURN_EXT_FRAME_MASK) == 0:
224-
table = self.FPU_REGISTER_OFFSETS
225-
hwStacked = 0x68
226-
swStacked = 0x64
226+
hasExtendedFrame = True
227+
228+
# Check bit 6 of the exception LR to determine if Secure stack is used.
229+
if (exceptionLR & EXC_RETURN_SECURE_STACK_MASK) != 0:
230+
hasSecureStack = True
231+
227232
except exceptions.TransferError:
228233
LOG.debug("Transfer error while reading thread's saved LR")
229234

235+
# Determine which register offset table to use and the offsets past the saved state.
236+
if hasExtendedFrame:
237+
table = self.FPU_REGISTER_OFFSETS
238+
hwStacked = 0x68
239+
swStacked = 0x64
240+
else:
241+
table = self._nofpu_register_offsets
242+
hwStacked = 0x20
243+
swStacked = 0x24
244+
230245
for reg in reg_list:
231246

232-
# Must handle stack pointer specially.
233-
if reg == 13:
247+
# Must handle stack pointer(s) specially.
248+
if (reg == index_for_reg('sp') or
249+
reg == index_for_reg('psp') or
250+
(reg == index_for_reg('psp_s') and hasSecureStack) or
251+
(reg == index_for_reg('psp_ns') and not hasSecureStack)):
234252
if inException:
235253
reg_vals.append(sp + hwStacked)
236254
else:

pyocd/rtos/zephyr.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pyOCD debugger
2-
# Copyright (c) 2016-2020 Arm Limited
2+
# Copyright (c) 2016-2020,2025 Arm Limited
33
# Copyright (c) 2022 Intel Corporation
44
# Copyright (c) 2022 Chris Reed
55
# SPDX-License-Identifier: Apache-2.0
@@ -106,7 +106,8 @@ def read_core_registers_raw(self, reg_list):
106106
for reg in reg_list:
107107

108108
# If this is a stack pointer register, add an offset to account for the exception stack frame
109-
if reg == 13:
109+
if (reg == index_for_reg('sp') or
110+
reg == index_for_reg('psp')):
110111
val = sp + exceptionFrame
111112
LOG.debug("Reading register %d = 0x%x", reg, val)
112113
reg_vals.append(val)

0 commit comments

Comments
 (0)