Subversion Repositories HelenOS

Rev

Rev 3438 | Rev 3457 | 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 <proc/task.h>
  39. #include <proc/thread.h>
  40. #include <arch.h>
  41. #include <errno.h>
  42. #include <ipc/ipc.h>
  43. #include <syscall/copy.h>
  44. #include <udebug/udebug.h>
  45. #include <udebug/udebug_ops.h>
  46. #include <udebug/udebug_ipc.h>
  47.  
  48. int udebug_request_preprocess(call_t *call, phone_t *phone)
  49. {
  50.     switch (IPC_GET_ARG1(call->data)) {
  51.     /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
  52.     default:
  53.         break;
  54.     }
  55.  
  56.     return 0;
  57. }
  58.  
  59. static void udebug_receive_begin(call_t *call)
  60. {
  61.     int rc;
  62.  
  63.     rc = udebug_begin(call);
  64.     if (rc < 0) {
  65.         IPC_SET_RETVAL(call->data, rc);
  66.         ipc_answer(&TASK->kernel_box, call);
  67.         return;
  68.     }
  69.  
  70.     if (rc != 0) {
  71.         IPC_SET_RETVAL(call->data, 0);
  72.         ipc_answer(&TASK->kernel_box, call);
  73.     }
  74. }
  75.  
  76. static void udebug_receive_end(call_t *call)
  77. {
  78.     int rc;
  79.  
  80.     rc = udebug_end();
  81.  
  82.     IPC_SET_RETVAL(call->data, rc);
  83.     ipc_answer(&TASK->kernel_box, call);
  84. }
  85.  
  86. static void udebug_receive_set_evmask(call_t *call)
  87. {
  88.     int rc;
  89.     udebug_evmask_t mask;
  90.  
  91.     mask = IPC_GET_ARG2(call->data);
  92.     rc = udebug_set_evmask(mask);
  93.  
  94.     IPC_SET_RETVAL(call->data, rc);
  95.     ipc_answer(&TASK->kernel_box, call);
  96. }
  97.  
  98.  
  99. static void udebug_receive_go(call_t *call)
  100. {
  101.     thread_t *t;
  102.     int rc;
  103.  
  104.     t = (thread_t *)IPC_GET_ARG2(call->data);
  105.  
  106.     rc = udebug_go(t, call);
  107.     if (rc < 0) {
  108.         IPC_SET_RETVAL(call->data, rc);
  109.         ipc_answer(&TASK->kernel_box, call);
  110.         return;
  111.     }
  112. }
  113.  
  114. static void udebug_receive_stop(call_t *call)
  115. {
  116.     thread_t *t;
  117.     int rc;
  118.  
  119.     t = (thread_t *)IPC_GET_ARG2(call->data);
  120.  
  121.     rc = udebug_stop(t, call);
  122.     IPC_SET_RETVAL(call->data, rc);
  123.     ipc_answer(&TASK->kernel_box, call);
  124. }
  125.  
  126. static void udebug_receive_thread_read(call_t *call)
  127. {
  128.     unative_t uspace_addr;
  129.     unative_t to_copy;
  130.     unsigned total_bytes;
  131.     unsigned buf_size;
  132.     void *buffer;
  133.     size_t n;
  134.     int rc;
  135.  
  136.     uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
  137.     buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
  138.  
  139.     /*
  140.      * Read thread list. Variable n will be filled with actual number
  141.      * of threads times thread-id size.
  142.      */
  143.     rc = udebug_thread_read(&buffer, buf_size, &n);
  144.     if (rc < 0) {
  145.         IPC_SET_RETVAL(call->data, rc);
  146.         ipc_answer(&TASK->kernel_box, call);
  147.         return;
  148.     }
  149.  
  150.     total_bytes = n;
  151.  
  152.     /* Copy MAX(buf_size, total_bytes) bytes */
  153.  
  154.     if (buf_size > total_bytes)
  155.         to_copy = total_bytes;
  156.     else
  157.         to_copy = buf_size;
  158.  
  159.     /*
  160.      * Make use of call->buffer to transfer data to caller's userspace
  161.      */
  162.  
  163.     IPC_SET_RETVAL(call->data, 0);
  164.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  165.        same code in process_answer() can be used
  166.        (no way to distinguish method in answer) */
  167.     IPC_SET_ARG1(call->data, uspace_addr);
  168.     IPC_SET_ARG2(call->data, to_copy);
  169.  
  170.     IPC_SET_ARG3(call->data, total_bytes);
  171.     call->buffer = buffer;
  172.  
  173.     ipc_answer(&TASK->kernel_box, call);
  174. }
  175.  
  176. static void udebug_receive_args_read(call_t *call)
  177. {
  178.     thread_t *t;
  179.     unative_t uspace_addr;
  180.     int rc;
  181.     void *buffer;
  182.  
  183.     t = (thread_t *)IPC_GET_ARG2(call->data);
  184.  
  185.     rc = udebug_args_read(t, &buffer);
  186.     if (rc != EOK) {
  187.         IPC_SET_RETVAL(call->data, rc);
  188.         ipc_answer(&TASK->kernel_box, call);
  189.         return;
  190.     }
  191.  
  192.     /*
  193.      * Make use of call->buffer to transfer data to caller's userspace
  194.      */
  195.  
  196.     uspace_addr = IPC_GET_ARG3(call->data);
  197.  
  198.     IPC_SET_RETVAL(call->data, 0);
  199.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  200.        same code in process_answer() can be used
  201.        (no way to distinguish method in answer) */
  202.     IPC_SET_ARG1(call->data, uspace_addr);
  203.     IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
  204.     call->buffer = buffer;
  205.  
  206.     ipc_answer(&TASK->kernel_box, call);
  207. }
  208.  
  209. static void udebug_receive_mem_read(call_t *call)
  210. {
  211.     unative_t uspace_dst;
  212.     unative_t uspace_src;
  213.     unsigned size;
  214.     void *buffer;
  215.     int rc;
  216.  
  217.     uspace_dst = IPC_GET_ARG2(call->data);
  218.     uspace_src = IPC_GET_ARG3(call->data);
  219.     size = IPC_GET_ARG4(call->data);
  220.  
  221.     rc = udebug_mem_read(uspace_src, size, &buffer);
  222.     if (rc < 0) {
  223.         IPC_SET_RETVAL(call->data, rc);
  224.         ipc_answer(&TASK->kernel_box, call);
  225.         return;
  226.     }
  227.  
  228.     IPC_SET_RETVAL(call->data, 0);
  229.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  230.        same code in process_answer() can be used
  231.        (no way to distinguish method in answer) */
  232.     IPC_SET_ARG1(call->data, uspace_dst);
  233.     IPC_SET_ARG2(call->data, size);
  234.     call->buffer = buffer;
  235.  
  236.     ipc_answer(&TASK->kernel_box, call);
  237. }
  238.  
  239. /**
  240.  * Handle a debug call received on the kernel answerbox.
  241.  *
  242.  * This is called by the kbox servicing thread.
  243.  */
  244. void udebug_call_receive(call_t *call)
  245. {
  246.     int debug_method;
  247.  
  248.     debug_method = IPC_GET_ARG1(call->data);
  249.  
  250.     if (debug_method != UDEBUG_M_BEGIN) {
  251.         /*
  252.          * Verify that the sender is this task's debugger.
  253.          * Note that this is the only thread that could change
  254.          * TASK->debugger. Therefore no locking is necessary
  255.          * and the sender can be safely considered valid until
  256.          * control exits this function.
  257.          */
  258.         if (TASK->udebug.debugger != call->sender) {
  259.             IPC_SET_RETVAL(call->data, EINVAL);
  260.             ipc_answer(&TASK->kernel_box, call);
  261.             return;
  262.         }
  263.     }
  264.  
  265.     switch (debug_method) {
  266.     case UDEBUG_M_BEGIN:
  267.         udebug_receive_begin(call);
  268.         break;
  269.     case UDEBUG_M_END:
  270.         udebug_receive_end(call);
  271.         break;
  272.     case UDEBUG_M_SET_EVMASK:
  273.         udebug_receive_set_evmask(call);
  274.         break;
  275.     case UDEBUG_M_GO:
  276.         udebug_receive_go(call);
  277.         break;
  278.     case UDEBUG_M_STOP:
  279.         udebug_receive_stop(call);
  280.         break;
  281.     case UDEBUG_M_THREAD_READ:
  282.         udebug_receive_thread_read(call);
  283.         break;
  284.     case UDEBUG_M_ARGS_READ:
  285.         udebug_receive_args_read(call);
  286.         break;
  287.     case UDEBUG_M_MEM_READ:
  288.         udebug_receive_mem_read(call);
  289.         break;
  290.     }
  291. }
  292.  
  293. /** @}
  294.  */
  295.