source: mainline/uspace/srv/rd/rd.c@ 2a3124c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2a3124c was 2f65fb0, checked in by Martin Decky <martin@…>, 18 years ago

devmap support, small fixes

  • Property mode set to 100644
File size: 7.4 KB
RevLine 
[228b135]1/*
[ff3a34b]2 * Copyright (c) 2007 Michal Konopa
3 * Copyright (c) 2007 Martin Jelen
4 * Copyright (c) 2007 Peter Majer
[84947a4]5 * Copyright (c) 2007 Jakub Jermar
[228b135]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>
[7c34822e]44#include <sysinfo.h>
45#include <as.h>
46#include <ddi.h>
47#include <align.h>
48#include <bool.h>
[228b135]49#include <errno.h>
50#include <async.h>
[ff3a34b]51#include <align.h>
52#include <async.h>
[84947a4]53#include <futex.h>
[2f65fb0]54#include <stdio.h>
55#include <ipc/devmap.h>
[ff3a34b]56#include "rd.h"
[228b135]57
[2f65fb0]58#define NAME "rd"
59
[84947a4]60/** Pointer to the ramdisk's image. */
[ff3a34b]61static void *rd_addr;
[3ae470a]62/** Size of the ramdisk. */
63static size_t rd_size;
[228b135]64
[84947a4]65/**
66 * This futex protects the ramdisk's data.
67 * If we were to serve multiple requests (read + write or several writes)
68 * concurrently (i.e. from two or more threads), each read and write needs to be
69 * protected by this futex.
70 */
71atomic_t rd_futex = FUTEX_INITIALIZER;
72
73/** Handle one connection to ramdisk.
74 *
75 * @param iid Hash of the request that opened the connection.
76 * @param icall Call data of the request that opened the connection.
77 */
[228b135]78static void rd_connection(ipc_callid_t iid, ipc_call_t *icall)
79{
80 ipc_callid_t callid;
81 ipc_call_t call;
82 int retval;
[3ae470a]83 void *fs_va = NULL;
[ff3a34b]84 ipcarg_t offset;
[228b135]85
[84947a4]86 /*
87 * We allocate VA for communication per connection.
88 * This allows us to potentionally have more clients and work
89 * concurrently.
90 */
91 fs_va = as_get_mappable_page(ALIGN_UP(BLOCK_SIZE, PAGE_SIZE));
92 if (!fs_va) {
93 /*
94 * Hang up the phone if we cannot proceed any further.
95 * This is the answer to the call that opened the connection.
96 */
[b74959bd]97 ipc_answer_0(iid, EHANGUP);
[84947a4]98 return;
99 } else {
100 /*
101 * Answer the first IPC_M_CONNECT_ME_TO call.
102 * Return supported block size as ARG1.
103 */
[b74959bd]104 ipc_answer_1(iid, EOK, BLOCK_SIZE);
[84947a4]105 }
106
107 /*
108 * Now we wait for the client to send us its communication as_area.
109 */
[27d293a]110 size_t size;
[2f65fb0]111 int flags;
112 if (ipc_share_out_receive(&callid, &size, &flags)) {
[27d293a]113 if (size >= BLOCK_SIZE) {
[84947a4]114 /*
115 * The client sends an as_area that can absorb the whole
116 * block.
117 */
[215e375]118 (void) ipc_share_out_finalize(callid, fs_va);
[84947a4]119 } else {
120 /*
121 * The client offered as_area too small.
122 * Close the connection.
123 */
[b74959bd]124 ipc_answer_0(callid, EHANGUP);
[84947a4]125 return;
126 }
127 } else {
128 /*
129 * The client doesn't speak the same protocol.
130 * At this point we can't handle protocol variations.
131 * Close the connection.
132 */
[b74959bd]133 ipc_answer_0(callid, EHANGUP);
[84947a4]134 return;
135 }
136
[228b135]137 while (1) {
138 callid = async_get_call(&call);
139 switch (IPC_GET_METHOD(call)) {
[8b243f2]140 case IPC_M_PHONE_HUNGUP:
[84947a4]141 /*
142 * The other side has hung up.
[0f78e74]143 * Answer the message and exit the fibril.
[84947a4]144 */
[b74959bd]145 ipc_answer_0(callid, EOK);
[8b243f2]146 return;
[84947a4]147 case RD_READ_BLOCK:
148 offset = IPC_GET_ARG1(call);
[3ae470a]149 if (offset * BLOCK_SIZE > rd_size - BLOCK_SIZE) {
150 /*
151 * Reading past the end of the device.
152 */
153 retval = ELIMIT;
154 break;
155 }
[84947a4]156 futex_down(&rd_futex);
[2f65fb0]157 memcpy(fs_va, rd_addr + offset * BLOCK_SIZE, BLOCK_SIZE);
[84947a4]158 futex_up(&rd_futex);
159 retval = EOK;
160 break;
161 case RD_WRITE_BLOCK:
[8b243f2]162 offset = IPC_GET_ARG1(call);
[3ae470a]163 if (offset * BLOCK_SIZE > rd_size - BLOCK_SIZE) {
164 /*
165 * Writing past the end of the device.
166 */
167 retval = ELIMIT;
168 break;
169 }
[84947a4]170 futex_up(&rd_futex);
[2f65fb0]171 memcpy(rd_addr + offset * BLOCK_SIZE, fs_va, BLOCK_SIZE);
[84947a4]172 futex_down(&rd_futex);
[8b243f2]173 retval = EOK;
174 break;
175 default:
[84947a4]176 /*
177 * The client doesn't speak the same protocol.
178 * Instead of closing the connection, we just ignore
179 * the call. This can be useful if the client uses a
180 * newer version of the protocol.
181 */
[8b243f2]182 retval = EINVAL;
[84947a4]183 break;
[228b135]184 }
[b74959bd]185 ipc_answer_0(callid, retval);
[8b243f2]186 }
[228b135]187}
188
[2f65fb0]189static int driver_register(char *name)
190{
191 ipcarg_t retval;
192 aid_t req;
193 ipc_call_t answer;
194 int phone;
195 ipcarg_t callback_phonehash;
196
197 phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
198
199 while (phone < 0) {
200 usleep(10000);
201 phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
202 DEVMAP_DRIVER, 0);
203 }
204
205 req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
206
207 retval = ipc_data_write_start(phone, (char *) name, strlen(name) + 1);
208
209 if (retval != EOK) {
210 async_wait_for(req, NULL);
211 return -1;
212 }
213
214 async_set_client_connection(rd_connection);
215
216 ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
217 async_wait_for(req, &retval);
218
219 return phone;
220}
221
222static int device_register(int driver_phone, char *name, int *handle)
223{
224 ipcarg_t retval;
225 aid_t req;
226 ipc_call_t answer;
227
228 req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
229
230 retval = ipc_data_write_start(driver_phone, (char *) name, strlen(name) + 1);
231
232 if (retval != EOK) {
233 async_wait_for(req, NULL);
234 return retval;
235 }
236
237 async_wait_for(req, &retval);
238
239 if (handle != NULL)
240 *handle = -1;
241
242 if (EOK == retval) {
243 if (NULL != handle)
244 *handle = (int) IPC_GET_ARG1(answer);
245 }
246
247 return retval;
248}
249
[84947a4]250/** Prepare the ramdisk image for operation. */
[7c34822e]251static bool rd_init(void)
[228b135]252{
[3ae470a]253 rd_size = sysinfo_value("rd.size");
[8b243f2]254 void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
[7c34822e]255
[2f65fb0]256 if (rd_size == 0) {
257 printf(NAME ": No RAM disk found\n");
[7c34822e]258 return false;
[2f65fb0]259 }
[228b135]260
[ff3a34b]261 rd_addr = as_get_mappable_page(rd_size);
[228b135]262
[2f65fb0]263 int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
264 int retval = physmem_map(rd_ph_addr, rd_addr,
[8b243f2]265 ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
[ff3a34b]266
[2f65fb0]267 if (retval < 0) {
268 printf(NAME ": Error mapping RAM disk\n");
269 return false;
270 }
271
272 printf(NAME ": Found RAM disk at %p, %d bytes\n", rd_ph_addr, rd_size);
273
274 int driver_phone = driver_register(NAME);
275 if (driver_phone < 0) {
276 printf(NAME ": Unable to register driver\n");
277 return false;
278 }
279
280 int dev_handle;
281 if (EOK != device_register(driver_phone, "initrd", &dev_handle)) {
282 ipc_hangup(driver_phone);
283 printf(NAME ": Unable to register device\n");
[ff3a34b]284 return false;
[2f65fb0]285 }
286
[7c34822e]287 return true;
288}
[228b135]289
[7c34822e]290int main(int argc, char **argv)
291{
[2f65fb0]292 printf(NAME ": HelenOS RAM disk server\n");
[7c34822e]293
[2f65fb0]294 if (!rd_init())
295 return -1;
296
297 printf(NAME ": Accepting connections\n");
298 async_manager();
299
300 /* Never reached */
301 return 0;
[228b135]302}
303
304/**
305 * @}
306 */
Note: See TracBrowser for help on using the repository browser.