00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00041 #include <ipc/services.h>
00042 #include <ipc/ns.h>
00043 #include <sysinfo.h>
00044 #include <as.h>
00045 #include <ddi.h>
00046 #include <align.h>
00047 #include <bool.h>
00048 #include <errno.h>
00049 #include <async.h>
00050 #include <align.h>
00051 #include <async.h>
00052 #include <fibril_synch.h>
00053 #include <stdio.h>
00054 #include <devmap.h>
00055 #include <ipc/bd.h>
00056 #include <macros.h>
00057
00058 #define NAME "rd"
00059
00061 static void *rd_addr;
00062
00064 static size_t rd_size;
00065
00067 static const size_t block_size = 512;
00068
00069 static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf);
00070 static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf);
00071
00079 fibril_rwlock_t rd_lock;
00080
00086 static void rd_connection(ipc_callid_t iid, ipc_call_t *icall)
00087 {
00088 ipc_callid_t callid;
00089 ipc_call_t call;
00090 int retval;
00091 void *fs_va = NULL;
00092 uint64_t ba;
00093 size_t cnt;
00094 size_t comm_size;
00095
00096
00097
00098
00099 async_answer_0(iid, EOK);
00100
00101
00102
00103
00104 unsigned int flags;
00105 if (async_share_out_receive(&callid, &comm_size, &flags)) {
00106 fs_va = as_get_mappable_page(comm_size);
00107 if (fs_va) {
00108 (void) async_share_out_finalize(callid, fs_va);
00109 } else {
00110 async_answer_0(callid, EHANGUP);
00111 return;
00112 }
00113 } else {
00114
00115
00116
00117
00118
00119 async_answer_0(callid, EHANGUP);
00120 return;
00121 }
00122
00123 while (true) {
00124 callid = async_get_call(&call);
00125 switch (IPC_GET_IMETHOD(call)) {
00126 case IPC_M_PHONE_HUNGUP:
00127
00128
00129
00130
00131 async_answer_0(callid, EOK);
00132 return;
00133 case BD_READ_BLOCKS:
00134 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00135 IPC_GET_ARG2(call));
00136 cnt = IPC_GET_ARG3(call);
00137 if (cnt * block_size > comm_size) {
00138 retval = ELIMIT;
00139 break;
00140 }
00141 retval = rd_read_blocks(ba, cnt, fs_va);
00142 break;
00143 case BD_WRITE_BLOCKS:
00144 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00145 IPC_GET_ARG2(call));
00146 cnt = IPC_GET_ARG3(call);
00147 if (cnt * block_size > comm_size) {
00148 retval = ELIMIT;
00149 break;
00150 }
00151 retval = rd_write_blocks(ba, cnt, fs_va);
00152 break;
00153 case BD_GET_BLOCK_SIZE:
00154 async_answer_1(callid, EOK, block_size);
00155 continue;
00156 case BD_GET_NUM_BLOCKS:
00157 async_answer_2(callid, EOK, LOWER32(rd_size / block_size),
00158 UPPER32(rd_size / block_size));
00159 continue;
00160 default:
00161
00162
00163
00164
00165
00166
00167 retval = EINVAL;
00168 break;
00169 }
00170 async_answer_0(callid, retval);
00171 }
00172 }
00173
00175 static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf)
00176 {
00177 if ((ba + cnt) * block_size > rd_size) {
00178
00179 return ELIMIT;
00180 }
00181
00182 fibril_rwlock_read_lock(&rd_lock);
00183 memcpy(buf, rd_addr + ba * block_size, block_size * cnt);
00184 fibril_rwlock_read_unlock(&rd_lock);
00185
00186 return EOK;
00187 }
00188
00190 static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
00191 {
00192 if ((ba + cnt) * block_size > rd_size) {
00193
00194 return ELIMIT;
00195 }
00196
00197 fibril_rwlock_write_lock(&rd_lock);
00198 memcpy(rd_addr + ba * block_size, buf, block_size * cnt);
00199 fibril_rwlock_write_unlock(&rd_lock);
00200
00201 return EOK;
00202 }
00203
00205 static bool rd_init(void)
00206 {
00207 int ret = sysinfo_get_value("rd.size", &rd_size);
00208 if ((ret != EOK) || (rd_size == 0)) {
00209 printf("%s: No RAM disk found\n", NAME);
00210 return false;
00211 }
00212
00213 sysarg_t rd_ph_addr;
00214 ret = sysinfo_get_value("rd.address.physical", &rd_ph_addr);
00215 if ((ret != EOK) || (rd_ph_addr == 0)) {
00216 printf("%s: Invalid RAM disk physical address\n", NAME);
00217 return false;
00218 }
00219
00220 rd_addr = as_get_mappable_page(rd_size);
00221
00222 int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
00223 int retval = physmem_map((void *) rd_ph_addr, rd_addr,
00224 ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
00225
00226 if (retval < 0) {
00227 printf("%s: Error mapping RAM disk\n", NAME);
00228 return false;
00229 }
00230
00231 printf("%s: Found RAM disk at %p, %zu bytes\n", NAME,
00232 (void *) rd_ph_addr, rd_size);
00233
00234 int rc = devmap_driver_register(NAME, rd_connection);
00235 if (rc < 0) {
00236 printf("%s: Unable to register driver (%d)\n", NAME, rc);
00237 return false;
00238 }
00239
00240 devmap_handle_t devmap_handle;
00241 if (devmap_device_register("bd/initrd", &devmap_handle) != EOK) {
00242 printf("%s: Unable to register device\n", NAME);
00243 return false;
00244 }
00245
00246 fibril_rwlock_initialize(&rd_lock);
00247
00248 return true;
00249 }
00250
00251 int main(int argc, char **argv)
00252 {
00253 printf("%s: HelenOS RAM disk server\n", NAME);
00254
00255 if (!rd_init())
00256 return -1;
00257
00258 printf("%s: Accepting connections\n", NAME);
00259 async_manager();
00260
00261
00262 return 0;
00263 }
00264