>Synopsis:      vesa driver garbles loaded vga fonts.
>Category:      kernel/X11
>Environment:
        System      : OpenBSD 5.7
        Details     : OpenBSD 5.7 (GENERIC) #0: Tue Mar 24 08:40:26 EDT 2015
                         root@node02:/usr/src/sys/arch/i386/compile/GENERIC
                        (to be thorough, the code is from Mar 7)
        Architecture: OpenBSD.i386
        Machine     : i386
>Description:
    if you have vga fonts loaded, and launch X with the vesa driver, when
    you switch to a screen configured with that font, it will be garbled.
    if you exit X, instead of being garbled, all cells will be either full
    or empty. if you delete and reload the font, the screen will function
    fine, even with X running, until you switch back to X, which will once
    again garble the font.
    it is clear that vesa uses that space as well, probably for its own
    font. i implemented WSDISPLAYIO_DELFONT to test (and temporarily fix)
    it. if i deleted and reinstalled the font while in X, it basically
    wrote the xterm data to the whole screen.
    vesa is always returned to it's proper state after switching back to
    it, but text mode is not properly restored.
>How-To-Repeat:
    load a font and reconfigure a screen for it:
    $ wsfontload -N iso8x8 -h 8 /usr/share/misc/pcvtfonts/iso8859-1.808
    $ wsconscfg -dF 1
    $ wsconscfg -t 80x50 -e vt100 1
    start X using the vesa driver. switch to the reconfigured screen, then
    switch to screen 1.
>Fix:
    i brought this up on tech@ because it had bearing on a memory leak i
    found, where the font data wansn't saved anywhere, and not freed. my
    solution was wrong because the data SHOULD be linked in.
    https://marc.info/?l=openbsd-tech&m=142701323010064&w=2

    i added a 'data' field to wsdisplay_font, and saved the font data
    there. when WSDISPLAY_SMODE is invoked to return to emulation, or when
    returning to emulation(text) mode in vga_doswitch(), a function
    vga_restore_palette() is run. right after this call i invoke a function
    i wrote called vga_reload_fonts() which cycles thru the loaded fonts
    and writes them back to the card using vga_loadchars() just as when
    they are initially loaded. (this is essentially what i was doing before
    by deleting and then reloading the font which worked as a short term
    solution until i could look further.)

    the diffs below implement what i mention above. i cleaned the code a
    bit, but left most of that out of these diffs (there is some ugliness
    to this code.) (tested without cleanup, just to be clear.)

the diffs below completely fix my problem.

here i added a buffer userbuf to take the value of the original font data,
to be restored to the invoking structure, instead of passing the kernel
memory back in it. i think this is the right thing to do given this line:
rasops.c:       font->cookie = font->data = NULL;       /* don't leak kernel 
pointers */
about kernel pointers. i added a 'data->cookie = NULL;' too.

i also added the size data to a few free()s that were in the way while i
was at it.

--- sys/dev/wscons/wsdisplay.c.orig     Mon Oct 27 16:28:53 2014
+++ sys/dev/wscons/wsdisplay.c  Sat Mar 28 02:30:26 2015
@@ -1280,6 +1280,7 @@ wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long
 {
        int error;
        void *buf;
+       void *userbuf;
        size_t fontsz;
 #if NWSKBD > 0
        struct wsevsrc *inp;
@@ -1318,14 +1319,17 @@ wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long
                buf = malloc(fontsz, M_DEVBUF, M_WAITOK);
                error = copyin(d->data, buf, fontsz);
                if (error) {
-                       free(buf, M_DEVBUF, 0);
+                       free(buf, M_DEVBUF, fontsz);
                        return (error);
                }
+               userbuf = d->data;
                d->data = buf;
                error =
                  (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
                if (error)
-                       free(buf, M_DEVBUF, 0);
+                       free(buf, M_DEVBUF, fontsz);
+               d->data = userbuf;
+               d->cookie = NULL;
                return (error);
 
        case WSDISPLAYIO_LSFONT:
--------------

i added the call for vga_reload_fonts(). i couldn't help myself, so i also
added VGA_MAXFONT so that it can be used instead of a bunch of '8's
scattered around.

--- sys/dev/ic/vgavar.h.orig    Sat Aug 28 08:48:14 2010
+++ sys/dev/ic/vgavar.h Fri Mar 27 06:48:17 2015
@@ -64,7 +64,8 @@ struct vga_config {
        const struct wsscreen_descr *currenttype;
        int currentfontset1, currentfontset2;
 
-       struct vgafont *vc_fonts[8];
+#define VGA_MAXFONT 8
+       struct vgafont *vc_fonts[VGA_MAXFONT];
        uint8_t vc_palette[256 * 3];
 
        struct vgascreen *wantedscreen;
@@ -185,6 +186,7 @@ struct wsscreen_descr;
 void   vga_loadchars(struct vga_handle *, int, int, int, int, char *);
 void   vga_restore_palette(struct vga_config *);
 void   vga_save_palette(struct vga_config *);
+void   vga_reload_fonts(void *);
 void   vga_setfontset(struct vga_handle *, int, int);
 void   vga_setscreentype(struct vga_handle *, const struct wsscreen_descr *);
 #if NVGA_PCI > 0

--------------

and here is where i add the 'data' field to struct vgafont, link the font
data to it in vga_load_font(), and call vga_reload_fonts() in vga_doswitch()
and vga_ioctl() right after vga_restore_palette().

i also added VGA_MAXFONT where appropriate while i was at it. one other
minor change i made was in vga_load_font(), where i did some cosmetic
rearranging of a few assignments:
-       f->slot = slot;
-       vc->vc_fonts[slot] = f;
-       data->cookie = f;
-       data->index = slot;
+       data->index  = f->slot = slot;
+       data->cookie = vc->vc_fonts[slot] = f;

in vga_reload_fonts() i start with slot=1 since slot==0 is builtin.


--- sys/dev/ic/vga.c.orig       Sun Jul 13 20:42:37 2014
+++ sys/dev/ic/vga.c    Sat Mar 28 02:17:59 2015
@@ -86,6 +86,7 @@ static struct vgafont {
        int firstchar, numchars;
 #endif
        int slot;
+       void *data;
 } vga_builtinfont = {
        "builtin",
        16,
@@ -93,6 +94,7 @@ static struct vgafont {
 #ifdef notyet
        0, 256,
 #endif
+       0,
        0
 };
 
@@ -354,7 +356,7 @@ vga_selectfont(struct vga_config *vc, struct vgascreen
 
        f1 = f2 = 0;
 
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < VGA_MAXFONT; i++) {
                struct vgafont *f = vc->vc_fonts[i];
                if (!f || f->height != type->fontheight)
                        continue;
@@ -500,7 +502,7 @@ vga_init(struct vga_config *vc, bus_space_tag_t iot, b
        vc->currenttype = vh->vh_mono ? &vga_stdscreen_mono : &vga_stdscreen;
 
        vc->vc_fonts[0] = &vga_builtinfont;
-       for (i = 1; i < 8; i++)
+       for (i = 1; i < VGA_MAXFONT; i++)
                vc->vc_fonts[i] = NULL;
 
        vc->currentfontset1 = vc->currentfontset2 = 0;
@@ -614,8 +616,10 @@ vga_ioctl(void *v, u_long cmd, caddr_t data, int flag,
 
        case WSDISPLAYIO_SMODE:
                mode = *(u_int *)data;
-               if (mode == WSDISPLAYIO_MODE_EMUL)
+               if (mode == WSDISPLAYIO_MODE_EMUL) {
                        vga_restore_palette(vc);
+                       vga_reload_fonts(vc);
+               }
                break;
 
        case WSDISPLAYIO_GVIDEO:
@@ -805,6 +809,7 @@ vga_doswitch(struct vga_config *vc)
 
        vga_setfont(vc, scr);
        vga_restore_palette(vc);
+       vga_reload_fonts(vc);
 
        scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset;
        if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
@@ -857,13 +862,13 @@ vga_load_font(void *v, void *cookie, struct wsdisplay_
                return (EINVAL);
 
        if (data->index < 0) {
-               for (slot = 0; slot < 8; slot++)
+               for (slot = 0; slot < VGA_MAXFONT; slot++)
                        if (!vc->vc_fonts[slot])
                                break;
        } else
                slot = data->index;
 
-       if (slot >= 8)
+       if (slot >= VGA_MAXFONT)
                return (ENOSPC);
 
        if (vc->vc_fonts[slot] != NULL)
@@ -883,10 +888,9 @@ vga_load_font(void *v, void *cookie, struct wsdisplay_
               f->height, f->encoding, slot);
 #endif
        vga_loadchars(&vc->hdl, slot, 0, 256, f->height, data->data);
-       f->slot = slot;
-       vc->vc_fonts[slot] = f;
-       data->cookie = f;
-       data->index = slot;
+       data->index  = f->slot = slot;
+       data->cookie = vc->vc_fonts[slot] = f;
+       f->data = data->data;
 
        return (0);
 }
@@ -897,7 +901,7 @@ vga_list_font(void *v, struct wsdisplay_font *data)
        struct vga_config *vc = v;
        struct vgafont *f;
 
-       if (data->index < 0 || data->index >= nitems(vc->vc_fonts))
+       if (data->index < 0 || data->index >= VGA_MAXFONT)
                return EINVAL;
 
        if ((f = vc->vc_fonts[data->index]) == NULL)
@@ -1214,6 +1218,19 @@ vga_restore_palette(struct vga_config *vc)
        vga_raw_read(vh, 0x0a);                 /* reset flip/flop */
 
        vga_enable(vh);
+}
+
+void
+vga_reload_fonts(struct vga_config *v)
+{
+       struct vga_config *vc = v;
+       int slot;
+       struct vgafont *f;
+
+       for (slot = 1; slot < VGA_MAXFONT; slot++)
+               if ((f = vc->vc_fonts[slot]))
+                       vga_loadchars(&vc->hdl, slot, 0, 256,
+                               f->height, f->data);
 }
 
 struct cfdriver vga_cd = {

--------------------

dmesg:
OpenBSD 5.7 (GENERIC) #0: Tue Mar 24 08:40:26 EDT 2015
    root@node02:/usr/src/sys/arch/i386/compile/GENERIC
cpu0: AMD Athlon(tm) Processor ("AuthenticAMD" 686-class, 64KB L2 cache) 1.01 
GHz
cpu0: 
FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,MMXX,3DNOW2,3DNOW
real mem  = 200753152 (191MB)
avail mem = 185110528 (176MB)
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: date 02/19/01, BIOS32 rev. 0 @ 0xfb3c0, SMBIOS rev. 2.2 @ 
0xf0800 (44 entries)
bios0: vendor Award Software International, Inc. version "6.00 PG" date 
02/19/2001
bios0: VIA Technologies, Inc. VT8363
acpi0 at bios0: rev 0
acpi0: sleep states S0 S1 S4 S5
acpi0: tables DSDT FACP
acpi0: wakeup devices USB0(S5) USB1(S5) MODM(S4) UAR1(S4) UAR2(S4) LPT1(S4) 
ECP1(S4) PCI0(S1)
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpiprt0 at acpi0: bus 0 (PCI0)
acpicpu0 at acpi0: C3, C2
acpibtn0 at acpi0: PWRB
bios0: ROM list: 0xc0000/0x8000
cpu0 at mainbus0: (uniprocessor)
mtrr: Pentium Pro MTRR support, 8 var ranges, 88 fixed ranges
pci0 at mainbus0 bus 0: configuration mode 1 (bios)
pchb0 at pci0 dev 0 function 0 "VIA VT8363 Host" rev 0x03
viaagp0 at pchb0: v2
agp0 at viaagp0: aperture at 0xd0000000, size 0x10000000
ppb0 at pci0 dev 1 function 0 "VIA VT8363 AGP" rev 0x00
pci1 at ppb0 bus 1
pcib0 at pci0 dev 7 function 0 "VIA VT82C686 ISA" rev 0x40
pciide0 at pci0 dev 7 function 1 "VIA VT82C571 IDE" rev 0x06: ATA100, channel 0 
configured to compatibility, channel 1 configured to compatibility
wd0 at pciide0 channel 0 drive 0: 
wd0: 16-sector PIO, LBA, 
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 5
wd1 at pciide0 channel 1 drive 0: 
wd1: 16-sector PIO, LBA48, 
wd1(pciide0:1:0): using PIO mode 4, Ultra-DMA mode 5
uhci0 at pci0 dev 7 function 2 "VIA VT83C572 USB" rev 0x16: irq 11
viapm0 at pci0 dev 7 function 4 "VIA VT82C686 SMBus" rev 0x40: SMI
iic0 at viapm0
iic0: addr 0x18 00=10 01=13 02=00 03=00 04=00 05=90 08=70 09=08 0a=00 0b=77 
0c=00 0d=70 10=fc 11=00 12=00 13=00 14=0f 15=00 16=00 20=60 21=13 words 00=10ff 
01=13ff 02=00ff 03=00ff 04=00ff 05=90ff 06=ffff 07=ffff
iic0: addr 0x19 00=ba 01=38 02=00 03=82 04=00 05=f7 08=00 09=00 0a=00 0b=00 
0c=00 0d=79 10=3c 11=00 12=00 13=00 14=0f 15=00 16=00 20=60 21=13 words 00=baff 
01=38ff 02=00ff 03=82ff 04=00ff 05=f7ff 06=ffff 07=ffff
iic0: addr 0x2d 00=01 01=02 02=16 03=ff 04=ff 07=f0 08=ad 09=dd 0b=0a 13=77 
14=71 15=ff 16=dd 17=82 1d=ff 1e=ff 1f=80 20=b6 21=88 22=92 23=11 24=ce 25=c0 
26=bf 27=7f 28=7f 2b=ff 2d=d6 2e=c1 2f=d4 30=bf 31=cd 32=ba 33=cb 34=b8 35=ff 
36=ff 37=ff 38=fb 39=ff 3b=ff 3c=ff 3d=ff 3f=a2 40=01 43=ff 44=ff 47=f0 48=ad 
49=dd 4b=0a 53=7f 54=e7 55=ff 56=5a 57=80 5d=ff 5e=ff 5f=80 60=b6 61=88 62=92 
63=11 64=ce 65=c0 66=bf 67=7f 68=7f 6b=ff 6d=d6 6e=c1 6f=d4 70=bf 71=cd 72=ba 
73=cb 74=b8 75=ff 76=ff 77=ff 78=fb 79=ff 7b=ff 7c=ff 7d=ff 7f=a2 80=01 83=ff 
84=ff 87=f0 88=ad 89=dd 8b=0a 93=48 94=f8 95=ff 96=5d 97=81 9d=ff 9e=ff 9f=80 
a0=b6 a1=88 a2=92 a3=11 a4=ce a5=c0 a6=bf a7=7f a8=7f ab=ff ad=d6 ae=c1 af=d4 
b0=bf b1=cd b2=ba b3=cb b4=b8 b5=ff b6=ff b7=ff b8=fb b9=ff bb=ff bc=ff bd=ff 
bf=a2 c0=01 c3=ff c4=ff c7=f0 c8=ad c9=9d cb=ca d3=48 d4=fd d5=ff d6=61 d7=81 
dd=ff de=ff df=80 e0=b6 e1=88 e2=92 e3=11 e4=ce e5=c0 e6=bf e7=7f e8=7f eb=ff 
ed=d6 ee=c1 ef=d4 f0=bf f1=cd f2=ba f3=cb f4=b8 f5=ff f!
 6=ff f7=f
 f f8=fb f9=ff fb=ff fc=ff fd=ff ff=a2 words 00=01ff 01=00ff 02=00ff 03=ffff 
04=ffff 05=00ff 06=00ff 07=f0ff
spdmem0 at iic0 addr 0x50: 128MB SDRAM non-parity PC100CL3
spdmem1 at iic0 addr 0x51: 64MB SDRAM non-parity PC100CL3
auvia0 at pci0 dev 7 function 5 "VIA VT82C686 AC97" rev 0x50: irq 9
ac97: codec id 0x49434511 (ICEnsemble ICE1232)
ac97: codec features headphone, 18 bit DAC, 18 bit ADC, KS Waves 3D
audio0 at auvia0
vga1 at pci0 dev 8 function 0 "S3 ViRGE DX/GX" rev 0x01
wsdisplay0 at vga1 mux 1: console (80x25, vt100 emulation)
wsdisplay0: screen 1-5 added (80x25, vt100 emulation)
rl0 at pci0 dev 9 function 0 "Realtek 8139" rev 0x10: irq 11, address 
00:20:18:89:82:d3
rlphy0 at rl0 phy 0: RTL internal PHY
isa0 at pcib0
isadma0 at isa0
fdc0 at isa0 port 0x3f0/6 irq 6 drq 2
com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
com1 at isa0 port 0x2f8/8 irq 3: ns16550a, 16 byte fifo
pckbc0 at isa0 port 0x60/5
pckbd0 at pckbc0 (kbd slot)
pckbc0: using irq 1 for kbd slot
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pms0 at pckbc0 (aux slot)
pckbc0: using irq 12 for aux slot
wsmouse0 at pms0 mux 0
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
lpt0 at isa0 port 0x378/4 irq 7
npx0 at isa0 port 0xf0/16: reported by CPUID; using exception 16
usb0 at uhci0: USB revision 1.0
uhub0 at usb0 "VIA UHCI root hub" rev 1.00/1.00 addr 1
vscsi0 at root
scsibus1 at vscsi0: 256 targets
softraid0 at root
scsibus2 at softraid0: 256 targets
sd0 at scsibus2 targ 1 lun 0: <OPENBSD, SR CRYPTO, 005> SCSI2 0/direct fixed
sd0: 
root on sd0a (d78aa6c2c8d6b251.a) swap on sd0b dump on sd0b

usbdevs:
Controller /dev/usb0:
addr 1: full speed, self powered, config 1, UHCI root hub(0x0000), VIA(0x1106), 
rev 1.00
 port 1 powered
 port 2 powered

Reply via email to