Lin­ux­u­la­tor explained (for devel­op­ers): adding ioctls direct­ly to the ker­nel

After giv­ing an overview of the in-kernel basics of the Lin­ux­u­la­tor, I want now to describe how to add sup­port for new ioctls to the Lin­ux­u­la­tor.

Where are the files to mod­i­fy?

The plat­form inde­pen­dent code for the ioctls is in SRC/sys/compat/lin­ux/linux_ioctl.c. The defines to have names for the ioctl val­ues are in SRC/sys/compat/linux/linux_ioctl.h.

How to mod­i­fy them?

First of all cre­ate a new head­er which will con­tain all the struc­tures, named val­ues and macros for those new ioctls. As writ­ten above, the ioctl val­ues (e.g. #define LINUX_VIDIOC_ENCODER_CMD 0x564d /* 0xc028564d */) do not belong there, they shall be added to linux_ioctl.h. Dur­ing the course of adding sup­port for ioctls, you will need this new head­er. Add it in the SRC/sys/compat/linux/ direc­to­ry, and pre­fix the name with a linux_. It would be good to decide on a com­mon tag here (ref­er­enced as yourtag in the fol­low­ing), and stay with it. Use it wher­ev­er you need to have some spe­cif­ic name for the ioctl-set you want to add. In this case it would result in linux_yourtag.h (or even linux_ioctl_yourtag.h, depend­ing if this is used for some­thing very spe­cif­ic to the ioctls, or some gener­ic lin­ux fea­ture) as the name of the head­er file. This was not done in the past, so do not expect that the names inside the linux_ioctl.c file will be con­sis­tent to this nam­ing scheme, but it is nev­er too late to cor­rect mis­takes of the past (at least in Open Source soft­ware devel­op­ment).

Now add this head­er to linux_ioctl.c (you need to include compat/linux/linux_yourtag.h). After that add the ioctl val­ues to linux_ioctl.h. As can be seen above, the defines should be named the same as on lin­ux, but with a LINUX_ pre­fix (make sure they where not defined before some­where else). The ioctl val­ues need to be the same hex val­ues as in Lin­ux, off course. Sort them accord­ing to their hex val­ue. When you added all, you need to add two more defines. The LINUX_IOCTL_yourtag_MIN and LINUX_IOCTL_yourtag_MAX ones. The MIN-one needs to be an alias for the first (sort­ed accord­ing to the hex val­ue) ioctl you added, and MAX needs to be an alias for the last (again, sort­ed accord­ing to the hex val­ue) ioctl you added.

The next step is to let the Lin­ux­u­la­tor know that it is able to han­dle the ioctls in the LINUX_IOCTL_yourtag_MIN to LINUX_IOCTL_yourtag_MAX range. Search the sta­t­ic linux_ioctl_function_t sec­tion of linux_ioctl.c and add such a vari­able for your ioctl set. The name of the vari­able should be some­thing like linux_ioctl_yourtag.

Sim­i­lar for the handler-definition for this. Search the sta­t­ic struct linux_ioctl_handler sec­tion and add a yourtag_handler. Set it to { linux_ioctl_yourtag, LINUX_IOCTL_yourtag_MIN, LINUX_IOCTL_yourtag_MAX }. To make this han­dler known to the Lin­ux­u­la­tor, you need to add it to the DATA_SET sec­tion. Add DATA_SET(linux_ioctl_handler_set, yourtag_handler) there.

Now the meat, the func­tion which han­dles the ioctls. You already defined it as linux_ioctl_function_t, but now you need to write it. The out­line of it looks like this:

static int
linux_ioctl_yourtag(struct thread *td, struct linux_ioctl_args *args)
        struct file *fp;
        int error;
        switch (args->cmd & 0xffff) {
        case LINUX_an_easy_ioctl:
        case LINUX_a_not_so_easy_ioctl:
                /* your handling of the ioctl */
                fdrop(fp, td);
                return (error);
        /* some more handling of your ioctls */
       return (ENOIOCTL);
        error = ioctl(td, (struct ioctl_args *)args);
        return (error);

An easy ioctl in the switch above is an ioctl where you do not have to do some­thing but can pass the ioctl through to FreeB­SD itself. The not so easy ioctl case is an ioctl where you need to do e.g. a fget(td, args->fd, &fp). This is just an exam­ple, there are also oth­er pos­si­bil­i­ties where you need to do addi­tion­al stuff before the return, or where you do not pass the ioctl to FreeB­SD. A typ­i­cal exam­ple of what needs to be done here is to copy val­ues from lin­ux struc­tures to FreeB­SD struc­tures (and the oth­er way too), or to trans­late between 64bit and 32bit. Lin­ux pro­grams on amd64 are 32bit exe­cuta­bles and 32bit structures/pointers. To make this work on amd64, you need to find a way to map between the two. There are exam­ples in the ker­nel where this is already the case. The more promi­nent exam­ples in the 64bit<->32bit regard are the v4l and v4l2 ioctls.

The tedious part is to research if a trans­la­tion has to be done and if yes what needs to be trans­lat­ed how. When this is done, most of the work is not so hard. The linux_yourtag.h should con­tain the struc­tures you need for this trans­la­tion work.

It is also pos­si­ble to add ioctls in a ker­nel mod­ule, but this is not sub­ject to this descrip­tion (I will update this post­ing with a link to it when I get time to write about it).

Send to Kin­dle

Bikesheds, FC4 and SoC

The last week has seen some bikesheds. One of them was my com­mit of the doxy­gen infra­struc­ture for the ker­nel sub­sys­tems. Some peo­ple don’t like the way doxy­gen requires some markup tags in the com­ments, some peo­ple don’t think such API docs pro­vide addi­tion­al val­ue and some peo­ple fear that 3rd par­ty devel­op­ers may use some func­tions which should­n’t be used. I don’t repeat the counter-arguments of myself and oth­er peo­ple here, but there are peo­ple out there which already make use of the cur­rent unsat­is­fac­to­ry doxy­gen out­put and are hap­py about this infra­struc­ture. Luck­i­ly is was super­seed­ed by anoth­er bikeshed (and gnn@ wants to work on doc­u­ment­ing a sub­sys­tem to show the ben­e­fits to those peo­ple which do not think yet, that this is a good idea). On a relat­ed issue, I’m wait­ing on a repo copy of src/sys/doc to src/tools (it’s one of two repo copies I’m wait­ing for, ncvs@ seems to be bussy ATM). Some doc@ peo­ple think it is more appro­pri­ate there.

The FC4 lin­ux base port and the xorg based lin­ux X11 libs port are sched­uled for test­ing in an exper­i­men­tal ports build run, we may see the switch of the default lin­ux base port in the not so dis­tant future. It seems Boris is work­ing on updates to the rest of the lin­ux­o­la­tor infra­struc­ture in the Ports Col­lec­tion (gtk, …), so we may see a lot of updates there after the switch of the default lin­ux base port.

In the last days I also helped/talked with my SoC stu­dents. Roman is play­ing a lit­tle bit with an amd64 tin­der­box he got access to and as a result he com­mit­ted sup­port for build­ing the lin­ux­o­la­tor on amd64 as a mod­ule to per­force (call for testers: he did send a patch to emulation@, please give it a try if you own an amd64 box). Ryan is cat­a­loging the IOCTL’s and their sta­tus (imple­ment­ed, obso­lete, …) in the FreeB­SD wiki. I already pri­or­ized those he did so far, and gave some sug­ges­tions how to pro­ceed with the impor­tant ones. This way he has­n’t to wait for me or Ariff when he is fin­ished with the cat­a­loging (being a men­tor liv­ing in a dif­fer­ent time zone means you should be ahead of your stu­dent… being ahead even before he is able to asks ques­tions is … a boost for your own ego 😉 ).

Send to Kin­dle