The existing fetch(9) / store(9) APIs have some problems.  Specifically:

==> Their return semantics mean that fuword() cannot disambiguate between an 
error condition (-1) and a legitimate fetch of -1 from user space.

==> “word” is poorly defined.  For all practical purposes, it means “long”, and 
there is thus no way to fetch/store an “int” value on LP64 platforms.

==> There are lots of legacy aliases lying about that are no longer meaningful 
(I-space and D-space variants, for example).

A project I’m working on has a need for a proper “int” size fetch / store on 
all platforms, and it seems best to just tidy the whole mess up.  So, I am 
proposing a new replacement user fetch/store API.

I have implemented the new API for alpha and amd64, and am putting together a 
test harness to exercise all aspects of the new API.  Once that is done, I’ll 
tackle the remaining architectures.

Outstanding question before I go too far down the rabbit hole: should I bother 
with the “intrsafe” variants?  The only application for it in the tree right 
now is in the profiling code, as an optimization to avoid taking an AST when 
it’s time to bump the counters.

Feedback appreciated.

=====

This API provides support for fetching and storing single cells of memory 
from/to user space addresses in 8-bit, 16-bit, 32-bit, and 64-bit (_LP64 
platforms only) widths.  The functions return 0 on success and an errno 
(usually EFAULT) if the address is not mapped, is not a user-space address, or 
is otherwise invalid.

These functions may block (to service a page fault), and are NOT safe to call 
from any interrupt context.

The implementation is entirely in architecture-dependent code.  The following 
fetch primitives must be supplied:

int     ufetch_8(const uint8_t *uaddr, uint8_t *valp);
int     ufetch_16(const uint16_t *uaddr, uint16_t *valp);
int     ufetch_32(const uint32_t *uaddr, uint32_t *valp);
#ifdef _LP64
int     ufetch_64(const uint64_t *uaddr, uint64_t *valp);
#endif

The following aliases must also be provided, mapped to the appropriate 
fixed-size primitives:

int     ufetch_char(const unsigned char *uaddr, unsigned char *valp);
int     ufetch_short(const unsigned short *uaddr, unsigned short *valp);
int     ufetch_int(const unsigned int *uaddr, unsigned int *valp);
int     ufetch_long(const unsigned long *uaddr, unsigned long *valp);
int     ufetch_ptr(const void **uaddr, void **valp);

The following store primitives must be suppled:

int     ustore_8(uint8_t *uaddr, uint8_t val);
int     ustore_16(uint16_t *uaddr, uint16_t val);
int     ustore_32(uint32_t *uaddr, uint32_t val);
#ifdef _LP64
int     ustore_64(uint64_t *uaddr, uint64_t val);
#endif

The following aliases must also be provided, mapped to the appropriate 
fixed-size primitives:

int     ustore_char(unsigned char *uaddr, unsigned char val);
int     ustore_short(unsigned short *uaddr, unsigned short val);
int     ustore_int(unsigned int *uaddr, unsigned int val);
int     ustore_long(unsigned long *uaddr, unsigned long val);
int     ustore_ptr(void **uaddr, void *val);

If __HAVE_INTRSAFE_USER_FETCH_STORE is defined by the architecture’s 
<machine/types.h> header, then "intrsafe" variants of each call are also 
provided, e.g.:

int     ustore_short_intrsafe(unsigned short *uaddr, unsigned short val);

These functions are equivalent to their non-intrsafe counterparts, except that 
they will NOT block; they will immediately return an error if a page fault 
occurs.

=====

-- thorpej

Reply via email to