Subversion Repositories HelenOS

Rev

Rev 2471 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2007 Michal Konopa
  3.  * Copyright (c) 2007 Martin Jelen
  4.  * Copyright (c) 2007 Peter Majer
  5.  * Copyright (c) 2007 Jakub Jermar
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  *
  12.  * - Redistributions of source code must retain the above copyright
  13.  *   notice, this list of conditions and the following disclaimer.
  14.  * - Redistributions in binary form must reproduce the above copyright
  15.  *   notice, this list of conditions and the following disclaimer in the
  16.  *   documentation and/or other materials provided with the distribution.
  17.  * - The name of the author may not be used to endorse or promote products
  18.  *   derived from this software without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  21.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  22.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  23.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  24.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  29.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30.  */
  31.  
  32. /** @addtogroup rd
  33.  * @{
  34.  */
  35.  
  36. /**
  37.  * @file    rd.c
  38.  * @brief   Initial RAM disk for HelenOS.
  39.  */
  40.  
  41. #include <ipc/ipc.h>
  42. #include <ipc/services.h>
  43. #include <ipc/ns.h>
  44. #include <sysinfo.h>
  45. #include <as.h>
  46. #include <ddi.h>
  47. #include <align.h>
  48. #include <bool.h>
  49. #include <errno.h>
  50. #include <async.h>
  51. #include <align.h>
  52. #include <async.h>
  53. #include <futex.h>
  54. #include "rd.h"
  55.  
  56. /** Pointer to the ramdisk's image. */
  57. static void *rd_addr;
  58.  
  59. /**
  60.  * This futex protects the ramdisk's data.
  61.  * If we were to serve multiple requests (read + write or several writes)
  62.  * concurrently (i.e. from two or more threads), each read and write needs to be
  63.  * protected by this futex.
  64.  */
  65. atomic_t rd_futex = FUTEX_INITIALIZER;
  66.  
  67. /** Handle one connection to ramdisk.
  68.  *
  69.  * @param iid       Hash of the request that opened the connection.
  70.  * @param icall     Call data of the request that opened the connection.
  71.  */
  72. static void rd_connection(ipc_callid_t iid, ipc_call_t *icall)
  73. {
  74.     ipc_callid_t callid;
  75.     ipc_call_t call;
  76.     int retval;
  77.     uintptr_t fs_va = NULL;
  78.     ipcarg_t offset;
  79.  
  80.     /*
  81.      * We allocate VA for communication per connection.
  82.      * This allows us to potentionally have more clients and work
  83.      * concurrently.
  84.      */
  85.     fs_va = as_get_mappable_page(ALIGN_UP(BLOCK_SIZE, PAGE_SIZE));
  86.     if (!fs_va) {
  87.         /*
  88.          * Hang up the phone if we cannot proceed any further.
  89.          * This is the answer to the call that opened the connection.
  90.          */
  91.         ipc_answer_fast(iid, EHANGUP, 0, 0);
  92.         return;
  93.     } else {
  94.         /*
  95.          * Answer the first IPC_M_CONNECT_ME_TO call.
  96.          * Return supported block size as ARG1.
  97.          */
  98.         ipc_answer_fast(iid, EOK, BLOCK_SIZE, 0);
  99.     }
  100.  
  101.     /*
  102.      * Now we wait for the client to send us its communication as_area.
  103.      */
  104.     callid = async_get_call(&call);
  105.     if (IPC_GET_METHOD(call) == IPC_M_AS_AREA_SEND) {
  106.         if (IPC_GET_ARG1(call) >= (ipcarg_t) BLOCK_SIZE) {
  107.             /*
  108.              * The client sends an as_area that can absorb the whole
  109.              * block.
  110.              */
  111.             ipc_answer_fast(callid, EOK, (uintptr_t) fs_va, 0);
  112.         } else {
  113.             /*
  114.              * The client offered as_area too small.
  115.              * Close the connection.
  116.              */
  117.             ipc_answer_fast(callid, EHANGUP, 0, 0);
  118.             return;    
  119.         }
  120.     } else {
  121.         /*
  122.          * The client doesn't speak the same protocol.
  123.          * At this point we can't handle protocol variations.
  124.          * Close the connection.
  125.          */
  126.         ipc_answer_fast(callid, EHANGUP, 0, 0);
  127.         return;
  128.     }
  129.    
  130.     while (1) {
  131.         callid = async_get_call(&call);
  132.         switch (IPC_GET_METHOD(call)) {
  133.         case IPC_M_PHONE_HUNGUP:
  134.             /*
  135.              * The other side has hung up.
  136.              * Answer the message and exit the pseudo thread.
  137.              */
  138.             ipc_answer_fast(callid, EOK, 0, 0);
  139.             return;
  140.         case RD_READ_BLOCK:
  141.             offset = IPC_GET_ARG1(call);
  142.             futex_down(&rd_futex);
  143.             memcpy((void *) fs_va, rd_addr + offset, BLOCK_SIZE);
  144.             futex_up(&rd_futex);
  145.             retval = EOK;
  146.             break;
  147.         case RD_WRITE_BLOCK:
  148.             offset = IPC_GET_ARG1(call);
  149.             futex_up(&rd_futex);
  150.             memcpy(rd_addr + offset, (void *) fs_va, BLOCK_SIZE);
  151.             futex_down(&rd_futex);
  152.             retval = EOK;
  153.             break;
  154.         default:
  155.             /*
  156.              * The client doesn't speak the same protocol.
  157.              * Instead of closing the connection, we just ignore
  158.              * the call. This can be useful if the client uses a
  159.              * newer version of the protocol.
  160.              */
  161.             retval = EINVAL;
  162.             break;
  163.         }
  164.         ipc_answer_fast(callid, retval, 0, 0);
  165.     }
  166. }
  167.  
  168. /** Prepare the ramdisk image for operation. */
  169. static bool rd_init(void)
  170. {
  171.     int retval, flags;
  172.  
  173.     size_t rd_size = sysinfo_value("rd.size");
  174.     void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
  175.    
  176.     if (rd_size == 0)
  177.         return false;
  178.    
  179.     rd_addr = as_get_mappable_page(rd_size);
  180.    
  181.     flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
  182.     retval = physmem_map(rd_ph_addr, rd_addr,
  183.         ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
  184.  
  185.     if (retval < 0)
  186.         return false;
  187.     return true;
  188. }
  189.  
  190. int main(int argc, char **argv)
  191. {
  192.     if (rd_init()) {
  193.         ipcarg_t phonead;
  194.        
  195.         async_set_client_connection(rd_connection);
  196.        
  197.         /* Register service at nameserver */
  198.         if (ipc_connect_to_me(PHONE_NS, SERVICE_RD, 0, &phonead) != 0)
  199.             return -1;
  200.        
  201.         async_manager();
  202.        
  203.         /* Never reached */
  204.         return 0;
  205.     }
  206.    
  207.     return -1;
  208. }
  209.  
  210. /**
  211.  * @}
  212.  */
  213.