1/* $NetBSD: ufetchstore_tester.c,v 1.1 2019/04/15 23:41:23 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/types.h> 33#include <sys/module.h> 34#include <sys/sysctl.h> 35#include <sys/systm.h> 36 37#include "common.h" 38 39static struct tester_ctx { 40 struct sysctllog *ctx_sysctllog; 41} tester_ctx; 42 43static int 44test_ufetch(void * const uaddr, struct ufetchstore_test_args * const args) 45{ 46 int error = 0; 47 48 switch (args->size) { 49 case 8: 50 args->fetchstore_error = ufetch_8(uaddr, &args->val8); 51 break; 52 case 16: 53 args->fetchstore_error = ufetch_16(uaddr, &args->val16); 54 break; 55 case 32: 56 args->fetchstore_error = ufetch_32(uaddr, &args->val32); 57 break; 58#ifdef _LP64 59 case 64: 60 args->fetchstore_error = ufetch_64(uaddr, &args->val64); 61 break; 62#endif /* _LP64 */ 63 default: 64 error = EINVAL; 65 } 66 67 return error; 68} 69 70static int 71test_ustore(void * const uaddr, struct ufetchstore_test_args * const args) 72{ 73 int error = 0; 74 75 switch (args->size) { 76 case 8: 77 args->fetchstore_error = ustore_8(uaddr, args->val8); 78 break; 79 case 16: 80 args->fetchstore_error = ustore_16(uaddr, args->val16); 81 break; 82 case 32: 83 args->fetchstore_error = ustore_32(uaddr, args->val32); 84 break; 85#ifdef _LP64 86 case 64: 87 args->fetchstore_error = ustore_64(uaddr, args->val64); 88 break; 89#endif /* _LP64 */ 90 default: 91 error = EINVAL; 92 } 93 94 return error; 95} 96 97static int 98test_ucas(void * const uaddr, struct ufetchstore_test_args * const args) 99{ 100 int error = 0; 101 102 switch (args->size) { 103 case 32: 104 args->fetchstore_error = ucas_32(uaddr, 105 args->ea_val32, args->val32, &args->ea_val32); 106 break; 107#ifdef _LP64 108 case 64: 109 args->fetchstore_error = ucas_64(uaddr, 110 args->ea_val64, args->val64, &args->ea_val64); 111 break; 112#endif /* _LP64 */ 113 default: 114 error = EINVAL; 115 } 116 117 return error; 118} 119 120static int 121do_ufetchstore_test(SYSCTLFN_ARGS) 122{ 123 struct sysctlnode node; 124 struct ufetchstore_test_args *uargs, args; 125 uint64_t args64; 126 int error; 127 128 node = *rnode; 129 130 uargs = NULL; 131 node.sysctl_data = &args64; 132 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 133 if (error) 134 return error; 135 if (newp == NULL) 136 return EINVAL; 137 138 uargs = (void *)(uintptr_t)args64; 139 140 error = copyin(uargs, &args, sizeof(args)); 141 if (error) 142 return error; 143 144 args.fetchstore_error = EBADF; /* poison */ 145 146 void *uaddr = (void *)(uintptr_t)args.uaddr64; 147 148 switch (args.test_op) { 149 case OP_LOAD: 150 error = test_ufetch(uaddr, &args); 151 break; 152 153 case OP_STORE: 154 error = test_ustore(uaddr, &args); 155 break; 156 157 case OP_CAS: 158 error = test_ucas(uaddr, &args); 159 break; 160 161 default: 162 error = EINVAL; 163 } 164 165 if (error == 0) 166 error = copyout(&args, uargs, sizeof(args)); 167 return error; 168} 169 170static int 171ufetchstore_tester_init(void) 172{ 173 struct sysctllog **log = &tester_ctx.ctx_sysctllog; 174 const struct sysctlnode *rnode, *cnode; 175 int error; 176 177 error = sysctl_createv(log, 0, NULL, &rnode, CTLFLAG_PERMANENT, 178 CTLTYPE_NODE, "ufetchstore_test", 179 SYSCTL_DESCR("ufetchstore testing interface"), 180 NULL, 0, NULL, 0, CTL_KERN, CTL_CREATE, CTL_EOL); 181 if (error) 182 goto return_error; 183 184 error = sysctl_createv(log, 0, &rnode, &cnode, 185 /* 186 * It's really a pointer to our argument structure, because 187 * we want to have precise control over when copyin / copyout 188 * happens. 189 */ 190 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_QUAD, "test", 191 SYSCTL_DESCR("execute a ufetchstore test"), 192 do_ufetchstore_test, 0, 193 (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 194 195 return_error: 196 if (error) 197 sysctl_teardown(log); 198 return error; 199} 200 201static int 202ufetchstore_tester_fini(void) 203{ 204 sysctl_teardown(&tester_ctx.ctx_sysctllog); 205 return 0; 206} 207 208static int 209ufetchstore_tester_modcmd(modcmd_t cmd, void *arg __unused) 210{ 211 int error; 212 213 switch (cmd) { 214 case MODULE_CMD_INIT: 215 error = ufetchstore_tester_init(); 216 break; 217 218 case MODULE_CMD_FINI: 219 error = ufetchstore_tester_fini(); 220 break; 221 222 case MODULE_CMD_STAT: 223 default: 224 error = ENOTTY; 225 } 226 227 return error; 228} 229 230MODULE(MODULE_CLASS_MISC, ufetchstore_tester, NULL); 231