Subversion Repositories HelenOS

Rev

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