ZephyrPlugin_CM4.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*********************************************************************
  2. * (c) SEGGER Microcontroller GmbH *
  3. * The Embedded Experts *
  4. * www.segger.com *
  5. **********************************************************************
  6. -------------------------- END-OF-HEADER -----------------------------
  7. File : ZephyrPlugin_CM4.js
  8. Purpose : Script for thread windows for Zephyr and SEGGER Embedded Studio/Ozone
  9. Includes FPU awareness.
  10. TODO: Restore FPU context
  11. */
  12. /**** Zephyr list names, constant ************************************/
  13. //var Mutexes = "Mutexes";
  14. //var Semaphores = "Semaphores";
  15. //var Queues = "Queues";
  16. //var Mailboxes = "Mailboxes";
  17. //var Timers = "Timers";
  18. //var MemoryPools = "Memory Pools";
  19. //var SystemInformation = "System Information";
  20. //@todo ...
  21. function isValid( task ) {
  22. return !( ( task == undefined ) || (task == 0) );
  23. }
  24. function get_tcb(hTask) {
  25. //对数值对象进行表达式转换,转换成TCB对象
  26. return Debug.evaluate("*(k_thread*)" + hTask);
  27. }
  28. function get_thread_tid(hTask) {
  29. //把TCB地址转换成TID字符串
  30. return "0x" + hTask.toString(16);
  31. }
  32. function get_thread_entry(hTask) {
  33. var task = get_tcb(hTask);
  34. if ( isValid(task) ) {
  35. //如果entry是一个符号,获取符号名称
  36. if (Debug.getSymbol) return Debug.getSymbol( task.entry.pEntry );
  37. //如果entry是一个函数地址,获取函数名称?
  38. if (Debug.getfunction) return Debug.getfunction( task.entry.pEntry );
  39. return "0x" + task.entry.pEntry.toString(16);
  40. }
  41. return "undefined";
  42. }
  43. function get_thread_prio(hTask) {
  44. var task = get_tcb(hTask);
  45. if ( isValid(task) ) {
  46. //旧版本zephyr存在prio成员
  47. if ( task.base.prio != undefined ) return task.base.prio;
  48. //新版本zephyr prio位于匿名的联合体中
  49. if ( task.base["<<anonymous>_1>"]["<<anonymous>_0>"].prio != undefined ) return task.base["<<anonymous>_1>"]["<<anonymous>_0>"].prio;
  50. }
  51. return "undefined";
  52. }
  53. function get_thread_exc_return(hTask) {
  54. var task = get_tcb(hTask);
  55. if ( isValid(task) ) {
  56. if ( task.arch["<<anonymous>_0>"]["<<anonymous>_0>"].mode_exc_return != undefined ) return task.arch["<<anonymous>_0>"]["<<anonymous>_0>"].mode_exc_return;
  57. }
  58. return "undefined";
  59. }
  60. function get_thread_state(hTask) {
  61. var task = get_tcb(hTask);
  62. if (task == undefined || task == 0) {
  63. return "invalid";
  64. } else {
  65. // Not a real thread _THREAD_DUMMY (BIT(0))
  66. // Thread is waiting on an object _THREAD_PENDING (BIT(1))
  67. // Thread has not yet started _THREAD_PRESTART (BIT(2))
  68. // Thread has terminated _THREAD_DEAD (BIT(3))
  69. // Thread is suspended _THREAD_SUSPENDED (BIT(4))
  70. // Thread is being aborted (SMP only) _THREAD_ABORTING (BIT(5))
  71. // Thread was aborted in interrupt context (SMP only) _THREAD_ABORTED_IN_ISR (BIT(6))
  72. // Thread is present in the ready queue _THREAD_QUEUED (BIT(7))
  73. var state = task.base.thread_state;
  74. if (state & (1 << 3)) {
  75. return "Dead";
  76. }
  77. if (state & (1 << 2)) {
  78. return "Prestart";
  79. }
  80. if (state & (1 << 5)) {
  81. return "Aborting";
  82. }
  83. if (state & (1 << 6)) {
  84. return "Aborting";
  85. }
  86. if (state & (1 << 1)) {
  87. return "Blocked";
  88. }
  89. if (state & (1 << 4)) {
  90. return "Waiting";
  91. }
  92. if (state & (1 << 7)) {
  93. return "Ready";
  94. }
  95. return "Invalid";
  96. }
  97. }
  98. function get_thread_name(hTask) {
  99. //将hTask地址转成TCB对象
  100. var task = get_tcb(hTask);
  101. if ( isValid(task) ) {
  102. var name = "";
  103. //如果task.name有效
  104. if ( isValid(task.name) ) {
  105. //获取name长度,但是length不是task成员???
  106. var name_len = task.name.length;
  107. if (name_len != 0){
  108. for (var i = 0; i < name_len; i++) {
  109. var c = task.name[i];
  110. if (c != 0) {
  111. name += String.fromCharCode(c);
  112. }
  113. }
  114. return name;
  115. }
  116. }
  117. //如果找不到name,则以TID+ENTRY作为标识符
  118. return "T0x"+hTask.toString(16)+"@"+get_thread_entry(hTask);
  119. }
  120. return "invalid";
  121. }
  122. function updateStackUsage(hTask){
  123. var unused;
  124. var StackUsage;
  125. var MaxStackUsed = "??";
  126. var task = get_tcb(hTask);
  127. var SP = task.callee_saved.psp;
  128. var sp_start = task.stack_info.start;
  129. var sp_size = task.stack_info.size;
  130. var sentinel;
  131. //获取不为0xaa的首数据
  132. if (TargetInterface.findByte) {
  133. //
  134. // Check if TargetInterface.findByte is implemented
  135. //
  136. sentinel = TargetInterface.peekWord(sp_start);
  137. unused = TargetInterface.findNotByte(sp_start+4, sp_size-4, 0xaa);
  138. if ((sentinel == 0xaaaaaaaa) || (sentinel == 0xf0f0f0f0)) {
  139. unused += 4;
  140. }
  141. }
  142. MaxStackUsed = sp_size - unused;
  143. StackUsage = MaxStackUsed + " / " + sp_size + " @ 0x" + SP.toString(16) + " @ 0x" + sp_start.toString(16);
  144. return StackUsage;
  145. }
  146. function updateThreads() {
  147. if (Threads.newqueue2 == undefined) {
  148. Threads.newqueue( "Task List" )
  149. }
  150. //z_idle_threads是idle线程TCB地址,这里获取idle线程TCB
  151. var idle_ptask = Debug.evaluate("&z_idle_threads[0]");
  152. //idle_ptask.toString(16);
  153. //获取main线程TCB地址
  154. var main_ptask = Debug.evaluate("&z_main_thread");
  155. //main_ptask.toString(16);
  156. //获取当前线程TCB地址
  157. var current_ptask = Debug.evaluate("_kernel.ready_q.cache");
  158. //current_ptask.toString(16);
  159. //这里获取所有线程链表的头指针地址
  160. var ptask = Debug.evaluate("_kernel.threads");
  161. //ptask.toString(16);
  162. //如果指针为空,说明THREAD_MONITOR配置项未打开,需要打开该配置项
  163. if( false == isValid(ptask) ) Threads.add( "Enable THREAD_MONITOR for information", undefined );
  164. while ( isValid(ptask) ) {
  165. //将ptask地址转成成TCB结构的对象
  166. var task = get_tcb(ptask);
  167. var task_name = get_thread_name(ptask);
  168. var tid = get_thread_tid(ptask);
  169. var entry = get_thread_entry(ptask);
  170. var prio = get_thread_prio(ptask).toString();
  171. var status;
  172. if (current_ptask == ptask) status = "Executing";
  173. else if (idle_ptask == ptask) status = "Ready";
  174. else status = get_thread_state(ptask);
  175. //var SP = task.callee_saved.psp;
  176. //Threads.add( task_name, tid, entry, prio, status, "0x" + SP.toString(16), (current_ptask == ptask) ? undefined : ptask);
  177. var sp = updateStackUsage(ptask);
  178. Threads.add( task_name, tid, entry, prio, status, sp, (current_ptask == ptask) ? undefined : ptask);
  179. ptask = task.next_thread;
  180. }
  181. }
  182. function UpdateMutexes( Window ) {
  183. var pMutex = undefined; // add here a valid address to get all OS objects of interest
  184. while (pMutex) {
  185. //
  186. // Get necessary information about OS object and populate them to table.
  187. //
  188. // Show values in table
  189. Window.add2( Mutextes, // Table Mutextes
  190. "0x" + pMutex.toString(16).toUpperCase(), // Address of mutex
  191. "..." // everything else
  192. );
  193. }
  194. }
  195. function UpdateTodo( Window ) {
  196. Window.add2("...", "Todo: Add more information" );
  197. }
  198. /*********************************************************************
  199. *
  200. * init
  201. *
  202. * Function description
  203. * Initializes all RTOS informational views of the RTOS Window.
  204. *
  205. **********************************************************************/
  206. function init() {
  207. //清除表格
  208. Threads.clear();
  209. //初始化任务列表
  210. Threads.newqueue("Task List");
  211. //设置任务列表信息,包括Threads名称,TID, 入口地址,优先级,运行状态以及堆栈指针
  212. Threads.setColumns("Threads", "TID", "Entry", "Priority", "Status", "Stack" );
  213. //设置任务列表可按TID大小排序
  214. Threads.setSortByNumber("TID");
  215. //设置任务列表可按优先级大小排序
  216. Threads.setSortByNumber("Priority");
  217. //设置任务列表可按stack地址排序
  218. Threads.setSortByNumber("Stack");
  219. //设置任务颜色,以任务状态作为颜色标记
  220. if (Threads.setColor) {
  221. Threads.setColor("Status", "Ready", "Executing", "Waiting");
  222. }
  223. //如果运行显示折叠的行
  224. if (Threads.setColumns2) {
  225. //如果允许显示mutexs,调用Threads.setColumns2方法进行显示,开关变量在开始有定义
  226. if(Mutexes ) Threads.setColumns2(Mutexes, "Mutexes" /*, "Name", "Owner", "Use Counter", "Waiting Tasks" */);
  227. if(Semaphores ) Threads.setColumns2(Queues, "Queues"/*, "Name", "Messages", "Buffer Address", "Buffer Size", "Waiting Tasks" */);
  228. if(Queues ) Threads.setColumns2(Semaphores, "Semaphores"/*, "Name", "Count", "Waiting Tasks" */);
  229. if(Mailboxes ) Threads.setColumns2(Mailboxes, "Mailboxes"/*, "Name", "Messages", "Message Size", "Buffer Address", "Waiting Tasks", "In Use" */);
  230. if(Timers ) Threads.setColumns2(Timers, "Timers"/*, "Name", "Hook", "Timeout", "Period" */);
  231. if(MemoryPools ) Threads.setColumns2(MemoryPools, "MemoryPools"/*, "Name", "Total Blocks", "Block Size", "Max. Usage", "Buffer Address", "Waiting Tasks"*/);
  232. if(SystemInformation) Threads.setColumns2(SystemInformation, SystemInformation, "Value" );
  233. Threads.setColumns2( "...", "..." );
  234. }
  235. TargetInterface.message( "Loaded" );
  236. }
  237. /*********************************************************************
  238. *
  239. * update
  240. *
  241. * Function description
  242. * Updates all RTOS informational views of the RTOS Window.
  243. *
  244. **********************************************************************
  245. */
  246. function update() {
  247. //
  248. // Clear entire threads window
  249. //
  250. Threads.clear();
  251. //
  252. // Update plug in lists
  253. //
  254. if (Threads.newqueue2 != undefined) {
  255. if (Mutexes && Threads.shown(Mutexes)) UpdateMutexes(Threads);
  256. if (Semaphores && Threads.shown(Semaphores)) UpdateSemaphores(Threads);
  257. if (Queues && Threads.shown(Queues)) UpdateQueues(Threads);
  258. if (Mailboxes && Threads.shown(Mailboxes)) UpdateMailboxes(Threads);
  259. if (Timers && Threads.shown(Timers)) UpdateTimers(Threads);
  260. if (MemoryPools && Threads.shown(MemoryPools)) UpdateMemoryPools(Threads);
  261. if (SystemInformation && Threads.shown(SystemInformation)) UpdateSystemInformation(Threads);
  262. // @todo Add more Lists
  263. if ( Threads.shown("...")) UpdateTodo(Threads);
  264. }
  265. updateThreads();
  266. }
  267. /*********************************************************************
  268. *
  269. * getname
  270. *
  271. * Function description
  272. * Returns the name of a task.
  273. *
  274. * Parameters
  275. * hTask: see the description of method getregs.
  276. *
  277. **********************************************************************
  278. */
  279. function getname(hTask) {
  280. return get_thread_name(hTask);
  281. }
  282. /*********************************************************************
  283. *
  284. * getregs
  285. *
  286. * Function description
  287. * Returns the register set of a task.
  288. * For ARM cores, this function is expected to return the values
  289. * of registers R0 to R15 and PSR.
  290. *
  291. * Parameters
  292. * hTask: integer number identifying the task.
  293. * Identical to the last parameter supplied to method Threads.add.
  294. * For convenience, this should be the address of the TCB.
  295. *
  296. * Return Values
  297. * An array of unsigned integers containing the task’s register values.
  298. * The array must be sorted according to the logical indexes of the regs.
  299. * The logical register indexing scheme is defined by the ELF-DWARF ABI.
  300. *
  301. **********************************************************************
  302. */
  303. function getregs(hTask) {
  304. TargetInterface.message( "refresh registers" );
  305. FPSCR = 39;
  306. S0ofs = 64;
  307. S16ofs = S0ofs + 16;
  308. var regs = new Array(100);
  309. var task = get_tcb(hTask);
  310. //
  311. // Restore task stack (SP) from thread
  312. //
  313. var SP = task.callee_saved.psp;
  314. //
  315. // Restore R4-R11 from thread
  316. //
  317. regs[ 4] = task.callee_saved.v1;
  318. regs[ 5] = task.callee_saved.v2;
  319. regs[ 6] = task.callee_saved.v3;
  320. regs[ 7] = task.callee_saved.v4;
  321. regs[ 8] = task.callee_saved.v5;
  322. regs[ 9] = task.callee_saved.v6;
  323. regs[10] = task.callee_saved.v7;
  324. regs[11] = task.callee_saved.v8;
  325. //
  326. //这些寄存器是硬件自动压栈的 Restore automatically saved R0-R3, and R12, LR, PC, xPSR from task stack
  327. //
  328. for (var i = 0; i < 4; i++){ // R0..R3
  329. regs[i] = TargetInterface.peekWord(SP);
  330. SP += 4;
  331. }
  332. regs[12] = TargetInterface.peekWord(SP); // IP
  333. SP += 4;
  334. regs[14] = TargetInterface.peekWord(SP); // LR
  335. SP += 4;
  336. regs[15] = TargetInterface.peekWord(SP); // PC = return address
  337. SP += 4;
  338. regs[16] = TargetInterface.peekWord(SP); // xPSR
  339. SP += 4;
  340. //
  341. // Restore saved FPU registers.
  342. //
  343. var pFPRegs = Debug.evaluate( "thread->arch.preempt_float" );
  344. var ExcReturn = get_thread_exc_return(hTask);
  345. if ((ExcReturn & 0x10) == 0) { // test EXC_RETURN.F_Type_Msk
  346. // FPU was active for this thread, so restore the FP-registers
  347. // restore S0..S15, FPSCR from stack
  348. for( var i=0; i<16; ++i ) {
  349. regs[S0ofs + i] = TargetInterface.peekWord(SP); // S0..15
  350. SP += 4;
  351. }
  352. regs[FPSCR] = TargetInterface.peekWord(SP); // FPSCR
  353. SP += 4;
  354. SP += 4; // Dummy read
  355. // restore S16..S31 form thread->arch.preempt_float
  356. for( var i=0; i<16; ++i ) {
  357. regs[S16ofs + i] = TargetInterface.peekWord(pFPRegs + 4*i); // S16..31
  358. }
  359. }
  360. //
  361. // 8 byte aligned SP in interrupt entry enabled? (Set in xPSR[9])
  362. // Increment SP after reading registers before accessing further variables from stack
  363. //
  364. if (regs[16] & (1<<9)) {
  365. if ((SP % 8) != 0) { // Check is stack is already aligned
  366. // enforce SP 8 byte alignement
  367. SP += 4;
  368. }
  369. }
  370. //
  371. // Restore SP after adjusting for saved registers.
  372. // Now points to function stack frame.
  373. //
  374. regs[13] = SP;
  375. return regs;
  376. }
  377. /*********************************************************************
  378. *
  379. * getContextSwitchAddrs
  380. *
  381. * Function description
  382. * Returns the base addresses of all functions and instructions
  383. * that complete a task switch when executed.
  384. *
  385. **********************************************************************
  386. */
  387. function getContextSwitchAddrs() {
  388. var aAddrs;
  389. var Addr;
  390. Addr = Debug.evaluate("&__swap")
  391. if (Addr == undefined) {
  392. Addr = Debug.evaluate("&arch_swap")
  393. }
  394. if (Addr == undefined) {
  395. return [];
  396. }
  397. aAddrs = new Array(1);
  398. aAddrs[0] = Addr;
  399. return aAddrs;
  400. }
  401. function getOSName() {
  402. return "Zephyr";
  403. }