NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/58972: madvise(MADV_WILLNEED) on EFI genfb framebuffer crashes kernel
>Number: 58972
>Category: kern
>Synopsis: madvise(MADV_WILLNEED) on EFI genfb framebuffer crashes kernel
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jan 07 09:25:00 +0000 2025
>Originator: RVP
>Release: NetBSD/amd64 10.99.12
>Organization:
>Environment:
NetBSD/amd64 10.99.12 GENERIC about a week old.
>Description:
In trying to find why genfb + wsfb(4) was so slow on NetBSD (twice as
slow as FreeBSD for OpenGL running on its efifb + scfb(4)), I wrote a
demo (which is not the one below) and then tried to speed it up by using
mlock() and madvise() on the framebuffer (this seems to have no effect).
Using mlock() causes the kernel to massively spew the console like
this:
```
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x76499355d000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x76499355e000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x76499355f000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993560000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993561000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993562000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993563000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993564000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993565000 did not change!
[ 145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993566000 did not change!
```
Hundreds of these messages spew on every tick. Bad, but not fatal.
Doing madvise() however, crashes the kernel (as _any_ user--no root reqd.)
in uvm_readahead(). Mebbe madvise() should do nothing on framebuffer
devices (like on Linux)?
>How-To-Repeat:
Compile and run the reproducer as follows (only EFI genfb console tested):
```
cc -DDO_MLOCK_UNWIRE_SPEW -o t1 fbtest.c
cc -DDO_MADV_CRASH_KERNEL -o t2 fbtest.c
./t1; clear; read x; ./t2
```
Reproducer:
```
/**
* NetBSD wsdisplay(4) framebuffer test.
*/
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dev/wscons/wsconsio.h>
typedef struct framebuffer {
int fd;
uint32_t xres;
uint32_t yres;
uint32_t bpp; /* bytes per pixel */
uint32_t stride;
u_int omode;
size_t len;
size_t mapsz;
void* fb;
} Framebuffer;
static Framebuffer* fb_init(char* fbdev);
static void fb_clear(Framebuffer* fb);
static void fb_done(Framebuffer* fb);
int
main(void)
{
Framebuffer* fb;
char* devname;
int rc = EXIT_FAILURE;
if (getenv("DISPLAY") != NULL)
errx(rc, "run this on a framebuffer-console--ie. not in X");
devname = ttyname(STDIN_FILENO);
if (devname == NULL)
devname = "/dev/ttyE0";
fb = fb_init(devname);
if (fb == NULL)
err(rc, "error initializing framebuffer: %s", devname);
fb_clear(fb);
fb_done(fb);
return EXIT_SUCCESS;
}
static Framebuffer*
fb_init(char* fbdev)
{
struct wsdisplayio_fbinfo fbi;
u_int omode, mode;
size_t pagemask;
Framebuffer* fb = NULL;
int fd = open(fbdev, O_RDWR);
if (fd == -1) {
warn("%s: open failed", fbdev);
return NULL;
}
if (ioctl(fd, WSDISPLAYIO_GET_FBINFO, &fbi) == -1) {
warn("ioctl(WSDISPLAYIO_GET_FBINFO) failed");
return NULL;
}
if (fbi.fbi_bitsperpixel != 32) {
warnx("Framebuffer depth (%d) != 32", fbi.fbi_bitsperpixel);
return NULL;
}
#define ROFF fbi.fbi_subtype.fbi_rgbmasks
if (ROFF.red_offset != 16 || ROFF.green_offset != 8 || ROFF.blue_offset != 0) {
warnx("FB pixel layout not BGRA");
return NULL;
}
#undef ROFF
if (ioctl(fd, WSDISPLAYIO_GMODE, &omode) == -1) {
warn("ioctl(WSDISPLAYIO_GMODE) failed");
return NULL;
}
mode = WSDISPLAYIO_MODE_DUMBFB;
if (ioctl(fd, WSDISPLAYIO_SMODE, &mode) == -1) {
warn("can't switch to dumb FB mode");
return NULL;
}
if ((fb = malloc(sizeof (Framebuffer))) == NULL) {
warn("error allocating FB struct");
return NULL;
}
fb->fd = fd;
fb->fb = NULL;
fb->xres = fbi.fbi_width;
fb->yres = fbi.fbi_height;
fb->bpp = fbi.fbi_bitsperpixel / 8; /* bytes per pixel */
fb->stride = fbi.fbi_stride; /* bytes, not pixels */
fb->omode = omode; /* save orig. mode */
fb->len = fbi.fbi_fbsize; /* should be == stride * yres */
pagemask = getpagesize() - 1;
fb->mapsz = (fb->len + pagemask) & ~pagemask;
fb->fb = mmap(0, fb->mapsz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)0);
if ((void* )fb->fb == MAP_FAILED) {
warn("error mapping framebuffer");
free(fb);
return NULL;
}
#ifdef DO_MADV_CRASH_KERNEL
if (madvise(fb->fb, fb->mapsz, MADV_WILLNEED) == -1)
warn("madvise(MADV_WILLNEED) failed");
#endif
#ifdef DO_MLOCK_UNWIRE_SPEW
if (mlock(fb->fb, fb->mapsz) != 0)
warn("error locking FB memory");
#endif
return fb;
}
static void
fb_clear(Framebuffer* fb)
{
memset(fb->fb, 0, fb->len);
}
static void
fb_done(Framebuffer* fb)
{
if (munmap(fb->fb, fb->mapsz) == -1)
warn("munmap() failed");
if (ioctl(fb->fd, WSDISPLAYIO_SMODE, &fb->omode) == -1)
warn("can't switch to orig. mode");
close(fb->fd);
free(fb);
}
```
>Fix:
No idea, but, users shouldn't be able to crash the kernel so easily.
Home |
Main Index |
Thread Index |
Old Index