Subversion Repositories HelenOS

Rev

Rev 2637 | 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>
2445 decky 54
#include "rd.h"
1999 decky 55
 
2475 jermar 56
/** Pointer to the ramdisk's image. */
2445 decky 57
static void *rd_addr;
2478 jermar 58
/** Size of the ramdisk. */
59
static size_t rd_size;
1999 decky 60
 
2475 jermar 61
/**
62
 * This futex protects the ramdisk's data.
63
 * 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
65
 * protected by this futex.
66
 */
67
atomic_t rd_futex = FUTEX_INITIALIZER;
68
 
69
/** Handle one connection to ramdisk.
70
 *
71
 * @param iid       Hash of the request that opened the connection.
72
 * @param icall     Call data of the request that opened the connection.
73
 */
1999 decky 74
static void rd_connection(ipc_callid_t iid, ipc_call_t *icall)
75
{
76
    ipc_callid_t callid;
77
    ipc_call_t call;
78
    int retval;
2478 jermar 79
    void *fs_va = NULL;
2445 decky 80
    ipcarg_t offset;
1999 decky 81
 
2475 jermar 82
    /*
83
     * We allocate VA for communication per connection.
84
     * This allows us to potentionally have more clients and work
85
     * concurrently.
86
     */
87
    fs_va = as_get_mappable_page(ALIGN_UP(BLOCK_SIZE, PAGE_SIZE));
88
    if (!fs_va) {
89
        /*
90
         * Hang up the phone if we cannot proceed any further.
91
         * This is the answer to the call that opened the connection.
92
         */
2619 jermar 93
        ipc_answer_0(iid, EHANGUP);
2475 jermar 94
        return;
95
    } else {
96
        /*
97
         * Answer the first IPC_M_CONNECT_ME_TO call.
98
         * Return supported block size as ARG1.
99
         */
2619 jermar 100
        ipc_answer_1(iid, EOK, BLOCK_SIZE);
2475 jermar 101
    }
102
 
103
    /*
104
     * Now we wait for the client to send us its communication as_area.
105
     */
2677 jermar 106
    size_t size;
107
    if (ipc_share_out_receive(&callid, &size, NULL)) {
108
        if (size >= BLOCK_SIZE) {
2475 jermar 109
            /*
110
             * The client sends an as_area that can absorb the whole
111
             * block.
112
             */
2677 jermar 113
            (void) ipc_share_out_deliver(callid, fs_va);
2475 jermar 114
        } else {
115
            /*
116
             * The client offered as_area too small.
117
             * Close the connection.
118
             */
2619 jermar 119
            ipc_answer_0(callid, EHANGUP);
2475 jermar 120
            return;    
121
        }
122
    } else {
123
        /*
124
         * The client doesn't speak the same protocol.
125
         * At this point we can't handle protocol variations.
126
         * Close the connection.
127
         */
2619 jermar 128
        ipc_answer_0(callid, EHANGUP);
2475 jermar 129
        return;
130
    }
131
 
1999 decky 132
    while (1) {
133
        callid = async_get_call(&call);
134
        switch (IPC_GET_METHOD(call)) {
2471 jermar 135
        case IPC_M_PHONE_HUNGUP:
2475 jermar 136
            /*
137
             * The other side has hung up.
2518 jermar 138
             * Answer the message and exit the fibril.
2475 jermar 139
             */
2619 jermar 140
            ipc_answer_0(callid, EOK);
2471 jermar 141
            return;
2475 jermar 142
        case RD_READ_BLOCK:
2471 jermar 143
            offset = IPC_GET_ARG1(call);
2478 jermar 144
            if (offset * BLOCK_SIZE > rd_size - BLOCK_SIZE) {
145
                /*
146
                 * Reading past the end of the device.
147
                 */
148
                retval = ELIMIT;
149
                break;
150
            }
2475 jermar 151
            futex_down(&rd_futex);
2478 jermar 152
            memcpy(fs_va, rd_addr + offset, BLOCK_SIZE);
2475 jermar 153
            futex_up(&rd_futex);
2471 jermar 154
            retval = EOK;
155
            break;
2475 jermar 156
        case RD_WRITE_BLOCK:
157
            offset = IPC_GET_ARG1(call);
2478 jermar 158
            if (offset * BLOCK_SIZE > rd_size - BLOCK_SIZE) {
159
                /*
160
                 * Writing past the end of the device.
161
                 */
162
                retval = ELIMIT;
163
                break;
164
            }
2475 jermar 165
            futex_up(&rd_futex);
2478 jermar 166
            memcpy(rd_addr + offset, fs_va, BLOCK_SIZE);
2475 jermar 167
            futex_down(&rd_futex);
168
            retval = EOK;
169
            break;
2471 jermar 170
        default:
2475 jermar 171
            /*
172
             * The client doesn't speak the same protocol.
173
             * Instead of closing the connection, we just ignore
174
             * the call. This can be useful if the client uses a
175
             * newer version of the protocol.
176
             */
2471 jermar 177
            retval = EINVAL;
2475 jermar 178
            break;
1999 decky 179
        }
2619 jermar 180
        ipc_answer_0(callid, retval);
2471 jermar 181
    }
1999 decky 182
}
183
 
2475 jermar 184
/** Prepare the ramdisk image for operation. */
2005 decky 185
static bool rd_init(void)
1999 decky 186
{
2445 decky 187
    int retval, flags;
188
 
2478 jermar 189
    rd_size = sysinfo_value("rd.size");
2471 jermar 190
    void *rd_ph_addr = (void *) sysinfo_value("rd.address.physical");
1999 decky 191
 
2005 decky 192
    if (rd_size == 0)
193
        return false;
1999 decky 194
 
2445 decky 195
    rd_addr = as_get_mappable_page(rd_size);
2005 decky 196
 
2445 decky 197
    flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
2471 jermar 198
    retval = physmem_map(rd_ph_addr, rd_addr,
199
        ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
2445 decky 200
 
201
    if (retval < 0)
202
        return false;
2005 decky 203
    return true;
204
}
1999 decky 205
 
2005 decky 206
int main(int argc, char **argv)
207
{
208
    if (rd_init()) {
209
        ipcarg_t phonead;
210
 
211
        async_set_client_connection(rd_connection);
212
 
213
        /* Register service at nameserver */
2637 cejka 214
        if (ipc_connect_to_me(PHONE_NS, SERVICE_RD, 0, 0, &phonead) != 0)
2005 decky 215
            return -1;
216
 
217
        async_manager();
218
 
219
        /* Never reached */
220
        return 0;
221
    }
222
 
223
    return -1;
1999 decky 224
}
225
 
226
/**
227
 * @}
228
 */