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