Kernel module: return a number from a device
Date: Sat, 06 Apr 2024 20:27:12 UTC
Hello! I'm trying to write a simple kernel module, using as a model the example in <https://docs.freebsd.org/en/books/arch-handbook/driverbasics/> I am a newbie. My module should be simpler than the one in the link: it should just create a read-only /dev/rolld file; each time it is read by the user (for example through `cat'), the file should provide a random number mod d_size. So, the "output" should always be 1 character. I modified the echo kernel module presented in the link. My module can successfully be loaded into the kernel and the device is created, but if I run as a user `cat /dev/rolld': $ cat /dev/rolld Opened device "rolld" successfully. and it hangs, giving no more output and without generating an error. May be this due to the fact that uiomove receives a pointer &random_out, which is a pointer to a uint32_t instead of for example a char? (And if this is the issue, how to convert a uint32_t to char inside the kernel?) Or is there some other error that I made? I paste my code below. Bye! Rocky #include <sys/types.h> #include <sys/systm.h> #include <sys/param.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/conf.h> #include <sys/uio.h> #include <sys/malloc.h> #include <sys/libkern.h> static d_open_t rolld_open; static d_close_t rolld_close; static d_read_t rolld_read; static struct cdevsw rolld_cdevsw = { .d_version = D_VERSION, .d_open = rolld_open, .d_close = rolld_close, .d_read = rolld_read, .d_name = "rolld", }; /* vars */ static struct cdev *rolld_dev; static uint32_t d_size = 6; static int rolld_loader(struct module *m __unused, int what, void *arg __unused) { int error = 0; switch (what) { case MOD_LOAD: /* kldload */ error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &rolld_dev, &rolld_cdevsw, 0, UID_ROOT, GID_WHEEL, 0444, "rolld"); if (error != 0) break; printf("Roll device loaded.\n"); break; case MOD_UNLOAD: destroy_dev(rolld_dev); printf("Roll device unloaded.\n"); break; default: error = EOPNOTSUPP; break; } return (error); } static int rolld_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) { int error = 0; uprintf("Opened device \"rolld\" successfully.\n"); return (error); } static int rolld_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused, struct thread *td __unused) { uprintf("Closing device \"rolld\".\n"); return (0); } static int rolld_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused) { uint32_t random_out; uint32_t random_item; int error; random_item = arc4random(); random_out = random_item % d_size; if ((error = uiomove(&random_out, 1, uio)) != 0) uprintf("uiomove failed!\n"); return (error); } DEV_MODULE(rolld, rolld_loader, NULL);