chardev related patches

-----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmM1evIcHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5evvD/49HQuMxsHaTvXSLPxi
 Bkv9W8cHSEOuAVsgizrd3Z/AEx8MMsZLprtGttYpQN4041aBbyDG7PR1PirVibe7
 s5uuqq2LB85dCkrPyiTkfGosbnndDy+VH9ZH+vS6CMKHYRSwpRjYUoKt5e75JhtP
 RefwFihkVyr3HbsD6SKjB8lV25yw2tQB6BizTedaNmM6ZSmX/TRtes1JgeK3l5jD
 7hQVqqEAJ6YvZnpg070Om43sae7j0yoW7Dg45DVViQNJeRG/0rwBKAbUZuLzs9lH
 hMjqlUW+It7Q7DvkkoLO6DiBsIceeZneZ3XHnv0/OrXDILS2ZWRnm2+qKJp75fub
 TXFafZX3RIn8ZL6Lw4uz/tsX5CllzuiT/2EO2/CzFIaGESi8Y5eFL3xku7tDWzq8
 EtsAehQeHOvNU/mw8Z1hPEozcPMFUY9eUPF7vPRHPV+g+YI+UlrZCFGcJaZpspeP
 h3rUXInftMHHocr/LvI9DMEzgHjOZrDqjECSavp1nHrGbRLfBl/1QNPql1cZJ+H/
 XDygo1x/QVlEkTaBWqcMFifgqJ7xvHPDQd6rvIbBYwUUWU1B79UKON0i6WOMk7A6
 vjsJz7Sk+cJMOMwc76w+qd0mRauWkcfiS08Y4g+4HksymZev5OeGNuuDfI6zwfFt
 T21TIS/c0zmcNU1sgXB6U2VTiw==
 =pMT6
 -----END PGP SIGNATURE-----

Merge tag 'char-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging

chardev related patches

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmM1evIcHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5evvD/49HQuMxsHaTvXSLPxi
# Bkv9W8cHSEOuAVsgizrd3Z/AEx8MMsZLprtGttYpQN4041aBbyDG7PR1PirVibe7
# s5uuqq2LB85dCkrPyiTkfGosbnndDy+VH9ZH+vS6CMKHYRSwpRjYUoKt5e75JhtP
# RefwFihkVyr3HbsD6SKjB8lV25yw2tQB6BizTedaNmM6ZSmX/TRtes1JgeK3l5jD
# 7hQVqqEAJ6YvZnpg070Om43sae7j0yoW7Dg45DVViQNJeRG/0rwBKAbUZuLzs9lH
# hMjqlUW+It7Q7DvkkoLO6DiBsIceeZneZ3XHnv0/OrXDILS2ZWRnm2+qKJp75fub
# TXFafZX3RIn8ZL6Lw4uz/tsX5CllzuiT/2EO2/CzFIaGESi8Y5eFL3xku7tDWzq8
# EtsAehQeHOvNU/mw8Z1hPEozcPMFUY9eUPF7vPRHPV+g+YI+UlrZCFGcJaZpspeP
# h3rUXInftMHHocr/LvI9DMEzgHjOZrDqjECSavp1nHrGbRLfBl/1QNPql1cZJ+H/
# XDygo1x/QVlEkTaBWqcMFifgqJ7xvHPDQd6rvIbBYwUUWU1B79UKON0i6WOMk7A6
# vjsJz7Sk+cJMOMwc76w+qd0mRauWkcfiS08Y4g+4HksymZev5OeGNuuDfI6zwfFt
# T21TIS/c0zmcNU1sgXB6U2VTiw==
# =pMT6
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 29 Sep 2022 07:01:06 EDT
# gpg:                using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg:                issuer "marcandre.lureau@redhat.com"
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg:                 aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276  F62D DAE8 E109 7596 9CE5

* tag 'char-pull-request' of https://gitlab.com/marcandre.lureau/qemu:
  vhost-user: Call qemu_socketpair() instead of socketpair()
  oslib-posix: Introduce qemu_socketpair()
  chardev: fix segfault in finalize
  serial: Allow unaligned i/o access
  msmouse: Add pnp data
  msmouse: Use fifo8 instead of array
  chardev: src buffer const for write functions
  msmouse: Handle mouse reset

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-09-29 14:12:00 -04:00
commit 539cb0876b
12 changed files with 179 additions and 36 deletions

View File

@ -193,7 +193,7 @@ int qemu_chr_be_can_write(Chardev *s)
return be->chr_can_read(be->opaque);
}
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
void qemu_chr_be_write_impl(Chardev *s, const uint8_t *buf, int len)
{
CharBackend *be = s->be;
@ -202,7 +202,7 @@ void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
}
}
void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
void qemu_chr_be_write(Chardev *s, const uint8_t *buf, int len)
{
if (qemu_chr_replay(s)) {
if (replay_mode == REPLAY_MODE_PLAY) {

View File

@ -24,23 +24,45 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/fifo8.h"
#include "chardev/char.h"
#include "chardev/char-serial.h"
#include "ui/console.h"
#include "ui/input.h"
#include "qom/object.h"
#define MSMOUSE_LO6(n) ((n) & 0x3f)
#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
#define MSMOUSE_PWR(cm) (cm & (CHR_TIOCM_RTS | CHR_TIOCM_DTR))
/* Serial PnP for 6 bit devices/mice sends all ASCII chars - 0x20 */
#define M(c) (c - 0x20)
/* Serial fifo size. */
#define MSMOUSE_BUF_SZ 64
/* Mouse ID: Send "M3" cause we behave like a 3 button logitech mouse. */
const uint8_t mouse_id[] = {'M', '3'};
/*
* PnP start "(", PnP version (1.0), vendor ID, product ID, '\\',
* serial ID (omitted), '\\', MS class name, '\\', driver ID (omitted), '\\',
* product description, checksum, ")"
* Missing parts are inserted later.
*/
const uint8_t pnp_data[] = {M('('), 1, '$', M('Q'), M('M'), M('U'),
M('0'), M('0'), M('0'), M('1'),
M('\\'), M('\\'),
M('M'), M('O'), M('U'), M('S'), M('E'),
M('\\'), M('\\')};
struct MouseChardev {
Chardev parent;
QemuInputHandlerState *hs;
int tiocm;
int axis[INPUT_AXIS__MAX];
bool btns[INPUT_BUTTON__MAX];
bool btnc[INPUT_BUTTON__MAX];
uint8_t outbuf[32];
int outlen;
Fifo8 outbuf;
};
typedef struct MouseChardev MouseChardev;
@ -51,20 +73,18 @@ DECLARE_INSTANCE_CHECKER(MouseChardev, MOUSE_CHARDEV,
static void msmouse_chr_accept_input(Chardev *chr)
{
MouseChardev *mouse = MOUSE_CHARDEV(chr);
int len;
uint32_t len, avail;
len = qemu_chr_be_can_write(chr);
if (len > mouse->outlen) {
len = mouse->outlen;
}
if (!len) {
return;
}
avail = fifo8_num_used(&mouse->outbuf);
while (len > 0 && avail > 0) {
const uint8_t *buf;
uint32_t size;
qemu_chr_be_write(chr, mouse->outbuf, len);
mouse->outlen -= len;
if (mouse->outlen) {
memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen);
buf = fifo8_pop_buf(&mouse->outbuf, MIN(len, avail), &size);
qemu_chr_be_write(chr, buf, size);
len = qemu_chr_be_can_write(chr);
avail -= size;
}
}
@ -91,12 +111,11 @@ static void msmouse_queue_event(MouseChardev *mouse)
mouse->btnc[INPUT_BUTTON_MIDDLE]) {
bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00);
mouse->btnc[INPUT_BUTTON_MIDDLE] = false;
count = 4;
count++;
}
if (mouse->outlen <= sizeof(mouse->outbuf) - count) {
memcpy(mouse->outbuf + mouse->outlen, bytes, count);
mouse->outlen += count;
if (fifo8_num_free(&mouse->outbuf) >= count) {
fifo8_push_all(&mouse->outbuf, bytes, count);
} else {
/* queue full -> drop event */
}
@ -109,6 +128,11 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
InputMoveEvent *move;
InputBtnEvent *btn;
/* Ignore events if serial mouse powered down. */
if (!MSMOUSE_PWR(mouse->tiocm)) {
return;
}
switch (evt->type) {
case INPUT_EVENT_KIND_REL:
move = evt->u.rel.data;
@ -132,6 +156,11 @@ static void msmouse_input_sync(DeviceState *dev)
MouseChardev *mouse = MOUSE_CHARDEV(dev);
Chardev *chr = CHARDEV(dev);
/* Ignore events if serial mouse powered down. */
if (!MSMOUSE_PWR(mouse->tiocm)) {
return;
}
msmouse_queue_event(mouse);
msmouse_chr_accept_input(chr);
}
@ -142,13 +171,6 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
return len;
}
static void char_msmouse_finalize(Object *obj)
{
MouseChardev *mouse = MOUSE_CHARDEV(obj);
qemu_input_handler_unregister(mouse->hs);
}
static QemuInputHandler msmouse_handler = {
.name = "QEMU Microsoft Mouse",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
@ -156,6 +178,81 @@ static QemuInputHandler msmouse_handler = {
.sync = msmouse_input_sync,
};
static int msmouse_ioctl(Chardev *chr, int cmd, void *arg)
{
MouseChardev *mouse = MOUSE_CHARDEV(chr);
int c, i, j;
uint8_t bytes[MSMOUSE_BUF_SZ / 2];
int *targ = (int *)arg;
const uint8_t hexchr[16] = {M('0'), M('1'), M('2'), M('3'), M('4'), M('5'),
M('6'), M('7'), M('8'), M('9'), M('A'), M('B'),
M('C'), M('D'), M('E'), M('F')};
switch (cmd) {
case CHR_IOCTL_SERIAL_SET_TIOCM:
c = mouse->tiocm;
mouse->tiocm = *(int *)arg;
if (MSMOUSE_PWR(mouse->tiocm)) {
if (!MSMOUSE_PWR(c)) {
/*
* Power on after reset: Send ID and PnP data
* No need to check fifo space as it is empty at this point.
*/
fifo8_push_all(&mouse->outbuf, mouse_id, sizeof(mouse_id));
/* Add PnP data: */
fifo8_push_all(&mouse->outbuf, pnp_data, sizeof(pnp_data));
/*
* Add device description from qemu handler name.
* Make sure this all fits into the queue beforehand!
*/
c = M(')');
for (i = 0; msmouse_handler.name[i]; i++) {
bytes[i] = M(msmouse_handler.name[i]);
c += bytes[i];
}
/* Calc more of checksum */
for (j = 0; j < sizeof(pnp_data); j++) {
c += pnp_data[j];
}
c &= 0xff;
bytes[i++] = hexchr[c >> 4];
bytes[i++] = hexchr[c & 0x0f];
bytes[i++] = M(')');
fifo8_push_all(&mouse->outbuf, bytes, i);
/* Start sending data to serial. */
msmouse_chr_accept_input(chr);
}
break;
}
/*
* Reset mouse buffers on power down.
* Mouse won't send anything without power.
*/
fifo8_reset(&mouse->outbuf);
memset(mouse->axis, 0, sizeof(mouse->axis));
memset(mouse->btns, false, sizeof(mouse->btns));
memset(mouse->btnc, false, sizeof(mouse->btns));
break;
case CHR_IOCTL_SERIAL_GET_TIOCM:
/* Remember line control status. */
*targ = mouse->tiocm;
break;
default:
return -ENOTSUP;
}
return 0;
}
static void char_msmouse_finalize(Object *obj)
{
MouseChardev *mouse = MOUSE_CHARDEV(obj);
if (mouse->hs) {
qemu_input_handler_unregister(mouse->hs);
}
fifo8_destroy(&mouse->outbuf);
}
static void msmouse_chr_open(Chardev *chr,
ChardevBackend *backend,
bool *be_opened,
@ -166,6 +263,8 @@ static void msmouse_chr_open(Chardev *chr,
*be_opened = false;
mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
&msmouse_handler);
mouse->tiocm = 0;
fifo8_create(&mouse->outbuf, MSMOUSE_BUF_SZ);
}
static void char_msmouse_class_init(ObjectClass *oc, void *data)
@ -175,6 +274,7 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data)
cc->open = msmouse_chr_open;
cc->chr_write = msmouse_chr_write;
cc->chr_accept_input = msmouse_chr_accept_input;
cc->chr_ioctl = msmouse_ioctl;
}
static const TypeInfo char_msmouse_type_info = {

View File

@ -319,7 +319,9 @@ static void wctablet_chr_finalize(Object *obj)
{
TabletChardev *tablet = WCTABLET_CHARDEV(obj);
if (tablet->hs) {
qemu_input_handler_unregister(tablet->hs);
}
}
static void wctablet_chr_open(Chardev *chr,

View File

@ -961,6 +961,9 @@ void serial_set_frequency(SerialState *s, uint32_t frequency)
const MemoryRegionOps serial_io_ops = {
.read = serial_ioport_read,
.write = serial_ioport_write,
.valid = {
.unaligned = 1,
},
.impl = {
.min_access_size = 1,
.max_access_size = 1,

View File

@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/sockets.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-gpu.h"
#include "chardev/char-fe.h"
@ -375,7 +376,7 @@ vhost_user_gpu_do_set_socket(VhostUserGPU *g, Error **errp)
Chardev *chr;
int sv[2];
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
error_setg_errno(errp, errno, "socketpair() failed");
return false;
}

View File

@ -1726,7 +1726,7 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
return 0;
}
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
int saved_errno = errno;
error_report("socketpair() failed");
return -saved_errno;

View File

@ -186,7 +186,7 @@ int qemu_chr_be_can_write(Chardev *s);
* the caller should call @qemu_chr_be_can_write to determine how much data
* the front end can currently accept.
*/
void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
void qemu_chr_be_write(Chardev *s, const uint8_t *buf, int len);
/**
* qemu_chr_be_write_impl:
@ -195,7 +195,7 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
*
* Implementation of back end writing. Used by replay module.
*/
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len);
void qemu_chr_be_write_impl(Chardev *s, const uint8_t *buf, int len);
/**
* qemu_chr_be_update_read_handlers:

View File

@ -14,6 +14,24 @@ int inet_aton(const char *cp, struct in_addr *ia);
/* misc helpers */
bool fd_is_socket(int fd);
int qemu_socket(int domain, int type, int protocol);
#ifndef WIN32
/**
* qemu_socketpair:
* @domain: specifies a communication domain, such as PF_UNIX
* @type: specifies the socket type.
* @protocol: specifies a particular protocol to be used with the socket
* @sv: an array to store the pair of socket created
*
* Creates an unnamed pair of connected sockets in the specified domain,
* of the specified type, and using the optionally specified protocol.
* And automatically set the close-on-exec flags on the returned sockets
*
* Return 0 on success.
*/
int qemu_socketpair(int domain, int type, int protocol, int sv[2]);
#endif
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int socket_set_cork(int fd, int v);
int socket_set_nodelay(int fd);

View File

@ -198,7 +198,7 @@ uint64_t blkreplay_next_id(void);
/*! Registers char driver to save it's events */
void replay_register_char_driver(struct Chardev *chr);
/*! Saves write to char device event to the log */
void replay_chr_be_write(struct Chardev *s, uint8_t *buf, int len);
void replay_chr_be_write(struct Chardev *s, const uint8_t *buf, int len);
/*! Writes char write return value to the replay log. */
void replay_char_write_event_save(int res, int offset);
/*! Reads char write return value from the replay log. */

View File

@ -48,7 +48,7 @@ void replay_register_char_driver(Chardev *chr)
char_drivers[drivers_count++] = chr;
}
void replay_chr_be_write(Chardev *s, uint8_t *buf, int len)
void replay_chr_be_write(Chardev *s, const uint8_t *buf, int len)
{
CharEvent *event = g_new0(CharEvent, 1);

View File

@ -53,7 +53,7 @@ void replay_register_char_driver(struct Chardev *chr)
{
}
void replay_chr_be_write(struct Chardev *s, uint8_t *buf, int len)
void replay_chr_be_write(struct Chardev *s, const uint8_t *buf, int len)
{
abort();
}

View File

@ -253,6 +253,25 @@ void qemu_set_cloexec(int fd)
assert(f != -1);
}
int qemu_socketpair(int domain, int type, int protocol, int sv[2])
{
int ret;
#ifdef SOCK_CLOEXEC
ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
if (ret != -1 || errno != EINVAL) {
return ret;
}
#endif
ret = socketpair(domain, type, protocol, sv);;
if (ret == 0) {
qemu_set_cloexec(sv[0]);
qemu_set_cloexec(sv[1]);
}
return ret;
}
char *
qemu_get_local_state_dir(void)
{