source: mainline/uspace/srv/rd/rd.c@ 860271d4

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

devmap support, small fixes

  • Property mode set to 100644
File size: 7.4 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 ipcarg_t offset;
85
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 */
97 ipc_answer_0(iid, EHANGUP);
98 return;
99 } else {
100 /*
101 * Answer the first IPC_M_CONNECT_ME_TO call.
102 * Return supported block size as ARG1.
103 */
104 ipc_answer_1(iid, EOK, BLOCK_SIZE);
105 }
106
107 /*
108 * Now we wait for the client to send us its communication as_area.
109 */
110 size_t size;
111 int flags;
112 if (ipc_share_out_receive(&callid, &size, &flags)) {
113 if (size >= BLOCK_SIZE) {
114 /*
115 * The client sends an as_area that can absorb the whole
116 * block.
117 */
118 (void) ipc_share_out_finalize(callid, fs_va);
119 } else {
120 /*
121 * The client offered as_area too small.
122 * Close the connection.
123 */
124 ipc_answer_0(callid, EHANGUP);
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 */
133 ipc_answer_0(callid, EHANGUP);
134 return;
135 }
136
137 while (1) {
138 callid = async_get_call(&call);
139 switch (IPC_GET_METHOD(call)) {
140 case IPC_M_PHONE_HUNGUP:
141 /*
142 * The other side has hung up.
143 * Answer the message and exit the fibril.
144 */
145 ipc_answer_0(callid, EOK);
146 return;
147 case RD_READ_BLOCK:
148 offset = IPC_GET_ARG1(call);
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 }
156 futex_down(&rd_futex);
157 memcpy(fs_va, rd_addr + offset * BLOCK_SIZE, BLOCK_SIZE);
158 futex_up(&rd_futex);
159 retval = EOK;
160 break;
161 case RD_WRITE_BLOCK:
162 offset = IPC_GET_ARG1(call);
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 }
170 futex_up(&rd_futex);
171 memcpy(rd_addr + offset * BLOCK_SIZE, fs_va, BLOCK_SIZE);
172 futex_down(&rd_futex);
173 retval = EOK;
174 break;
175 default:
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 */
182 retval = EINVAL;
183 break;
184 }
185 ipc_answer_0(callid, retval);
186 }
187}
188
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
250/** Prepare the ramdisk image for operation. */
251static bool rd_init(void)
252{
253 rd_size = sysinfo_value("rd.size");
254 void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
255
256 if (rd_size == 0) {
257 printf(NAME ": No RAM disk found\n");
258 return false;
259 }
260
261 rd_addr = as_get_mappable_page(rd_size);
262
263 int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
264 int retval = physmem_map(rd_ph_addr, rd_addr,
265 ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
266
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");
284 return false;
285 }
286
287 return true;
288}
289
290int main(int argc, char **argv)
291{
292 printf(NAME ": HelenOS RAM disk server\n");
293
294 if (!rd_init())
295 return -1;
296
297 printf(NAME ": Accepting connections\n");
298 async_manager();
299
300 /* Never reached */
301 return 0;
302}
303
304/**
305 * @}
306 */
Note: See TracBrowser for help on using the repository browser.