ui/console: default vc encoding to cp437 for machine < 11.1
Add a QOM "encoding" enum property to some chardev-vc backends (console-vc & dbus - gtk and spice don't make use of it) so that the machine compat mechanism can override the default. For machine versions prior to 11.1, the charset defaults to cp437 (raw 8-bit VGA) instead of utf8, preserving the historical behaviour. The following commits are going to wire this to VT100 emulation code and an extra exported D-Bus property. Note that GTK libvte uses utf8 unconditionally, and Spice doesn't have a way to set the encoding, and typically just use libvte in client too. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Marc-André Lureau committed
Apr 23, 2026 at 15:41 UTC
0b1f0367533eb2dc91688f45f18e7da7890aed88
4 files changed
+80
-1
hw/core/machine.c
+3
-1
@@ -39,7 +39,9 @@
39
#include "hw/acpi/generic_event_device.h"
40
#include "qemu/audio.h"
41
42
-GlobalProperty hw_compat_11_0[] = {};
42
+GlobalProperty hw_compat_11_0[] = {
43
+ { "chardev-vc", "encoding", "cp437" },
44
+};
45
const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0);
46
47
GlobalProperty hw_compat_10_2[] = {
include/chardev/char.h
+19
@@ -332,4 +332,23 @@ void resume_mux_open(void);
332
char *qemu_chr_get_pty_name(Chardev *chr);
333
char *qemu_chr_get_filename(Chardev *chr);
334
335
+#define CHARDEV_VC_ENCODING_PROPERTY_DEFINE(cast_func) \
336
+static int get_encoding(Object *obj, Error **errp) \
337
+{ \
338
+ return cast_func(obj)->encoding; \
339
+} \
340
+ \
341
+static void set_encoding(Object *obj, int value, Error **errp) \
342
+{ \
343
+ cast_func(obj)->encoding = value; \
344
+}
345
+
346
+static inline void chardev_vc_add_encoding_prop(ObjectClass *oc,
347
+ int (*get)(Object *, Error **),
348
+ void (*set)(Object *, int, Error **))
349
+{
350
+ object_class_property_add_enum(oc, "encoding", "ChardevVCEncoding",
351
+ &ChardevVCEncoding_lookup, get, set);
352
+}
353
+
354
#endif
ui/console-vc.c
+18
@@ -9,6 +9,7 @@
9
#include "qemu/fifo8.h"
10
#include "qemu/option.h"
11
#include "qemu/queue.h"
12
+#include "qom/compat-properties.h"
13
#include "ui/console.h"
14
#include "ui/vgafont.h"
15
@@ -109,6 +110,7 @@ struct VCChardev {
110
TextAttributes t_attrib; /* currently active text attributes */
111
TextAttributes t_attrib_saved;
112
int x_saved, y_saved;
113
+ ChardevVCEncoding encoding;
114
};
115
typedef struct VCChardev VCChardev;
116
@@ -1189,6 +1191,9 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
1191
1192
s->chr = chr;
1193
drv->console = s;
1194
+ if (vc->has_encoding) {
1195
+ drv->encoding = vc->encoding;
1196
+ }
1197
1198
/* set current text attributes to default */
1199
drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
@@ -1253,6 +1258,8 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
1258
}
1259
}
1260
1261
+CHARDEV_VC_ENCODING_PROPERTY_DEFINE(VC_CHARDEV)
1262
+
1263
static void char_vc_class_init(ObjectClass *oc, const void *data)
1264
{
1265
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1264,12 +1271,23 @@ static void char_vc_class_init(ObjectClass *oc, const void *data)
1271
cc->chr_set_echo = vc_chr_set_echo;
1272
cc->supports_size_opts = true;
1273
cc->supports_encoding_opts = true;
1274
+
1275
+ chardev_vc_add_encoding_prop(oc, get_encoding, set_encoding);
1276
+}
1277
+
1278
+static void char_vc_init(Object *obj)
1279
+{
1280
+ VCChardev *vc = VC_CHARDEV(obj);
1281
+
1282
+ vc->encoding = CHARDEV_VC_ENCODING_UTF8;
1283
}
1284
1285
static const TypeInfo char_vc_type_info = {
1286
.name = TYPE_CHARDEV_VC,
1287
.parent = TYPE_CHARDEV,
1288
.instance_size = sizeof(VCChardev),
1289
+ .instance_init = char_vc_init,
1290
+ .instance_post_init = object_apply_compat_props,
1291
.class_init = char_vc_class_init,
1292
};
1293
ui/dbus.c
+40
@@ -28,6 +28,7 @@
28
#include "qemu/main-loop.h"
29
#include "qemu/option.h"
30
#include "qom/object_interfaces.h"
31
+#include "qapi-types-char.h"
32
#include "system/system.h"
33
#include "ui/dbus-module.h"
34
#ifdef CONFIG_OPENGL
@@ -455,12 +456,20 @@ dbus_display_class_init(ObjectClass *oc, const void *data)
456
457
#define TYPE_CHARDEV_VC "chardev-vc"
458
459
+typedef struct DBusVCChardev {
460
+ DBusChardev parent;
461
+
462
+ ChardevVCEncoding encoding;
463
+} DBusVCChardev;
464
+
465
typedef struct DBusVCClass {
466
DBusChardevClass parent_class;
467
468
void (*parent_parse)(QemuOpts *opts, ChardevBackend *b, Error **errp);
469
} DBusVCClass;
470
471
+DECLARE_INSTANCE_CHECKER(DBusVCChardev, DBUS_VC_CHARDEV,
472
+ TYPE_CHARDEV_VC)
473
DECLARE_CLASS_CHECKERS(DBusVCClass, DBUS_VC,
474
TYPE_CHARDEV_VC)
475
@@ -500,6 +509,23 @@ dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend,
509
}
510
}
511
512
+CHARDEV_VC_ENCODING_PROPERTY_DEFINE(DBUS_VC_CHARDEV)
513
+
514
+static bool
515
+dbus_vc_open(Chardev *chr, ChardevBackend *backend, Error **errp)
516
+{
517
+ DBusVCChardev *vc = DBUS_VC_CHARDEV(chr);
518
+ ChardevClass *parent =
519
+ CHARDEV_CLASS(object_class_by_name(TYPE_CHARDEV_DBUS));
520
+ ChardevDBus *be = backend->u.dbus.data;
521
+
522
+ if (be->has_encoding) {
523
+ vc->encoding = be->encoding;
524
+ }
525
+
526
+ return parent->chr_open(chr, backend, errp);
527
+}
528
+
529
static void
530
dbus_vc_class_init(ObjectClass *oc, const void *data)
531
{
@@ -508,12 +534,26 @@ dbus_vc_class_init(ObjectClass *oc, const void *data)
534
535
klass->parent_parse = cc->chr_parse;
536
cc->chr_parse = dbus_vc_parse;
537
+ cc->chr_open = dbus_vc_open;
538
cc->supports_encoding_opts = true;
539
+
540
+ chardev_vc_add_encoding_prop(oc, get_encoding, set_encoding);
541
+}
542
+
543
+static void
544
+dbus_vc_init(Object *obj)
545
+{
546
+ DBusVCChardev *vc = DBUS_VC_CHARDEV(obj);
547
+
548
+ vc->encoding = CHARDEV_VC_ENCODING_UTF8;
549
}
550
551
static const TypeInfo dbus_vc_type_info = {
552
.name = TYPE_CHARDEV_VC,
553
.parent = TYPE_CHARDEV_DBUS,
554
+ .instance_size = sizeof(DBusVCChardev),
555
+ .instance_init = dbus_vc_init,
556
+ .instance_post_init = object_apply_compat_props,
557
.class_size = sizeof(DBusVCClass),
558
.class_init = dbus_vc_class_init,
559
};