Subversion Repositories HelenOS

Rev

Rev 2927 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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