MSP430EEMTarget.cpp
Go to the documentation of this file.
2 #include "stdafx.h"
3 #include "MSP430EEMTarget.h"
4 
5 #include <MSP430_EEM.h>
7 
8 #define REPORT_AND_RETURN(msg, result) { ReportLastMSP430Error(msg); return result; }
9 
10 using namespace GDBServerFoundation;
11 using namespace MSP430Proxy;
12 
13 //Breakpoint cookie format:
14 //32 bits: [type : 4] [reserved : 12] [user_data : 16]
15 //For RAM breakpoints user_data contains the original insn
16 //For hardware breakpoints user_data contains the handle returned by EEM API
17 
18 enum {kBpCookieTypeMask = 0xF0000000,
19  kBpCookieTypeHardware = 0x10000000,
22  kBpCookieDataMask = 0x0000FFFF};
23 
24 #define MAKE_BP_COOKIE(type, data) (((type) & kBpCookieTypeMask) | ((data) & kBpCookieDataMask))
25 
27 {
28  WMX_SINGLESTEP = WM_USER + 1,
34 };
35 
37 {
38  if (!__super::Initialize(settings))
39  return false;
40 
41  if (m_pBreakpointManager)
42  return false;
43 
44  m_BreakpointPolicy = settings.SoftBreakPolicy;
45 
46  MESSAGE_ID msgs = {0,};
47  msgs.uiMsgIdSingleStep = WMX_SINGLESTEP;
48  msgs.uiMsgIdBreakpoint = WMX_BREKAPOINT;
49  msgs.uiMsgIdStorage = WMX_STORAGE;
50  msgs.uiMsgIdState = WMX_STATE;
51  msgs.uiMsgIdWarning = WMX_WARNING;
52  msgs.uiMsgIdCPUStopped = WMX_STOPPED;
53 
54  C_ASSERT(sizeof(LONG) == sizeof(this));
55  if (MSP430_EEM_Init(sEEMHandler, (LONG)this, &msgs) != STATUS_OK)
56  REPORT_AND_RETURN("Cannot enter EEM mode", false);
57 
58  m_bEEMInitialized = true;
59 
60  if (m_BreakpointPolicy != HardwareOnly)
61  {
62  BpParameter_t bkpt;
63  memset(&bkpt, 0, sizeof(bkpt));
64 
65  bkpt.bpMode = BP_COMPLEX;
66  bkpt.lAddrVal = settings.BreakpointInstruction;
67  bkpt.bpType = BP_MDB;
68  bkpt.bpAccess = BP_FETCH;
69  bkpt.bpAction = BP_BRK;
70  bkpt.bpOperat = BP_EQUAL;
71  bkpt.bpCondition = BP_NO_COND;
72  bkpt.lMask = 0xffff;
73  if (MSP430_EEM_SetBreakpoint(&m_SoftwareBreakpointWrapperHandle, &bkpt) != STATUS_OK)
74  REPORT_AND_RETURN("Cannot create a MDB breakpoint for handling software breakpoints", false);
75  m_HardwareBreakpointsUsed++;
76  }
77  else
78  m_SoftwareBreakpointWrapperHandle = -1;
79 
80  m_pBreakpointManager = new SoftwareBreakpointManager(m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd, settings.BreakpointInstruction, settings.InstantBreakpointCleanup);
81 
82  return true;
83 }
84 
86 {
87  delete m_pBreakpointManager;
88 
89  if (m_SoftwareBreakpointWrapperHandle != -1)
90  {
91  BpParameter_t bkpt;
92  memset(&bkpt, 0, sizeof(bkpt));
93  bkpt.bpMode = BP_CLEAR;
94 
95  MSP430_EEM_SetBreakpoint(&m_SoftwareBreakpointWrapperHandle, &bkpt);
96  }
97 
98  if (m_bEEMInitialized)
99  MSP430_EEM_Close();
100 }
101 
102 void MSP430Proxy::MSP430EEMTarget::EEMNotificationHandler( MSP430_MSG wMsg, WPARAM wParam, LPARAM lParam )
103 {
104  switch(wMsg)
105  {
106  case WMX_BREKAPOINT:
107  case WMX_SINGLESTEP:
108  case WMX_STOPPED:
109  m_LastStopEvent = wMsg;
110  m_TargetStopped.Set();
111  break;
112  }
113 }
114 
115 void MSP430Proxy::MSP430EEMTarget::sEEMHandler( UINT MsgId, UINT wParam, LONG lParam, LONG clientHandle )
116 {
117  C_ASSERT(sizeof(clientHandle) == sizeof(MSP430EEMTarget *));
118  ((MSP430EEMTarget *)clientHandle)->EEMNotificationHandler((MSP430_MSG)MsgId, wParam, lParam);
119 }
120 
122 {
123  for (;;)
124  {
125  m_TargetStopped.Wait();
126 
127  bool breakIn = m_BreakInPending;
128  m_BreakInPending = false;
129 
130  LONG regPC = 0;
131 
132  if (MSP430_Read_Register(&regPC, PC) != STATUS_OK)
133  REPORT_AND_RETURN("Cannot read PC register", false);
134 
135  SoftwareBreakpointManager::BreakpointState bpState = m_pBreakpointManager->GetBreakpointState(regPC - 2);
136  if (m_RAMBreakpoints.IsBreakpointPresent((USHORT)regPC - 2))
137  bpState = SoftwareBreakpointManager::BreakpointActive;
138 
139  switch(bpState)
140  {
141  case SoftwareBreakpointManager::BreakpointActive:
142  case SoftwareBreakpointManager::BreakpointInactive:
143  regPC -= 2;
144 
145  if (regPC == m_BreakpointAddrOfLastResumeOp)
146  {
147  //We have just continued from the breakpoint event by patching the original instruction into the instruction fetcher.
148  //We don't want to stop indefinitely here.
149  if (m_LastResumeMode != SINGLE_STEP)
150  {
151  if (!DoResumeTarget(m_LastResumeMode))
152  return false;
153  continue;
154  }
155  return true;
156  }
157 
158  if (MSP430_Write_Register(&regPC, PC) != STATUS_OK)
159  REPORT_AND_RETURN("Cannot read PC register", false);
160 
161  if (bpState == SoftwareBreakpointManager::BreakpointInactive && m_LastResumeMode != SINGLE_STEP && !breakIn)
162  {
163  //Skip the breakpoint
164  if (!DoResumeTarget(m_LastResumeMode))
165  return false;
166  continue;
167  }
168 
169  return true;
170  case SoftwareBreakpointManager::NoBreakpoint:
171  default:
172  return true; //The stop is not related to a software breakpoint
173  }
174  }
175 }
176 
177 GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::CreateBreakpoint( BreakpointType type, ULONGLONG Address, unsigned kind, OUT INT_PTR *pCookie )
178 {
179  switch(type)
180  {
181  case bptSoftwareBreakpoint:
182  switch(m_BreakpointPolicy)
183  {
184  case HardwareOnly:
185  return DoCreateCodeBreakpoint(true, Address, pCookie);
187  return DoCreateCodeBreakpoint((m_HardwareBreakpointsUsed < m_DeviceInfo.nBreakpoints), Address, pCookie);
188  case SoftwareOnly:
189  default:
190  return DoCreateCodeBreakpoint(false, Address, pCookie);
191  }
192  case bptHardwareBreakpoint:
193  if (m_BreakpointPolicy == HardwareThenSoftware && m_bFLASHCommandsUsed)
194  return DoCreateCodeBreakpoint((m_HardwareBreakpointsUsed < m_DeviceInfo.nBreakpoints), Address, pCookie);
195  else
196  return DoCreateCodeBreakpoint(true, Address, pCookie);
197  case bptAccessWatchpoint:
198  case bptWriteWatchpoint:
199  case bptReadWatchpoint:
200  break;
201  default:
202  return kGDBNotSupported;
203  }
204 
205  BpParameter_t bkpt;
206  memset(&bkpt, 0, sizeof(bkpt));
207  bkpt.bpMode = BP_COMPLEX;
208  bkpt.lAddrVal = (ULONG)Address;
209  bkpt.bpType = BP_MAB;
210  switch(type)
211  {
212  case bptAccessWatchpoint:
213  bkpt.bpAccess = BP_NO_FETCH;
214  break;
215  case bptReadWatchpoint:
216  bkpt.bpAccess = BP_READ;
217  break;
218  case bptWriteWatchpoint:
219  bkpt.bpAccess = BP_WRITE;
220  break;
221  }
222  bkpt.bpAction = BP_BRK;
223  bkpt.bpOperat = BP_EQUAL;
224  bkpt.bpCondition = BP_NO_COND;
225  bkpt.lMask = 0xffff;
226 
227  WORD bpHandle = 0;
228  if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
229  REPORT_AND_RETURN("Cannot set an EEM breakpoint", kGDBUnknownError);
230 
231  *pCookie = MAKE_BP_COOKIE(kBpCookieTypeHardware, bpHandle);
232 
233  return kGDBSuccess;
234 }
235 
236 GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::RemoveBreakpoint( BreakpointType type, ULONGLONG Address, INT_PTR Cookie )
237 {
238  switch(type)
239  {
240  case bptSoftwareBreakpoint:
241  return DoRemoveCodeBreakpoint(false, Address, Cookie);
242  case bptHardwareBreakpoint:
243  case bptReadWatchpoint:
244  case bptWriteWatchpoint:
245  case bptAccessWatchpoint:
246  return DoRemoveCodeBreakpoint(true, Address, Cookie);
247  default:
248  return kGDBNotSupported;
249  }
250 
251  return kGDBSuccess;
252 }
253 
255 {
256  unsigned short originalInsn;
257  LONG regPC = 0;
258  if (MSP430_Read_Register(&regPC, PC) != STATUS_OK)
259  REPORT_AND_RETURN("Cannot read PC register", false);
260  if (m_pBreakpointManager->GetOriginalInstruction(regPC, &originalInsn))
261  {
262  if (MSP430_Configure(SET_MDB_BEFORE_RUN, originalInsn) != STATUS_OK)
263  REPORT_AND_RETURN("Cannot resume from a software breakpoint", false);
264  m_BreakpointAddrOfLastResumeOp = regPC;
265  }
266  else
267  m_BreakpointAddrOfLastResumeOp = -1;
268 
269  m_LastResumeMode = mode;
270  m_TargetStopped.Reset();
271  if (!m_pBreakpointManager->CommitBreakpoints())
272  {
273  printf("ERROR: Cannot commit software breakpoints\n");
274  return false;
275  }
276  return __super::DoResumeTarget(mode);
277 }
278 
280 {
281  LONG state;
282  m_BreakInPending = true;
283  if (MSP430_State(&state, TRUE, NULL) != STATUS_OK)
284  REPORT_AND_RETURN("Cannot stop device", kGDBNotSupported);
285  return kGDBSuccess;
286 }
287 
288 GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::ReadTargetMemory( ULONGLONG Address, void *pBuffer, size_t *pSizeInBytes )
289 {
290  GDBStatus status = __super::ReadTargetMemory(Address, pBuffer, pSizeInBytes);
291  if (status != kGDBSuccess)
292  return status;
293 
294  m_pBreakpointManager->HideOrRestoreBreakpointsInMemorySnapshot((unsigned)Address, pBuffer, *pSizeInBytes, true);
295 
296  return kGDBSuccess;
297 }
298 
299 GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::WriteTargetMemory( ULONGLONG Address, const void *pBuffer, size_t sizeInBytes )
300 {
301  GDBStatus status = __super::WriteTargetMemory(Address, pBuffer, sizeInBytes);
302  if (status != kGDBSuccess)
303  return status;
304 
305 // m_pBreakpointManager->HideOrRestoreBreakpointsInMemorySnapshot((unsigned)Address, pBuffer, *pSizeInBytes, false);
306 
307  return kGDBSuccess;
308 }
309 
310 GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoCreateCodeBreakpoint( bool hardware, ULONGLONG Address, INT_PTR *pCookie )
311 {
312  if (hardware)
313  {
314  BpParameter_t bkpt;
315  memset(&bkpt, 0, sizeof(bkpt));
316  bkpt.bpMode = BP_CODE;
317  bkpt.lAddrVal = (LONG)Address;
318  bkpt.bpCondition = BP_NO_COND;
319  bkpt.bpAction = BP_BRK;
320 
321  WORD bpHandle = 0;
322  if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
323  REPORT_AND_RETURN("Cannot set an EEM breakpoint", kGDBUnknownError);
324 
325  m_HardwareBreakpointsUsed++;
326 
327  C_ASSERT(sizeof(bpHandle) == 2);
328  *pCookie = MAKE_BP_COOKIE(kBpCookieTypeHardware, bpHandle);
329 
330  return kGDBSuccess;
331  }
332  else
333  {
334  if (!IsFLASHAddress(Address))
335  {
336  ULONG addr = (ULONG)(Address & ~1);
337 
338  if (m_RAMBreakpoints.IsBreakpointPresent((USHORT)addr))
339  {
340  printf("Cannot set a breakpoint at 0x%04x. Breakpoint already exists.\n", (unsigned)Address);
341  return kGDBUnknownError;
342  }
343 
344  unsigned short insn;
345  if (MSP430_Read_Memory(addr, (char *)&insn, 2) != STATUS_OK)
346  REPORT_AND_RETURN("Cannot set a software breakpoint in RAM", kGDBUnknownError);
347 
348  *pCookie = MAKE_BP_COOKIE(kBpCookieTypeSoftwareRAM, insn);
349 
350  insn = m_BreakpointInstruction;
351  if (MSP430_Write_Memory(addr, (char *)&insn, 2) != STATUS_OK)
352  REPORT_AND_RETURN("Cannot set a software breakpoint in RAM", kGDBUnknownError);
353 
354  m_RAMBreakpoints.InsertBreakpoint((USHORT)addr);
355  }
356  else
357  {
358  if (!m_pBreakpointManager->SetBreakpoint((unsigned)Address))
359  return kGDBUnknownError;
361  }
362  return kGDBSuccess;
363  }
364 }
365 
366 GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoRemoveCodeBreakpoint( bool hardware, ULONGLONG Address, INT_PTR Cookie )
367 {
368  if ((Cookie & kBpCookieTypeMask) == kBpCookieTypeHardware)
369  {
370  BpParameter_t bkpt;
371  memset(&bkpt, 0, sizeof(bkpt));
372  bkpt.bpMode = BP_CLEAR;
373 
374  WORD bpHandle = (WORD)(Cookie & kBpCookieDataMask);
375 
376  if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
377  REPORT_AND_RETURN("Cannot remove an EEM breakpoint", kGDBUnknownError);
378  m_HardwareBreakpointsUsed--;
379  return kGDBSuccess;
380  }
381  else
382  {
383  if (!IsFLASHAddress(Address))
384  {
385  ASSERT((Cookie & kBpCookieTypeMask) == kBpCookieTypeSoftwareRAM);
386  unsigned short originalINSN = (unsigned short)(Cookie & kBpCookieDataMask);
387 
388  if (MSP430_Write_Memory(Address & ~1, (char *)&originalINSN, 2) != STATUS_OK)
389  REPORT_AND_RETURN("Cannot remove a software breakpoint from RAM", kGDBUnknownError);
390 
391  m_RAMBreakpoints.RemoveBreakpoint((USHORT)(Address & ~1));
392  }
393  else
394  {
395  ASSERT((Cookie & kBpCookieTypeMask) == kBpCookieTypeSoftwareFLASH);
396  if (!m_pBreakpointManager->RemoveBreakpoint((unsigned)Address))
397  return kGDBUnknownError;
398  }
399 
400  return kGDBSuccess;
401  }
402 
403 }