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
00032 #define RTAI_SHM_MISC_MINOR 254 // The same minor used to mknod for major 10.
00033
00034 #include <linux/version.h>
00035 #include <linux/module.h>
00036 #include <linux/errno.h>
00037 #include <linux/fs.h>
00038 #include <linux/mm.h>
00039 #include <linux/miscdevice.h>
00040
00041 #include <rtai_trace.h>
00042 #include <rtai_schedcore.h>
00043 #include <rtai_registry.h>
00044 #include "rtai_shm.h"
00045
00046 MODULE_LICENSE("GPL");
00047
00048 #define ALIGN2PAGE(adr) ((void *)PAGE_ALIGN((unsigned long)adr))
00049 #define RT_SHM_OP_PERM() (!(_rt_whoami()->is_hard))
00050
00051 static int SUPRT[] = { 0, GFP_KERNEL, GFP_ATOMIC, GFP_DMA };
00052
00053 static inline void *_rt_shm_alloc(unsigned long name, int size, int suprt)
00054 {
00055 void *adr;
00056
00057
00058 if (!(adr = rt_get_adr_cnt(name)) && size > 0 && suprt >= 0 && RT_SHM_OP_PERM()) {
00059 size = ((size - 1) & PAGE_MASK) + PAGE_SIZE;
00060 if ((adr = suprt ? rkmalloc(&size, SUPRT[suprt]) : rvmalloc(size))) {
00061 if (!rt_register(name, adr, suprt ? -size : size, 0)) {
00062 if (suprt) {
00063 rkfree(adr, size);
00064 } else {
00065 rvfree(adr, size);
00066 }
00067 return 0;
00068 }
00069 memset(ALIGN2PAGE(adr), 0, size);
00070 }
00071 }
00072 return ALIGN2PAGE(adr);
00073 }
00074
00075 static inline int _rt_shm_free(unsigned long name, int size)
00076 {
00077 void *adr;
00078
00079 if (size && (adr = rt_get_adr(name))) {
00080 if (RT_SHM_OP_PERM()) {
00081 if (!rt_drg_on_name_cnt(name) && name != GLOBAL_HEAP_ID) {
00082 if (size < 0) {
00083 rkfree(adr, -size);
00084 } else {
00085 rvfree(adr, size);
00086 }
00087 }
00088 }
00089 return abs(size);
00090 }
00091 return 0;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 void *rt_shm_alloc(unsigned long name, int size, int suprt)
00131 {
00132 TRACE_RTAI_SHM(TRACE_RTAI_EV_SHM_KMALLOC, name, size, 0);
00133 return _rt_shm_alloc(name, size, suprt);
00134 }
00135
00136 static RTAI_SYSCALL_MODE int rt_shm_alloc_usp(unsigned long name, int size, int suprt)
00137 {
00138 TRACE_RTAI_SHM(TRACE_RTAI_EV_SHM_MALLOC, name, size, current->pid);
00139
00140 if (_rt_shm_alloc(name, size, suprt)) {
00141 current->rtai_tskext(TSKEXT1) = (void *)name;
00142 return abs(rt_get_type(name));
00143 }
00144 return 0;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 RTAI_SYSCALL_MODE int rt_shm_free(unsigned long name)
00168 {
00169 TRACE_RTAI_SHM(TRACE_RTAI_EV_SHM_KFREE, name, 0, 0);
00170 return _rt_shm_free(name, rt_get_type(name));
00171 }
00172
00173 static RTAI_SYSCALL_MODE int rt_shm_size(unsigned long *arg)
00174 {
00175 int size;
00176 struct vm_area_struct *vma;
00177
00178 size = abs(rt_get_type(*arg));
00179 for (vma = (current->mm)->mmap; vma; vma = vma->vm_next) {
00180 if (vma->vm_private_data == (void *)*arg && (vma->vm_end - vma->vm_start) == size) {
00181 *arg = vma->vm_start;
00182 return size;
00183 }
00184 }
00185 return 0;
00186 }
00187
00188 static void rtai_shm_vm_open(struct vm_area_struct *vma)
00189 {
00190 rt_get_adr_cnt((unsigned long)vma->vm_private_data);
00191 }
00192
00193 static void rtai_shm_vm_close(struct vm_area_struct *vma)
00194 {
00195 _rt_shm_free((unsigned long)vma->vm_private_data, rt_get_type((unsigned long)vma->vm_private_data));
00196 }
00197
00198 static struct vm_operations_struct rtai_shm_vm_ops = {
00199 open: rtai_shm_vm_open,
00200 close: rtai_shm_vm_close
00201 };
00202
00203 #ifdef CONFIG_RTAI_MALLOC
00204 static RTAI_SYSCALL_MODE void rt_set_heap(unsigned long, void *);
00205 #endif
00206
00207 static int rtai_shm_f_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
00208 {
00209 switch (cmd) {
00210 case SHM_ALLOC: {
00211 TRACE_RTAI_SHM(TRACE_RTAI_EV_SHM_MALLOC, ((unsigned long *)arg)[0], cmd, current->pid);
00212 return rt_shm_alloc_usp(((unsigned long *)arg)[0], ((long *)arg)[1], ((long *)arg)[2]);
00213 }
00214 case SHM_FREE: {
00215 TRACE_RTAI_SHM(TRACE_RTAI_EV_SHM_FREE, arg, cmd, current->pid);
00216 return _rt_shm_free(arg, rt_get_type(arg));
00217 }
00218 case SHM_SIZE: {
00219 TRACE_RTAI_SHM(TRACE_RTAI_EV_SHM_GET_SIZE, arg, cmd, current->pid);
00220 return rt_shm_size((unsigned long *)((unsigned long *)arg)[0]);
00221 }
00222 #ifdef CONFIG_RTAI_MALLOC
00223 case HEAP_SET: {
00224 rt_set_heap(((unsigned long *)arg)[0], (void *)((unsigned long *)arg)[1]);
00225 return 0;
00226 }
00227 #endif
00228 }
00229 return 0;
00230 }
00231
00232 static int rtai_shm_f_mmap(struct file *file, struct vm_area_struct *vma)
00233 {
00234 unsigned long name;
00235 int size;
00236 if (!vma->vm_ops) {
00237 vma->vm_ops = &rtai_shm_vm_ops;
00238 vma->vm_flags |= VM_LOCKED;
00239 name = (unsigned long)(vma->vm_private_data = current->rtai_tskext(TSKEXT1));
00240 current->rtai_tskext(TSKEXT1) = current->rtai_tskext(TSKEXT0) ? current : NULL;
00241 return (size = rt_get_type(name)) < 0 ? rkmmap(ALIGN2PAGE(rt_get_adr(name)), -size, vma) : rvmmap(rt_get_adr(name), size, vma);
00242 }
00243 return -EFAULT;
00244 }
00245
00246 static struct file_operations rtai_shm_fops = {
00247 ioctl: rtai_shm_f_ioctl,
00248 mmap: rtai_shm_f_mmap
00249 };
00250
00251 static struct miscdevice rtai_shm_dev =
00252 { RTAI_SHM_MISC_MINOR, "rtai_shm", &rtai_shm_fops };
00253
00254 #ifdef CONFIG_RTAI_MALLOC
00255
00256 static inline void *_rt_halloc(int size, struct rt_heap_t *heap)
00257 {
00258 void *mem_ptr = NULL;
00259
00260 if ((mem_ptr = rtheap_alloc(heap->heap, size, 0))) {
00261 mem_ptr = heap->uadr + (mem_ptr - heap->kadr);
00262 }
00263 return mem_ptr;
00264 }
00265
00266 static inline void _rt_hfree(void *addr, struct rt_heap_t *heap)
00267 {
00268 rtheap_free(heap->heap, heap->kadr + (addr - heap->uadr));
00269 }
00270
00271 #define GLOBAL 0
00272 #define SPECIFIC 1
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 void *rt_named_malloc(unsigned long name, int size)
00331 {
00332 void *mem_ptr;
00333
00334 if ((mem_ptr = rt_get_adr_cnt(name))) {
00335 return mem_ptr;
00336 }
00337 if ((mem_ptr = _rt_halloc(size, &rt_smp_linux_task->heap[GLOBAL]))) {
00338 if (rt_register(name, mem_ptr, IS_HPCK, 0)) {
00339 return mem_ptr;
00340 }
00341 rt_hfree(mem_ptr);
00342 }
00343 return NULL;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 void rt_named_free(void *adr)
00366 {
00367 unsigned long name;
00368
00369 name = rt_get_name(adr);
00370 if (!rt_drg_on_name_cnt(name)) {
00371 _rt_hfree(adr, &rt_smp_linux_task->heap[GLOBAL]);
00372 }
00373 }
00374
00375
00376
00377
00378
00379 #define RTAI_TASK(return_instr) \
00380 do { \
00381 if (!(task = _rt_whoami())->is_hard) { \
00382 if (!(task = current->rtai_tskext(TSKEXT0))) { \
00383 return_instr; \
00384 } \
00385 } \
00386 } while (0)
00387
00388 static inline void *rt_halloc_typed(int size, int htype)
00389 {
00390 RT_TASK *task;
00391
00392 RTAI_TASK(return NULL);
00393 return _rt_halloc(size, &task->heap[htype]);
00394 }
00395
00396 static inline void rt_hfree_typed(void *addr, int htype)
00397 {
00398 RT_TASK *task;
00399
00400 RTAI_TASK(return);
00401 _rt_hfree(addr, &task->heap[htype]);
00402 }
00403
00404 static inline void *rt_named_halloc_typed(unsigned long name, int size, int htype)
00405 {
00406 RT_TASK *task;
00407 void *mem_ptr;
00408
00409 RTAI_TASK(return NULL);
00410 if ((mem_ptr = rt_get_adr_cnt(name))) {
00411 return task->heap[htype].uadr + (mem_ptr - task->heap[htype].kadr);
00412 }
00413 if ((mem_ptr = _rt_halloc(size, &task->heap[htype]))) {
00414 if (rt_register(name, task->heap[htype].kadr + (mem_ptr - task->heap[htype].uadr), IS_HPCK, 0)) {
00415 return mem_ptr;
00416 }
00417 _rt_hfree(mem_ptr, &task->heap[htype]);
00418 }
00419 return NULL;
00420 }
00421
00422 static inline void rt_named_hfree_typed(void *adr, int htype)
00423 {
00424 RT_TASK *task;
00425 unsigned long name;
00426
00427 RTAI_TASK(return);
00428 name = rt_get_name(task->heap[htype].kadr + (adr - task->heap[htype].uadr));
00429 if (!rt_drg_on_name_cnt(name)) {
00430 _rt_hfree(adr, &task->heap[htype]);
00431 }
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 RTAI_SYSCALL_MODE void *rt_halloc(int size)
00455 {
00456 return rt_halloc_typed(size, SPECIFIC);
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 RTAI_SYSCALL_MODE void rt_hfree(void *adr)
00472 {
00473 rt_hfree_typed(adr, SPECIFIC);
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 RTAI_SYSCALL_MODE void *rt_named_halloc(unsigned long name, int size)
00508 {
00509 return rt_named_halloc_typed(name, size, SPECIFIC);
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 RTAI_SYSCALL_MODE void rt_named_hfree(void *adr)
00532 {
00533 rt_named_hfree_typed(adr, SPECIFIC);
00534 }
00535
00536 extern rtheap_t rtai_global_heap;
00537 extern void *rtai_global_heap_adr;
00538 extern int rtai_global_heap_size;
00539
00540 static RTAI_SYSCALL_MODE void *rt_malloc_usp(int size)
00541 {
00542 return rtai_global_heap_adr ? rt_halloc_typed(size, GLOBAL) : NULL;
00543 }
00544
00545 static RTAI_SYSCALL_MODE void rt_free_usp(void *adr)
00546 {
00547 if (rtai_global_heap_adr) {
00548 rt_hfree_typed(adr, GLOBAL);
00549 }
00550 }
00551
00552 static RTAI_SYSCALL_MODE void *rt_named_malloc_usp(unsigned long name, int size)
00553 {
00554 return rtai_global_heap_adr ? rt_named_halloc_typed(name, size, GLOBAL) : NULL;
00555 }
00556
00557 static RTAI_SYSCALL_MODE void rt_named_free_usp(void *adr)
00558 {
00559 if (rtai_global_heap_adr) {
00560 rt_named_hfree_typed(adr, GLOBAL);
00561 }
00562 }
00563
00564 static RTAI_SYSCALL_MODE void rt_set_heap(unsigned long name, void *adr)
00565 {
00566 void *heap, *hptr;
00567 int size;
00568 RT_TASK *task;
00569
00570 heap = rt_get_adr(name);
00571 hptr = ALIGN2PAGE(heap);
00572 size = ((abs(rt_get_type(name)) - sizeof(rtheap_t) - (hptr - heap)) & PAGE_MASK);
00573 heap = hptr + size;
00574 if (!atomic_cmpxchg((atomic_t *)hptr, 0, name)) {
00575 rtheap_init(heap, hptr, size, PAGE_SIZE, 0);
00576 }
00577 RTAI_TASK(return);
00578 if (name == GLOBAL_HEAP_ID) {
00579 task->heap[GLOBAL].heap = &rtai_global_heap;
00580 task->heap[GLOBAL].kadr = rtai_global_heap_adr;
00581 task->heap[GLOBAL].uadr = adr;
00582 } else {
00583 task->heap[SPECIFIC].heap = heap;
00584 task->heap[SPECIFIC].kadr = hptr;
00585 task->heap[SPECIFIC].uadr = adr;
00586 }
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 void *rt_heap_open(unsigned long name, int size, int suprt)
00625 {
00626 void *adr;
00627 if ((adr = rt_shm_alloc(name, ((size - 1) & PAGE_MASK) + PAGE_SIZE + sizeof(rtheap_t), suprt))) {
00628 rt_set_heap(name, adr);
00629 return adr;
00630 }
00631 return 0;
00632 }
00633
00634 #endif
00635
00636 struct rt_native_fun_entry rt_shm_entries[] = {
00637 { { 0, rt_shm_alloc_usp }, SHM_ALLOC },
00638 { { 0, rt_shm_free }, SHM_FREE },
00639 { { 0, rt_shm_size }, SHM_SIZE },
00640 #ifdef CONFIG_RTAI_MALLOC
00641 { { 0, rt_set_heap }, HEAP_SET},
00642 { { 0, rt_halloc }, HEAP_ALLOC },
00643 { { 0, rt_hfree }, HEAP_FREE },
00644 { { 0, rt_named_halloc }, HEAP_NAMED_ALLOC },
00645 { { 0, rt_named_hfree }, HEAP_NAMED_FREE },
00646 { { 0, rt_malloc_usp }, MALLOC },
00647 { { 0, rt_free_usp }, FREE },
00648 { { 0, rt_named_malloc_usp }, NAMED_MALLOC },
00649 { { 0, rt_named_free_usp }, NAMED_FREE },
00650 #endif
00651 { { 0, 0 }, 000 }
00652 };
00653
00654 extern int set_rt_fun_entries(struct rt_native_fun_entry *entry);
00655 extern void reset_rt_fun_entries(struct rt_native_fun_entry *entry);
00656
00657 #define USE_UDEV_CLASS 0
00658
00659 #if USE_UDEV_CLASS
00660 static class_t *shm_class = NULL;
00661 #endif
00662
00663 int __rtai_shm_init (void)
00664 {
00665 #if USE_UDEV_CLASS
00666 if ((shm_class = class_create(THIS_MODULE, "rtai_shm")) == NULL) {
00667 printk("RTAI-SHM: cannot create class.\n");
00668 return -EBUSY;
00669 }
00670 if (CLASS_DEVICE_CREATE(shm_class, MKDEV(MISC_MAJOR, RTAI_SHM_MISC_MINOR), NULL, "rtai_shm") == NULL) {
00671 printk("RTAI-SHM: cannot attach class.\n");
00672 class_destroy(shm_class);
00673 return -EBUSY;
00674 }
00675 #endif
00676
00677 if (misc_register(&rtai_shm_dev) < 0) {
00678 printk("***** UNABLE TO REGISTER THE SHARED MEMORY DEVICE (miscdev minor: %d) *****\n", RTAI_SHM_MISC_MINOR);
00679 return -EBUSY;
00680 }
00681 #ifdef CONFIG_RTAI_MALLOC
00682 #ifdef CONFIG_RTAI_MALLOC_VMALLOC
00683 rt_register(GLOBAL_HEAP_ID, rtai_global_heap_adr, rtai_global_heap_size, 0);
00684 rt_smp_linux_task->heap[GLOBAL].heap = &rtai_global_heap;
00685 rt_smp_linux_task->heap[GLOBAL].kadr =
00686 rt_smp_linux_task->heap[GLOBAL].uadr = rtai_global_heap_adr;
00687 #else
00688 printk("***** WARNING: GLOBAL HEAP NEITHER SHARABLE NOR USABLE FROM USER SPACE (use the vmalloc option for RTAI malloc) *****\n");
00689 #endif
00690 #endif
00691 return set_rt_fun_entries(rt_shm_entries);
00692 }
00693
00694 void __rtai_shm_exit (void)
00695 {
00696 extern int max_slots;
00697 int slot;
00698 struct rt_registry_entry entry;
00699
00700 #ifdef CONFIG_RTAI_MALLOC_VMALLOC
00701 rt_drg_on_name_cnt(GLOBAL_HEAP_ID);
00702 #endif
00703 for (slot = 1; slot <= max_slots; slot++) {
00704 if (rt_get_registry_slot(slot, &entry)) {
00705 if (abs(entry.type) >= PAGE_SIZE) {
00706 char name[8];
00707 while (_rt_shm_free(entry.name, entry.type));
00708 num2nam(entry.name, name);
00709 rt_printk("\nSHM_CLEANUP_MODULE releases: '%s':0x%lx:%lu (%d).\n", name, entry.name, entry.name, entry.type);
00710 }
00711 }
00712 }
00713 reset_rt_fun_entries(rt_shm_entries);
00714 misc_deregister(&rtai_shm_dev);
00715 #if USE_UDEV_CLASS
00716 class_device_destroy(shm_class, MKDEV(MISC_MAJOR, RTAI_SHM_MISC_MINOR));
00717 class_destroy(shm_class);
00718 #endif
00719 return;
00720 }
00721
00722
00723
00724 #ifndef CONFIG_RTAI_SHM_BUILTIN
00725 module_init(__rtai_shm_init);
00726 module_exit(__rtai_shm_exit);
00727 #endif
00728
00729 #ifdef CONFIG_KBUILD
00730 EXPORT_SYMBOL(rt_shm_alloc);
00731 EXPORT_SYMBOL(rt_shm_free);
00732 #ifdef CONFIG_RTAI_MALLOC
00733 EXPORT_SYMBOL(rt_named_malloc);
00734 EXPORT_SYMBOL(rt_named_free);
00735 EXPORT_SYMBOL(rt_halloc);
00736 EXPORT_SYMBOL(rt_hfree);
00737 EXPORT_SYMBOL(rt_named_halloc);
00738 EXPORT_SYMBOL(rt_named_hfree);
00739 EXPORT_SYMBOL(rt_heap_open);
00740 #endif
00741 #endif