Subversion Repositories HelenOS

Rev

Rev 2919 | Rev 3471 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup generic
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file
  35.  * @brief   Udebug IPC message handling.
  36.  */
  37.  
  38. #include <console/klog.h>
  39. #include <proc/task.h>
  40. #include <proc/thread.h>
  41. #include <arch.h>
  42. #include <errno.h>
  43. #include <ipc/ipc.h>
  44. #include <syscall/copy.h>
  45. #include <udebug/udebug.h>
  46. #include <udebug/udebug_ops.h>
  47. #include <udebug/udebug_ipc.h>
  48.  
  49. static int udebug_rp_regs_write(call_t *call, phone_t *phone)
  50. {
  51.     void *uspace_data;
  52.     unative_t to_copy;
  53.     int rc;
  54.     void *buffer;
  55.  
  56.     klog_printf("debug_regs_write()");
  57.  
  58.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  59.     to_copy = sizeof(istate_t);
  60.     buffer = malloc(to_copy, 0);
  61.  
  62.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  63.     if (rc != 0) {
  64.         klog_printf("debug_regs_write() - copy failed");
  65.         return rc;
  66.     }
  67.  
  68.     call->buffer = buffer;
  69.  
  70.     klog_printf(" - done");
  71.     return 0;
  72. }
  73.  
  74. static int udebug_rp_mem_write(call_t *call, phone_t *phone)
  75. {
  76.     void *uspace_data;
  77.     unative_t to_copy;
  78.     int rc;
  79.     void *buffer;
  80.  
  81.     klog_printf("udebug_rp_mem_write()");
  82.  
  83.     uspace_data = (void *)IPC_GET_ARG2(call->data);
  84.     to_copy = IPC_GET_ARG4(call->data);
  85.  
  86.     buffer = malloc(to_copy, 0);
  87.  
  88.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  89.     if (rc != 0) {
  90.         klog_printf(" - copy failed");
  91.         return rc;
  92.     }
  93.  
  94.     call->buffer = buffer;
  95.  
  96.     klog_printf(" - done");
  97.     return 0;
  98. }
  99.  
  100.  
  101. int udebug_request_preprocess(call_t *call, phone_t *phone)
  102. {
  103.     int rc;
  104.  
  105.     switch (IPC_GET_ARG1(call->data)) {
  106.     case UDEBUG_M_REGS_WRITE:
  107.         rc = udebug_rp_regs_write(call, phone);
  108.         return rc;
  109.     case UDEBUG_M_MEM_WRITE:
  110.         rc = udebug_rp_mem_write(call, phone);
  111.         return rc;
  112.     default:
  113.         break;
  114.     }
  115.  
  116.     return 0;
  117. }
  118.  
  119. static void udebug_receive_begin(call_t *call)
  120. {
  121.     int rc;
  122.  
  123.     rc = udebug_begin(call);
  124.     if (rc < 0) {
  125.         IPC_SET_RETVAL(call->data, rc);
  126.         ipc_answer(&TASK->kernel_box, call);
  127.         return;
  128.     }
  129.  
  130.     if (rc != 0) {
  131.         IPC_SET_RETVAL(call->data, 0);
  132.         ipc_answer(&TASK->kernel_box, call);
  133.     }
  134. }
  135.  
  136. static void udebug_receive_end(call_t *call)
  137. {
  138.     int rc;
  139.  
  140.     rc = udebug_end();
  141.  
  142.     IPC_SET_RETVAL(call->data, rc);
  143.     ipc_answer(&TASK->kernel_box, call);
  144. }
  145.  
  146. static void udebug_receive_set_evmask(call_t *call)
  147. {
  148.     int rc;
  149.     udebug_evmask_t mask;
  150.  
  151.     mask = IPC_GET_ARG2(call->data);
  152.     rc = udebug_set_evmask(mask);
  153.  
  154.     IPC_SET_RETVAL(call->data, rc);
  155.     ipc_answer(&TASK->kernel_box, call);
  156. }
  157.  
  158.  
  159. static void udebug_receive_go(call_t *call)
  160. {
  161.     thread_t *t;
  162.     int rc;
  163.  
  164.     //klog_printf("debug_go()");
  165.  
  166.     t = (thread_t *)IPC_GET_ARG2(call->data);
  167.  
  168.     rc = udebug_go(t, call);
  169.     if (rc < 0) {
  170.         IPC_SET_RETVAL(call->data, rc);
  171.         ipc_answer(&TASK->kernel_box, call);
  172.         return;
  173.     }
  174. }
  175.  
  176. static void udebug_receive_stop(call_t *call)
  177. {
  178.     thread_t *t;
  179.     int rc;
  180.  
  181.     klog_printf("debug_stop()");
  182.  
  183.     t = (thread_t *)IPC_GET_ARG2(call->data);
  184.  
  185.     rc = udebug_stop(t, call);
  186.     IPC_SET_RETVAL(call->data, rc);
  187.     ipc_answer(&TASK->kernel_box, call);
  188. }
  189.  
  190. static void udebug_receive_thread_read(call_t *call)
  191. {
  192.     unative_t uspace_addr;
  193.     unative_t to_copy;
  194.     unsigned total_bytes;
  195.     unsigned buf_size;
  196.     void *buffer;
  197.     size_t n;
  198.     int rc;
  199.  
  200.     uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
  201.     buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
  202.  
  203.     /*
  204.      * Read thread list. Variable n will be filled with actual number
  205.      * of threads times thread-id size.
  206.      */
  207.     rc = udebug_thread_read(&buffer, buf_size, &n);
  208.     if (rc < 0) {
  209.         IPC_SET_RETVAL(call->data, rc);
  210.         ipc_answer(&TASK->kernel_box, call);
  211.         return;
  212.     }
  213.  
  214.     total_bytes = n;
  215.  
  216.     /* Copy MAX(buf_size, total_bytes) bytes */
  217.  
  218.     if (buf_size > total_bytes)
  219.         to_copy = total_bytes;
  220.     else
  221.         to_copy = buf_size;
  222.  
  223.     /*
  224.      * Make use of call->buffer to transfer data to caller's userspace
  225.      */
  226.  
  227.     IPC_SET_RETVAL(call->data, 0);
  228.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  229.        same code in process_answer() can be used
  230.        (no way to distinguish method in answer) */
  231.     IPC_SET_ARG1(call->data, uspace_addr);
  232.     IPC_SET_ARG2(call->data, to_copy);
  233.  
  234.     IPC_SET_ARG3(call->data, total_bytes);
  235.     call->buffer = buffer;
  236.  
  237.     ipc_answer(&TASK->kernel_box, call);
  238. }
  239.  
  240. static void udebug_receive_args_read(call_t *call)
  241. {
  242.     thread_t *t;
  243.     unative_t uspace_addr;
  244.     int rc;
  245.     void *buffer;
  246.  
  247.     t = (thread_t *)IPC_GET_ARG2(call->data);
  248.  
  249.     rc = udebug_args_read(t, &buffer);
  250.     if (rc != EOK) {
  251.         IPC_SET_RETVAL(call->data, rc);
  252.         ipc_answer(&TASK->kernel_box, call);
  253.         return;
  254.     }
  255.  
  256.     /*
  257.      * Make use of call->buffer to transfer data to caller's userspace
  258.      */
  259.  
  260.     uspace_addr = IPC_GET_ARG3(call->data);
  261.  
  262.     IPC_SET_RETVAL(call->data, 0);
  263.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  264.        same code in process_answer() can be used
  265.        (no way to distinguish method in answer) */
  266.     IPC_SET_ARG1(call->data, uspace_addr);
  267.     IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
  268.     call->buffer = buffer;
  269.  
  270.     ipc_answer(&TASK->kernel_box, call);
  271. }
  272.  
  273. static void udebug_receive_regs_read(call_t *call)
  274. {
  275.     thread_t *t;
  276.     unative_t uspace_addr;
  277.     unative_t to_copy;
  278.     void *buffer;
  279.     int rc;
  280.  
  281.     klog_printf("debug_regs_read()");
  282.  
  283.     t = (thread_t *) IPC_GET_ARG2(call->data);
  284.     buffer = malloc(sizeof(istate_t), 0);
  285.  
  286.     rc = udebug_regs_read(t, buffer);
  287.     if (rc < 0) {
  288.         IPC_SET_RETVAL(call->data, rc);
  289.         ipc_answer(&TASK->kernel_box, call);
  290.         return;
  291.     }
  292.  
  293.     /*
  294.      * Make use of call->buffer to transfer data to caller's userspace
  295.      */
  296.  
  297.     uspace_addr = IPC_GET_ARG3(call->data);
  298.     to_copy = sizeof(istate_t);
  299.  
  300.     IPC_SET_RETVAL(call->data, 0);
  301.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  302.        same code in process_answer() can be used
  303.        (no way to distinguish method in answer) */
  304.     IPC_SET_ARG1(call->data, uspace_addr);
  305.     IPC_SET_ARG2(call->data, to_copy);
  306.  
  307.     call->buffer = buffer;
  308.  
  309.     ipc_answer(&TASK->kernel_box, call);
  310. }
  311.  
  312. static void udebug_receive_regs_write(call_t *call)
  313. {
  314.     thread_t *t;
  315.     void *uspace_data;
  316.     int rc;
  317.  
  318.     t = (thread_t *) IPC_GET_ARG2(call->data);
  319.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  320.  
  321.     rc = udebug_regs_write(t, call->buffer);
  322.     if (rc < 0) {
  323.         IPC_SET_RETVAL(call->data, rc);
  324.         ipc_answer(&TASK->kernel_box, call);
  325.         return;
  326.     }
  327.  
  328.     /* Set answer values */
  329.  
  330.     IPC_SET_RETVAL(call->data, 0);
  331.     free(call->buffer);
  332.     call->buffer = NULL;
  333.  
  334.     ipc_answer(&TASK->kernel_box, call);
  335. }
  336.  
  337.  
  338. static void udebug_receive_mem_read(call_t *call)
  339. {
  340.     unative_t uspace_dst;
  341.     unative_t uspace_src;
  342.     unsigned size;
  343.     void *buffer;
  344.     int rc;
  345.  
  346.     uspace_dst = IPC_GET_ARG2(call->data);
  347.     uspace_src = IPC_GET_ARG3(call->data);
  348.     size = IPC_GET_ARG4(call->data);
  349.  
  350.     rc = udebug_mem_read(uspace_src, size, &buffer);
  351.     if (rc < 0) {
  352.         IPC_SET_RETVAL(call->data, rc);
  353.         ipc_answer(&TASK->kernel_box, call);
  354.         return;
  355.     }
  356.  
  357.     IPC_SET_RETVAL(call->data, 0);
  358.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  359.        same code in process_answer() can be used
  360.        (no way to distinguish method in answer) */
  361.     IPC_SET_ARG1(call->data, uspace_dst);
  362.     IPC_SET_ARG2(call->data, size);
  363.     call->buffer = buffer;
  364.  
  365.     ipc_answer(&TASK->kernel_box, call);
  366. }
  367.  
  368. static void udebug_receive_mem_write(call_t *call)
  369. {
  370.     unative_t uspace_dst;
  371.     unsigned size;
  372.     int rc;
  373.  
  374.     klog_printf("udebug_receive_mem_write()");
  375.  
  376.     uspace_dst = IPC_GET_ARG3(call->data);
  377.     size = IPC_GET_ARG4(call->data);
  378.  
  379.     rc = udebug_mem_write(uspace_dst, call->buffer, size);
  380.     if (rc < 0) {
  381.         IPC_SET_RETVAL(call->data, rc);
  382.         ipc_answer(&TASK->kernel_box, call);
  383.         return;
  384.     }
  385.  
  386.     IPC_SET_RETVAL(call->data, 0);
  387.     free(call->buffer);
  388.     call->buffer = NULL;
  389.  
  390.     ipc_answer(&TASK->kernel_box, call);
  391. }
  392.  
  393.  
  394. /**
  395.  * Handle a debug call received on the kernel answerbox.
  396.  *
  397.  * This is called by the kbox servicing thread.
  398.  */
  399. void udebug_call_receive(call_t *call)
  400. {
  401.     int debug_method;
  402.  
  403.     debug_method = IPC_GET_ARG1(call->data);
  404.  
  405.     if (debug_method != UDEBUG_M_BEGIN) {
  406.         /*
  407.          * Verify that the sender is this task's debugger.
  408.          * Note that this is the only thread that could change
  409.          * TASK->debugger. Therefore no locking is necessary
  410.          * and the sender can be safely considered valid until
  411.          * control exits this function.
  412.          */
  413.         if (TASK->udebug.debugger != call->sender) {
  414.             IPC_SET_RETVAL(call->data, EINVAL);
  415.             ipc_answer(&TASK->kernel_box, call);
  416.             return;
  417.         }
  418.     }
  419.  
  420.     switch (debug_method) {
  421.     case UDEBUG_M_BEGIN:
  422.         udebug_receive_begin(call);
  423.         break;
  424.     case UDEBUG_M_END:
  425.         udebug_receive_end(call);
  426.         break;
  427.     case UDEBUG_M_SET_EVMASK:
  428.         udebug_receive_set_evmask(call);
  429.         break;
  430.     case UDEBUG_M_GO:
  431.         udebug_receive_go(call);
  432.         break;
  433.     case UDEBUG_M_STOP:
  434.         udebug_receive_stop(call);
  435.         break;
  436.     case UDEBUG_M_THREAD_READ:
  437.         udebug_receive_thread_read(call);
  438.         break;
  439.     case UDEBUG_M_ARGS_READ:
  440.         udebug_receive_args_read(call);
  441.         break;
  442.     case UDEBUG_M_REGS_READ:
  443.         udebug_receive_regs_read(call);
  444.         break;
  445.     case UDEBUG_M_REGS_WRITE:
  446.         udebug_receive_regs_write(call);
  447.         break;
  448.     case UDEBUG_M_MEM_READ:
  449.         udebug_receive_mem_read(call);
  450.         break;
  451.     case UDEBUG_M_MEM_WRITE:
  452.         udebug_receive_mem_write(call);
  453.         break;
  454.     }
  455. }
  456.  
  457. /** @}
  458.  */
  459.