Problem with Joseph Kong's "FreeBSD Device Drivers"

Hi there!

Right now I'm learnig driver development with the mentioned book. Now, in chapter 3, "Implementing sysctls, Part 1", there are compiler errors by using my own sourcecode and by using the sample code directly from the webiste, https://nostarch.com/bsddrivers.htm :

Code:
root@FreeBSD:/home/ralf # make
Warning: Object directory not changed from original /usr/home/ralf
cc  -O2 -pipe  -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc   -I. -I/usr/src/sys -I/usr/src/sys/contrib/ck/include -fno-common  -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer   -MD  -MF.depend.pointless.o -MTpointless.o -mcmodel=kernel -mno-red-zone -mno-mmx -mno-sse -msoft-float  -fno-asynchronous-unwind-tables -ffreestanding -fwrapv -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wcast-qual -Wundef -Wno-pointer-sign -D__printf__=__freebsd_kprintf__ -Wmissing-include-dirs -fdiagnostics-show-option -Wno-unknown-pragmas -Wno-error-tautological-compare -Wno-error-empty-body -Wno-error-parentheses-equality -Wno-error-unused-function -Wno-error-pointer-sign -Wno-error-shift-negative-value -Wno-address-of-packed-member  -mno-aes -mno-avx  -std=iso9899:1999 -c pointless.c -o pointless.o
pointless.c:62:7: error: use of undeclared identifier 'sysctl__'
                    SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO,
                    ^
/usr/src/sys/sys/sysctl.h:241:44: note: expanded from macro 'SYSCTL_STATIC_CHILDREN'
#define SYSCTL_STATIC_CHILDREN(oid_name)        (&sysctl__##oid_name.oid_children)
                                                  ^
pointless.c:61:8: error: assigning to 'struct sysctl_oid *' from incompatible type 'void'
                poid = SYSCTL_ADD_NODE(&clist,
                     ^ ~~~~~~~~~~~~~~~~~~~~~~~
pointless.c:80:3: error: static_assert failed "compile-time assertion failed"
                SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(poid), OID_AUTO,
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/src/sys/sys/sysctl.h:759:2: note: expanded from macro 'SYSCTL_ADD_PROC'
        CTASSERT(((access) & CTLTYPE) != 0);                            \
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/src/sys/sys/systm.h:120:21: note: expanded from macro 'CTASSERT'
#define CTASSERT(x)     _Static_assert(x, "compile-time assertion failed")
                        ^              ~
3 errors generated.
*** Error code 1

is this book outdated or something?
 
The book should state somewhere what version it is written for. That will give you a hint whether and how much the book is outdated. You might want to download the FreeBSD source code for that version. Not necessarily to build on, but to compare. But most likely this can be figured out without even looking at the old source.

Seems the root cause is the lack of a declaration for "sysctl__". Which kernel include files does your program include? Search those for something related to sysctl. Mostly likely you'll find something there, and probably it is something like a feature flag (ifdef) or a spelling change. Also look for the definition of the macro SYSCTL_STATIC_CHILDREN, and see how it fits in.

At this point, focus only on the first error that the compiler gives you. Once you have fixed that first error, the other errors will probably change completely, so don't waste time on fixing them.

A lot of kernel development is making your code fit into the existing infrastructure. That often requires figuring out the existing infrastructure. The skill of reading and understanding the existing code will be vital anyway, it seems that for you it's time to practice that skill.
 
For the first error, I think you should replace /* tree top */
Code:
SYSCTL_STATIC_CHILDREN(/* tree top */)
with something real like
Code:
SYSCTL_STATIC_CHILDREN(_dev)
but I haven't red the book yet.
 
I remember that a driver which I wrote back in 2012 for a National Instruments PCI-DAQ board did not compile anymore on FreeBSD 11. Among other resources, I used also the book "FreeBSD Device Drivers" as a reference.

I looked in the SVN history of my driver and found the following comment of mine from Sept 2016:
FreeBSD 11 introduced the new macro SYSCTL_ADD_ROOT_NODE(&clist, ...), use this one instead of SYSCTL_ADD_NODE(&clist, SYSCTL_ADD_NODE(/* root */), ...).

Well, that solved the issue:

Old code (working until FreeBSD 10):
C:
sysctl_ctx_init(&clist);
...
poid = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(/* root */), OID_AUTO, "cydaq", CTLFLAG_RW, 0, "cydaq root node");
...

New code (still working since FreeBSD 11):
C:
sysctl_ctx_init(&clist);
...
poid = SYSCTL_ADD_ROOT_NODE(&clist, OID_AUTO, "cydaq", CTLFLAG_RW, 0, "cydaq root node");
...
 
well i followed ralphbsz's advice to look in the header file. the SYSCTL_STATIC_CHILDREN macro converts its parameter into an existing sysctl_ struct. there are some standard nodes like hw, debug, kernel etc, and as it looks like, SYSCTL_STATIC_CHILDREN is for those. but i uses SYSCTL_ADD_ROOT_NODE and it worked.

the second error is a litte strange: the assert macro most probably wants me to OR one of the CTLTYPE define to CTLFLAG_RD, which makes sense, because you maybe want to ask for the type later. but there are only defines for data types like int, string etc:

Code:
#define    SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr) \
({                                    \
    CTASSERT(((access) & CTLTYPE) != 0);                \
    sysctl_add_oid(ctx, parent, nbr, name, (access),        \
        (ptr), (arg), (handler), (fmt), __DESCR(descr), NULL);    \
})

but there is no CTLTYPE_PROC:

Code:
#define    CTLTYPE        0xf    /* mask for the type */
#define    CTLTYPE_NODE    1    /* name is a node */
#define    CTLTYPE_INT    2    /* name describes an integer */
#define    CTLTYPE_STRING    3    /* name describes a string */
#define    CTLTYPE_S64    4    /* name describes a signed 64-bit number */
#define    CTLTYPE_OPAQUE    5    /* name describes a structure */
#define    CTLTYPE_STRUCT    CTLTYPE_OPAQUE    /* name describes a structure */
#define    CTLTYPE_UINT    6    /* name describes an unsigned integer */
#define    CTLTYPE_LONG    7    /* name describes a long */
#define    CTLTYPE_ULONG    8    /* name describes an unsigned long */
#define    CTLTYPE_U64    9    /* name describes an unsigned 64-bit number */
#define    CTLTYPE_U8    0xa    /* name describes an unsigned 8-bit number */
#define    CTLTYPE_U16    0xb    /* name describes an unsigned 16-bit number */
#define    CTLTYPE_S8    0xc    /* name describes a signed 8-bit number */
#define    CTLTYPE_S16    0xd    /* name describes a signed 16-bit number */
#define    CTLTYPE_S32    0xe    /* name describes a signed 32-bit number */
#define    CTLTYPE_U32    0xf    /* name describes an unsigned 32-bit number */

just or-ing any one of them makes the code compile without any errors, but actually it's wrong, isn't it?
 
I found there is man 9 sysctl .
And with a grep i found :sys/sys/sysctl.h:
#define CTLFLAG_RD 0x80000000 /* Allow reads of variable */
#define CTLFLAG_WR 0x40000000 /* Allow writes to the variable */
#define CTLFLAG_RW (CTLFLAG_RD|CTLFLAG_WR)
 
yes but (0x8000000 | 0x40000000) is 0xC0000000 and (0xC0000000 & 0xf) is 0x00000000, which makes the assert fail.
 
yes that's right, but i'm not adding an int but a function. it also works fine with or-ing one of the available CTLTYPE values, but the problem is, that there's a function to be called and not an int to be read.
 
In the file :
/usr/src/share/examples/kld/dyn_sysctl/dyn_sysctl.c I found :
ctlflags=CTLTYPE_STRING | CTLFLAG_RD
SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(a_root1),OID_AUTO, "procedure", CTLTYPE_STRING | CTLFLAG_RD,NULL, 0, sysctl_dyn_sysctl_test, "A","I can be here, too");
 
Back
Top