diff --git a/kernel-src/include/kernel/usercopy.h b/kernel-src/include/kernel/usercopy.h index 290bae4c..aeb25ab4 100644 --- a/kernel-src/include/kernel/usercopy.h +++ b/kernel-src/include/kernel/usercopy.h @@ -17,13 +17,20 @@ static inline int _usercopy_strlen_wrapper(void *str, size_t *size) { return 0; } +static inline int _usercopy_memset_wrapper(void *dst, uint8_t byte, size_t size) { + memset(dst, byte, size); + return 0; +} + #define USERCOPY_POSSIBLY_FROM_USER(kernel, user, size) (IS_USER_ADDRESS(user) ? usercopy_fromuser(kernel, user, size) : _usercopy_memcpy_wrapper(kernel, user, size)) #define USERCOPY_POSSIBLY_TO_USER(user, kernel, size) (IS_USER_ADDRESS(user) ? usercopy_touser(user, kernel, size) : _usercopy_memcpy_wrapper(user, kernel, size)) #define USERCOPY_POSSIBLY_STRLEN_FROM_USER(user, sizep) (IS_USER_ADDRESS(user) ? usercopy_strlen(user, sizep) : _usercopy_strlen_wrapper(user, sizep)) +#define USERCOPY_POSSIBLY_MEMSET_TO_USER(user, byte, size) (IS_USER_ADDRESS(user) ? usercopy_memset(user, byte, size) : _usercopy_memset_wrapper(user, byte, size)) int usercopy_touser(void *user, void *kernel, size_t size); int usercopy_fromuser(void *kernel, void *user, size_t size); int usercopy_fromuseratomic32(uint32_t *user32, uint32_t *value); int usercopy_strlen(const char *, size_t *size); +int usercopy_memset(void *user, uint8_t byte, size_t size); #endif diff --git a/kernel-src/mm/usercopy.c b/kernel-src/mm/usercopy.c index 13e2d540..e65a9cf7 100644 --- a/kernel-src/mm/usercopy.c +++ b/kernel-src/mm/usercopy.c @@ -18,6 +18,12 @@ typedef struct { uint32_t *address; } atomic32desc_t; +typedef struct { + void *dst; + uint8_t byte; + size_t size; +} memsetdesc_t; + static void memcpyinternal(context_t *ctx, void *arg) { memcpydesc_t *desc = arg; @@ -60,6 +66,20 @@ static void atomic32internal(context_t *ctx, void *arg) { current_thread()->usercopyctx = NULL; } +static void memset_internal(context_t *ctx, void *arg) { + memsetdesc_t *desc = arg; + + // this sets up the thread so that in the next invalid page fault, it will jump to + // this context with CTX_RET set to EFAULT + current_thread()->usercopyctx = ctx; + + memset(desc->dst, desc->byte, desc->size); + + // no errors! + CTX_RET(ctx) = 0; + current_thread()->usercopyctx = NULL; +} + int usercopy_touser(void *user, void *kernel, size_t size) { memcpydesc_t desc = { .dst = user, @@ -109,3 +129,16 @@ int usercopy_fromuseratomic32(uint32_t *user32, uint32_t *value) { return arch_context_saveandcall(atomic32internal, NULL, &desc); } + +int usercopy_memset(void *user, uint8_t byte, size_t size) { + memsetdesc_t desc = { + .dst = user, + .byte = byte, + .size = size + }; + + if (IS_USER_ADDRESS(user) == false) + return EFAULT; + + return arch_context_saveandcall(memset_internal, NULL, &desc); +}