qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

Merge remote-tracking branch 'remotes/kraxel/tags/ui-20180827-v4-pull-request' into staging

ui: misc fixes which piled up during 3.0 release freeze

# gpg: Signature made Mon 27 Aug 2018 09:53:07 BST
# gpg: using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/ui-20180827-v4-pull-request:
util: promote qemu_egl_rendernode_open() to libqemuutil
dmabuf: add y0_top, pass it to spice
ui/vnc: Remove useless parenthesis around DIV_ROUND_UP macro
ui/sdl2: Fix broken -full-screen CLI option
spice-display: fix qemu_spice_cursor_refresh_bh locking
spice-display: access ptr_x/ptr_y under Mutex
vnc: remove support for deprecated tls, x509, x509verify options
doc: switch to modern syntax for VNC TLS setup
sdl2: redraw correctly when scanout_mode enabled.
ui: use enum to string helpers
vnc: fix memleak of the "vnc-worker-output" name
ui/sdl2: Remove the obsolete SDL_INIT_NOPARACHUTE flag

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

+139 -237
+1
MAINTAINERS
··· 1576 1576 F: ui/ 1577 1577 F: include/ui/ 1578 1578 F: qapi/ui.json 1579 + F: util/drm.c 1579 1580 1580 1581 Cocoa graphics 1581 1582 M: Peter Maydell <peter.maydell@linaro.org>
+6
include/qemu/drm.h
··· 1 + #ifndef QEMU_DRM_H_ 2 + #define QEMU_DRM_H_ 3 + 4 + int qemu_drm_rendernode_open(const char *rendernode); 5 + 6 + #endif
+1
include/ui/console.h
··· 186 186 uint32_t stride; 187 187 uint32_t fourcc; 188 188 uint32_t texture; 189 + bool y0_top; 189 190 }; 190 191 191 192 typedef struct DisplayChangeListenerOps {
-20
qemu-deprecated.texi
··· 40 40 The ``-no-kvm'' argument is now a synonym for setting 41 41 ``-machine accel=tcg''. 42 42 43 - @subsection -vnc tls (since 2.5.0) 44 - 45 - The ``-vnc tls'' argument is now a synonym for setting 46 - ``-object tls-creds-anon,id=tls0'' combined with 47 - ``-vnc tls-creds=tls0' 48 - 49 - @subsection -vnc x509 (since 2.5.0) 50 - 51 - The ``-vnc x509=/path/to/certs'' argument is now a 52 - synonym for setting 53 - ``-object tls-creds-x509,dir=/path/to/certs,id=tls0,verify-peer=no'' 54 - combined with ``-vnc tls-creds=tls0' 55 - 56 - @subsection -vnc x509verify (since 2.5.0) 57 - 58 - The ``-vnc x509verify=/path/to/certs'' argument is now a 59 - synonym for setting 60 - ``-object tls-creds-x509,dir=/path/to/certs,id=tls0,verify-peer=yes'' 61 - combined with ``-vnc tls-creds=tls0' 62 - 63 43 @subsection -tftp (since 2.6.0) 64 44 65 45 The ``-tftp /some/dir'' argument is replaced by either
+15 -5
qemu-doc.texi
··· 1103 1103 client to connect, and provides an encrypted session. 1104 1104 1105 1105 @example 1106 - qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509=/etc/pki/qemu -monitor stdio 1106 + qemu-system-i386 [...OPTIONS...] \ 1107 + -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=no \ 1108 + -vnc :1,tls-creds=tls0 -monitor stdio 1107 1109 @end example 1108 1110 1109 1111 In the above example @code{/etc/pki/qemu} should contain at least three files, ··· 1118 1120 Certificates can also provide a means to authenticate the client connecting. 1119 1121 The server will request that the client provide a certificate, which it will 1120 1122 then validate against the CA certificate. This is a good choice if deploying 1121 - in an environment with a private internal certificate authority. 1123 + in an environment with a private internal certificate authority. It uses the 1124 + same syntax as previously, but with @code{verify-peer} set to @code{yes} 1125 + instead. 1122 1126 1123 1127 @example 1124 - qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509verify=/etc/pki/qemu -monitor stdio 1128 + qemu-system-i386 [...OPTIONS...] \ 1129 + -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \ 1130 + -vnc :1,tls-creds=tls0 -monitor stdio 1125 1131 @end example 1126 1132 1127 1133 ··· 1132 1138 to provide two layers of authentication for clients. 1133 1139 1134 1140 @example 1135 - qemu-system-i386 [...OPTIONS...] -vnc :1,password,tls,x509verify=/etc/pki/qemu -monitor stdio 1141 + qemu-system-i386 [...OPTIONS...] \ 1142 + -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \ 1143 + -vnc :1,tls-creds=tls0,password -monitor stdio 1136 1144 (qemu) change vnc password 1137 1145 Password: ******** 1138 1146 (qemu) ··· 1169 1177 with the aforementioned TLS + x509 options: 1170 1178 1171 1179 @example 1172 - qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio 1180 + qemu-system-i386 [...OPTIONS...] \ 1181 + -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \ 1182 + -vnc :1,tls-creds=tls0,sasl -monitor stdio 1173 1183 @end example 1174 1184 1175 1185 @node vnc_setup_sasl
+1 -1
qemu-keymap.c
··· 84 84 } 85 85 fprintf(outfile, "# evdev %d (0x%x), QKeyCode \"%s\", number 0x%x\n", 86 86 evdev, evdev, 87 - QKeyCode_lookup.array[qcode], 87 + QKeyCode_str(qcode), 88 88 qcode_to_number(qcode)); 89 89 90 90 /*
-43
qemu-options.hx
··· 1632 1632 mechanism. The credentials should have been previously created 1633 1633 using the @option{-object tls-creds} argument. 1634 1634 1635 - The @option{tls-creds} parameter obsoletes the @option{tls}, 1636 - @option{x509}, and @option{x509verify} options, and as such 1637 - it is not permitted to set both new and old type options at 1638 - the same time. 1639 - 1640 - @item tls 1641 - 1642 - Require that client use TLS when communicating with the VNC server. This 1643 - uses anonymous TLS credentials so is susceptible to a man-in-the-middle 1644 - attack. It is recommended that this option be combined with either the 1645 - @option{x509} or @option{x509verify} options. 1646 - 1647 - This option is now deprecated in favor of using the @option{tls-creds} 1648 - argument. 1649 - 1650 - @item x509=@var{/path/to/certificate/dir} 1651 - 1652 - Valid if @option{tls} is specified. Require that x509 credentials are used 1653 - for negotiating the TLS session. The server will send its x509 certificate 1654 - to the client. It is recommended that a password be set on the VNC server 1655 - to provide authentication of the client when this is used. The path following 1656 - this option specifies where the x509 certificates are to be loaded from. 1657 - See the @ref{vnc_security} section for details on generating certificates. 1658 - 1659 - This option is now deprecated in favour of using the @option{tls-creds} 1660 - argument. 1661 - 1662 - @item x509verify=@var{/path/to/certificate/dir} 1663 - 1664 - Valid if @option{tls} is specified. Require that x509 credentials are used 1665 - for negotiating the TLS session. The server will send its x509 certificate 1666 - to the client, and request that the client send its own x509 certificate. 1667 - The server will validate the client's certificate against the CA certificate, 1668 - and reject clients when validation fails. If the certificate authority is 1669 - trusted, this is a sufficient authentication mechanism. You may still wish 1670 - to set a password on the VNC server as a second authentication layer. The 1671 - path following this option specifies where the x509 certificates are to 1672 - be loaded from. See the @ref{vnc_security} section for details on generating 1673 - certificates. 1674 - 1675 - This option is now deprecated in favour of using the @option{tls-creds} 1676 - argument. 1677 - 1678 1635 @item sasl 1679 1636 1680 1637 Require that the client use SASL to authenticate with the VNC server.
+3 -3
ui/console.c
··· 2319 2319 2320 2320 for (i = 0; i < ARRAY_SIZE(prio); i++) { 2321 2321 if (dpys[prio[i]] == NULL) { 2322 - ui_module_load_one(DisplayType_lookup.array[prio[i]]); 2322 + ui_module_load_one(DisplayType_str(prio[i])); 2323 2323 } 2324 2324 if (dpys[prio[i]] == NULL) { 2325 2325 continue; ··· 2337 2337 return; 2338 2338 } 2339 2339 if (dpys[opts->type] == NULL) { 2340 - ui_module_load_one(DisplayType_lookup.array[opts->type]); 2340 + ui_module_load_one(DisplayType_str(opts->type)); 2341 2341 } 2342 2342 if (dpys[opts->type] == NULL) { 2343 2343 error_report("Display '%s' is not available.", 2344 - DisplayType_lookup.array[opts->type]); 2344 + DisplayType_str(opts->type)); 2345 2345 exit(1); 2346 2346 } 2347 2347 if (dpys[opts->type]->early_init) {
+2 -49
ui/egl-helpers.c
··· 15 15 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 #include "qemu/osdep.h" 18 - #include <glob.h> 19 - #include <dirent.h> 20 - 18 + #include "qemu/drm.h" 21 19 #include "qemu/error-report.h" 22 20 #include "ui/console.h" 23 21 #include "ui/egl-helpers.h" ··· 147 145 struct gbm_device *qemu_egl_rn_gbm_dev; 148 146 EGLContext qemu_egl_rn_ctx; 149 147 150 - static int qemu_egl_rendernode_open(const char *rendernode) 151 - { 152 - DIR *dir; 153 - struct dirent *e; 154 - int r, fd; 155 - char *p; 156 - 157 - if (rendernode) { 158 - return open(rendernode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 159 - } 160 - 161 - dir = opendir("/dev/dri"); 162 - if (!dir) { 163 - return -1; 164 - } 165 - 166 - fd = -1; 167 - while ((e = readdir(dir))) { 168 - if (e->d_type != DT_CHR) { 169 - continue; 170 - } 171 - 172 - if (strncmp(e->d_name, "renderD", 7)) { 173 - continue; 174 - } 175 - 176 - p = g_strdup_printf("/dev/dri/%s", e->d_name); 177 - 178 - r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 179 - if (r < 0) { 180 - g_free(p); 181 - continue; 182 - } 183 - fd = r; 184 - g_free(p); 185 - break; 186 - } 187 - 188 - closedir(dir); 189 - if (fd < 0) { 190 - return -1; 191 - } 192 - return fd; 193 - } 194 - 195 148 int egl_rendernode_init(const char *rendernode, DisplayGLMode mode) 196 149 { 197 150 qemu_egl_rn_fd = -1; 198 151 int rc; 199 152 200 - qemu_egl_rn_fd = qemu_egl_rendernode_open(rendernode); 153 + qemu_egl_rn_fd = qemu_drm_rendernode_open(rendernode); 201 154 if (qemu_egl_rn_fd == -1) { 202 155 error_report("egl: no drm render node available"); 203 156 goto err;
+5
ui/sdl2-gl.c
··· 124 124 { 125 125 assert(scon->opengl); 126 126 127 + if (scon->scanout_mode) { 128 + /* sdl2_gl_scanout_flush actually only care about 129 + * the first argument. */ 130 + return sdl2_gl_scanout_flush(&scon->dcl, 0, 0, 0, 0); 131 + } 127 132 if (scon->surface) { 128 133 sdl2_gl_render_surface(scon); 129 134 }
+5 -8
ui/sdl2.c
··· 761 761 762 762 static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) 763 763 { 764 - int flags; 765 764 uint8_t data = 0; 766 765 char *filename; 767 766 int i; ··· 782 781 setenv("SDL_VIDEODRIVER", "x11", 0); 783 782 #endif 784 783 785 - flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; 786 - if (SDL_Init(flags)) { 784 + if (SDL_Init(SDL_INIT_VIDEO)) { 787 785 fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", 788 786 SDL_GetError()); 789 787 exit(1); ··· 791 789 SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); 792 790 memset(&info, 0, sizeof(info)); 793 791 SDL_VERSION(&info.version); 792 + 793 + gui_fullscreen = o->has_full_screen && o->full_screen; 794 794 795 795 for (i = 0;; i++) { 796 796 QemuConsole *con = qemu_console_lookup_by_index(i); ··· 844 844 g_free(filename); 845 845 } 846 846 847 - if (sdl2_console->opts->has_full_screen && 848 - sdl2_console->opts->full_screen) { 849 - gui_fullscreen = 1; 847 + gui_grab = 0; 848 + if (gui_fullscreen) { 850 849 sdl_grab_start(0); 851 850 } 852 851 853 852 mouse_mode_notifier.notify = sdl_mouse_mode_change; 854 853 qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier); 855 - 856 - gui_grab = 0; 857 854 858 855 sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); 859 856 sdl_cursor_normal = SDL_GetCursor();
+28 -14
ui/spice-display.c
··· 450 450 qemu_mutex_unlock(&ssd->lock); 451 451 } 452 452 453 - static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) 453 + void qemu_spice_cursor_refresh_bh(void *opaque) 454 454 { 455 + SimpleSpiceDisplay *ssd = opaque; 456 + 457 + qemu_mutex_lock(&ssd->lock); 455 458 if (ssd->cursor) { 459 + QEMUCursor *c = ssd->cursor; 456 460 assert(ssd->dcl.con); 457 - dpy_cursor_define(ssd->dcl.con, ssd->cursor); 461 + cursor_get(c); 462 + qemu_mutex_unlock(&ssd->lock); 463 + dpy_cursor_define(ssd->dcl.con, c); 464 + qemu_mutex_lock(&ssd->lock); 465 + cursor_put(c); 458 466 } 467 + 459 468 if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { 469 + int x, y; 460 470 assert(ssd->dcl.con); 461 - dpy_mouse_set(ssd->dcl.con, ssd->mouse_x, ssd->mouse_y, 1); 471 + x = ssd->mouse_x; 472 + y = ssd->mouse_y; 462 473 ssd->mouse_x = -1; 463 474 ssd->mouse_y = -1; 475 + qemu_mutex_unlock(&ssd->lock); 476 + dpy_mouse_set(ssd->dcl.con, x, y, 1); 477 + } else { 478 + qemu_mutex_unlock(&ssd->lock); 464 479 } 465 - } 466 - 467 - void qemu_spice_cursor_refresh_bh(void *opaque) 468 - { 469 - SimpleSpiceDisplay *ssd = opaque; 470 - 471 - qemu_mutex_lock(&ssd->lock); 472 - qemu_spice_cursor_refresh_unlocked(ssd); 473 - qemu_mutex_unlock(&ssd->lock); 474 480 } 475 481 476 482 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) ··· 976 982 { 977 983 SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); 978 984 985 + qemu_mutex_lock(&ssd->lock); 979 986 ssd->ptr_x = pos_x; 980 987 ssd->ptr_y = pos_y; 988 + qemu_mutex_unlock(&ssd->lock); 981 989 } 982 990 983 991 static void qemu_spice_gl_release_dmabuf(DisplayChangeListener *dcl, ··· 1048 1056 /* note: spice server will close the fd, so hand over a dup */ 1049 1057 spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd), 1050 1058 dmabuf->width, dmabuf->height, 1051 - dmabuf->stride, dmabuf->fourcc, false); 1059 + dmabuf->stride, dmabuf->fourcc, 1060 + dmabuf->y0_top); 1052 1061 } 1053 1062 qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height); 1054 1063 ssd->guest_dmabuf_refresh = false; 1055 1064 } 1056 1065 1057 1066 if (render_cursor) { 1067 + int x, y; 1068 + qemu_mutex_lock(&ssd->lock); 1069 + x = ssd->ptr_x; 1070 + y = ssd->ptr_y; 1071 + qemu_mutex_unlock(&ssd->lock); 1058 1072 egl_texture_blit(ssd->gls, &ssd->blit_fb, &ssd->guest_fb, 1059 1073 !y_0_top); 1060 1074 egl_texture_blend(ssd->gls, &ssd->blit_fb, &ssd->cursor_fb, 1061 - !y_0_top, ssd->ptr_x, ssd->ptr_y); 1075 + !y_0_top, x, y); 1062 1076 glFlush(); 1063 1077 } 1064 1078
+1 -1
ui/vnc-enc-tight.c
··· 979 979 } 980 980 #endif 981 981 982 - bytes = (DIV_ROUND_UP(w, 8)) * h; 982 + bytes = DIV_ROUND_UP(w, 8) * h; 983 983 984 984 vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); 985 985 vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
+2 -1
ui/vnc-jobs.c
··· 193 193 194 194 static void vnc_async_encoding_end(VncState *orig, VncState *local) 195 195 { 196 + buffer_free(&local->output); 196 197 orig->tight = local->tight; 197 198 orig->zlib = local->zlib; 198 199 orig->hextile = local->hextile; ··· 278 279 /* Copy persistent encoding data */ 279 280 vnc_async_encoding_end(job->vs, &vs); 280 281 281 - qemu_bh_schedule(job->vs->bh); 282 + qemu_bh_schedule(job->vs->bh); 282 283 } else { 283 284 buffer_reset(&vs.output); 284 285 /* Copy persistent encoding data */
+2 -92
ui/vnc.c
··· 2967 2967 PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb)); 2968 2968 guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb); 2969 2969 guest_stride = pixman_image_get_stride(vd->guest.fb); 2970 - guest_ll = pixman_image_get_width(vd->guest.fb) * (DIV_ROUND_UP(guest_bpp, 8)); 2970 + guest_ll = pixman_image_get_width(vd->guest.fb) 2971 + * DIV_ROUND_UP(guest_bpp, 8); 2971 2972 } 2972 2973 line_bytes = MIN(server_stride, guest_ll); 2973 2974 ··· 3345 3346 .name = "tls-creds", 3346 3347 .type = QEMU_OPT_STRING, 3347 3348 },{ 3348 - /* Deprecated in favour of tls-creds */ 3349 - .name = "x509", 3350 - .type = QEMU_OPT_STRING, 3351 - },{ 3352 3349 .name = "share", 3353 3350 .type = QEMU_OPT_STRING, 3354 3351 },{ ··· 3384 3381 },{ 3385 3382 .name = "sasl", 3386 3383 .type = QEMU_OPT_BOOL, 3387 - },{ 3388 - /* Deprecated in favour of tls-creds */ 3389 - .name = "tls", 3390 - .type = QEMU_OPT_BOOL, 3391 - },{ 3392 - /* Deprecated in favour of tls-creds */ 3393 - .name = "x509verify", 3394 - .type = QEMU_OPT_STRING, 3395 3384 },{ 3396 3385 .name = "acl", 3397 3386 .type = QEMU_OPT_BOOL, ··· 3519 3508 } 3520 3509 3521 3510 3522 - /* 3523 - * Handle back compat with old CLI syntax by creating some 3524 - * suitable QCryptoTLSCreds objects 3525 - */ 3526 - static QCryptoTLSCreds * 3527 - vnc_display_create_creds(bool x509, 3528 - bool x509verify, 3529 - const char *dir, 3530 - const char *id, 3531 - Error **errp) 3532 - { 3533 - gchar *credsid = g_strdup_printf("tlsvnc%s", id); 3534 - Object *parent = object_get_objects_root(); 3535 - Object *creds; 3536 - Error *err = NULL; 3537 - 3538 - if (x509) { 3539 - creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_X509, 3540 - parent, 3541 - credsid, 3542 - &err, 3543 - "endpoint", "server", 3544 - "dir", dir, 3545 - "verify-peer", x509verify ? "yes" : "no", 3546 - NULL); 3547 - } else { 3548 - creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON, 3549 - parent, 3550 - credsid, 3551 - &err, 3552 - "endpoint", "server", 3553 - NULL); 3554 - } 3555 - 3556 - g_free(credsid); 3557 - 3558 - if (err) { 3559 - error_propagate(errp, err); 3560 - return NULL; 3561 - } 3562 - 3563 - return QCRYPTO_TLS_CREDS(creds); 3564 - } 3565 - 3566 - 3567 3511 static int vnc_display_get_address(const char *addrstr, 3568 3512 bool websocket, 3569 3513 bool reverse, ··· 3930 3874 credid = qemu_opt_get(opts, "tls-creds"); 3931 3875 if (credid) { 3932 3876 Object *creds; 3933 - if (qemu_opt_get(opts, "tls") || 3934 - qemu_opt_get(opts, "x509") || 3935 - qemu_opt_get(opts, "x509verify")) { 3936 - error_setg(errp, 3937 - "'tls-creds' parameter is mutually exclusive with " 3938 - "'tls', 'x509' and 'x509verify' parameters"); 3939 - goto fail; 3940 - } 3941 - 3942 3877 creds = object_resolve_path_component( 3943 3878 object_get_objects_root(), credid); 3944 3879 if (!creds) { ··· 3960 3895 error_setg(errp, 3961 3896 "Expecting TLS credentials with a server endpoint"); 3962 3897 goto fail; 3963 - } 3964 - } else { 3965 - const char *path; 3966 - bool tls = false, x509 = false, x509verify = false; 3967 - tls = qemu_opt_get_bool(opts, "tls", false); 3968 - if (tls) { 3969 - path = qemu_opt_get(opts, "x509"); 3970 - 3971 - if (path) { 3972 - x509 = true; 3973 - } else { 3974 - path = qemu_opt_get(opts, "x509verify"); 3975 - if (path) { 3976 - x509 = true; 3977 - x509verify = true; 3978 - } 3979 - } 3980 - vd->tlscreds = vnc_display_create_creds(x509, 3981 - x509verify, 3982 - path, 3983 - vd->id, 3984 - errp); 3985 - if (!vd->tlscreds) { 3986 - goto fail; 3987 - } 3988 3898 } 3989 3899 } 3990 3900 acl = qemu_opt_get_bool(opts, "acl", false);
+1
util/Makefile.objs
··· 50 50 util-obj-y += systemd.o 51 51 util-obj-y += iova-tree.o 52 52 util-obj-$(CONFIG_LINUX) += vfio-helpers.o 53 + util-obj-$(CONFIG_OPENGL) += drm.o
+66
util/drm.c
··· 1 + /* 2 + * Copyright (C) 2015-2016 Gerd Hoffmann <kraxel@redhat.com> 3 + * 4 + * This library is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU Lesser General Public 6 + * License as published by the Free Software Foundation; either 7 + * version 2.1 of the License, or (at your option) any later version. 8 + * 9 + * This library is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 + * Lesser General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU Lesser General Public 15 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + #include "qemu/osdep.h" 18 + #include "qemu/drm.h" 19 + 20 + #include <glob.h> 21 + #include <dirent.h> 22 + 23 + int qemu_drm_rendernode_open(const char *rendernode) 24 + { 25 + DIR *dir; 26 + struct dirent *e; 27 + int r, fd; 28 + char *p; 29 + 30 + if (rendernode) { 31 + return open(rendernode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 32 + } 33 + 34 + dir = opendir("/dev/dri"); 35 + if (!dir) { 36 + return -1; 37 + } 38 + 39 + fd = -1; 40 + while ((e = readdir(dir))) { 41 + if (e->d_type != DT_CHR) { 42 + continue; 43 + } 44 + 45 + if (strncmp(e->d_name, "renderD", 7)) { 46 + continue; 47 + } 48 + 49 + p = g_strdup_printf("/dev/dri/%s", e->d_name); 50 + 51 + r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 52 + if (r < 0) { 53 + g_free(p); 54 + continue; 55 + } 56 + fd = r; 57 + g_free(p); 58 + break; 59 + } 60 + 61 + closedir(dir); 62 + if (fd < 0) { 63 + return -1; 64 + } 65 + return fd; 66 + }