Subversion Repositories HelenOS

Rev

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

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