Subversion Repositories HelenOS

Rev

Rev 2927 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1999 decky 1
/*
2445 decky 2
 * Copyright (c) 2007 Michal Konopa
3
 * Copyright (c) 2007 Martin Jelen
4
 * Copyright (c) 2007 Peter Majer
2475 jermar 5
 * Copyright (c) 2007 Jakub Jermar
1999 decky 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>
2005 decky 44
#include <sysinfo.h>
45
#include <as.h>
46
#include <ddi.h>
47
#include <align.h>
48
#include <bool.h>
1999 decky 49
#include <errno.h>
50
#include <async.h>
2445 decky 51
#include <align.h>
52
#include <async.h>
2475 jermar 53
#include <futex.h>
3150 svoboda 54
#include <stdio.h>
55
#include <ipc/devmap.h>
2445 decky 56
#include "rd.h"
1999 decky 57
 
3150 svoboda 58
#define NAME "rd"
59
 
2475 jermar 60
/** Pointer to the ramdisk's image. */
2445 decky 61
static void *rd_addr;
2478 jermar 62
/** Size of the ramdisk. */
63
static size_t rd_size;
1999 decky 64
 
2475 jermar 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
 */
71
atomic_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
 */
1999 decky 78
static 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;
2478 jermar 83
    void *fs_va = NULL;
2445 decky 84
    ipcarg_t offset;
1999 decky 85
 
2475 jermar 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
         */
2619 jermar 97
        ipc_answer_0(iid, EHANGUP);
2475 jermar 98
        return;
99
    } else {
100
        /*
101
         * Answer the first IPC_M_CONNECT_ME_TO call.
102
         * Return supported block size as ARG1.
103
         */
2619 jermar 104
        ipc_answer_1(iid, EOK, BLOCK_SIZE);
2475 jermar 105
    }
106
 
107
    /*
108
     * Now we wait for the client to send us its communication as_area.
109
     */
2677 jermar 110
    size_t size;
3150 svoboda 111
    int flags;
112
    if (ipc_share_out_receive(&callid, &size, &flags)) {
2677 jermar 113
        if (size >= BLOCK_SIZE) {
2475 jermar 114
            /*
115
             * The client sends an as_area that can absorb the whole
116
             * block.
117
             */
2678 jermar 118
            (void) ipc_share_out_finalize(callid, fs_va);
2475 jermar 119
        } else {
120
            /*
121
             * The client offered as_area too small.
122
             * Close the connection.
123
             */
2619 jermar 124
            ipc_answer_0(callid, EHANGUP);
2475 jermar 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
         */
2619 jermar 133
        ipc_answer_0(callid, EHANGUP);
2475 jermar 134
        return;
135
    }
136
 
1999 decky 137
    while (1) {
138
        callid = async_get_call(&call);
139
        switch (IPC_GET_METHOD(call)) {
2471 jermar 140
        case IPC_M_PHONE_HUNGUP:
2475 jermar 141
            /*
142
             * The other side has hung up.
2518 jermar 143
             * Answer the message and exit the fibril.
2475 jermar 144
             */
2619 jermar 145
            ipc_answer_0(callid, EOK);
2471 jermar 146
            return;
2475 jermar 147
        case RD_READ_BLOCK:
2471 jermar 148
            offset = IPC_GET_ARG1(call);
2478 jermar 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
            }
2475 jermar 156
            futex_down(&rd_futex);
3150 svoboda 157
            memcpy(fs_va, rd_addr + offset * BLOCK_SIZE, BLOCK_SIZE);
2475 jermar 158
            futex_up(&rd_futex);
2471 jermar 159
            retval = EOK;
160
            break;
2475 jermar 161
        case RD_WRITE_BLOCK:
162
            offset = IPC_GET_ARG1(call);
2478 jermar 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
            }
2475 jermar 170
            futex_up(&rd_futex);
3150 svoboda 171
            memcpy(rd_addr + offset * BLOCK_SIZE, fs_va, BLOCK_SIZE);
2475 jermar 172
            futex_down(&rd_futex);
173
            retval = EOK;
174
            break;
2471 jermar 175
        default:
2475 jermar 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
             */
2471 jermar 182
            retval = EINVAL;
2475 jermar 183
            break;
1999 decky 184
        }
2619 jermar 185
        ipc_answer_0(callid, retval);
2471 jermar 186
    }
1999 decky 187
}
188
 
3150 svoboda 189
static 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
 
222
static 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
 
2475 jermar 250
/** Prepare the ramdisk image for operation. */
2005 decky 251
static bool rd_init(void)
1999 decky 252
{
2478 jermar 253
    rd_size = sysinfo_value("rd.size");
2471 jermar 254
    void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
1999 decky 255
 
3150 svoboda 256
    if (rd_size == 0) {
257
        printf(NAME ": No RAM disk found\n");
2005 decky 258
        return false;
3150 svoboda 259
    }
1999 decky 260
 
2445 decky 261
    rd_addr = as_get_mappable_page(rd_size);
2005 decky 262
 
3150 svoboda 263
    int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
264
    int retval = physmem_map(rd_ph_addr, rd_addr,
2471 jermar 265
        ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
2445 decky 266
 
3150 svoboda 267
    if (retval < 0) {
268
        printf(NAME ": Error mapping RAM disk\n");
2445 decky 269
        return false;
3150 svoboda 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
 
2005 decky 287
    return true;
288
}
1999 decky 289
 
2005 decky 290
int main(int argc, char **argv)
291
{
3150 svoboda 292
    printf(NAME ": HelenOS RAM disk server\n");
2005 decky 293
 
3150 svoboda 294
    if (!rd_init())
295
        return -1;
296
 
297
    printf(NAME ": Accepting connections\n");
298
    async_manager();
299
 
300
    /* Never reached */
301
    return 0;
1999 decky 302
}
303
 
304
/**
305
 * @}
306
 */