Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 07 Apr 2024 12:50:00 +0200
From:      =?utf-8?Q?Dag-Erling_Sm=C3=B8rgrav?= <des@FreeBSD.org>
To:        Rocky Hotas <rockyhotas@tilde.team>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Kernel module: return a number from a device
Message-ID:  <86r0fh5twn.fsf@ltc.des.dev>
In-Reply-To: <oghsl7sgcl6p6ym3wwa3w56hn52cdophcr4jxau4ronxevy4ar@ux223whjcthj> (Rocky Hotas's message of "Sat, 6 Apr 2024 22:27:12 %2B0200")
References:  <oghsl7sgcl6p6ym3wwa3w56hn52cdophcr4jxau4ronxevy4ar@ux223whjcthj>

next in thread | previous in thread | raw e-mail | index | archive | help
Rocky Hotas <rockyhotas@tilde.team> writes:
> static int
> rolld_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unuse=
d)
> {
> 	uint32_t random_out;
> 	uint32_t random_item;
> 	int error;
>
> 	random_item =3D arc4random();
> 	random_out =3D random_item % d_size;
>
> 	if ((error =3D uiomove(&random_out, 1, uio)) !=3D 0)
> 		uprintf("uiomove failed!\n");
>
> 	return (error);
> }

Using a uint32_t will work on little-endian systems (such as amd64)
because the least-significant byte, which is the only non-zero byte,
comes first.  On big-endian systems, it would simply always return 0.

Furthermore, this won't only return one byte; rather, it will return one
byte _at a time_, very inefficiently.  This is why cat appears to hang.
To truly only return one byte, you need to look at uio->uio_offset and
return 0 without calling uiomove(), signaling EOF, if it is non-zero.

In summary, you should write rolld_read() as:

        uint8_t roll =3D arc4random() % d_size;
        if (uio->uio_offset > 0)
                return (0);
 	return (uiomove(&roll, 1, uio));

You can also use uiomove_frombuf(), which will take care of that check
for you.  It's a bit overkill when you're only writing a single byte,
but if you wanted to output text instead of binary, you could use this:

        char roll[2];
        roll[0] =3D '0' + arc4random() % d_size;
        roll[1] =3D '\n';
        return (uiomove_frombuf(roll, sizeof(roll), uio));

Obviously, this will only work for d_size <=3D 9.  For larger values, you
will want to use snprintf():

        char roll[16];
        int len =3D snprintf(roll, sizeof(roll), "%d\n", arc4random() % d_s=
ize);
        return (uiomove_frombuf(roll, len, uio));

Have fun,

DES
--=20
Dag-Erling Sm=C3=B8rgrav - des@FreeBSD.org



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?86r0fh5twn.fsf>