[ create a new paste ] login | about

Link: http://codepad.org/i1Sv1qri    [ raw code | fork ]

Plain Text, pasted on Jun 13:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
/**
 * @ingroup shm
 * @file
 *
 * Interface of the @ref shm "RTAI SHM module".
 *
 * @author Paolo Mantegazza
 *
 * @note Copyright &copy; 1999-2004 Paolo Mantegazza <mantegazza@aero.polimi.it>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
ACKNOWLEDGMENTS:
- The suggestion and the code for mmapping at a user specified address is due to  Trevor Woolven (trevw@zentropix.com).
*/


#ifndef _RTAI_SHM_H
#define _RTAI_SHM_H

/** @addtogroup shm
 *@{*/

#define GLOBAL_HEAP_ID  0x9ac6d9e7  // nam2num("RTGLBH");

#define USE_VMALLOC     0
#define USE_GFP_KERNEL  1
#define USE_GFP_ATOMIC  2
#define USE_GFP_DMA     3

/**
 * Allocate a chunk of memory to be shared inter-intra kernel modules and 
 * Linux processes.
 *
 * @internal
 * 
 * rtai_kalloc is used to allocate shared memory from kernel space.
 * 
 * @param name is an unsigned long identifier;
 * 
 * @param size is the amount of required shared memory;
 * 
 * rtai_kmalloc is a legacy helper macro, the real job is carried out by a
 * call to rt_shm_alloc() with the same name, size and with vmalloc support.
 * This function should not be used in newly developed applications. See 
 * rt_shm_alloc for more details.
 *
 * @returns a valid address on succes, 0 on failure.
 *
 */

#define rtai_kmalloc(name, size) \
	rt_shm_alloc(name, size, USE_VMALLOC)  // legacy

/**
 * Free a chunk of shared memory being shared inter-intra kernel modules and 
 * Linux processes.
 *
 * rtai_kfree is used to free a shared memory chunk from kernel space.
 *
 * @param name is the unsigned long identifier used when the memory was
 * allocated;
 *
 * rtai_kfree is a legacy helper macro, the real job is carried out by a
 * call to rt_shm_free with the same name. This function should not be used 
 * in newly developed applications. See rt_shm_free for more details.
 *
 * @returns the size of the succesfully freed memory, 0 on failure.
 *
 */

#define rtai_kfree(name) \
	rt_shm_free(name)  // legacy

#if defined(__KERNEL__)

#include <linux/module.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>

#if 0
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#include <linux/wrapper.h>
#else /* >= 2.6.0 */
#include <linux/mm.h>
#define mem_map_reserve(p)   SetPageReserved(p)
#define mem_map_unreserve(p) ClearPageReserved(p)
#endif /* < 2.6.0 */
#endif

#define UVIRT_TO_KVA(adr)  uvirt_to_kva(pgd_offset_k(adr), (adr))

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
static inline int remap_page_range(struct vm_area_struct *vma, unsigned long uvaddr, unsigned long paddr, unsigned long size, pgprot_t prot)
{
	return remap_pfn_range(vma, uvaddr, paddr >> PAGE_SHIFT, size, prot);
}
#endif

#include <rtai.h>
//#include <asm/rtai_shm.h>

#include <rtai_malloc.h>

#ifndef CONFIG_MMU

static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
{
	return adr;
}

#else

static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
{
	if (!pgd_none(*pgd) && !pgd_bad(*pgd)) {
		pmd_t *pmd;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
		pmd = pmd_offset(pgd, adr);
#else /* >= 2.6.11 */
		pmd = pmd_offset(pud_offset(pgd, adr), adr);
#endif /* < 2.6.11 */
		if (!pmd_none(*pmd)) {
			pte_t *ptep, pte;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
			ptep = pte_offset(pmd, adr);
#else /* >= 2.6.0 */
			ptep = pte_offset_kernel(pmd, adr);
#endif /* < 2.6.0 */
			pte = *ptep;
			if (pte_present(pte)) {
				return (((unsigned long)page_address(pte_page(pte))) | (adr & (PAGE_SIZE - 1)));
			}
		}
	}
	return 0UL;
}

static inline unsigned long kvirt_to_pa(unsigned long adr)
{
	return virt_to_phys((void *)uvirt_to_kva(pgd_offset_k(adr), adr));
}

#endif

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

int __rtai_shm_init(void);

void __rtai_shm_exit(void);

void *rt_shm_alloc(unsigned long name,
		   int size,
		   int suprt);

#define rt_shm_alloc_adr(adr, name, size) \
	rt_shm_alloc(name, size, suprt)

RTAI_SYSCALL_MODE int rt_shm_free(unsigned long name);

void *rt_heap_open(unsigned long name,
		   int size,
		   int suprt);

#define rt_heap_open_adr(adr, name, size, suprt) \
	rt_heap_open(name, size, suprt)

RTAI_SYSCALL_MODE void *rt_halloc(int size);

RTAI_SYSCALL_MODE void rt_hfree(void *addr);

RTAI_SYSCALL_MODE void *rt_named_halloc(unsigned long name, int size);

RTAI_SYSCALL_MODE void rt_named_hfree(void *addr);

void *rt_named_malloc(unsigned long name,
		      int size);

void rt_named_free(void *addr);

void *rvmalloc(unsigned long size);

void rvfree(void *mem,
	    unsigned long size);

int rvmmap(void *mem,
	   unsigned long memsize,
	   struct vm_area_struct *vma);

void *rkmalloc(int *size,
	       int suprt);

void rkfree(void *mem,
	    unsigned long size);

int rkmmap(void *mem,
	   unsigned long memsize,
	   struct vm_area_struct *vma);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#else /* !__KERNEL__ */

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <rtai_lxrt.h>

//#define SHM_USE_LXRT

#define RTAI_SHM_DEV  "/dev/rtai_shm"

RTAI_PROTO (void *, _rt_shm_alloc, (void *start, unsigned long name, int size, int suprt, int isheap))
{
	int hook;
	void *adr = NULL;

	if ((hook = open(RTAI_SHM_DEV, O_RDWR)) <= 0) {
		return NULL;
	} else {
		struct { unsigned long name, arg, suprt; } arg = { name, size, suprt };
#ifdef SHM_USE_LXRT
		if ((size = rtai_lxrt(BIDX, SIZARG, SHM_ALLOC, &arg).i[LOW])) {
#else
		if ((size = ioctl(hook, SHM_ALLOC, (unsigned long)(&arg)))) {
#endif
			if ((adr = mmap(start, size, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_LOCKED, hook, 0)) == MAP_FAILED) {;
#ifdef SHM_USE_LXRT
				rtai_lxrt(BIDX, sizeof(name), SHM_FREE, &name);
#else
				ioctl(hook, SHM_FREE, &name);
#endif
			} else if (isheap) {
				arg.arg = (unsigned long)adr;
#ifdef SHM_USE_LXRT
				rtai_lxrt(BIDX, SIZARG, HEAP_SET, &arg);
#else
				ioctl(hook, HEAP_SET, &arg);
#endif
			}
		}
	}
	close(hook);
	return adr;
}

#define rt_shm_alloc(name, size, suprt)  \
	_rt_shm_alloc(0, name, size, suprt, 0)

#define rt_heap_open(name, size, suprt)  \
	_rt_shm_alloc(0, name, size, suprt, 1)

/**
 * Allocate a chunk of memory to be shared inter-intra kernel modules and 
 * Linux processes.
 *
 * @internal
 * 
 * rtai_malloc is used to allocate shared memory from user space.
 * 
 * @param name is an unsigned long identifier;
 * 
 * @param size is the amount of required shared memory;
 * 
 * rtai_malloc is a legacy helper macro, the real job is carried out by a
 * call to rt_shm_alloc() with the same name, size and with vmalloc support.
 * This function should not be used in newly developed applications. See
 * rt_shm_alloc fro more details.
 *
 * @returns a valid address on succes, on failure: 0 if it was unable to 
 * allocate any memory, MAP_FAILED if it was possible to allocate the
 * required memory but failed to mmap it to user space, in which case the
 * allocated memory is freed anyhow.
 *
 */

#define rtai_malloc(name, size)  \
	_rt_shm_alloc(0, name, size, USE_VMALLOC, 0)  // legacy

/**
 * Allocate a chunk of memory to be shared inter-intra kernel modules and Linux
 * processes.
 *
 * rt_shm_alloc_adr is used to allocate in user space.
 *
 * @param start_address is a user desired address where the allocated memory
 * should be mapped in user space;
 *
 * @param name is an unsigned long identifier;
 * 
 * @param size is the amount of required shared memory.
 *
 * @param suprt is the kernel allocation method to be used, it can be:
 * - USE_VMALLOC, use vmalloc;
 * - USE_GFP_KERNEL, use kmalloc with GFP_KERNEL;
 * - USE_GFP_ATOMIC, use kmalloc with GFP_ATOMIC;
 * - USE_GFP_DMA, use kmalloc with GFP_DMA.
 *
 * Since @c name can be a clumsy identifier, services are provided to
 * convert 6 characters identifiers to unsigned long, and vice versa.
 *
 * @see the functions nam2num() and num2nam().
 *
 * It must be remarked that only the very first call does a real allocation, 
 * any subsequent call to allocate with the same name from anywhere will just
 * increase the usage count and map the area to user space, or return the
 * related pointer to the already allocated space in kernel space. The function 
 * returns a pointer to the allocated memory, appropriately mapped to the memory
 * space in use. So if one is really sure that the named shared memory has been 
 * allocated already parameters size and suprt are not used and can be 
 * assigned any value.
 *
 * @note If the same process calls rtai_malloc_adr and rtai_malloc() twice in
 * the same process it get a zero return value on the second call.
 *
 * @returns a valid address on succes, on failure: 0 if it was unable to
 * allocate any memory, MAP_FAILED if it was possible to allocate the
 * required memory but failed to mmap it to user space, in which case the
 * allocated memory is freed anyhow.
 *
 */

#define rt_shm_alloc_adr(start_address, name, size, suprt)  \
	_rt_shm_alloc(start_address, name, size, suprt, 0)

#define rt_heap_open_adr(start, name, size, suprt)  \
	_rt_shm_alloc(start, name, size, suprt, 1)

/**
 * Allocate a chunk of memory to be shared inter-intra kernel modules and 
 * Linux processes.
 *
 * @internal
 * 
 * rtai_malloc_adr is used to allocate shared memory from user space.
 *
 * @param start_address is the adr were the shared memory should be mapped.
 * 
 * @param name is an unsigned long identifier;
 * 
 * @param size is the amount of required shared memory;
 * 
 * rtai_malloc_adr is a legacy helper macro, the real job is carried out by a
 * call to rt_shm_alloc_adr() with the same name, size and with vmalloc support.
 * This function should not be used in newly developed applications. See
 * rt_shm_alloc_adr for more details.
 *
 * @returns a valid address on succes, 0 on failure.
 *
 */

#define rtai_malloc_adr(start_address, name, size)  \
	_rt_shm_alloc(start_address, name, size, USE_VMALLOC, 0)  // legacy

RTAI_PROTO(int, rt_shm_free, (unsigned long name))
{
	int hook, size;
	struct { void *nameadr; } arg = { &name };
	if ((hook = open(RTAI_SHM_DEV, O_RDWR)) <= 0) {
		return 0;
	}
// no SHM_FREE needed, we release it all and munmap will do it through 
// the vma close operation provided by shm.c
#ifdef SHM_USE_LXRT
	if ((size = rtai_lxrt(BIDX, SIZARG, SHM_SIZE, &arg).i[LOW])) {
#else
	if ((size = ioctl(hook, SHM_SIZE, (unsigned long)&arg))) {
#endif
		if (munmap((void *)name, size)) {
			size = 0;
		}
	}
	close(hook);
	return size;
}

/**
 * Free a chunk of shared memory being shared inter-intra 
 * kernel modules and Linux processes.
 *
 * rtai_free is used to free a shared memory chunk from user space.
 *
 * @param name is the unsigned long identifier used when the memory was
 * allocated;
 *
 * @param adr is not used.
 *
 * rtai_free is a legacy helper macro, the real job is carried out by a
 * call to rt_shm_free with the same name. This function should not be used 
 * in newly developed applications. See rt_shm_alloc_adr for more details.
 *
 * @returns the size of the succesfully freed memory, 0 on failure.
 *
 */

#define rtai_free(name, adr)  \
	rt_shm_free(name)  // legacy

RTAI_PROTO(void *, rt_halloc, (int size))
{
	struct { long size; } arg = { size };
	return rtai_lxrt(BIDX, SIZARG, HEAP_ALLOC, &arg).v[LOW];
}

RTAI_PROTO(void, rt_hfree, (void *addr))
{
	struct { void *addr; } arg = { addr };
	rtai_lxrt(BIDX, SIZARG, HEAP_FREE, &arg);
}

RTAI_PROTO(void *, rt_named_halloc, (unsigned long name, int size))
{
	struct { unsigned long name; long size; } arg = { name, size };
	return rtai_lxrt(BIDX, SIZARG, HEAP_NAMED_ALLOC, &arg).v[LOW];
}

RTAI_PROTO(void, rt_named_hfree, (void *addr))
{
	struct { void *addr; } arg = { addr };
	rtai_lxrt(BIDX, SIZARG, HEAP_NAMED_FREE, &arg);
}

RTAI_PROTO(void *, rt_malloc, (int size))
{
	struct { long size; } arg = { size };
	return rtai_lxrt(BIDX, SIZARG, MALLOC, &arg).v[LOW];
}

RTAI_PROTO(void, rt_free, (void *addr))
{
	struct { void *addr; } arg = { addr };
	rtai_lxrt(BIDX, SIZARG, FREE, &arg);
}

RTAI_PROTO(void *, rt_named_malloc, (unsigned long name, int size))
{
	struct { unsigned long name; long size; } arg = { name, size };
	return rtai_lxrt(BIDX, SIZARG, NAMED_MALLOC, &arg).v[LOW];
}

RTAI_PROTO(void, rt_named_free, (void *addr))
{
	struct { void *addr; } arg = { addr };
	rtai_lxrt(BIDX, SIZARG, NAMED_FREE, &arg);
}

#endif /* __KERNEL__ */

/**
 * Close a real time group heap being shared inter-intra kernel modules and
 * Linux processes.
 *
 * @internal
 * 
 * rt_heap_close is used to close a previously opened real time group heap.
 *
 * @param name is the unsigned long identifier used to identify the heap.
 *
 * @param adr is not used.
 *
 * Analogously to what done by any allocation function this group real time
 * heap closing call have just the effect of decrementing a usage count, 
 * unmapping any user space heap being closed, till the last is done, as that 
 * is the one the really closes the group heap, freeing any allocated memory.
 *
 * @returns the size of the succesfully freed heap, 0 on failure.
 *
 */

#define rt_heap_close(name, adr)  rt_shm_free(name)

// aliases in use already, different heads different choices
#define rt_heap_init         rt_heap_open
#define rt_heap_create       rt_heap_open
#define rt_heap_acquire      rt_heap_open
#define rt_heap_init_adr     rt_heap_open_adr
#define rt_heap_create_adr   rt_heap_open_adr
#define rt_heap_acquire_adr  rt_heap_open_adr

#define rt_heap_delete       rt_heap_close
#define rt_heap_destroy      rt_heap_close
#define rt_heap_release      rt_heap_close

// these have no aliases, and never will

/**
 * Open the global real time heap to be shared inter-intra kernel modules and 
 * Linux processes.
 *
 * @internal
 * 
 * rt_global_heap_open is used to open the global real time heap.
 * 
 * The global heap is created by the shared memory module and its opening is
 * needed in user space to map it to the process address space. In kernel
 * space opening the global heap in a task is not required but should be done
 * anyhow, both for symmetry and to register its usage.
 *
 */

#define rt_global_heap_open()  rt_heap_open(GLOBAL_HEAP_ID, 0, 0)

/**
 * Close the global real time heap being shared inter-intra kernel modules and 
 * Linux processes.
 *
 * @internal
 * 
 * rt_global_heap_close is used to close the global real time heap.
 * 
 * Closing a global heap in user space has just the effect of deregistering
 * its use and unmapping the related memory from a process address space.
 * In kernel tasks just the deregistration is performed.
 * The global real time heap is destroyed just a the rmmoding of the shared
 * memory module.
 *
 */

#define rt_global_heap_close()  rt_heap_close(GLOBAL_HEAP_ID, 0)

/*@}*/

#endif /* !_RTAI_SHM_H */



Create a new paste based on this one


Comments: