source: trunk/kernel/kern/rpc.c @ 1

Last change on this file since 1 was 1, checked in by alain, 7 years ago

First import

File size: 52.1 KB
Line 
1/*
2 * rpc.c - RPC related operations implementation.
3 *
4 * Authors Mohamed Lamine Karaoui (2015)
5 *         Alain Greiner (2016)
6 *
7 * Copyright (c)  UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <almos_config.h>
26#include <hal_types.h>
27#include <hal_atomic.h>
28#include <hal_remote.h>
29#include <hal_irqmask.h>
30#include <hal_special.h>
31#include <printk.h>
32#include <remote_sem.h>
33#include <core.h>
34#include <mapper.h>
35#include <device.h>
36#include <bits.h>
37#include <thread.h>
38#include <cluster.h>
39#include <process.h>
40#include <vfs.h>
41#include <fatfs.h>
42#include <dev_icu.h>
43#include <rpc.h>
44
45/////////////////////////////////////////////////////////////////////////////////////////
46//      array of function pointers  (must be consistent with enum in rpc.h)
47/////////////////////////////////////////////////////////////////////////////////////////
48
49rpc_server_t * rpc_server[RPC_MAX_INDEX] =
50{
51    &rpc_pmem_get_pages_server,         // 0
52    &rpc_process_pid_alloc_server,      // 1
53    &rpc_process_exec_server,           // 2
54    &rpc_process_kill_server,           // 3
55    &rpc_thread_user_create_server,     // 4
56    &rpc_thread_kernel_create_server,   // 5
57    &rpc_icu_wti_alloc_server,          // 6                       
58    &rpc_device_alloc_server,           // 7
59    &rpc_undefined,                     // 8
60    &rpc_undefined,                     // 9
61
62    &rpc_vfs_inode_create_server,       // 10 
63    &rpc_vfs_inode_destroy_server,      // 11 
64    &rpc_vfs_dentry_create_server,      // 12 
65    &rpc_vfs_dentry_destroy_server,     // 13 
66    &rpc_undefined,                     // 14
67    &rpc_undefined,                     // 15
68    &rpc_undefined,                     // 16
69    &rpc_undefined,                     // 17
70    &rpc_undefined,                     // 18
71    &rpc_undefined,                     // 19
72
73    &rpc_vmm_get_ref_vseg_server,       // 20
74    &rpc_vmm_get_pte_server,            // 21
75    &rpc_semaphore_alloc_server,        // 22
76    &rpc_semaphore_free_server,         // 23
77    &rpc_mapper_move_server,            // 24
78    &rpc_undefined,                     // 25
79    &rpc_undefined,                     // 26
80    &rpc_undefined,                     // 27
81    &rpc_undefined,                     // 28
82    &rpc_undefined,                     // 29
83
84    &rpc_fatfs_get_cluster_server       // 30
85};
86
87//////////////////////////////////////////////
88void __attribute__((noinline)) rpc_undefined()
89{
90    printk("\n[PANIC] ‰s called in cluster %x\n", __FUNCTION__ , local_cxy );
91    hal_core_sleep();
92}
93
94/////////////////////////////////////////////////////////////////////////////////////////
95//               Marshaling functions attached to RPC_PMEM_GET_PAGES
96/////////////////////////////////////////////////////////////////////////////////////////
97
98///////////////////////////////////////////////
99void rpc_pmem_get_pages_client( cxy_t      cxy,
100                                uint32_t   order,      // in
101                                error_t  * error,      // out
102                                uint32_t * ppn )       // out
103{
104    // any RPC must be remote
105    if( cxy == local_cxy ) 
106    {
107        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
108        hal_core_sleep();
109    }
110
111    // initialise RPC descriptor header
112    rpc_desc_t  rpc;
113    rpc.index    = RPC_PMEM_GET_PAGES;
114    rpc.response = 1;
115
116    // set input arguments in RPC descriptor
117    rpc.args[0] = (uint64_t)order;
118
119    // register RPC request in remote RPC fifo (blocking function)
120    rpc_send_sync( cxy , &rpc );
121
122    // get output arguments RPC descriptor
123    *error  = (error_t)rpc.args[0];     
124    *ppn    = (uint32_t)rpc.args[1];
125}
126
127///////////////////////////////////////////
128void rpc_pmem_get_pages_server( xptr_t xp )
129{
130    uint32_t order;  // input
131    error_t  error;  // output
132    uint32_t ppn;    // output
133
134    // get client cluster identifier and pointer on RPC descriptor
135    cxy_t        cxy  = (cxy_t)GET_CXY( xp );
136    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
137
138    // get input arguments from client RPC descriptor
139    order = hal_remote_lw( XPTR( cxy , &desc->args[0] ) );
140   
141    // call local pmem allocator
142    page_t * page = ppm_alloc_pages( order ); 
143    error = ( page == NULL ) ? ENOMEM : 0;
144    ppn   = ppm_page2ppn( page );
145
146    // set output arguments into client RPC descriptor
147    hal_remote_sw( XPTR( cxy , &desc->args[0] ) , error );
148    hal_remote_sw( XPTR( cxy , &desc->args[1] ) , ppn );
149}
150
151/////////////////////////////////////////////////////////////////////////////////////////
152//               Marshaling functions attached to RPC_PROCESS_PID_ALLOC
153/////////////////////////////////////////////////////////////////////////////////////////
154
155//////////////////////////////////////////////////
156void rpc_process_pid_alloc_client( cxy_t       cxy, 
157                                   process_t * process,  // in
158                                   error_t   * error,    // out
159                                   pid_t     * pid )     // out
160{
161    // RPC must be remote
162    if( cxy == local_cxy ) 
163    {
164        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
165        hal_core_sleep();
166    }
167
168    // initialise RPC descriptor header
169    rpc_desc_t  rpc;
170    rpc.index    = RPC_PROCESS_PID_ALLOC;
171    rpc.response = 1;
172
173    // set input arguments in RPC descriptor
174    rpc.args[0] = (uint64_t)(intptr_t)process;
175
176    // register RPC request in remote RPC fifo (blocking function)
177    rpc_send_sync( cxy , &rpc );
178
179    // get output arguments RPC descriptor
180    *pid    = (pid_t)rpc.args[1];
181    *error  = (error_t)rpc.args[2];     
182}
183
184//////////////////////////////////////////////
185void rpc_process_pid_alloc_server( xptr_t xp )
186{
187    process_t * process;   // input  : client process descriptor
188    error_t     error;     // output : error status
189    pid_t       pid;       // output : process identifier
190
191    // get client cluster identifier and pointer on RPC descriptor
192    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
193    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
194
195    // get input argument from client RPC descriptor
196    process = (process_t*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
197   
198    // call local pid allocator
199    xptr_t xp_process = XPTR( client_cxy , process );
200    error = cluster_pid_alloc( xp_process , &pid ); 
201
202    // set output arguments into client RPC descriptor
203    hal_remote_sw( XPTR( client_cxy , &desc->args[0] ) , (uint64_t)error );
204    hal_remote_sw( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)pid );
205}
206
207
208/////////////////////////////////////////////////////////////////////////////////////////
209//               Marshaling functions attached to RPC_PROCESS_EXEC
210/////////////////////////////////////////////////////////////////////////////////////////
211
212////////////////////////////////////////////////
213void rpc_process_exec_client( cxy_t         cxy,
214                              exec_info_t * info,     // in
215                              error_t     * error )   // out
216{
217    // RPC must be remote
218    if( cxy == local_cxy ) 
219    {
220        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
221        hal_core_sleep();
222    }
223
224    // initialise RPC descriptor header
225    rpc_desc_t  rpc;
226    rpc.index    = RPC_PROCESS_EXEC;
227    rpc.response = 1;
228
229    // set input arguments in RPC descriptor 
230    rpc.args[0] = (uint64_t)(intptr_t)info;
231
232    // register RPC request in remote RPC fifo (blocking function)
233    rpc_send_sync( cxy , &rpc );
234
235    // get output arguments from RPC descriptor
236    *error  = (error_t)rpc.args[1];     
237}
238
239/////////////////////////////////////////
240void rpc_process_exec_server( xptr_t xp )
241{
242    exec_info_t * ptr;       // local pointer on remote exec_info structure
243    exec_info_t   info;      // local copy of exec_info structure
244    error_t       error;     // local error error status
245
246    // get client cluster identifier and pointer on RPC descriptor
247    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
248    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
249
250    // get pointer on exec_info structure in client cluster from RPC descriptor
251    ptr = (exec_info_t*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
252
253    // copy exec_info structure from client buffer to server buffer
254    hal_remote_memcpy( XPTR( client_cxy , ptr ),
255                       XPTR( local_cxy , &info ),
256                       sizeof(exec_info_t) );
257
258    // call local kernel function
259    error = process_make_exec( &info ); 
260
261    // set output argument into client RPC descriptor
262    hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error );
263}
264
265
266/////////////////////////////////////////////////////////////////////////////////////////
267//               Marshaling functions attached to RPC_PROCESS_KILL
268/////////////////////////////////////////////////////////////////////////////////////////
269
270///////////////////////////////////////////////////
271void rpc_process_kill_client( process_t * process ) 
272{
273    // only reference cluster can send this RPC
274    if( !process->is_ref )
275    {
276        printk("PANIC in %s : caller is not the reference process\n", __FUNCTION__ );
277        hal_core_sleep();
278    }
279
280    // get local process index in reference cluster
281    lpid_t lpid = LPID_FROM_PID( process->pid );
282
283    // get local process manager pointer
284    pmgr_t * pmgr = &LOCAL_CLUSTER->pmgr;
285
286    // get number of copies
287    uint32_t copies = pmgr->copies_nr[lpid];
288
289    // initialise RPC descriptor
290    rpc_desc_t  rpc;
291    rpc.index    = RPC_PROCESS_KILL;
292    rpc.response = copies;
293    rpc.args[0]  = (uint64_t)process->pid;
294
295    // loop on list of copies to send RPC
296    xptr_t  iter;
297    XLIST_FOREACH( XPTR( local_cxy , &pmgr->copies_root[lpid] ) , iter )
298    {
299        // get cluster_identifier for current copy
300        cxy_t  target_cxy = GET_CXY( iter );
301
302        // register RPC request in remote RPC fifo ... but the reference
303        if( target_cxy != local_cxy ) rpc_send_sync( target_cxy , &rpc );
304    }
305} 
306
307/////////////////////////////////////////
308void rpc_process_kill_server( xptr_t xp )
309{
310    pid_t       pid;
311    process_t * process; 
312
313    // get client cluster identifier and pointer on RPC descriptor
314    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
315    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
316
317    // get pid argument from RPC descriptor
318    pid = (pid_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
319
320    // get process pointer to call local kernel function
321    process = cluster_get_local_process_from_pid( pid );
322
323    if( process == NULL )  // process not found => do nothing
324    {
325        printk("\n[WARNING] in %s : process %x not found in cluster %x\n",
326               __FUNCTION__ , pid , local_cxy );
327    }
328    else                   // destroy process
329    {
330        process_kill( process ); 
331    }
332} 
333
334
335/////////////////////////////////////////////////////////////////////////////////////////
336//               Marshaling functions attached to RPC_THREAD_USER_CREATE               
337/////////////////////////////////////////////////////////////////////////////////////////
338
339/////////////////////////////////////////////////////////
340void rpc_thread_user_create_client( cxy_t            cxy, 
341                                    pthread_attr_t * attr,        // in
342                                    xptr_t         * thread_xp,   // out
343                                    error_t        * error )      // out
344{
345    // RPC must be remote
346    if( cxy == local_cxy ) 
347    {
348        printk("\n[PANIC] in %s : target is not remote\n", __FUNCTION__ );
349        hal_core_sleep();
350    }
351
352    // initialise RPC descriptor header
353    rpc_desc_t  rpc;
354    rpc.index    = RPC_THREAD_USER_CREATE;
355    rpc.response = 1;
356
357    // set input arguments in RPC descriptor
358    rpc.args[0] = (uint64_t)(intptr_t)attr;
359
360    // register RPC request in remote RPC fifo
361    rpc_send_sync( cxy , &rpc );
362
363    // get output arguments from RPC descriptor
364    *thread_xp = (xptr_t)rpc.args[1];
365    *error     = (error_t)rpc.args[2];
366}
367
368///////////////////////////////////////////////
369void rpc_thread_user_create_server( xptr_t xp )
370{
371    pthread_attr_t * attr_ptr;   // pointer on attributes structure in client cluster
372    pthread_attr_t   attr_copy;  // attributes structure  copy in server cluster
373    thread_t       * thread_ptr; // local pointer on thread descriptor
374    xptr_t           thread_xp;  // extended pointer on thread descriptor
375    pid_t            pid;        // process identifier
376    process_t      * process;    // local pointer on process descriptor
377    vseg_t         * vseg;       // local pointer on stack vseg
378
379    error_t          error = 0;
380
381    // get client cluster identifier and pointer on RPC descriptor
382    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
383    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
384
385    // get pointer on attributes structure in client cluster from RPC descriptor
386    attr_ptr = (pthread_attr_t *)(intptr_t)hal_remote_lwd( XPTR(client_cxy , &desc->args[0]) );
387
388    // makes a local copy of attributes structure
389    hal_remote_memcpy( XPTR( local_cxy , &attr_copy ),
390                       XPTR( client_cxy , attr_ptr ), 
391                       sizeof(pthread_attr_t) );
392   
393    if( attr_copy.cxy != local_cxy )
394    {
395        printk("\n[PANIC] in %s : target cluster = %X / local_cluster = %x\n",
396               __FUNCTION__ , attr_copy.cxy , local_cxy );
397        hal_core_sleep();
398    }
399
400    // get local process descriptor
401    pid     = attr_copy.pid; 
402    process = cluster_get_local_process_from_pid( pid );
403
404    if( process == NULL )
405    {
406        printk("\n[ERROR] in %s : no process descriptor in cluster %x for pid = %x\n",
407               __FUNCTION__ , local_cxy , pid );
408        error = ENOMEM;
409       
410    }
411
412    // allocate a stack from local VMM
413    vseg = vmm_create_vseg( process, 
414                            0,
415                            0,
416                            VSEG_TYPE_STACK );
417    if( vseg == NULL )
418    {
419        printk("\n[ERROR] in %s : cannot create stack vseg in cluster %x for pid %x\n",
420               __FUNCTION__ , local_cxy , pid );
421        error = ENOMEM;
422    } 
423
424    // create thread in local cluster
425    if( thread_user_create( &thread_ptr,
426                            &attr_copy,
427                            vseg->min,
428                            vseg->max - vseg->min ) ) error = ENOMEM;
429
430
431    // set output arguments
432    thread_xp = XPTR( local_cxy , thread_ptr );
433    hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error );
434    hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)thread_xp );
435}
436
437/////////////////////////////////////////////////////////////////////////////////////////
438//               Marshaling functions attached to RPC_THREAD_KERNEL_CREATE
439/////////////////////////////////////////////////////////////////////////////////////////
440
441////////////////////////////////////////////////////
442void rpc_thread_kernel_create_client( cxy_t     cxy,
443                                      uint32_t  type,        // in
444                                      void    * func,        // in
445                                      void    * args,        // in
446                                      xptr_t  * thread_xp,   // out
447                                      error_t * error )      // out
448{
449    // RPC must be remote
450    if( cxy == local_cxy ) 
451    {
452        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
453        hal_core_sleep();
454    }
455
456    // initialise RPC descriptor header
457    rpc_desc_t  rpc;
458    rpc.index    = RPC_THREAD_KERNEL_CREATE;
459    rpc.response = 1;
460
461    // set input arguments in RPC descriptor
462    rpc.args[0] = (uint64_t)type;
463    rpc.args[1] = (uint64_t)(intptr_t)func;
464    rpc.args[2] = (uint64_t)(intptr_t)args;
465   
466    // register RPC request in remote RPC fifo
467    rpc_send_sync( cxy , &rpc );
468
469    // get output arguments from RPC descriptor
470    *thread_xp = (xptr_t)rpc.args[3];
471    *error     = (error_t)rpc.args[4];
472}
473
474/////////////////////////////////////////////////
475void rpc_thread_kernel_create_server( xptr_t xp )
476{
477    thread_t       * thread_ptr;  // local pointer on thread descriptor
478    xptr_t           thread_xp;   // extended pointer on thread descriptor
479    lid_t            core_lid;    // core local index
480    error_t          error;   
481
482    // get client cluster identifier and pointer on RPC descriptor
483    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
484    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
485
486    // get attributes from RPC descriptor
487    uint32_t  type = (uint32_t)       hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
488    void    * func = (void*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) );
489    void    * args = (void*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) );
490
491    // select one core
492    core_lid = cluster_select_local_core();
493
494    // call local kernel function
495    error = thread_kernel_create( &thread_ptr , type , func , args , core_lid );
496
497    // set output arguments
498    thread_xp = XPTR( local_cxy , thread_ptr );
499    hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error );
500    hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)thread_xp );
501}
502
503/////////////////////////////////////////////////////////////////////////////////////////
504//               Marshaling functions attached to RPC_VFS_INODE_CREATE
505/////////////////////////////////////////////////////////////////////////////////////////
506
507/////////////////////////////////////////////////////
508void rpc_vfs_inode_create_client( cxy_t          cxy,     
509                                  xptr_t         dentry_xp,  // in
510                                  uint32_t       type,       // in
511                                  uint32_t       attr,       // in
512                                  uint32_t       mode,       // in
513                                  uint32_t       uid,        // in
514                                  uint32_t       gid,        // in
515                                  xptr_t       * inode_xp,   // out
516                                  error_t      * error )     // out
517{
518    // RPC must be remote
519    if( cxy == local_cxy ) 
520    {
521        printk("PANIC in %s : target cluster is not remote\n", __FUNCTION__ );
522        hal_core_sleep();
523    }
524
525    // initialise RPC descriptor header
526    rpc_desc_t  rpc;
527    rpc.index    = RPC_VFS_INODE_CREATE;
528    rpc.response = 1;
529
530    // set input arguments in RPC descriptor
531    rpc.args[0] = (uint64_t)dentry_xp;
532    rpc.args[1] = (uint64_t)type;
533    rpc.args[2] = (uint64_t)attr;
534    rpc.args[3] = (uint64_t)mode;
535    rpc.args[4] = (uint64_t)uid;
536    rpc.args[5] = (uint64_t)gid;
537
538    // register RPC request in remote RPC fifo (blocking function)
539    rpc_send_sync( cxy , &rpc );
540
541    // get output values from RPC descriptor
542    *inode_xp = (xptr_t)rpc.args[6];
543    *error    = (error_t)rpc.args[7];
544}
545
546/////////////////////////////////////////////
547void rpc_vfs_inode_create_server( xptr_t xp )
548{
549    xptr_t           dentry_xp;
550    uint32_t         type;
551    uint32_t         attr;
552    uint32_t         mode;
553    uint32_t         uid;
554    uint32_t         gid;
555    xptr_t           inode_xp;
556    error_t          error;
557
558    // get client cluster identifier and pointer on RPC descriptor
559    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
560    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
561
562    // get input arguments from client rpc descriptor
563    dentry_xp = (xptr_t)  hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
564    type      = (uint32_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) );
565    attr      = (uint32_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) );
566    mode      = (uint32_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[3] ) );
567    uid       = (uid_t)   hal_remote_lwd( XPTR( client_cxy , &desc->args[4] ) );
568    gid       = (gid_t)   hal_remote_lwd( XPTR( client_cxy , &desc->args[5] ) );
569
570    // call local kernel function
571    error = vfs_inode_create( dentry_xp,
572                              type,
573                              attr,
574                              mode,
575                              uid,
576                              gid,
577                              &inode_xp );
578
579    // set output arguments
580    hal_remote_swd( XPTR( client_cxy , &desc->args[6] ) , (uint64_t)inode_xp );
581    hal_remote_swd( XPTR( client_cxy , &desc->args[7] ) , (uint64_t)error );
582}
583
584/////////////////////////////////////////////////////////////////////////////////////////
585//               Marshaling functions attached to RPC_VFS_INODE_DESTROY
586/////////////////////////////////////////////////////////////////////////////////////////
587
588/////////////////////////////////////////////////////////////
589void rpc_vfs_inode_destroy_client( cxy_t                cxy,
590                                   struct vfs_inode_s * inode )
591{
592    // RPC must be remote
593    if( cxy == local_cxy ) 
594    {
595        printk("PANIC in %s : target cluster is not remote\n", __FUNCTION__ );
596        hal_core_sleep();
597    }
598
599    // initialise RPC descriptor header
600    rpc_desc_t  rpc;
601    rpc.index    = RPC_VFS_INODE_DESTROY;
602    rpc.response = 1;
603
604    // set input arguments in RPC descriptor
605    rpc.args[0] = (uint64_t)(intptr_t)inode;
606   
607    // register RPC request in remote RPC fifo (blocking function)
608    rpc_send_sync( cxy , &rpc );
609}
610
611//////////////////////////////////////////////
612void rpc_vfs_inode_destroy_server( xptr_t xp )
613{
614    vfs_inode_t * inode;
615
616    // get client cluster identifier and pointer on RPC descriptor
617    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
618    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
619
620    // get arguments "inode" from client RPC descriptor
621    inode = (vfs_inode_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
622                       
623    // call local kernel function
624    vfs_inode_destroy( inode );
625}
626
627/////////////////////////////////////////////////////////////////////////////////////////
628//               Marshaling functions attached to RPC_VFS_DENTRY_CREATE
629/////////////////////////////////////////////////////////////////////////////////////////
630
631//////////////////////////////////////////////////////////////
632void rpc_vfs_dentry_create_client( cxy_t                  cxy,
633                                   uint32_t               type,         // in
634                                   char                 * name,         // in
635                                   struct vfs_inode_s   * parent,       // in
636                                   xptr_t               * dentry_xp,    // out
637                                   error_t              * error )       // out
638{
639    // RPC must be remote
640    if( cxy == local_cxy ) 
641    {
642        printk("PANIC in %s : target cluster is not remote\n", __FUNCTION__ );
643        hal_core_sleep();
644    }
645
646    // initialise RPC descriptor header
647    rpc_desc_t  rpc;
648    rpc.index    = RPC_VFS_DENTRY_CREATE;
649    rpc.response = 1;
650
651    // set input arguments in RPC descriptor
652    rpc.args[0] = (uint64_t)type;
653    rpc.args[1] = (uint64_t)(intptr_t)name;
654    rpc.args[2] = (uint64_t)strlen( name );
655    rpc.args[3] = (uint64_t)(intptr_t)parent;
656
657    // register RPC request in remote RPC fifo (blocking function)
658    rpc_send_sync( cxy , &rpc );
659
660    // get output values from RPC descriptor
661    *dentry_xp = (xptr_t)rpc.args[4];
662    *error     = (error_t)rpc.args[5];
663}
664
665//////////////////////////////////////////////
666void rpc_vfs_dentry_create_server( xptr_t xp )
667{
668    uint32_t      type;
669    char        * name;
670    vfs_inode_t * parent;
671    xptr_t        dentry_xp;
672    char          name_copy[CONFIG_VFS_MAX_NAME_LENGTH];
673    uint32_t      length;
674    error_t       error;
675
676    // get client cluster identifier and pointer on RPC descriptor
677    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
678    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
679
680    // get argument "name" & "length" from client RPC descriptor and makes a local copy
681    name   = (char *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) );
682    length = (uint32_t)        hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) );
683    hal_remote_memcpy( XPTR( local_cxy , name_copy ),
684                       XPTR( client_cxy , name ),
685                                           length + 1 );               // +1 for the NUL char
686
687    // get arguments "type" and "parent" from client RPC descriptor
688    type   = (uint32_t)               hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
689    parent = (vfs_inode_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[3] ) );
690                       
691    // call local kernel function
692    error = vfs_dentry_create( type,
693                               name_copy,
694                               parent,
695                               &dentry_xp );
696 
697    // set output arguments
698    hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)dentry_xp );
699    hal_remote_swd( XPTR( client_cxy , &desc->args[5] ) , (uint64_t)error );
700}
701
702/////////////////////////////////////////////////////////////////////////////////////////
703//               Marshaling functions attached to RPC_VFS_DENTRY_DESTROY
704/////////////////////////////////////////////////////////////////////////////////////////
705
706///////////////////////////////////////////////////////
707void rpc_vfs_dentry_destroy_client( cxy_t          cxy,
708                                    vfs_dentry_t * dentry )
709{
710    // RPC must be remote
711    if( cxy == local_cxy ) 
712    {
713        printk("PANIC in %s : target cluster is not remote\n", __FUNCTION__ );
714        hal_core_sleep();
715    }
716
717    // initialise RPC descriptor header
718    rpc_desc_t  rpc;
719    rpc.index    = RPC_VFS_DENTRY_DESTROY;
720    rpc.response = 1;
721
722    // set input arguments in RPC descriptor
723    rpc.args[0] = (uint64_t)(intptr_t)dentry;
724   
725    // register RPC request in remote RPC fifo (blocking function)
726    rpc_send_sync( cxy , &rpc );
727}
728
729///////////////////////////////////////////////
730void rpc_vfs_dentry_destroy_server( xptr_t xp )
731{
732    vfs_dentry_t * dentry;
733
734    // get client cluster identifier and pointer on RPC descriptor
735    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
736    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
737
738    // get arguments "dentry" from client RPC descriptor
739    dentry = (vfs_dentry_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
740                       
741    // call local kernel function
742    vfs_dentry_destroy( dentry );
743}
744
745
746/////////////////////////////////////////////////////////////////////////////////////////
747//               Marshaling functions attached to RPC_VMM_GET_VSEG
748/////////////////////////////////////////////////////////////////////////////////////////
749
750//////////////////////////////////////////////////
751void rpc_vmm_get_ref_vseg_client( cxy_t       cxy,     
752                                  process_t * process,     // in 
753                                  intptr_t    vaddr,       // in 
754                                  xptr_t    * vseg_xp )    // out
755{
756    // RPC must be remote
757    if( cxy == local_cxy ) 
758    {
759        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
760        hal_core_sleep();
761    }
762
763    // initialise RPC descriptor header
764    rpc_desc_t  rpc;
765    rpc.index    = RPC_VMM_GET_REF_VSEG;
766    rpc.response = 1;
767
768    // set input arguments in RPC descriptor
769    rpc.args[0] = (uint64_t)(intptr_t)process;
770    rpc.args[1] = (uint64_t)vaddr;
771
772    // register RPC request in remote RPC fifo (blocking function)
773    rpc_send_sync( cxy , &rpc );
774
775    // get output argument from rpc descriptor
776    *vseg_xp = rpc.args[2];
777}
778
779/////////////////////////////////////////////
780void rpc_vmm_get_ref_vseg_server( xptr_t xp )
781{
782    process_t   * process;
783    intptr_t      vaddr;
784    vseg_t      * vseg_ptr;
785    xptr_t        vseg_xp;
786
787    // get client cluster identifier and pointer on RPC descriptor
788    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
789    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
790
791    // get input argument from client RPC descriptor
792    process = (process_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
793    vaddr   = (intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) );
794   
795    // call local kernel function
796    vseg_ptr = vmm_get_vseg( process , vaddr );
797
798    // set output argument to client RPC descriptor
799    vseg_xp = XPTR( local_cxy , vseg_ptr );
800    hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)vseg_xp );
801}
802
803
804/////////////////////////////////////////////////////////////////////////////////////////
805//               Marshaling functions attached to RPC_VMM_GET_PTE
806/////////////////////////////////////////////////////////////////////////////////////////
807
808////////////////////////////////////////////
809void rpc_vmm_get_pte_client( cxy_t       cxy,   
810                             process_t * process,  // in
811                             vpn_t       vpn,      // in
812                             uint32_t  * attr,     // out
813                             ppn_t     * ppn,      // out
814                             error_t   * error )   // out
815{
816    // RPC must be remote
817    if( cxy == local_cxy ) 
818    {
819        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
820        hal_core_sleep();
821    }
822
823    // initialise RPC descriptor header
824    rpc_desc_t  rpc;
825    rpc.index    = RPC_VMM_GET_PTE;
826    rpc.response = 1;
827
828    // set input arguments in RPC descriptor
829    rpc.args[0] = (uint64_t)(intptr_t)process;
830    rpc.args[1] = (uint64_t)vpn;
831
832    // register RPC request in remote RPC fifo (blocking function)
833    rpc_send_sync( cxy , &rpc );
834
835    // get output argument from rpc descriptor
836    *attr  = (uint32_t)rpc.args[2];
837    *ppn   = (ppn_t)rpc.args[3];
838    *error = (error_t)rpc.args[4];
839}
840
841////////////////////////////////////////
842void rpc_vmm_get_pte_server( xptr_t xp )
843{
844    process_t   * process;
845    vpn_t         vpn;
846    uint32_t      attr;
847    ppn_t         ppn;
848    error_t       error;
849
850    // get client cluster identifier and pointer on RPC descriptor
851    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
852    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
853
854    // get input argument "process" & "vpn" from client RPC descriptor
855    process = (process_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
856    vpn     = (vpn_t)                hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) );
857   
858    // call local kernel function
859    error = vmm_get_pte( process , vpn , &attr , &ppn ); 
860
861    // set output argument "attr" & "ppn" to client RPC descriptor
862    hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)attr );
863    hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)ppn );
864    hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error );
865}
866
867/////////////////////////////////////////////////////////////////////////////////////////
868//               Marshaling functions attached to RPC_SEMAPHORE_ALLOC
869/////////////////////////////////////////////////////////////////////////////////////////
870
871//////////////////////////////////////////////
872void rpc_semaphore_alloc_client( cxy_t    cxy,
873                                 xptr_t * sem_xp )     // out
874{
875    // RPC must be remote
876    if( cxy == local_cxy ) 
877    {
878        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
879        hal_core_sleep();
880    }
881
882    // initialise RPC descriptor header
883    rpc_desc_t  rpc;
884    rpc.index    = RPC_THREAD_USER_CREATE;
885    rpc.response = 1;
886
887    // register RPC request in remote RPC fifo
888    rpc_send_sync( cxy , &rpc );
889
890    // get output arguments from RPC descriptor
891    *sem_xp = (xptr_t)rpc.args[0];
892}
893
894////////////////////////////////////////////
895void rpc_semaphore_alloc_server( xptr_t xp )
896{
897    // get client cluster identifier and pointer on RPC descriptor
898    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
899    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
900
901    // allocates memory for semaphore
902    kmem_req_t  req;
903    req.type  = KMEM_SEM;
904    req.flags = AF_ZERO;
905    remote_sem_t * sem_ptr = kmem_alloc( &req );
906
907    // set output argument
908    xptr_t sem_xp = XPTR( local_cxy , sem_ptr );
909    hal_remote_swd( XPTR( client_cxy , &desc->args[0] ) , (uint64_t)sem_xp );
910}   
911
912/////////////////////////////////////////////////////////////////////////////////////////
913//               Marshaling functions attached to RPC_SEMAPHORE_FREE
914/////////////////////////////////////////////////////////////////////////////////////////
915
916///////////////////////////////////////////////////
917void rpc_semaphore_free_client( cxy_t          cxy,
918                                remote_sem_t * sem )   // in
919{
920    // RPC must be remote
921    if( cxy == local_cxy ) 
922    {
923        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
924        hal_core_sleep();
925    }
926
927    // initialise RPC descriptor header
928    rpc_desc_t  rpc;
929    rpc.index    = RPC_THREAD_USER_CREATE;
930    rpc.response = 1;
931
932    // set input arguments in RPC descriptor
933    rpc.args[0] = (uint64_t)(intptr_t)sem;
934
935    // register RPC request in remote RPC fifo
936    rpc_send_sync( cxy , &rpc );
937}
938
939///////////////////////////////////////////
940void rpc_semaphore_free_server( xptr_t xp )
941{
942    // get client cluster identifier and pointer on RPC descriptor
943    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
944    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
945
946    // get input argument "sem_ptr" from client RPC descriptor
947    void * sem = (void *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
948
949    // releases memory
950    kmem_req_t  req;
951    req.type = KMEM_SEM;
952    req.ptr  = sem;
953    kmem_free(&req);
954}   
955
956/////////////////////////////////////////////////////////////////////////////////////////
957//               Marshaling functions attached to RPC_MAPPER_MOVE
958/////////////////////////////////////////////////////////////////////////////////////////
959
960//////////////////////////////////////////////
961void rpc_mapper_move_client( cxy_t        cxy,
962                             mapper_t   * mapper,      // in
963                             bool_t       read,        // in
964                             uint32_t     nb_frags,    // in
965                             fragment_t * frags,       // in
966                             error_t    * error )      // out
967{
968    // RPC must be remote
969    if( cxy == local_cxy ) 
970    {
971        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
972        hal_core_sleep();
973    }
974
975    // initialise RPC descriptor header
976    rpc_desc_t  rpc;
977    rpc.index    = RPC_MAPPER_MOVE;
978    rpc.response = 1;
979
980    // set input arguments in RPC descriptor
981    rpc.args[0] = (uint64_t)(intptr_t)mapper;
982    rpc.args[1] = (uint64_t)read;
983    rpc.args[2] = (uint64_t)nb_frags;
984    rpc.args[3] = (uint64_t)(intptr_t)frags;
985
986    // register RPC request in remote RPC fifo
987    rpc_send_sync( cxy , &rpc );
988
989    // get output argument from rpc descriptor
990    *error = (error_t)rpc.args[4];
991}
992
993////////////////////////////////////////
994void rpc_mapper_move_server( xptr_t xp )
995{
996    mapper_t    * mapper;
997    bool_t        read;
998    uint32_t      nb;
999    void        * frags;
1000    error_t       error;
1001
1002    // get client cluster identifier and pointer on RPC descriptor
1003    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
1004    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
1005
1006    // get input arguments
1007    mapper = (mapper_t*)(intptr_t)hal_remote_lpt( XPTR( client_cxy , &desc->args[0] ) );
1008    read   = (bool_t)             hal_remote_lw ( XPTR( client_cxy , &desc->args[1] ) );
1009    nb     = (uint32_t)           hal_remote_lw ( XPTR( client_cxy , &desc->args[2] ) );
1010    frags  = (void*)(intptr_t)    hal_remote_lpt( XPTR( client_cxy , &desc->args[3] ) );
1011
1012    // call the mapper_move_fragments() function
1013    error = mapper_move_fragments( mapper , read , nb , XPTR( client_cxy , frags ) );
1014
1015    // set output argument
1016    hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error );
1017}
1018
1019/////////////////////////////////////////////////////////////////////////////////////////
1020//               Marshaling functions attached to RPC_ICU_WTI_ALLOC
1021/////////////////////////////////////////////////////////////////////////////////////////
1022
1023//////////////////////////////////////////////
1024void rpc_icu_wti_alloc_client( cxy_t      cxy,
1025                               uint32_t * wti_id )    // out
1026{
1027    // RPC must be remote
1028    if( cxy == local_cxy ) 
1029    {
1030        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
1031        hal_core_sleep();
1032    }
1033
1034    // initialise RPC descriptor header
1035    rpc_desc_t  rpc;
1036    rpc.index    = RPC_ICU_WTI_ALLOC;
1037    rpc.response = 1;
1038
1039    // register RPC request in remote RPC fifo
1040    rpc_send_sync( cxy , &rpc );
1041
1042    // get output argument from rpc descriptor
1043    *wti_id = (uint32_t)rpc.args[0];
1044}
1045
1046//////////////////////////////////////////
1047void rpc_icu_wti_alloc_server( xptr_t xp )
1048{
1049    uint32_t      wti_id;
1050
1051    // get client cluster identifier and pointer on RPC descriptor
1052    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
1053    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
1054
1055    // call icu_wti_alloc() function
1056    wti_id = dev_icu_wti_alloc();
1057
1058    // set output argument
1059    hal_remote_swd( XPTR( client_cxy , &desc->args[0] ) , (uint64_t)wti_id);
1060}
1061
1062/////////////////////////////////////////////////////////////////////////////////////////
1063//               Marshaling functions attached to RPC_DEVICE_ALLOC
1064/////////////////////////////////////////////////////////////////////////////////////////
1065
1066/////////////////////////////////////////////
1067void rpc_device_alloc_client( cxy_t     cxy,
1068                              xptr_t  * dev_xp,      // out
1069                              error_t * error )      // out
1070{
1071    // RPC must be remote
1072    if( cxy == local_cxy ) 
1073    {
1074        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
1075        hal_core_sleep();
1076    }
1077
1078    // initialise RPC descriptor header
1079    rpc_desc_t  rpc;
1080    rpc.index    = RPC_DEVICE_ALLOC;
1081    rpc.response = 1;
1082
1083    // register RPC request in remote RPC fifo
1084    rpc_send_sync( cxy , &rpc );
1085
1086    // get output argument from rpc descriptor
1087    *dev_xp = (xptr_t)rpc.args[0];
1088    *error  = (error_t)rpc.args[1];
1089}   
1090
1091/////////////////////////////////////////
1092void rpc_device_alloc_server( xptr_t xp )
1093{
1094    error_t      error;
1095    kmem_req_t   req;
1096    device_t   * dev_ptr; 
1097    xptr_t       dev_xp;
1098
1099    // get client cluster identifier and pointer on RPC descriptor
1100    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
1101    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
1102
1103    // allocate memory for a device descriptor
1104    req.type   = KMEM_DEVICE;
1105    req.flags  = AF_ZERO;
1106    dev_ptr    = (device_t *)kmem_alloc( &req );
1107
1108    // set output arguments
1109    error  = ( dev_ptr == NULL );
1110    dev_xp = XPTR( local_cxy , dev_ptr );
1111    hal_remote_swd( XPTR( client_cxy , &desc->args[0] ) , (uint64_t)dev_xp );
1112    hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error );
1113}
1114
1115
1116/////////////////////////////////////////////////////////////////////////////////////////
1117//               Marshaling functions attached to RPC_FATFS_GET_CLUSTER
1118/////////////////////////////////////////////////////////////////////////////////////////
1119
1120//////////////////////////////////////////////////
1121void rpc_fatfs_get_cluster_client( cxy_t      cxy,
1122                                   mapper_t * mapper,    // in
1123                                   uint32_t   first,     // in
1124                                   uint32_t   page,      // in
1125                                   uint32_t * cluster,   // out
1126                                   error_t  * error )    // out
1127{
1128    // RPC must be remote
1129    if( cxy == local_cxy ) 
1130    {
1131        printk("PANIC in %s : target is not remote\n", __FUNCTION__ );
1132        hal_core_sleep();
1133    }
1134
1135    // initialise RPC descriptor header
1136    rpc_desc_t  rpc;
1137    rpc.index    = RPC_FATFS_GET_CLUSTER;
1138    rpc.response = 1;
1139
1140    // set input arguments in RPC descriptor
1141    rpc.args[0] = (uint64_t)(intptr_t)mapper;
1142    rpc.args[1] = (uint64_t)first;
1143    rpc.args[2] = (uint64_t)page;
1144
1145    // register RPC request in remote RPC fifo
1146    rpc_send_sync( cxy , &rpc );
1147
1148    // get output argument from rpc descriptor
1149    *cluster = (uint32_t)rpc.args[3];
1150    *error   = (error_t)rpc.args[4];
1151}
1152
1153//////////////////////////////////////////////
1154void rpc_fatfs_get_cluster_server( xptr_t xp )
1155{
1156    mapper_t    * mapper;
1157    uint32_t      first;
1158    uint32_t      page;
1159    uint32_t      cluster;
1160    error_t       error;
1161
1162    // get client cluster identifier and pointer on RPC descriptor
1163    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
1164    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
1165
1166    // get input arguments
1167    mapper = (mapper_t*)(intptr_t)hal_remote_lpt( XPTR( client_cxy , &desc->args[0] ) );
1168    first  = (uint32_t)           hal_remote_lw ( XPTR( client_cxy , &desc->args[1] ) );
1169    page   = (uint32_t)           hal_remote_lw ( XPTR( client_cxy , &desc->args[2] ) );
1170
1171    // call the kernel function
1172    error = fatfs_get_cluster( mapper , first , page , &cluster );
1173
1174    // set output argument
1175    hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)cluster );
1176    hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error );
1177}
1178
1179/***************************************************************************************/
1180/************ Generic functions supporting RPCs : client side **************************/
1181/***************************************************************************************/
1182
1183////////////////////////////////////////////
1184void rpc_send_sync( cxy_t        server_cxy, 
1185                    rpc_desc_t * rpc )
1186{
1187        thread_t * this = CURRENT_THREAD;
1188    uint32_t   cores;
1189    error_t    error;
1190    bool_t     first;
1191    reg_t      sr_save;
1192
1193    // get client CPU and cluster coordinates
1194    cxy_t      client_cxy = local_cxy;   
1195    lid_t      client_lid = CURRENT_CORE->lid;
1196
1197    // allocate and initialise an extended pointer on the RPC descriptor
1198        xptr_t   xp = XPTR( client_cxy , rpc );
1199
1200    // get local pointer on rpc_fifo in remote cluster with the
1201    // assumption that addresses are identical in all clusters
1202    rpc_fifo_t * rf = &LOCAL_CLUSTER->rpc_fifo;
1203
1204        // try to post an item in remote fifo
1205    // deschedule and retry if remote fifo full
1206    do
1207    { 
1208        error = remote_fifo_put_item( XPTR( server_cxy , &rf->fifo ),
1209                                      (void *)&xp,
1210                                      sizeof(xptr_t), 
1211                                      &first );
1212
1213            if ( error ) 
1214        {
1215            printk("\n[WARNING] %s : core %d in cluster %x cannot post RPC to cluster %x\n",
1216                   __FUNCTION__ , client_lid , client_cxy , server_cxy );
1217            if( thread_can_yield() ) sched_yield();
1218        }
1219    }
1220    while( error );
1221 
1222    rpc_dmsg("\n[INFO] %s on core %d in cluster %x sent RPC %p to cluster %x\n", 
1223              __FUNCTION__ , client_lid , client_cxy , rpc , server_cxy );
1224       
1225    // send IPI if this is the first RPC in remote FIFO
1226    // and no CPU is in kernel mode in server cluster.
1227    // the selected CPU in server has the same lid as the client CPU.
1228        if( first )
1229        {
1230        // get number of cores in kernel mode in server cluster
1231        cores = hal_remote_lw( XPTR( server_cxy , &LOCAL_CLUSTER->cores_in_kernel ) );
1232
1233                if( cores == 0 ) // no core in kernel mode in server
1234                {
1235                    dev_icu_send_ipi( server_cxy , client_lid );
1236
1237                    rpc_dmsg("\n[INFO] %s : core %d in cluster %x send IPI to core %d in cluster %x\n",
1238                      __FUNCTION__, client_lid , client_cxy , client_lid , server_cxy );
1239        }
1240        }
1241
1242        // activate preemption to allow incoming RPC and avoid deadlock
1243        if( this->type == THREAD_RPC ) hal_enable_irq( &sr_save );
1244
1245    // the sending thread poll the response slot until RPC completed
1246        while( 1 )
1247    {
1248        if( rpc->response == 0 ) break;
1249    }
1250
1251    // restore preemption
1252        if( this->type == THREAD_RPC ) hal_restore_irq( sr_save );
1253
1254}  // end rpc_send_sync()
1255
1256
1257
1258/***************************************************************************************/
1259/************ Generic functions supporting RPCs : server side **************************/
1260/***************************************************************************************/
1261
1262///////////////////////////////////////////
1263void rpc_fifo_init( rpc_fifo_t * rpc_fifo )
1264{
1265        rpc_fifo->count       = 0;
1266        rpc_fifo->owner       = 0;
1267        local_fifo_init( &rpc_fifo->fifo );
1268}
1269
1270////////////////////////////////////////////////
1271error_t rpc_execute_all( rpc_fifo_t * rpc_fifo )
1272{
1273        xptr_t         xp;             // extended pointer on RPC descriptor
1274        uint32_t       count;          // handled RPC request counter
1275        thread_t     * this;           // pointer on this RPC thread
1276    core_t       * core;           // pointer on core running this thread
1277    rpc_desc_t   * desc;           // pointer on RPC descriptor
1278    uint32_t       index;          // RPC index
1279    uint32_t       expected;       // number of expected responses
1280    cxy_t          client_cxy;     // client cluster identifier
1281        error_t        error;
1282     
1283        this = CURRENT_THREAD; 
1284    core = this->core;   
1285
1286
1287    // handle up to CONFIG_RPC_PENDING_MAX requests before exit
1288        count = 0;
1289        do
1290    {
1291            error = local_fifo_get_item( &rpc_fifo->fifo, 
1292                                     &xp,
1293                                     sizeof(xptr_t) );
1294
1295                if ( error == 0 )  // One RPC request successfully extracted from RPC_FIFO
1296        {
1297            rpc_dmsg("\n[INFO] %s : RPC_THREAD %x on core %x in cluster %x handles RPC %d\n"
1298                                     __FUNCTION__ , this->trdid , core->lid , local_cxy , count );
1299
1300            // get client cluster identifier and pointer on RPC descriptor
1301            client_cxy = (cxy_t)GET_CXY( xp );
1302            desc       = (rpc_desc_t *)GET_PTR( xp );
1303
1304            // get rpc index and expected responses from RPC descriptor
1305                index     = hal_remote_lw( XPTR( client_cxy , &desc->index ) );
1306                expected  = hal_remote_lw( XPTR( client_cxy , &desc->response ) );
1307
1308            // call the relevant server function
1309            rpc_server[index]( xp );
1310
1311            // increment handled RPC counter
1312                count++;
1313
1314            // notify RPC completion as required
1315            if( expected == 1 ) hal_remote_sw( XPTR(client_cxy,&desc->response) , 0 );
1316            if( expected >  1 ) hal_remote_atomic_add( XPTR(client_cxy,&desc->response) , -1 );
1317                }
1318       
1319                // exit loop in three cases:
1320        // - fifo is empty
1321        // - look has been released (because descheduling)
1322        // - max number of RPCs has been reached
1323                if( error || 
1324            (rpc_fifo->owner != this->trdid) || 
1325            (count > CONFIG_RPC_PENDING_MAX) ) break;
1326        }
1327    while( 1 )
1328
1329        rpc_dmsg("\n[INFO] %s running on core %d in cluster %x exit\n"
1330              __FUNCTION__ , CURRENT_CORE->lid , local_cxy );
1331               
1332    // update RPC_FIFO global counter
1333        rpc_fifo->count += count;
1334
1335        return 0;
1336}  // end rpc_execute_all()
1337
1338////////////////////////////////////////////////////
1339error_t rpc_activate_thread( rpc_fifo_t * rpc_fifo )
1340{
1341        core_t      * core;
1342        thread_t    * thread;
1343        thread_t    * this;
1344    scheduler_t * sched;
1345        error_t       error;
1346    bool_t        found;
1347    reg_t         sr_save;
1348
1349        this   = CURRENT_THREAD;
1350    core   = this->core;
1351    sched  = &core->scheduler;
1352    found  = false;
1353
1354    // calling thread must be the RPC_FIFO owner
1355    if( this->trdid != rpc_fifo->owner )
1356    {
1357        printk("\n[PANIC] in %s : calling thread is not RPC_FIFO owner\n", __FUNCTION__ );
1358        hal_core_sleep();
1359    }
1360
1361    // makes the calling thread not preemptable
1362    // during activation / creation of the RPC thread
1363        hal_disable_irq( &sr_save );
1364
1365    // search a free RPC thread (must be in THREAD_BLOCKED_IDLE state)   
1366    list_entry_t * iter;
1367    LIST_FOREACH( &sched->k_root , iter )
1368    {
1369        thread = LIST_ELEMENT( iter , thread_t , sched_list );
1370        if( (thread->type == THREAD_RPC) && (thread->blocked ==  THREAD_BLOCKED_IDLE ) ) 
1371        {
1372            found = true;
1373            break;
1374        }
1375    }
1376
1377    if( found )                    // activate this idle RPC thread     
1378    {
1379        thread->blocked = 0;
1380    }
1381    else                           // create a new RPC thread
1382    {
1383        error = thread_kernel_create( &thread,
1384                                      THREAD_RPC, 
1385                                                  &rpc_thread_func, 
1386                                      NULL,
1387                                                  core->lid );
1388            if( error ) 
1389        {
1390                hal_restore_irq( sr_save );
1391            printk("\n[ERROR] in %s : no memory for new RPC thread in cluster %x\n",
1392                   __FUNCTION__ , local_cxy );
1393            return ENOMEM;
1394        }
1395
1396        rpc_dmsg("\n[INFO] %s creates RPC thread %x on core %x in cluster %x at cycle %d\n", 
1397                          __FUNCTION__ , thread , core->gid , local_cxy , hal_time_stamp() );
1398
1399        // update core descriptor counter 
1400            core->rpc_threads++;
1401    }
1402
1403    // update owner in rpc_fifo
1404    rpc_fifo->owner = thread->trdid;
1405
1406    rpc_dmsg ("\n[INFO] %s activates RPC thread %x on core %x in cluster %x at cycle %d\n",
1407                      __FUNCTION__ , thread , core->gid , local_cxy , hal_time_stamp() );
1408
1409    // current thread deschedules / RPC thread start execution
1410        sched_switch_to( thread );
1411
1412    // restore IRQs for the calling thread
1413        hal_restore_irq( sr_save );
1414
1415    // return success
1416        return 0;
1417
1418}  // end rpc_activate_thread()
1419
1420//////////////////
1421bool_t rpc_check()
1422{
1423        thread_t   * this     = CURRENT_THREAD;
1424        rpc_fifo_t * rpc_fifo = &LOCAL_CLUSTER->rpc_fifo;
1425    error_t      error;
1426
1427    // do nothing if light lock already taken or FIFO empty 
1428        if( (rpc_fifo->owner != 0) || (local_fifo_is_empty( &rpc_fifo->fifo )) )
1429    {
1430        return false;
1431    }
1432
1433        // The calling thread try to take the light lock,
1434    // and activate an RPC thread if success
1435    if( hal_atomic_test_set( &rpc_fifo->owner , this->trdid ) )
1436        {
1437        error = rpc_activate_thread( rpc_fifo );
1438
1439        if( error )    // cannot activate an RPC_THREAD
1440        {
1441            rpc_fifo->owner = 0;
1442
1443            printk("\n[ERROR] in %s : no memory to create a RPC thread for core %d"
1444                   " in cluster %x => do nothing\n",
1445                   __FUNCTION__ , CURRENT_CORE->lid , local_cxy );
1446        }
1447
1448        return true;
1449    }
1450    else  // light lock taken by another thread
1451    {
1452        return false;
1453    }
1454} // end __rpc_check()
1455
1456
1457//////////////////////
1458void rpc_thread_func()
1459{
1460    // makes the calling thread not preemptable
1461        hal_disable_irq( NULL );
1462 
1463        thread_t   * this     = CURRENT_THREAD;
1464        rpc_fifo_t * rpc_fifo = &LOCAL_CLUSTER->rpc_fifo;
1465
1466    rpc_dmsg("\n[INFO] RPC thread %x created on core %d in cluster %x at cycle %d\n",
1467             this->trdid , this->core->lid , local_cxy , hal_time_stamp() );
1468
1469    // this infinite loop is not preemptable
1470    // the RPC thread deschedule when the RPC_FIFO is empty
1471        while(1)
1472        {
1473        // check fifo ownership (ownership should be given by rpc_activate()
1474        if( this->trdid != rpc_fifo->owner )
1475        {
1476            printk("\n[PANIC] in %s : RPC_THREAD %x not owner of RPC_FIFO in cluster %x\n",
1477                   __FUNCTION__ , this->trdid , local_cxy );
1478            hal_core_sleep();
1479        }
1480 
1481        // executes pending RPC(s)
1482        rpc_execute_all( rpc_fifo );
1483
1484        // release rpc_fifo ownership (can be lost during RPC execution)
1485        if( rpc_fifo->owner == this->trdid ) rpc_fifo->owner = 0;
1486
1487
1488        // suicide if too much RPC threads for this core
1489                if( this->core->rpc_threads > CONFIG_RPC_THREADS_MAX ) 
1490                {
1491            rpc_dmsg("\n[INFO] RPC thread %x suicide on core %d in cluster %x at cycle %d\n", 
1492                             this->trdid , this->core->lid , local_cxy , hal_time_stamp() );
1493
1494            // update core descriptor counter
1495                        this->core->rpc_threads--;
1496
1497            // suicide
1498                        thread_exit();
1499                }
1500
1501        // block and deschedule
1502        rpc_dmsg("\n[INFO] RPC thread %x deschedule on core %d in cluster %x at cycle %d\n", 
1503                              this->trdid , this->core->lid , local_cxy , hal_time_stamp() ); 
1504
1505                thread_block( this , THREAD_BLOCKED_IDLE );
1506        sched_yield();
1507
1508                rpc_dmsg("\n[INFO] RPC thread %x wake up on core %d in cluster %x at cycle %d\n", 
1509                              this->trdid , this->core->lid , local_cxy , hal_time_stamp() );
1510        }
1511} // end rpc_thread_func()
1512
Note: See TracBrowser for help on using the repository browser.