Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (C) 2005 Martin Decky
  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. #include <syscall/syscall.h>
  30. #include <proc/thread.h>
  31. #include <mm/as.h>
  32. #include <print.h>
  33. #include <putchar.h>
  34. #include <ipc/ipc.h>
  35. #include <errno.h>
  36. #include <proc/task.h>
  37. #include <arch.h>
  38. #include <debug.h>
  39.  
  40. static __native sys_ctl(void) {
  41.     printf("Thread finished\n");
  42.     thread_exit();
  43.     /* Unreachable */
  44.     return 0;
  45. }
  46.  
  47. static __native sys_io(int fd, const void * buf, size_t count) {
  48.    
  49.     // TODO: buf sanity checks and a lot of other stuff ...
  50.  
  51.     size_t i;
  52.    
  53.     for (i = 0; i < count; i++)
  54.         putchar(((char *) buf)[i]);
  55.    
  56.     return count;
  57. }
  58.  
  59. static phone_t * get_phone(__native phoneid)
  60. {
  61.     phone_t *phone;
  62.  
  63.     if (phoneid >= IPC_MAX_PHONES)
  64.         return NULL;
  65.  
  66.     phone = &TASK->phones[phoneid];
  67.     if (!phone->callee)
  68.         return NULL;
  69.     return phone;
  70. }
  71.  
  72. /** Send a call over IPC, wait for reply, return to user
  73.  *
  74.  * @return Call identification, returns -1 on fatal error,
  75.            -2 on 'Too many async request, handle answers first
  76.  */
  77. static __native sys_ipc_call_sync_fast(__native phoneid, __native method,
  78.                        __native arg1, __native *data)
  79. {
  80.     call_t call;
  81.     phone_t *phone;
  82.     /* Special answerbox for synchronous messages */
  83.  
  84.     phone = get_phone(phoneid);
  85.     if (!phone)
  86.         return IPC_CALLRET_FATAL;
  87.  
  88.     ipc_call_init(&call);
  89.     IPC_SET_METHOD(call.data, method);
  90.     IPC_SET_ARG1(call.data, arg1);
  91.    
  92.     ipc_call_sync(phone, &call);
  93.  
  94.     copy_to_uspace(data, &call.data, sizeof(call.data));
  95.  
  96.     return 0;
  97. }
  98.  
  99. /** Synchronous IPC call allowing to send whole message */
  100. static __native sys_ipc_call_sync(__native phoneid, __native *question,
  101.                   __native *reply)
  102. {
  103.     call_t call;
  104.     phone_t *phone;
  105.     /* Special answerbox for synchronous messages */
  106.  
  107.     phone = get_phone(phoneid);
  108.     if (!phone)
  109.         return IPC_CALLRET_FATAL;
  110.  
  111.     ipc_call_init(&call);
  112.     copy_from_uspace(&call.data, question, sizeof(call.data));
  113.    
  114.     ipc_call_sync(phone, &call);
  115.  
  116.     copy_to_uspace(reply, &call.data, sizeof(call.data));
  117.  
  118.     return 0;
  119. }
  120.  
  121. /** Check that the task did not exceed allowed limit
  122.  *
  123.  * @return 0 - Limit OK,   -1 - limit exceeded
  124.  */
  125. static int check_call_limit(void)
  126. {
  127.     if (atomic_inc_post(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
  128.         atomic_dec(&TASK->active_calls);
  129.         return -1;
  130.     }
  131.     return 0;
  132. }
  133.  
  134. /** Send an asynchronous call over ipc
  135.  *
  136.  * @return Call identification, returns -1 on fatal error,
  137.            -2 on 'Too many async request, handle answers first
  138.  */
  139. static __native sys_ipc_call_async_fast(__native phoneid, __native method,
  140.                     __native arg1, __native arg2)
  141. {
  142.     call_t *call;
  143.     phone_t *phone;
  144.  
  145.     phone = get_phone(phoneid);
  146.     if (!phone)
  147.         return IPC_CALLRET_FATAL;
  148.  
  149.     if (check_call_limit())
  150.         return IPC_CALLRET_TEMPORARY;
  151.  
  152.     call = ipc_call_alloc();
  153.     IPC_SET_METHOD(call->data, method);
  154.     IPC_SET_ARG1(call->data, arg1);
  155.     IPC_SET_ARG2(call->data, arg2);
  156.  
  157.     ipc_call(phone, call);
  158.  
  159.     return (__native) call;
  160. }
  161.  
  162. /** Synchronous IPC call allowing to send whole message
  163.  *
  164.  * @return The same as sys_ipc_call_async
  165.  */
  166. static __native sys_ipc_call_async(__native phoneid, __native *data)
  167. {
  168.     call_t *call;
  169.     phone_t *phone;
  170.  
  171.     phone = get_phone(phoneid);
  172.     if (!phone)
  173.         return IPC_CALLRET_FATAL;
  174.  
  175.     if (check_call_limit())
  176.         return IPC_CALLRET_TEMPORARY;
  177.  
  178.     call = ipc_call_alloc();
  179.     copy_from_uspace(&call->data, data, sizeof(call->data));
  180.    
  181.     ipc_call(phone, call);
  182.  
  183.     return (__native) call;
  184. }
  185.  
  186.  
  187. /** Send IPC answer */
  188. static __native sys_ipc_answer_fast(__native callid, __native retval,
  189.                     __native arg1, __native arg2)
  190. {
  191.     call_t *call;
  192.  
  193.     /* Check that the user is not sending us answer callid */
  194.     ASSERT(! (callid & 1));
  195.     /* TODO: Check that the callid is in the dispatch table */
  196.     call = (call_t *) callid;
  197.  
  198.     IPC_SET_RETVAL(call->data, retval);
  199.     IPC_SET_ARG1(call->data, arg1);
  200.     IPC_SET_ARG2(call->data, arg2);
  201.  
  202.     ipc_answer(&TASK->answerbox, call);
  203.     return 0;
  204. }
  205.  
  206. /** Send IPC answer */
  207. static __native sys_ipc_answer(__native callid, __native *data)
  208. {
  209.     call_t *call;
  210.  
  211.     /* Check that the user is not sending us answer callid */
  212.     ASSERT(! (callid & 1));
  213.     /* TODO: Check that the callid is in the dispatch table */
  214.     call = (call_t *) callid;
  215.     copy_from_uspace(&call->data, data, sizeof(call->data));
  216.     ipc_answer(&TASK->answerbox, call);
  217.  
  218.     return 0;
  219. }
  220.  
  221. /** Wait for incoming ipc call or answer
  222.  *
  223.  * @param result
  224.  * @param flags
  225.  * @return Callid, if callid & 1, then the call is answer
  226.  */
  227. static __native sys_ipc_wait_for_call(__native *calldata, task_id_t *taskid,
  228.                       __native flags)
  229. {
  230.     call_t *call;
  231.    
  232.     call = ipc_wait_for_call(&TASK->answerbox, flags);
  233.  
  234.     copy_to_uspace(calldata, &call->data, sizeof(call->data));
  235.  
  236.     if (call->flags & IPC_CALL_ANSWERED) {
  237.         ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
  238.         ipc_call_free(call);
  239.         atomic_dec(&TASK->active_calls);
  240.         return ((__native)call) | IPC_CALLID_ANSWERED;
  241.     }
  242.     copy_to_uspace(taskid, (void *)&TASK->taskid, sizeof(TASK->taskid));
  243.     return (__native)call;
  244. }
  245.  
  246. static __native sys_mremap(void *address, size_t size, unsigned long flags)
  247. {
  248.     return as_remap(AS, (__address) address, size, 0);
  249. }
  250.  
  251. syshandler_t syscall_table[SYSCALL_END] = {
  252.     sys_ctl,
  253.     sys_io,
  254.     sys_mremap,
  255.     sys_ipc_call_sync_fast,
  256.     sys_ipc_call_sync,
  257.     sys_ipc_call_async_fast,
  258.     sys_ipc_call_async,
  259.     sys_ipc_answer_fast,
  260.     sys_ipc_answer,
  261.     sys_ipc_wait_for_call
  262. };
  263.