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
00039 #include <ipc/ipc.h>
00040 #include <ipc/ns.h>
00041 #include <ipc/services.h>
00042 #include <stdio.h>
00043 #include <unistd.h>
00044 #include <stdlib.h>
00045 #include <errno.h>
00046 #include <assert.h>
00047 #include <libadt/list.h>
00048 #include <libadt/hash_table.h>
00049 #include <sysinfo.h>
00050 #include <ddi.h>
00051 #include <as.h>
00052
00053 #define NAME "NS"
00054
00055 #define NS_HASH_TABLE_CHAINS 20
00056
00057 static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
00058 static int connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid);
00059
00060
00061 static hash_index_t ns_hash(unsigned long *key);
00062 static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item);
00063 static void ns_remove(link_t *item);
00064
00066 static hash_table_operations_t ns_hash_table_ops = {
00067 .hash = ns_hash,
00068 .compare = ns_compare,
00069 .remove_callback = ns_remove
00070 };
00071
00073 static hash_table_t ns_hash_table;
00074
00076 typedef struct {
00077 link_t link;
00078 ipcarg_t service;
00079 ipcarg_t phone;
00080 ipcarg_t in_phone_hash;
00081 } hashed_service_t;
00082
00083 static void *clockaddr = NULL;
00084 static void *klogaddr = NULL;
00085
00086 static void get_as(ipc_callid_t callid, ipc_call_t *call, char *name, void **addr)
00087 {
00088 void *ph_addr;
00089
00090 if (!*addr) {
00091 ph_addr = (void *)sysinfo_value(name);
00092 if (!ph_addr) {
00093 ipc_answer_fast(callid, ENOENT, 0, 0);
00094 return;
00095 }
00096 *addr = as_get_mappable_page(PAGE_SIZE);
00097 map_physmem(ph_addr, *addr, 1, AS_AREA_READ | AS_AREA_CACHEABLE);
00098 }
00099 ipc_answer_fast(callid, 0, (ipcarg_t)*addr, AS_AREA_READ);
00100 }
00101
00102 int main(int argc, char **argv)
00103 {
00104 ipc_call_t call;
00105 ipc_callid_t callid;
00106
00107 ipcarg_t retval;
00108
00109 if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3, &ns_hash_table_ops)) {
00110 return ENOMEM;
00111 }
00112
00113 while (1) {
00114 callid = ipc_wait_for_call(&call);
00115 switch (IPC_GET_METHOD(call)) {
00116 case IPC_M_AS_AREA_RECV:
00117 switch (IPC_GET_ARG3(call)) {
00118 case SERVICE_MEM_REALTIME:
00119 get_as(callid, &call, "clock.faddr", &clockaddr);
00120 break;
00121 case SERVICE_MEM_KLOG:
00122 get_as(callid, &call, "klog.faddr", &klogaddr);
00123 break;
00124 default:
00125 ipc_answer_fast(callid, ENOENT, 0, 0);
00126 }
00127 continue;
00128 case IPC_M_PHONE_HUNGUP:
00129 retval = 0;
00130 break;
00131 case IPC_M_CONNECT_TO_ME:
00132
00133
00134
00135 retval = register_service(IPC_GET_ARG1(call), IPC_GET_ARG3(call), &call);
00136 break;
00137 case IPC_M_CONNECT_ME_TO:
00138
00139
00140
00141 retval = connect_to_service(IPC_GET_ARG1(call), &call, callid);
00142 break;
00143 default:
00144 retval = ENOENT;
00145 break;
00146 }
00147 if (! (callid & IPC_CALLID_NOTIFICATION)) {
00148 ipc_answer_fast(callid, retval, 0, 0);
00149 }
00150 }
00151 }
00152
00161 int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
00162 {
00163 unsigned long keys[3] = { service, call->in_phone_hash, 0 };
00164 hashed_service_t *hs;
00165
00166 if (hash_table_find(&ns_hash_table, keys)) {
00167 return EEXISTS;
00168 }
00169
00170 hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
00171 if (!hs) {
00172 return ENOMEM;
00173 }
00174
00175 link_initialize(&hs->link);
00176 hs->service = service;
00177 hs->phone = phone;
00178 hs->in_phone_hash = call->in_phone_hash;
00179 hash_table_insert(&ns_hash_table, keys, &hs->link);
00180
00181 return 0;
00182 }
00183
00192 int connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
00193 {
00194 unsigned long keys[3] = { service, 0, 0 };
00195 link_t *hlp;
00196 hashed_service_t *hs;
00197
00198 hlp = hash_table_find(&ns_hash_table, keys);
00199 if (!hlp) {
00200 return ENOENT;
00201 }
00202 hs = hash_table_get_instance(hlp, hashed_service_t, link);
00203 return ipc_forward_fast(callid, hs->phone, 0, 0);
00204 }
00205
00212 hash_index_t ns_hash(unsigned long *key)
00213 {
00214 assert(key);
00215 return *key % NS_HASH_TABLE_CHAINS;
00216 }
00217
00231 int ns_compare(unsigned long key[], hash_count_t keys, link_t *item)
00232 {
00233 hashed_service_t *hs;
00234
00235 assert(key);
00236 assert(keys <= 3);
00237 assert(item);
00238
00239 hs = hash_table_get_instance(item, hashed_service_t, link);
00240
00241 if (keys == 2)
00242 return key[1] == hs->in_phone_hash;
00243 else
00244 return key[0] == hs->service;
00245 }
00246
00251 void ns_remove(link_t *item)
00252 {
00253 assert(item);
00254 free(hash_table_get_instance(item, hashed_service_t, link));
00255 }
00256