master
c 190 lines 6.2 KB
Raw
1 /*
2 * Virtio RTC device core
3 *
4 * Copyright (c) 2026 Kuan-Wei Chiu <visitorckw@gmail.com>
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "qemu/osdep.h"
9 #include "qemu/iov.h"
10 #include "qemu/timer.h"
11 #include "hw/virtio/virtio.h"
12 #include "hw/virtio/virtio-rtc.h"
13 #include "standard-headers/linux/virtio_ids.h"
14 #include "standard-headers/linux/virtio_rtc.h"
15
16 static void virtio_rtc_handle_request(VirtIODevice *vdev, VirtQueue *vq)
17 {
18 VirtQueueElement *elem;
19 struct virtio_rtc_req_head req_head;
20 size_t written;
21
22 while ((elem = virtqueue_pop(vq, sizeof(VirtQueueElement)))) {
23 if (elem->out_num < 1 || elem->in_num < 1) {
24 virtio_error(vdev, "virtio-rtc: request missing in/out buffers");
25 virtqueue_detach_element(vq, elem, 0);
26 g_free(elem);
27 break;
28 }
29
30 if (iov_to_buf(elem->out_sg, elem->out_num, 0, &req_head,
31 sizeof(req_head)) != sizeof(req_head)) {
32 virtio_error(vdev, "virtio-rtc: request header too short");
33 virtqueue_detach_element(vq, elem, 0);
34 g_free(elem);
35 break;
36 }
37
38 written = 0;
39
40 switch (le16_to_cpu(req_head.msg_type)) {
41 case VIRTIO_RTC_REQ_CFG: {
42 struct virtio_rtc_resp_cfg resp = {0};
43 resp.head.status = VIRTIO_RTC_S_OK;
44 resp.num_clocks = cpu_to_le16(1);
45 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
46 sizeof(resp));
47 break;
48 }
49 case VIRTIO_RTC_REQ_CLOCK_CAP: {
50 struct virtio_rtc_req_clock_cap req;
51 struct virtio_rtc_resp_clock_cap resp = {0};
52
53 if (iov_to_buf(elem->out_sg, elem->out_num, 0, &req,
54 sizeof(req)) != sizeof(req)) {
55 resp.head.status = VIRTIO_RTC_S_EINVAL;
56 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
57 sizeof(resp.head));
58 break;
59 }
60
61 if (le16_to_cpu(req.clock_id) != 0) {
62 resp.head.status = VIRTIO_RTC_S_ENODEV;
63 } else {
64 resp.head.status = VIRTIO_RTC_S_OK;
65 resp.type = VIRTIO_RTC_CLOCK_UTC;
66 }
67 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
68 sizeof(resp));
69 break;
70 }
71 case VIRTIO_RTC_REQ_CROSS_CAP: {
72 struct virtio_rtc_req_cross_cap req;
73 struct virtio_rtc_resp_cross_cap resp = {0};
74
75 if (iov_to_buf(elem->out_sg, elem->out_num, 0, &req,
76 sizeof(req)) != sizeof(req)) {
77 resp.head.status = VIRTIO_RTC_S_EINVAL;
78 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
79 sizeof(resp.head));
80 break;
81 }
82
83 if (le16_to_cpu(req.clock_id) != 0) {
84 resp.head.status = VIRTIO_RTC_S_ENODEV;
85 } else {
86 resp.head.status = VIRTIO_RTC_S_OK;
87 }
88 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
89 sizeof(resp));
90 break;
91 }
92 case VIRTIO_RTC_REQ_READ: {
93 struct virtio_rtc_req_read req;
94 struct virtio_rtc_resp_read resp = {0};
95
96 if (iov_to_buf(elem->out_sg, elem->out_num, 0, &req,
97 sizeof(req)) != sizeof(req)) {
98 resp.head.status = VIRTIO_RTC_S_EINVAL;
99 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
100 sizeof(resp.head));
101 break;
102 }
103
104 if (le16_to_cpu(req.clock_id) != 0) {
105 resp.head.status = VIRTIO_RTC_S_ENODEV;
106 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
107 sizeof(resp.head));
108 } else {
109 resp.head.status = VIRTIO_RTC_S_OK;
110 resp.clock_reading =
111 cpu_to_le64(qemu_clock_get_ns(QEMU_CLOCK_HOST));
112 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
113 sizeof(resp));
114 }
115 break;
116 }
117 default: {
118 struct virtio_rtc_resp_head resp = {0};
119 resp.status = VIRTIO_RTC_S_EOPNOTSUPP;
120 written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
121 sizeof(resp));
122 break;
123 }
124 }
125
126 virtqueue_push(vq, elem, written);
127 virtio_notify(vdev, vq);
128 g_free(elem);
129 }
130 }
131
132 static void virtio_rtc_device_realize(DeviceState *dev, Error **errp)
133 {
134 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
135 VirtIORtc *vrtc = VIRTIO_RTC(dev);
136
137 virtio_init(vdev, VIRTIO_ID_CLOCK, 0);
138 vrtc->vq = virtio_add_queue(vdev, 64, virtio_rtc_handle_request);
139 }
140
141 static void virtio_rtc_device_unrealize(DeviceState *dev)
142 {
143 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
144 VirtIORtc *vrtc = VIRTIO_RTC(dev);
145
146 virtio_delete_queue(vrtc->vq);
147 virtio_cleanup(vdev);
148 }
149
150 static uint64_t virtio_rtc_get_features(VirtIODevice *vdev, uint64_t f,
151 Error **errp)
152 {
153 return f;
154 }
155
156 static const VMStateDescription vmstate_virtio_rtc = {
157 .name = "virtio-rtc",
158 .minimum_version_id = 1,
159 .version_id = 1,
160 .fields = (const VMStateField[]) {
161 VMSTATE_VIRTIO_DEVICE,
162 VMSTATE_END_OF_LIST()
163 },
164 };
165
166 static void virtio_rtc_class_init(ObjectClass *klass, const void *data)
167 {
168 DeviceClass *dc = DEVICE_CLASS(klass);
169 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
170
171 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
172 vdc->realize = virtio_rtc_device_realize;
173 vdc->unrealize = virtio_rtc_device_unrealize;
174 vdc->get_features = virtio_rtc_get_features;
175 dc->vmsd = &vmstate_virtio_rtc;
176 }
177
178 static const TypeInfo virtio_rtc_info = {
179 .name = TYPE_VIRTIO_RTC,
180 .parent = TYPE_VIRTIO_DEVICE,
181 .instance_size = sizeof(VirtIORtc),
182 .class_init = virtio_rtc_class_init,
183 };
184
185 static void virtio_rtc_register_types(void)
186 {
187 type_register_static(&virtio_rtc_info);
188 }
189
190 type_init(virtio_rtc_register_types)