tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

RFC: New userspace fetch/store API



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



Home | Main Index | Thread Index | Old Index