1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2013 Damian Bogel. All rights reserved. 14 */ 15 16 /* 17 * Kernel module part of the Hello World pseudo-device driver for illumos. 18 */ 19 20 /* 21 * TODO: 22 * - fsd_open(): check privilages 23 */ 24 25 #include <sys/conf.h> 26 #include <sys/cred.h> 27 #include <sys/ddi.h> 28 #include <sys/devops.h> 29 #include <sys/errno.h> 30 #include <sys/file.h> 31 #include <sys/fsd.h> 32 #include <sys/modctl.h> 33 #include <sys/open.h> 34 #include <sys/stat.h> 35 #include <sys/sunddi.h> 36 #include <sys/types.h> 37 38 #include "fsd_impl.h" 39 40 /* Internal fsd world variables */ 41 static dev_info_t *fsd_devinfo; 42 43 static int 44 fsd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 45 { 46 if (cmd != DDI_ATTACH) 47 return (DDI_FAILURE); 48 49 if (fsd_devinfo != NULL) 50 return (DDI_FAILURE); 51 52 int instance; 53 instance = ddi_get_instance(dip); 54 if (ddi_create_minor_node(dip, "fsd", S_IFCHR, instance, 55 DDI_PSEUDO, 0) == DDI_FAILURE) { 56 fsd_print("Failed to create minor node\n"); 57 return (DDI_FAILURE); 58 } 59 fsd_devinfo = dip; 60 return (DDI_SUCCESS); 61 } 62 63 static int 64 fsd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 65 { 66 if (cmd != DDI_DETACH) 67 return (DDI_FAILURE); 68 ddi_remove_minor_node(dip, NULL); 69 fsd_devinfo = NULL; 70 return (DDI_SUCCESS); 71 } 72 73 static int 74 fsd_getinfo( 75 dev_info_t *dip, 76 ddi_info_cmd_t infocmd, 77 void *arg, 78 void **resultp 79 ) 80 { 81 _NOTE(ARGUNUSED(dip)); 82 switch (infocmd) { 83 case DDI_INFO_DEVT2DEVINFO: 84 *resultp = (void*)(uintptr_t)getminor((dev_t)arg); 85 return (DDI_SUCCESS); 86 case DDI_INFO_DEVT2INSTANCE: 87 *resultp = fsd_devinfo; 88 return (DDI_SUCCESS); 89 default: 90 return (DDI_FAILURE); 91 } 92 } 93 94 static int 95 fsd_open(dev_t *devp, int oflag, int sflag, cred_t *cred_p) 96 { 97 _NOTE(ARGUNUSED(devp)); 98 _NOTE(ARGUNUSED(oflag)); 99 _NOTE(ARGUNUSED(sflag)); 100 _NOTE(ARGUNUSED(cred_p)); 101 return (0); 102 } 103 104 static int 105 fsd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 106 { 107 _NOTE(ARGUNUSED(dev)); 108 _NOTE(ARGUNUSED(flag)); 109 _NOTE(ARGUNUSED(otyp)); 110 _NOTE(ARGUNUSED(cred_p)); 111 return (0); 112 } 113 114 static int 115 fsd_ioctl( 116 dev_t dev, 117 int cmd, 118 intptr_t arg, 119 int mode, 120 cred_t *cred_p, 121 int *rval_p 122 ) 123 { 124 _NOTE(ARGUNUSED(dev)); 125 _NOTE(ARGUNUSED(cred_p)); 126 _NOTE(ARGUNUSED(rval_p)); 127 128 switch (cmd) { 129 case FSD_PRINT_MSG: 130 { 131 struct fsd_msg m; 132 if (ddi_copyin( 133 (void*)arg, &m.len, sizeof (m.len), mode) != 0) 134 return (EFAULT); 135 if (m.len > FSD_MAX_MSG_LEN) 136 return (EINVAL); 137 if (ddi_copyin( 138 (void*)((uintptr_t)arg + sizeof (m.len)), 139 m.s, m.len, mode) != 0) 140 return (EFAULT); 141 m.s[m.len] = '\0'; 142 fsd_print(m.s); 143 break; 144 } 145 default: 146 return (EINVAL); 147 } 148 return (0); 149 } 150 151 152 static struct cb_ops cb_ops = { 153 fsd_open, /* open(9E) */ 154 fsd_close, /* close(9E) */ 155 nodev, /* strategy(9E) */ 156 nodev, /* print(9E) */ 157 nodev, /* dump(9E) */ 158 nodev, /* read(9E) */ 159 nodev, /* write(9E) */ 160 fsd_ioctl, /* ioctl(9E) */ 161 nodev, /* devmap(9E) */ 162 nodev, /* mmap(9E) */ 163 nodev, /* segmap(9E) */ 164 nochpoll, /* chpoll(9E) */ 165 ddi_prop_op, /* prop_op(9E) */ 166 NULL, /* streamtab(9E) */ 167 D_MP | D_64BIT, /* cb_flag(9E) */ 168 CB_REV, /* cb_rev(9E) */ 169 nodev, /* aread(9E) */ 170 nodev, /* awrite(9E) */ 171 }; 172 173 static struct dev_ops dev_ops = { 174 DEVO_REV, /* driver build version */ 175 0, /* reference count */ 176 fsd_getinfo, /* getinfo */ 177 nulldev, 178 nulldev, /* probe */ 179 fsd_attach, /* attach */ 180 fsd_detach, /* detach */ 181 nodev, 182 &cb_ops, /* cb_ops */ 183 NULL, /* bus_ops */ 184 NULL, /* power */ 185 ddi_quiesce_not_needed, /* quiesce */ 186 }; 187 188 static struct modldrv modldrv = { 189 &mod_driverops, "Filesystem Disturber Driver", &dev_ops 190 }; 191 192 static struct modlinkage modlinkage = { 193 MODREV_1, &modldrv, NULL 194 }; 195 196 int 197 _init(void) 198 { 199 return (mod_install(&modlinkage)); 200 } 201 202 int 203 _info(struct modinfo *modinfop) 204 { 205 return (mod_info(&modlinkage, modinfop)); 206 } 207 208 int 209 _fini(void) 210 { 211 return (mod_remove(&modlinkage)); 212 }