1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
4 * (C) Copyright 2021 Copyright The Asahi Linux Contributors
11 #include <asm/arch/rtkit.h>
12 #include <linux/apple-mailbox.h>
13 #include <linux/bitfield.h>
15 #define APPLE_RTKIT_EP_MGMT 0
16 #define APPLE_RTKIT_EP_CRASHLOG 1
17 #define APPLE_RTKIT_EP_SYSLOG 2
18 #define APPLE_RTKIT_EP_DEBUG 3
19 #define APPLE_RTKIT_EP_IOREPORT 4
20 #define APPLE_RTKIT_EP_TRACEKIT 10
22 /* Messages for management endpoint. */
23 #define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
25 #define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
27 #define APPLE_RTKIT_MGMT_HELLO 1
28 #define APPLE_RTKIT_MGMT_HELLO_REPLY 2
29 #define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
30 #define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
32 #define APPLE_RTKIT_MGMT_STARTEP 5
33 #define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
34 #define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
36 #define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
37 #define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
39 #define APPLE_RTKIT_MGMT_EPMAP 8
40 #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
41 #define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
42 #define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
44 #define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
45 #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
47 #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
48 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
50 /* Messages for internal endpoints. */
51 #define APPLE_RTKIT_BUFFER_REQUEST 1
52 #define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
53 #define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
55 #define TIMEOUT_1SEC_US 1000000
58 struct mbox_chan *chan;
60 apple_rtkit_shmem_setup shmem_setup;
61 apple_rtkit_shmem_destroy shmem_destroy;
63 struct apple_rtkit_buffer syslog_buffer;
64 struct apple_rtkit_buffer crashlog_buffer;
65 struct apple_rtkit_buffer ioreport_buffer;
68 struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
69 apple_rtkit_shmem_setup shmem_setup,
70 apple_rtkit_shmem_destroy shmem_destroy)
72 struct apple_rtkit *rtk;
74 rtk = calloc(sizeof(*rtk), 1);
80 rtk->shmem_setup = shmem_setup;
81 rtk->shmem_destroy = shmem_destroy;
86 void apple_rtkit_free(struct apple_rtkit *rtk)
88 if (rtk->shmem_destroy) {
89 if (rtk->syslog_buffer.buffer)
90 rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
91 if (rtk->crashlog_buffer.buffer)
92 rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
93 if (rtk->ioreport_buffer.buffer)
94 rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
99 static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
101 struct apple_rtkit_buffer *buf;
105 num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
107 if (num_4kpages == 0) {
108 printf("%s: unexpected request for buffer without size\n", __func__);
113 case APPLE_RTKIT_EP_CRASHLOG:
114 buf = &rtk->crashlog_buffer;
116 case APPLE_RTKIT_EP_SYSLOG:
117 buf = &rtk->syslog_buffer;
119 case APPLE_RTKIT_EP_IOREPORT:
120 buf = &rtk->ioreport_buffer;
123 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
127 buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
128 buf->size = num_4kpages << 12;
129 buf->is_mapped = false;
131 if (rtk->shmem_setup) {
132 ret = rtk->shmem_setup(rtk->cookie, buf);
134 printf("%s: shmen_setup failed for endpoint %d\n", __func__,
140 if (!buf->is_mapped) {
141 msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
142 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
143 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
144 msg->msg1 = endpoint;
146 return mbox_send(rtk->chan, msg);
152 int apple_rtkit_boot(struct apple_rtkit *rtk)
154 struct apple_mbox_msg msg;
158 int min_ver, max_ver, want_ver;
159 int msgtype, pwrstate;
165 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
166 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
167 msg.msg1 = APPLE_RTKIT_EP_MGMT;
168 ret = mbox_send(rtk->chan, &msg);
172 /* Wait for protocol version negotiation message. */
173 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
178 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
179 if (endpoint != APPLE_RTKIT_EP_MGMT) {
180 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
183 if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
184 printf("%s: unexpected message type %d\n", __func__, msgtype);
188 min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
189 max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
190 want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
192 if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
193 printf("%s: firmware min version %d is too new\n",
198 if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
199 printf("%s: firmware max version %d is too old\n",
205 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
206 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
207 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
208 msg.msg1 = APPLE_RTKIT_EP_MGMT;
209 ret = mbox_send(rtk->chan, &msg);
214 /* Wait for endpoint map message. */
215 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
220 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
221 if (endpoint != APPLE_RTKIT_EP_MGMT) {
222 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
225 if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
226 printf("%s: unexpected message type %d\n", __func__, msgtype);
230 bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
231 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
232 for (i = 0; i < 32; i++) {
233 if (bitmap & (1U << i))
234 endpoints[nendpoints++] = base * 32 + i;
237 /* Ack endpoint map. */
238 reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
239 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
240 if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
241 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
243 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
245 msg.msg1 = APPLE_RTKIT_EP_MGMT;
246 ret = mbox_send(rtk->chan, &msg);
250 if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
253 for (i = 0; i < nendpoints; i++) {
254 /* Start only necessary endpoints. The syslog endpoint is
255 * particularly noisy and its message can't easily be handled
258 switch (endpoints[i]) {
259 case APPLE_RTKIT_EP_MGMT:
260 case APPLE_RTKIT_EP_SYSLOG:
261 case APPLE_RTKIT_EP_DEBUG:
262 case APPLE_RTKIT_EP_TRACEKIT:
268 /* Request endpoint. */
269 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
270 FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
271 APPLE_RTKIT_MGMT_STARTEP_FLAG;
272 msg.msg1 = APPLE_RTKIT_EP_MGMT;
273 ret = mbox_send(rtk->chan, &msg);
278 pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP;
279 while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) {
280 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
285 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
287 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
288 endpoint == APPLE_RTKIT_EP_SYSLOG ||
289 endpoint == APPLE_RTKIT_EP_IOREPORT) {
290 if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
291 ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
298 if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
299 // these two messages have to be ack-ed for proper startup
300 if (msgtype == 0xc || msgtype == 0x8) {
301 ret = mbox_send(rtk->chan, &msg);
308 if (endpoint != APPLE_RTKIT_EP_MGMT) {
309 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
312 if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) {
313 printf("%s: unexpected message type %d\n", __func__, msgtype);
317 pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
323 int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
325 struct apple_mbox_msg msg;
328 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
329 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
330 msg.msg1 = APPLE_RTKIT_EP_MGMT;
331 ret = mbox_send(rtk->chan, &msg);
335 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);