tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Patching wscons_keydesc at runtime



I just upgraded an HP Jornada 720 from NetBSD 2.0 to NetBSD 7.1, and
discovered the wscons keymaps were broken in the meantime: it is impossible to
change the keymap using wsconsctl encoding or wsconsctl map. Both commands
succeed but have no effect.

After poking a few printf in the kernel, I found this in
src/sys/dev/hpc/hpckbd.c:

        /* fix keydesc table */
        /* 
         * XXX The way this is done is really wrong.  The __UNCONST()
         * is a hint as to what is wrong.  This actually ends up modifying
         * initialized data which is marked "const".
         * The reason we get away with it here is apparently that text
         * and read-only data gets mapped read/write on the platforms
         * using this code.
         */
        desc = (struct wscons_keydesc *)__UNCONST(hpckbd_keymapdata.keydesc);
        for (i = 0; desc[i].name != 0; i++) {
                if ((desc[i].name & KB_MACHDEP) && desc[i].map == NULL) {
                        desc[i].map = map;
                        desc[i].map_size = mapsize;
                }
        }

I managed to restore wscons keymaps by copying hpckbd_keymapdata.keydesc into
a malloc() buffer and changing the hpckbd_keymapdata.keydesc to the new
location, which is mapped read/write. 

The offending code did not change since NetBSD 2.0, except the XXX comment
added in 2015. That suggests the compiler behavior changed about initalized
const data, which was still mapped R/W in the ancient time and is now really
read-only, altough it accepts nilpotent writes without raising an exception.

Is the patch below fine to commit, or is there a smarter way to sort this out?
I am not sure why hpc(adm|mips|sh) ports need to patch this const data and if
it can be done differently.

Another point: In order to have french keymap, I used to do wsconsctl -w
encoding=fr, and I must now do wsconsctl -w encoding=fr.machdep. I wonder ig
it is on purpose or if it is a bug (that is: should the KB_MACHDEP flag be
filtered somewhere?)

--- sys/dev/hpc/hpckbd.c        27 Oct 2012 17:18:17 -0000      1.30
+++ sys/dev/hpc/hpckbd.c        9 Jun 2017 15:34:42 -0000
@@ -34,8 +34,9 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
+#include <sys/malloc.h>
 
 #include <sys/tty.h>
 
 #include <sys/bus.h>
@@ -263,24 +264,32 @@
 hpckbd_keymap_setup(struct hpckbd_core *hc,
                    const keysym_t *map, int mapsize)
 {
        int i;
-       struct wscons_keydesc *desc;
+       const struct wscons_keydesc *desc;
+       static struct wscons_keydesc *ndesc = NULL;
 
-       /* fix keydesc table */
        /* 
-        * XXX The way this is done is really wrong.  The __UNCONST()
-        * is a hint as to what is wrong.  This actually ends up modifying
-        * initialized data which is marked "const".
-        * The reason we get away with it here is apparently that text
-        * and read-only data gets mapped read/write on the platforms
-        * using this code.
+        * fix keydesc table. Since it is const data, we must 
+        * copy it once before changingg it.
         */
-       desc = (struct wscons_keydesc *)__UNCONST(hpckbd_keymapdata.keydesc);
+
+       if (ndesc == NULL) {
+               size_t sz;
+
+               for (sz = 0; hpckbd_keymapdata.keydesc[sz].name != 0; sz++);
+
+               ndesc = malloc(sz * sizeof(*ndesc), M_DEVBUF, M_WAITOK);
+               memcpy(ndesc, hpckbd_keymapdata.keydesc, sz * sizeof(*ndesc));
+
+               hpckbd_keymapdata.keydesc = ndesc;
+       }
+
+       desc = hpckbd_keymapdata.keydesc;
        for (i = 0; desc[i].name != 0; i++) {
                if ((desc[i].name & KB_MACHDEP) && desc[i].map == NULL) {
-                       desc[i].map = map;
-                       desc[i].map_size = mapsize;
+                       ndesc[i].map = map;
+                       ndesc[i].map_size = mapsize;
                }
        }
 
        return;




-- 
Emmanuel Dreyfus
http://hcpnet.free.fr/pubz
manu%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index