/* $NetBSD: apple_rtkit.c,v 1.1 2022/04/27 08:06:20 skrll Exp $ */ /* $OpenBSD: rtkit.c,v 1.3 2022/01/10 09:07:28 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #define RTKIT_EP_MGMT 0 #define RTKIT_EP_CRASHLOG 1 #define RTKIT_EP_SYSLOG 2 #define RTKIT_EP_DEBUG 3 #define RTKIT_EP_IOREPORT 4 #define RTKIT_MGMT_TYPE_MASK __BITS(59, 52) #define RTKIT_MGMT_TYPE(x) __SHIFTOUT((x), RTKIT_MGMT_TYPE_MASK) #define RTKIT_MGMT_PWR_STATE_MASK __BITS(7, 0) #define RTKIT_MGMT_PWR_STATE(x) __SHIFTOUT((x), RTKIT_MGMT_PWR_STATE_MASK) #define RTKIT_MGMT_PWR_STATE_ON 0x20 #define RTKIT_MGMT_HELLO 1 #define RTKIT_MGMT_HELLO_ACK 2 #define RTKIT_MGMT_STARTEP 5 #define RTKIT_MGMT_IOP_PWR_STATE 6 #define RTKIT_MGMT_IOP_PWR_STATE_ACK 7 #define RTKIT_MGMT_EPMAP 8 #define RTKIT_MGMT_HELLO_MINVER_MASK __BITS(15, 0) #define RTKIT_MGMT_HELLO_MINVER(x) __SHIFTOUT((x), RTKIT_MGMT_HELLO_MINVER_MASK) #define RTKIT_MGMT_HELLO_MAXVER_MASK __BITS(31, 16) #define RTKIT_MGMT_HELLO_MAXVER(x) __SHIFTOUT((x), RTKIT_MGMT_HELLO_MAXVER_MASK) #define RTKIT_MGMT_STARTEP_EP_SHIFT 32 #define RTKIT_MGMT_STARTEP_EP_MASK __BITS(39, 32) #define RTKIT_MGMT_STARTEP_START __BIT(1) #define RTKIT_MGMT_EPMAP_LAST __BIT(51) #define RTKIT_MGMT_EPMAP_BASE_MASK __BITS(34, 32) #define RTKIT_MGMT_EPMAP_BASE(x) __SHIFTOUT((x), RTKIT_MGMT_EPMAP_BASE_MASK) #define RTKIT_MGMT_EPMAP_BITMAP_MASK __BITS(31, 0) #define RTKIT_MGMT_EPMAP_BITMAP(x) __SHIFTOUT((x), RTKIT_MGMT_EPMAP_BITMAP_MASK) #define RTKIT_MGMT_EPMAP_MORE __BIT(0) #define RTKIT_BUFFER_REQUEST 1 #define RTKIT_BUFFER_ADDR_MASK __BITS(41, 0) #define RTKIT_BUFFER_ADDR(x) __SHIFTOUT((x), RTKIT_BUFFER_ADDR_MASK) #define RTKIT_BUFFER_SIZE_MASK __BITS(51, 44) #define RTKIT_BUFFER_SIZE(x) __SHIFTOUT((x), RTKIT_BUFFER_SIZE_MASK) /* Versions we support. */ #define RTKIT_MINVER 11 #define RTKIT_MAXVER 12 struct rtkit_state { struct fdtbus_mbox_channel *mc; int pwrstate; uint64_t epmap; void (*callback[32])(void *, uint64_t); void *arg[32]; }; static int rtkit_recv(struct fdtbus_mbox_channel *mc, struct apple_mbox_msg *msg) { int error, timo; for (timo = 0; timo < 10000; timo++) { error = fdtbus_mbox_recv(mc, msg, sizeof(*msg)); if (error == 0) break; delay(10); } return error; } static int rtkit_send(struct fdtbus_mbox_channel *mc, uint32_t endpoint, uint64_t type, uint64_t data) { struct apple_mbox_msg msg; msg.data0 = __SHIFTIN(type, RTKIT_MGMT_TYPE_MASK) | data; msg.data1 = endpoint; return fdtbus_mbox_send(mc, &msg, sizeof(msg)); } static int rtkit_start(struct rtkit_state *state, uint32_t endpoint) { struct fdtbus_mbox_channel *mc = state->mc; uint64_t reply; reply = __SHIFTIN(endpoint, RTKIT_MGMT_STARTEP_EP_MASK); reply |= RTKIT_MGMT_STARTEP_START; return rtkit_send(mc, RTKIT_EP_MGMT, RTKIT_MGMT_STARTEP, reply); } static int rtkit_handle_mgmt(struct rtkit_state *state, struct apple_mbox_msg *msg) { struct fdtbus_mbox_channel *mc = state->mc; uint64_t minver, maxver, ver; uint64_t base, bitmap, reply; uint32_t endpoint; int error; switch (RTKIT_MGMT_TYPE(msg->data0)) { case RTKIT_MGMT_HELLO: minver = RTKIT_MGMT_HELLO_MINVER(msg->data0); maxver = RTKIT_MGMT_HELLO_MAXVER(msg->data0); if (minver > RTKIT_MAXVER) { printf("unsupported minimum firmware version " "%"PRId64"\n", minver); return EINVAL; } if (maxver < RTKIT_MINVER) { printf("unsupported maximum firmware version " "%"PRId64"\n", maxver); return EINVAL; } ver = MIN(RTKIT_MAXVER, maxver); error = rtkit_send(mc, RTKIT_EP_MGMT, RTKIT_MGMT_HELLO_ACK, __SHIFTIN(ver, RTKIT_MGMT_HELLO_MINVER_MASK) | __SHIFTIN(ver, RTKIT_MGMT_HELLO_MAXVER_MASK)); if (error) return error; break; case RTKIT_MGMT_IOP_PWR_STATE_ACK: state->pwrstate = RTKIT_MGMT_PWR_STATE(msg->data0); break; case RTKIT_MGMT_EPMAP: base = RTKIT_MGMT_EPMAP_BASE(msg->data0); bitmap = RTKIT_MGMT_EPMAP_BITMAP(msg->data0); state->epmap |= (bitmap << (base * 32)); reply = __SHIFTIN(base, RTKIT_MGMT_EPMAP_BASE_MASK); if (msg->data0 & RTKIT_MGMT_EPMAP_LAST) reply |= RTKIT_MGMT_EPMAP_LAST; else reply |= RTKIT_MGMT_EPMAP_MORE; error = rtkit_send(state->mc, RTKIT_EP_MGMT, RTKIT_MGMT_EPMAP, reply); if (error) return error; if (msg->data0 & RTKIT_MGMT_EPMAP_LAST) { for (endpoint = 1; endpoint < 32; endpoint++) { if ((state->epmap & __BIT(endpoint)) == 0) continue; switch (endpoint) { case RTKIT_EP_CRASHLOG: case RTKIT_EP_DEBUG: case RTKIT_EP_IOREPORT: error = rtkit_start(state, endpoint); if (error) return error; break; } } } break; default: printf("unhandled management event " "0x%016"PRIx64"\n", msg->data0); return EIO; } return 0; } static int rtkit_handle_crashlog(struct rtkit_state *state, struct apple_mbox_msg *msg) { struct fdtbus_mbox_channel *mc = state->mc; bus_addr_t addr; bus_size_t size; int error; switch (RTKIT_MGMT_TYPE(msg->data0)) { case RTKIT_BUFFER_REQUEST: addr = RTKIT_BUFFER_ADDR(msg->data0); size = RTKIT_BUFFER_SIZE(msg->data0); // XXXNH WTF is this conditional if (addr) break; error = rtkit_send(mc, RTKIT_EP_CRASHLOG, RTKIT_BUFFER_REQUEST, __SHIFTIN(size, RTKIT_BUFFER_SIZE_MASK) | addr); if (error) return error; break; default: printf("unhandled crashlog event " "0x%016"PRIx64"\n", msg->data0); return EIO; } return 0; } static int rtkit_handle_ioreport(struct rtkit_state *state, struct apple_mbox_msg *msg) { struct fdtbus_mbox_channel *mc = state->mc; bus_addr_t addr; bus_size_t size; int error; switch (RTKIT_MGMT_TYPE(msg->data0)) { case RTKIT_BUFFER_REQUEST: addr = RTKIT_BUFFER_ADDR(msg->data0); size = RTKIT_BUFFER_SIZE(msg->data0); // XXXNH WTF is this conditional if (addr) break; error = rtkit_send(mc, RTKIT_EP_IOREPORT, RTKIT_BUFFER_REQUEST, __SHIFTIN(size, RTKIT_BUFFER_SIZE_MASK) | addr); if (error) return error; break; default: printf("unhandled ioreport event" "0x%016"PRIx64"\n", msg->data0); return EIO; } return 0; } int rtkit_poll(struct rtkit_state *state) { struct fdtbus_mbox_channel *mc = state->mc; struct apple_mbox_msg msg; void (*callback)(void *, uint64_t); void *arg; uint32_t endpoint; int error; error = rtkit_recv(mc, &msg); if (error) return error; endpoint = msg.data1; switch (endpoint) { case RTKIT_EP_MGMT: error = rtkit_handle_mgmt(state, &msg); if (error) return error; break; case RTKIT_EP_CRASHLOG: error = rtkit_handle_crashlog(state, &msg); if (error) return error; break; case RTKIT_EP_IOREPORT: error = rtkit_handle_ioreport(state, &msg); if (error) return error; break; default: if (endpoint >= 32 && endpoint < 64 && state->callback[endpoint - 32]) { callback = state->callback[endpoint - 32]; arg = state->arg[endpoint - 32]; callback(arg, msg.data0); break; } printf("unhandled endpoint %d\n", msg.data1); return EIO; } return 0; } static void rtkit_rx_callback(void *cookie) { rtkit_poll(cookie); } struct rtkit_state * rtkit_init(int node, const char *name) { struct rtkit_state *state; state = kmem_zalloc(sizeof(*state), KM_SLEEP); if (name) { state->mc = fdtbus_mbox_get(node, name, rtkit_rx_callback, state); } else { state->mc = fdtbus_mbox_get_index(node, 0, rtkit_rx_callback, state); } if (state->mc == NULL) { kmem_free(state, sizeof(*state)); return NULL; } return state; } int rtkit_boot(struct rtkit_state *state) { struct fdtbus_mbox_channel *mc = state->mc; int error; /* Wake up! */ error = rtkit_send(mc, RTKIT_EP_MGMT, RTKIT_MGMT_IOP_PWR_STATE, RTKIT_MGMT_PWR_STATE_ON); if (error) { return error; } while (state->pwrstate != RTKIT_MGMT_PWR_STATE_ON) rtkit_poll(state); return 0; } int rtkit_start_endpoint(struct rtkit_state *state, uint32_t endpoint, void (*callback)(void *, uint64_t), void *arg) { if (endpoint < 32 || endpoint >= 64) return EINVAL; if ((state->epmap & __BIT(endpoint)) == 0) return EINVAL; state->callback[endpoint - 32] = callback; state->arg[endpoint - 32] = arg; return rtkit_start(state, endpoint); } int rtkit_send_endpoint(struct rtkit_state *state, uint32_t endpoint, uint64_t data) { return rtkit_send(state->mc, endpoint, 0, data); }