Xenomai  3.0.8
Buffer descriptor

Abstraction for copying data to/from different address spaces. More...

Collaboration diagram for Buffer descriptor:

Functions

static void xnbufd_map_uread (struct xnbufd *bufd, const void __user *ptr, size_t len)
 Initialize a buffer descriptor for reading from user memory. More...
 
static void xnbufd_map_uwrite (struct xnbufd *bufd, void __user *ptr, size_t len)
 Initialize a buffer descriptor for writing to user memory. More...
 
ssize_t xnbufd_unmap_uread (struct xnbufd *bufd)
 Finalize a buffer descriptor obtained from xnbufd_map_uread(). More...
 
ssize_t xnbufd_unmap_uwrite (struct xnbufd *bufd)
 Finalize a buffer descriptor obtained from xnbufd_map_uwrite(). More...
 
static void xnbufd_map_kread (struct xnbufd *bufd, const void *ptr, size_t len)
 Initialize a buffer descriptor for reading from kernel memory. More...
 
static void xnbufd_map_kwrite (struct xnbufd *bufd, void *ptr, size_t len)
 Initialize a buffer descriptor for writing to kernel memory. More...
 
ssize_t xnbufd_unmap_kread (struct xnbufd *bufd)
 Finalize a buffer descriptor obtained from xnbufd_map_kread(). More...
 
ssize_t xnbufd_unmap_kwrite (struct xnbufd *bufd)
 Finalize a buffer descriptor obtained from xnbufd_map_kwrite(). More...
 
ssize_t xnbufd_copy_to_kmem (void *ptr, struct xnbufd *bufd, size_t len)
 Copy memory covered by a buffer descriptor to kernel memory. More...
 
ssize_t xnbufd_copy_from_kmem (struct xnbufd *bufd, void *from, size_t len)
 Copy kernel memory to the area covered by a buffer descriptor. More...
 
void xnbufd_invalidate (struct xnbufd *bufd)
 Invalidate a buffer descriptor. More...
 
static void xnbufd_reset (struct xnbufd *bufd)
 Reset a buffer descriptor. More...
 

Detailed Description

Abstraction for copying data to/from different address spaces.

A buffer descriptor is a simple abstraction dealing with copy operations to/from memory buffers which may belong to different address spaces.

To this end, the buffer descriptor library provides a small set of copy routines which are aware of address space restrictions when moving data, and a generic container type which can hold a reference to - or cover - a particular memory area, either present in kernel space, or in any of the existing user memory contexts.

The goal of the buffer descriptor abstraction is to hide address space specifics from Xenomai services dealing with memory areas, allowing them to operate on multiple address spaces seamlessly.

The common usage patterns are as follows:

[Syscall implementation]
ssize_t rt_bulk_read_inner(struct xnbufd *bufd)
{
ssize_t ret;
size_t len;
void *bulk;
bulk = get_next_readable_bulk(&len);
ret = xnbufd_copy_from_kmem(bufd, bulk, min(bufd->b_len, len));
free_bulk(bulk);
ret = this_may_fail();
if (ret)
return ret;
}
[Kernel wrapper for in-kernel calls]
int rt_bulk_read(void *ptr, size_t len)
{
struct xnbufd bufd;
ssize_t ret;
xnbufd_map_kwrite(&bufd, ptr, len);
ret = rt_bulk_read_inner(&bufd);
return ret;
}
[Userland trampoline for user syscalls]
int __rt_bulk_read(struct pt_regs *regs)
{
struct xnbufd bufd;
void __user *ptr;
ssize_t ret;
size_t len;
ptr = (void __user *)__xn_reg_arg1(regs);
len = __xn_reg_arg2(regs);
xnbufd_map_uwrite(&bufd, ptr, len);
ret = rt_bulk_read_inner(&bufd);
return ret;
}
[Syscall implementation]
ssize_t rt_bulk_write_inner(struct xnbufd *bufd)
{
void *bulk = get_free_bulk(bufd->b_len);
return xnbufd_copy_to_kmem(bulk, bufd, bufd->b_len);
}
[Kernel wrapper for in-kernel calls]
int rt_bulk_write(const void *ptr, size_t len)
{
struct xnbufd bufd;
ssize_t ret;
xnbufd_map_kread(&bufd, ptr, len);
ret = rt_bulk_write_inner(&bufd);
return ret;
}
[Userland trampoline for user syscalls]
int __rt_bulk_write(struct pt_regs *regs)
{
struct xnbufd bufd;
void __user *ptr;
ssize_t ret;
size_t len;
ptr = (void __user *)__xn_reg_arg1(regs);
len = __xn_reg_arg2(regs);
xnbufd_map_uread(&bufd, ptr, len);
ret = rt_bulk_write_inner(&bufd);
return ret;
}

Function Documentation

◆ xnbufd_copy_from_kmem()

ssize_t xnbufd_copy_from_kmem ( struct xnbufd *  bufd,
void *  from,
size_t  len 
)

Copy kernel memory to the area covered by a buffer descriptor.

This routine copies len bytes from the kernel memory starting at from to the area referred to by the buffer descriptor bufd. xnbufd_copy_from_kmem() tracks the write offset within the destination memory internally, so that it may be called several times in a loop, until the entire memory area is stored.

The destination address space is dealt with, according to the following rules:

  • if bufd refers to a writable kernel area (i.e. see xnbufd_map_kwrite()), the copy is immediatly and fully performed with no restriction.
  • if bufd refers to a writable user area (i.e. see xnbufd_map_uwrite()), the copy is performed only if that area lives in the currently active address space, and only if the caller may sleep Linux-wise to process any potential page fault which may arise while writing to that memory.
  • if bufd refers to a user area which may not be immediately written to from the current context, the copy is postponed until xnbufd_unmap_uwrite() is invoked for ubufd, at which point the copy will take place. In such a case, the source memory is transferred to a carry over buffer allocated internally; this operation may lead to request dynamic memory from the nucleus heap if len is greater than 64 bytes.
Parameters
bufdThe address of the buffer descriptor covering the user memory to copy data to.
fromThe start address of the kernel memory to copy from.
lenThe length of the kernel memory to copy to bufd.
Returns
The number of bytes written so far to the memory area covered by ubufd. Otherwise,
  • -ENOMEM is returned when no memory is available from the nucleus heap to allocate the carry over buffer.
Tags cobalt-core-tags "unrestricted"
Note
Calling this routine while holding the nklock and/or running with interrupts disabled is invalid, and doing so will trigger a debug assertion.

This routine may switch the caller to secondary mode if a page fault occurs while reading from the user area. For that reason, xnbufd_copy_to_kmem() may only be called from a preemptible section (Linux-wise).

◆ xnbufd_copy_to_kmem()

ssize_t xnbufd_copy_to_kmem ( void *  to,
struct xnbufd *  bufd,
size_t  len 
)

Copy memory covered by a buffer descriptor to kernel memory.

This routine copies len bytes from the area referred to by the buffer descriptor bufd to the kernel memory area to. xnbufd_copy_to_kmem() tracks the read offset within the source memory internally, so that it may be called several times in a loop, until the entire memory area is loaded.

The source address space is dealt with, according to the following rules:

  • if bufd refers to readable kernel area (i.e. see xnbufd_map_kread()), the copy is immediately and fully performed with no restriction.
  • if bufd refers to a readable user area (i.e. see xnbufd_map_uread()), the copy is performed only if that area lives in the currently active address space, and only if the caller may sleep Linux-wise to process any potential page fault which may arise while reading from that memory.
  • any attempt to read from bufd from a non-suitable context is considered as a bug, and will raise a panic assertion when the nucleus is compiled in debug mode.
Parameters
toThe start address of the kernel memory to copy to.
bufdThe address of the buffer descriptor covering the user memory to copy data from.
lenThe length of the user memory to copy from bufd.
Returns
The number of bytes read so far from the memory area covered by ubufd. Otherwise:
  • -EINVAL is returned upon attempt to read from the user area from an invalid context. This error is only returned when the debug mode is disabled; otherwise a panic assertion is raised.
Tags cobalt-core-tags "task-unrestricted"
Note
Calling this routine while holding the nklock and/or running with interrupts disabled is invalid, and doing so will trigger a debug assertion.

This routine may switch the caller to secondary mode if a page fault occurs while reading from the user area. For that reason, xnbufd_copy_to_kmem() may only be called from a preemptible section (Linux-wise).

◆ xnbufd_invalidate()

void xnbufd_invalidate ( struct xnbufd *  bufd)

Invalidate a buffer descriptor.

The buffer descriptor is invalidated, making it unusable for further copy operations. If an outstanding carry over buffer was allocated by a previous call to xnbufd_copy_from_kmem(), it is immediately freed so that no data transfer will happen when the descriptor is finalized.

The only action that may subsequently be performed on an invalidated descriptor is calling the relevant unmapping routine for it. For that reason, xnbufd_invalidate() should be invoked on the error path when data may have been transferred to the carry over buffer.

Parameters
bufdThe address of the buffer descriptor to invalidate.
Tags cobalt-core-tags "unrestricted"

◆ xnbufd_map_kread()

void xnbufd_map_kread ( struct xnbufd *  bufd,
const void *  ptr,
size_t  len 
)
inlinestatic

Initialize a buffer descriptor for reading from kernel memory.

The new buffer descriptor may be used to copy data from kernel memory. This routine should be used in pair with xnbufd_unmap_kread().

Parameters
bufdThe address of the buffer descriptor which will map a len bytes kernel memory area, starting from ptr.
ptrThe start of the kernel buffer to map.
lenThe length of the kernel buffer starting at ptr.
Tags cobalt-core-tags "unrestricted"

◆ xnbufd_map_kwrite()

void xnbufd_map_kwrite ( struct xnbufd *  bufd,
void *  ptr,
size_t  len 
)
inlinestatic

Initialize a buffer descriptor for writing to kernel memory.

The new buffer descriptor may be used to copy data to kernel memory. This routine should be used in pair with xnbufd_unmap_kwrite().

Parameters
bufdThe address of the buffer descriptor which will map a len bytes kernel memory area, starting from ptr.
ptrThe start of the kernel buffer to map.
lenThe length of the kernel buffer starting at ptr.
Tags cobalt-core-tags "unrestricted"

◆ xnbufd_map_uread()

void xnbufd_map_uread ( struct xnbufd *  bufd,
const void __user *  ptr,
size_t  len 
)
inlinestatic

Initialize a buffer descriptor for reading from user memory.

The new buffer descriptor may be used to copy data from user memory. This routine should be used in pair with xnbufd_unmap_uread().

Parameters
bufdThe address of the buffer descriptor which will map a len bytes user memory area, starting from ptr. ptr is never dereferenced directly, since it may refer to a buffer that lives in another address space.
ptrThe start of the user buffer to map.
lenThe length of the user buffer starting at ptr.
Tags cobalt-core-tags "task-unrestricted"

◆ xnbufd_map_uwrite()

void xnbufd_map_uwrite ( struct xnbufd *  bufd,
void __user *  ptr,
size_t  len 
)
inlinestatic

Initialize a buffer descriptor for writing to user memory.

The new buffer descriptor may be used to copy data to user memory. This routine should be used in pair with xnbufd_unmap_uwrite().

Parameters
bufdThe address of the buffer descriptor which will map a len bytes user memory area, starting from ptr. ptr is never dereferenced directly, since it may refer to a buffer that lives in another address space.
ptrThe start of the user buffer to map.
lenThe length of the user buffer starting at ptr.
Tags cobalt-core-tags "task-unrestricted"

◆ xnbufd_reset()

void xnbufd_reset ( struct xnbufd *  bufd)
inlinestatic

Reset a buffer descriptor.

The buffer descriptor is reset, so that all data already copied is forgotten. Any carry over buffer allocated is kept, though.

Parameters
bufdThe address of the buffer descriptor to reset.
Tags cobalt-core-tags "unrestricted"

◆ xnbufd_unmap_kread()

ssize_t xnbufd_unmap_kread ( struct xnbufd *  bufd)

Finalize a buffer descriptor obtained from xnbufd_map_kread().

This routine finalizes a buffer descriptor previously initialized by a call to xnbufd_map_kread(), to read data from a kernel area.

Parameters
bufdThe address of the buffer descriptor to finalize.
Returns
The number of bytes read so far from the memory area covered by ubufd.
Tags cobalt-core-tags "task-unrestricted"

◆ xnbufd_unmap_kwrite()

ssize_t xnbufd_unmap_kwrite ( struct xnbufd *  bufd)

Finalize a buffer descriptor obtained from xnbufd_map_kwrite().

This routine finalizes a buffer descriptor previously initialized by a call to xnbufd_map_kwrite(), to write data to a kernel area.

Parameters
bufdThe address of the buffer descriptor to finalize.
Returns
The number of bytes written so far to the memory area covered by ubufd.
Tags cobalt-core-tags "task-unrestricted"

◆ xnbufd_unmap_uread()

ssize_t xnbufd_unmap_uread ( struct xnbufd *  bufd)

Finalize a buffer descriptor obtained from xnbufd_map_uread().

This routine finalizes a buffer descriptor previously initialized by a call to xnbufd_map_uread(), to read data from a user area.

Parameters
bufdThe address of the buffer descriptor to finalize.
Returns
The number of bytes read so far from the memory area covered by ubufd.
Tags cobalt-core-tags "task-unrestricted"
Note
Calling this routine while holding the nklock and/or running with interrupts disabled is invalid, and doing so will trigger a debug assertion.

◆ xnbufd_unmap_uwrite()

ssize_t xnbufd_unmap_uwrite ( struct xnbufd *  bufd)

Finalize a buffer descriptor obtained from xnbufd_map_uwrite().

This routine finalizes a buffer descriptor previously initialized by a call to xnbufd_map_uwrite(), to write data to a user area.

The main action taken is to write the contents of the kernel memory area passed to xnbufd_copy_from_kmem() whenever the copy operation was postponed at that time; the carry over buffer is eventually released as needed. If xnbufd_copy_from_kmem() was allowed to copy to the destination user memory at once, then xnbufd_unmap_uwrite() leads to a no-op.

Parameters
bufdThe address of the buffer descriptor to finalize.
Returns
The number of bytes written so far to the memory area covered by ubufd.
Tags cobalt-core-tags "task-unrestricted"
Note
Calling this routine while holding the nklock and/or running with interrupts disabled is invalid, and doing so will trigger a debug assertion.