When I execute the following function, after mmap returns, I get a kernel mapped pointer returned but its not accessible. All functions returns 0 so succeeds without errors. The offset value is set to 4311556096 after DRM_IOCTL_MODE_MAP_DUMB IOCTL is returned and this gets passed as part of mmap offset args.
I am working with a arm64 device with kernel version 4.19.0, libdrm.so.2.4.0. The
(gdb) p *fb
$5 = {
fd = 0,
buffer_id = 41,
res_x = 0,
res_y = 0,
data = 0x7fbec8a000 <error: Cannot access memory at address 0x7fbec8a000>,
size = 0,
dumb_framebuffer = {
height = 1080,
width = 1920,
bpp = 32,
flags = 0,
handle = 1,
pitch = 7680,
size = 8294400
},
crtc = 0x55594b23f0,
connector = 0x0,
resolution = 0x0
}
(gdb) p mreq
$3 = {
handle = 1,
pad = 0,
offset = 4311556096
(gdb) p *connector
$6 = {
connector_id = 37,
encoder_id = 36,
connector_type = 11,
connector_type_id = 1,
connection = DRM_MODE_CONNECTED,
mmWidth = 480,
mmHeight = 270,
subpixel = DRM_MODE_SUBPIXEL_UNKNOWN,
count_modes = 32,
modes = 0x55594b2d30,
count_props = 4,
props = 0x55594b2ce0,
prop_values = 0x55594b2d00,
count_encoders = 1,
encoders = 0x55594b35c0
}
Ofcourse the returned mem-mapped region is not useable. I believe the returned pointer is in the heap, the stack pointer is around 0x7ffffffd97.
(gdb) p connector_name
$9 = 0x7ffffffd97 "HDMI-A-1
I would like to see if anybody knows anything about this. Thanks.
int get_framebuffer(const char *dri_device, const char *connector_name, struct framebuffer *fb,
int selected_resolution)
{
int err;
int fd;
drmModeResPtr res;
drmModeEncoderPtr encoder = 0;
/* Open the dri device /dev/dri/cardX */
fd = open(dri_device, O_RDWR);
if (fd < 0) {
printf("Could not open dri device %sn", dri_device);
return -EINVAL;
}
/* Get the resources of the DRM device (connectors, encoders, etc.)*/
res = drmModeGetResources(fd);
if (!res) {
printf("Could not get drm resourcesn");
return -EINVAL;
}
/* Search the connector provided as argument */
drmModeConnectorPtr connector = 0;
for (int i = 0; i < res->count_connectors; i++) {
char name[32];
connector = drmModeGetConnectorCurrent(fd, res->connectors[i]);
if (!connector)
continue;
snprintf(name, sizeof(name), "%s-%u", connector_type_name(connector->connector_type),
connector->connector_type_id);
if (strncmp(name, connector_name, sizeof(name)) == 0)
break;
drmModeFreeConnector(connector);
connector = 0;
}
if (!connector) {
printf("Could not find matching connector %sn", connector_name);
return -EINVAL;
}
if (connector->count_modes <= 0) {
printf("No modes found for connector %sn", connector_name);
return -EINVAL;
}
/* Get the resolution */
drmModeModeInfoPtr resolution = 0;
if (selected_resolution >= 0 && selected_resolution < connector->count_modes) {
resolution = &connector->modes[selected_resolution];
}
else {
for (int i = 0; i < connector->count_modes; i++) {
drmModeModeInfoPtr res = 0;
res = &connector->modes[i];
if (res->type & DRM_MODE_TYPE_PREFERRED)
resolution = res;
}
}
if (!resolution) {
printf("Could not find preferred resolution, use first possible resolutionn");
resolution = &connector->modes[0];
}
fb->dumb_framebuffer.height = resolution->vdisplay;
fb->dumb_framebuffer.width = resolution->hdisplay;
fb->dumb_framebuffer.bpp = 32;
err = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &fb->dumb_framebuffer);
if (err) {
printf("Could not create dumb framebuffer (err=%d)n", err);
goto cleanup;
}
err = drmModeAddFB(fd, resolution->hdisplay, resolution->vdisplay, 24, 32,
fb->dumb_framebuffer.pitch, fb->dumb_framebuffer.handle, &fb->buffer_id);
if (err) {
printf("Could not add framebuffer to drm (err=%d)n", err);
goto cleanup;
}
encoder = drmModeGetEncoder(fd, connector->encoder_id);
if (!encoder) {
printf("Could not get encodern");
err = -EINVAL;
goto cleanup;
}
/* Get the crtc settings */
fb->crtc = drmModeGetCrtc(fd, encoder->crtc_id);
struct drm_mode_map_dumb mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.handle = fb->dumb_framebuffer.handle;
err = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (err) {
printf("Mode map dumb framebuffer failed (err=%d)n", err);
goto cleanup;
}
fb->data = mmap(0, fb->dumb_framebuffer.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
if (fb->data == MAP_FAILED) {
err = errno;
printf("Mode map failed (err=%d)n", err);
goto cleanup;
}
/* Make sure we are not master anymore so that other processes can add new framebuffers as well */
drmDropMaster(fd);
fb->fd = fd;
fb->connector = connector;
fb->resolution = resolution;
cleanup:
/* We don't need the encoder and connector anymore so let's free them */
if (encoder)
drmModeFreeEncoder(encoder);
if (err)
release_framebuffer(fb);
return err;
}
The mem-mapped region returned from the mmu should be an accessible pointer.