Subversion Repositories HelenOS

Rev

Rev 2899 | Rev 2913 | 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 = IPC_GET_ARG4(call->data);
  60.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  61.  
  62.     buffer = malloc(to_copy, 0);
  63.  
  64.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  65.     if (rc != 0) {
  66.         klog_printf("debug_regs_write() - copy failed");
  67.         return rc;
  68.     }
  69.  
  70.     call->buffer = buffer;
  71.  
  72.     klog_printf(" - done");
  73.     return 0;
  74. }
  75.  
  76. static int udebug_rp_mem_write(call_t *call, phone_t *phone)
  77. {
  78.     void *uspace_data;
  79.     unative_t to_copy;
  80.     int rc;
  81.     void *buffer;
  82.  
  83.     klog_printf("udebug_rp_mem_write()");
  84.  
  85.     uspace_data = (void *)IPC_GET_ARG2(call->data);
  86.     to_copy = IPC_GET_ARG4(call->data);
  87.  
  88.     buffer = malloc(to_copy, 0);
  89.  
  90.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  91.     if (rc != 0) {
  92.         klog_printf(" - copy failed");
  93.         return rc;
  94.     }
  95.  
  96.     call->buffer = buffer;
  97.  
  98.     klog_printf(" - done");
  99.     return 0;
  100. }
  101.  
  102.  
  103. int udebug_request_preprocess(call_t *call, phone_t *phone)
  104. {
  105.     int rc;
  106.  
  107.     switch (IPC_GET_ARG1(call->data)) {
  108.     case UDEBUG_M_REGS_WRITE:
  109.         rc = udebug_rp_regs_write(call, phone);
  110.         return rc;
  111.     case UDEBUG_M_MEM_WRITE:
  112.         rc = udebug_rp_mem_write(call, phone);
  113.         return rc;
  114.     default:
  115.         break;
  116.     }
  117.  
  118.     return 0;
  119. }
  120.  
  121. static void udebug_receive_begin(call_t *call)
  122. {
  123.     int rc;
  124.  
  125.     rc = udebug_begin(call);
  126.     if (rc < 0) {
  127.         IPC_SET_RETVAL(call->data, rc);
  128.         ipc_answer(&TASK->kernel_box, call);
  129.         return;
  130.     }
  131.  
  132.     if (rc != 0) {
  133.         IPC_SET_RETVAL(call->data, 0);
  134.         ipc_answer(&TASK->kernel_box, call);
  135.     }
  136. }
  137.  
  138. static void udebug_receive_end(call_t *call)
  139. {
  140.     int rc;
  141.  
  142.     rc = udebug_end();
  143.  
  144.     IPC_SET_RETVAL(call->data, rc);
  145.     ipc_answer(&TASK->kernel_box, call);
  146. }
  147.  
  148. static void udebug_receive_set_evmask(call_t *call)
  149. {
  150.     int rc;
  151.     udebug_evmask_t mask;
  152.  
  153.     mask = IPC_GET_ARG2(call->data);
  154.     rc = udebug_set_evmask(mask);
  155.  
  156.     IPC_SET_RETVAL(call->data, rc);
  157.     ipc_answer(&TASK->kernel_box, call);
  158. }
  159.  
  160.  
  161. static void udebug_receive_go(call_t *call)
  162. {
  163.     thread_t *t;
  164.     int rc;
  165.  
  166.     klog_printf("debug_go()");
  167.  
  168.     t = (thread_t *)IPC_GET_ARG2(call->data);
  169.  
  170.     rc = udebug_go(t, call);
  171.     if (rc < 0) {
  172.         IPC_SET_RETVAL(call->data, rc);
  173.         ipc_answer(&TASK->kernel_box, call);
  174.         return;
  175.     }
  176. }
  177.  
  178. static void udebug_receive_stop(call_t *call)
  179. {
  180.     thread_t *t;
  181.     int rc;
  182.  
  183.     klog_printf("debug_stop()");
  184.  
  185.     t = (thread_t *)IPC_GET_ARG2(call->data);
  186.  
  187.     rc = udebug_stop(t, call);
  188.     IPC_SET_RETVAL(call->data, rc);
  189.     ipc_answer(&TASK->kernel_box, call);
  190. }
  191.  
  192. static void udebug_receive_thread_read(call_t *call)
  193. {
  194.     unative_t uspace_addr;
  195.     unative_t to_copy;
  196.     unsigned total_bytes;
  197.     unsigned buf_size;
  198.     void *buffer;
  199.     size_t n;
  200.     int rc;
  201.  
  202.     uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
  203.     buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
  204.  
  205.     /*
  206.      * Read thread list. Variable n will be filled with actual number
  207.      * of threads times thread-id size.
  208.      */
  209.     rc = udebug_thread_read(&buffer, buf_size, &n);
  210.     if (rc < 0) {
  211.         IPC_SET_RETVAL(call->data, rc);
  212.         ipc_answer(&TASK->kernel_box, call);
  213.         return;
  214.     }
  215.  
  216.     total_bytes = n;
  217.  
  218.     /* Copy MAX(buf_size, total_bytes) bytes */
  219.  
  220.     if (buf_size > total_bytes)
  221.         to_copy = total_bytes;
  222.     else
  223.         to_copy = buf_size;
  224.  
  225.     /*
  226.      * Make use of call->buffer to transfer data to caller's userspace
  227.      */
  228.  
  229.     IPC_SET_RETVAL(call->data, 0);
  230.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  231.        same code in process_answer() can be used
  232.        (no way to distinguish method in answer) */
  233.     IPC_SET_ARG1(call->data, uspace_addr);
  234.     IPC_SET_ARG2(call->data, to_copy);
  235.  
  236.     IPC_SET_ARG3(call->data, total_bytes);
  237.     call->buffer = buffer;
  238.  
  239.     ipc_answer(&TASK->kernel_box, call);
  240. }
  241.  
  242. static void udebug_receive_args_read(call_t *call)
  243. {
  244.     thread_t *t;
  245.     unative_t uspace_addr;
  246.     int rc;
  247.     void *buffer;
  248.  
  249.     t = (thread_t *)IPC_GET_ARG2(call->data);
  250.  
  251.     rc = udebug_args_read(t, &buffer);
  252.     if (rc != EOK) {
  253.         IPC_SET_RETVAL(call->data, rc);
  254.         ipc_answer(&TASK->kernel_box, call);
  255.         return;
  256.     }
  257.  
  258.     /*
  259.      * Make use of call->buffer to transfer data to caller's userspace
  260.      */
  261.  
  262.     uspace_addr = IPC_GET_ARG3(call->data);
  263.  
  264.     IPC_SET_RETVAL(call->data, 0);
  265.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  266.        same code in process_answer() can be used
  267.        (no way to distinguish method in answer) */
  268.     IPC_SET_ARG1(call->data, uspace_addr);
  269.     IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
  270.     call->buffer = buffer;
  271.  
  272.     ipc_answer(&TASK->kernel_box, call);
  273. }
  274.  
  275. static void udebug_receive_regs_read(call_t *call)
  276. {
  277.     thread_t *t;
  278.     unative_t uspace_addr;
  279.     unative_t to_copy;
  280.     unative_t buf_size;
  281.     unative_t total_bytes;
  282.     void *buffer;
  283.     int rc;
  284.     size_t n;
  285.  
  286.     klog_printf("debug_regs_read()");
  287.  
  288.     t = (thread_t *) IPC_GET_ARG2(call->data);
  289.  
  290.     rc = udebug_regs_read(t, &buffer, &n);
  291.     if (rc < 0) {
  292.         IPC_SET_RETVAL(call->data, rc);
  293.         ipc_answer(&TASK->kernel_box, call);
  294.         return;
  295.     }
  296.  
  297.     /*
  298.      * Make use of call->buffer to transfer data to caller's userspace
  299.      */
  300.  
  301.     uspace_addr = IPC_GET_ARG3(call->data);
  302.     buf_size = IPC_GET_ARG4(call->data);
  303.  
  304.     total_bytes = n;
  305.  
  306.     if (buf_size > total_bytes)
  307.         to_copy = total_bytes;
  308.     else
  309.         to_copy = buf_size;
  310.  
  311.     IPC_SET_RETVAL(call->data, 0);
  312.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  313.        same code in process_answer() can be used
  314.        (no way to distinguish method in answer) */
  315.     IPC_SET_ARG1(call->data, uspace_addr);
  316.     IPC_SET_ARG2(call->data, to_copy);
  317.  
  318.     IPC_SET_ARG3(call->data, total_bytes);
  319.     call->buffer = buffer;
  320.  
  321.     ipc_answer(&TASK->kernel_box, call);
  322. }
  323.  
  324. static void udebug_receive_regs_write(call_t *call)
  325. {
  326.     thread_t *t;
  327.     void *uspace_data;
  328.     unative_t to_copy;
  329.     int rc;
  330.  
  331.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  332.     to_copy = IPC_GET_ARG4(call->data);
  333.  
  334.     t = (thread_t *) IPC_GET_ARG2(call->data);
  335.  
  336.     rc = udebug_regs_write(t, call->buffer);
  337.     if (rc < 0) {
  338.         IPC_SET_RETVAL(call->data, rc);
  339.         ipc_answer(&TASK->kernel_box, call);
  340.         return;
  341.     }
  342.  
  343.     /* Set answer values */
  344.  
  345.     IPC_SET_ARG1(call->data, to_copy);
  346.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  347.  
  348.     IPC_SET_RETVAL(call->data, 0);
  349.     free(call->buffer);
  350.     call->buffer = NULL;
  351.  
  352.     ipc_answer(&TASK->kernel_box, call);
  353. }
  354.  
  355.  
  356. static void udebug_receive_mem_read(call_t *call)
  357. {
  358.     unative_t uspace_dst;
  359.     unative_t uspace_src;
  360.     unsigned size;
  361.     void *buffer;
  362.     int rc;
  363.  
  364.     uspace_dst = IPC_GET_ARG2(call->data);
  365.     uspace_src = IPC_GET_ARG3(call->data);
  366.     size = IPC_GET_ARG4(call->data);
  367.  
  368.     rc = udebug_mem_read(uspace_src, size, &buffer);
  369.     if (rc < 0) {
  370.         IPC_SET_RETVAL(call->data, rc);
  371.         ipc_answer(&TASK->kernel_box, call);
  372.         return;
  373.     }
  374.  
  375.     IPC_SET_RETVAL(call->data, 0);
  376.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  377.        same code in process_answer() can be used
  378.        (no way to distinguish method in answer) */
  379.     IPC_SET_ARG1(call->data, uspace_dst);
  380.     IPC_SET_ARG2(call->data, size);
  381.     call->buffer = buffer;
  382.  
  383.     ipc_answer(&TASK->kernel_box, call);
  384. }
  385.  
  386. static void udebug_receive_mem_write(call_t *call)
  387. {
  388.     unative_t uspace_dst;
  389.     unsigned size;
  390.     int rc;
  391.  
  392.     klog_printf("udebug_receive_mem_write()");
  393.  
  394.     uspace_dst = IPC_GET_ARG3(call->data);
  395.     size = IPC_GET_ARG4(call->data);
  396.  
  397.     rc = udebug_mem_write(uspace_dst, call->buffer, size);
  398.     if (rc < 0) {
  399.         IPC_SET_RETVAL(call->data, rc);
  400.         ipc_answer(&TASK->kernel_box, call);
  401.         return;
  402.     }
  403.  
  404.     IPC_SET_RETVAL(call->data, 0);
  405.     free(call->buffer);
  406.     call->buffer = NULL;
  407.  
  408.     ipc_answer(&TASK->kernel_box, call);
  409. }
  410.  
  411.  
  412. /**
  413.  * Handle a debug call received on the kernel answerbox.
  414.  *
  415.  * This is called by the kbox servicing thread.
  416.  */
  417. void udebug_call_receive(call_t *call)
  418. {
  419.     int debug_method;
  420.  
  421.     debug_method = IPC_GET_ARG1(call->data);
  422.  
  423.     if (debug_method != UDEBUG_M_BEGIN) {
  424.         /*
  425.          * Verify that the sender is this task's debugger.
  426.          * Note that this is the only thread that could change
  427.          * TASK->debugger. Therefore no locking is necessary
  428.          * and the sender can be safely considered valid until
  429.          * control exits this function.
  430.          */
  431.         if (TASK->debugger != call->sender) {
  432.             IPC_SET_RETVAL(call->data, EINVAL);
  433.             ipc_answer(&TASK->kernel_box, call);
  434.             return;
  435.         }
  436.     }
  437.  
  438.     switch (debug_method) {
  439.     case UDEBUG_M_BEGIN:
  440.         udebug_receive_begin(call);
  441.         break;
  442.     case UDEBUG_M_END:
  443.         udebug_receive_end(call);
  444.         break;
  445.     case UDEBUG_M_SET_EVMASK:
  446.         udebug_receive_set_evmask(call);
  447.         break;
  448.     case UDEBUG_M_GO:
  449.         udebug_receive_go(call);
  450.         break;
  451.     case UDEBUG_M_STOP:
  452.         udebug_receive_stop(call);
  453.         break;
  454.     case UDEBUG_M_THREAD_READ:
  455.         udebug_receive_thread_read(call);
  456.         break;
  457.     case UDEBUG_M_ARGS_READ:
  458.         udebug_receive_args_read(call);
  459.         break;
  460.     case UDEBUG_M_REGS_READ:
  461.         udebug_receive_regs_read(call);
  462.         break;
  463.     case UDEBUG_M_REGS_WRITE:
  464.         udebug_receive_regs_write(call);
  465.         break;
  466.     case UDEBUG_M_MEM_READ:
  467.         udebug_receive_mem_read(call);
  468.         break;
  469.     case UDEBUG_M_MEM_WRITE:
  470.         udebug_receive_mem_write(call);
  471.         break;
  472.     }
  473. }
  474.  
  475. /** @}
  476.  */
  477.