source: mainline/uspace/srv/rd/rd.c@ c544c5d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c544c5d was c544c5d, checked in by Jakub Jermar <jakub@…>, 17 years ago

Stop using fixed size BLOCK_SIZE in the ramdisk task and allow each client to negotiate its own
maximum block size. Allow the individual transfers to use block sizes smaller and equal to the
negotiated maximum block size.

  • Property mode set to 100644
File size: 7.2 KB
Line 
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 <stdio.h>
55#include <ipc/devmap.h>
56#include "rd.h"
57
58#define NAME "rd"
59
60/** Pointer to the ramdisk's image. */
61static void *rd_addr;
62/** Size of the ramdisk. */
63static size_t rd_size;
64
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 */
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;
83 void *fs_va = NULL;
84 off_t offset;
85 size_t block_size;
86 size_t maxblock_size;
87
88 /*
89 * Answer the first IPC_M_CONNECT_ME_TO call.
90 */
91 ipc_answer_0(iid, EOK);
92
93 /*
94 * Now we wait for the client to send us its communication as_area.
95 */
96 int flags;
97 if (ipc_share_out_receive(&callid, &maxblock_size, &flags)) {
98 fs_va = as_get_mappable_page(maxblock_size);
99 if (fs_va) {
100 (void) ipc_share_out_finalize(callid, fs_va);
101 } else {
102 ipc_answer_0(callid, EHANGUP);
103 return;
104 }
105 } else {
106 /*
107 * The client doesn't speak the same protocol.
108 * At this point we can't handle protocol variations.
109 * Close the connection.
110 */
111 ipc_answer_0(callid, EHANGUP);
112 return;
113 }
114
115 while (1) {
116 callid = async_get_call(&call);
117 switch (IPC_GET_METHOD(call)) {
118 case IPC_M_PHONE_HUNGUP:
119 /*
120 * The other side has hung up.
121 * Answer the message and exit the fibril.
122 */
123 ipc_answer_0(callid, EOK);
124 return;
125 case RD_READ_BLOCK:
126 offset = IPC_GET_ARG1(call);
127 block_size = IPC_GET_ARG2(call);
128 if (block_size > maxblock_size) {
129 /*
130 * Maximum block size exceeded.
131 */
132 retval = ELIMIT;
133 break;
134 }
135 if (offset * block_size > rd_size - block_size) {
136 /*
137 * Reading past the end of the device.
138 */
139 retval = ELIMIT;
140 break;
141 }
142 futex_down(&rd_futex);
143 memcpy(fs_va, rd_addr + offset * block_size, block_size);
144 futex_up(&rd_futex);
145 retval = EOK;
146 break;
147 case RD_WRITE_BLOCK:
148 offset = IPC_GET_ARG1(call);
149 block_size = IPC_GET_ARG2(call);
150 if (block_size > maxblock_size) {
151 /*
152 * Maximum block size exceeded.
153 */
154 retval = ELIMIT;
155 break;
156 }
157 if (offset * block_size > rd_size - block_size) {
158 /*
159 * Writing past the end of the device.
160 */
161 retval = ELIMIT;
162 break;
163 }
164 futex_up(&rd_futex);
165 memcpy(rd_addr + offset * block_size, fs_va, block_size);
166 futex_down(&rd_futex);
167 retval = EOK;
168 break;
169 default:
170 /*
171 * The client doesn't speak the same protocol.
172 * Instead of closing the connection, we just ignore
173 * the call. This can be useful if the client uses a
174 * newer version of the protocol.
175 */
176 retval = EINVAL;
177 break;
178 }
179 ipc_answer_0(callid, retval);
180 }
181}
182
183static int driver_register(char *name)
184{
185 ipcarg_t retval;
186 aid_t req;
187 ipc_call_t answer;
188 int phone;
189 ipcarg_t callback_phonehash;
190
191 phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
192
193 while (phone < 0) {
194 usleep(10000);
195 phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
196 DEVMAP_DRIVER, 0);
197 }
198
199 req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
200
201 retval = ipc_data_write_start(phone, (char *) name, strlen(name) + 1);
202
203 if (retval != EOK) {
204 async_wait_for(req, NULL);
205 return -1;
206 }
207
208 async_set_client_connection(rd_connection);
209
210 ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
211 async_wait_for(req, &retval);
212
213 return phone;
214}
215
216static int device_register(int driver_phone, char *name, int *handle)
217{
218 ipcarg_t retval;
219 aid_t req;
220 ipc_call_t answer;
221
222 req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
223
224 retval = ipc_data_write_start(driver_phone, (char *) name, strlen(name) + 1);
225
226 if (retval != EOK) {
227 async_wait_for(req, NULL);
228 return retval;
229 }
230
231 async_wait_for(req, &retval);
232
233 if (handle != NULL)
234 *handle = -1;
235
236 if (EOK == retval) {
237 if (NULL != handle)
238 *handle = (int) IPC_GET_ARG1(answer);
239 }
240
241 return retval;
242}
243
244/** Prepare the ramdisk image for operation. */
245static bool rd_init(void)
246{
247 rd_size = sysinfo_value("rd.size");
248 void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
249
250 if (rd_size == 0) {
251 printf(NAME ": No RAM disk found\n");
252 return false;
253 }
254
255 rd_addr = as_get_mappable_page(rd_size);
256
257 int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
258 int retval = physmem_map(rd_ph_addr, rd_addr,
259 ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
260
261 if (retval < 0) {
262 printf(NAME ": Error mapping RAM disk\n");
263 return false;
264 }
265
266 printf(NAME ": Found RAM disk at %p, %d bytes\n", rd_ph_addr, rd_size);
267
268 int driver_phone = driver_register(NAME);
269 if (driver_phone < 0) {
270 printf(NAME ": Unable to register driver\n");
271 return false;
272 }
273
274 int dev_handle;
275 if (EOK != device_register(driver_phone, "initrd", &dev_handle)) {
276 ipc_hangup(driver_phone);
277 printf(NAME ": Unable to register device\n");
278 return false;
279 }
280
281 return true;
282}
283
284int main(int argc, char **argv)
285{
286 printf(NAME ": HelenOS RAM disk server\n");
287
288 if (!rd_init())
289 return -1;
290
291 printf(NAME ": Accepting connections\n");
292 async_manager();
293
294 /* Never reached */
295 return 0;
296}
297
298/**
299 * @}
300 */
Note: See TracBrowser for help on using the repository browser.