Re: Kernel module: return a number from a device

From: Warner Losh <imp_at_bsdimp.com>
Date: Sat, 06 Apr 2024 20:39:26 UTC
When this happens, hit ^t (control t). That will give a traceback of the
call stack which may help you track down where it is hanging (most likely
something is sleeping waiting for an event).

Warner

On Sat, Apr 6, 2024, 2:27 PM Rocky Hotas <rockyhotas@tilde.team> wrote:

> 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);
>
>