// SPDX-License-Identifier: GPL-2.0-only OR MIT/* * Apple RTKit IPC library * Copyright (C) The Asahi Linux Contributors */ #include "rtkit-internal.h" enum { APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */ APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */ APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */ APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */ APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */ APPLE_RTKIT_PWR_STATE_INIT = 0x220, /* init after starting the coproc */}; enum { APPLE_RTKIT_EP_MGMT = 0, APPLE_RTKIT_EP_CRASHLOG = 1, APPLE_RTKIT_EP_SYSLOG = 2, APPLE_RTKIT_EP_DEBUG = 3, APPLE_RTKIT_EP_IOREPORT = 4, APPLE_RTKIT_EP_OSLOG = 8,}; #define APPLE_RTKIT_MGMT_TYPE GENMASK_ULL(59, 52) enum { APPLE_RTKIT_MGMT_HELLO = 1, APPLE_RTKIT_MGMT_HELLO_REPLY = 2, APPLE_RTKIT_MGMT_STARTEP = 5, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE = 6, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK = 7, APPLE_RTKIT_MGMT_EPMAP = 8, APPLE_RTKIT_MGMT_EPMAP_REPLY = 8, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE = 0xb, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK = 0xb,}; #define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK_ULL(15, 0)#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK_ULL(31, 16) #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT_ULL(51)#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK_ULL(34, 32)#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK_ULL(31, 0) #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT_ULL(0) #define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK_ULL(39, 32)#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT_ULL(1) #define APPLE_RTKIT_MGMT_PWR_STATE GENMASK_ULL(15, 0) #define APPLE_RTKIT_CRASHLOG_CRASH 1 #define APPLE_RTKIT_BUFFER_REQUEST 1#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44)#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0) #define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52) #define APPLE_RTKIT_SYSLOG_LOG 5 #define APPLE_RTKIT_SYSLOG_INIT 8#define APPLE_RTKIT_SYSLOG_N_ENTRIES GENMASK_ULL(7, 0)#define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24) #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56)#define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1#define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36)#define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0) #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 struct apple_rtkit_rx_work { struct apple_rtkit *rtk; u8 ep; u64 msg; struct work_struct work;}; bool apple_rtkit_is_running(struct apple_rtkit *rtk){ if (rtk->crashed) return false; if ((rtk->iop_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) return false; if ((rtk->ap_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) return false; return true;}EXPORT_SYMBOL_GPL(apple_rtkit_is_running); bool apple_rtkit_is_crashed(struct apple_rtkit *rtk){ return rtk->crashed;}EXPORT_SYMBOL_GPL(apple_rtkit_is_crashed); static int apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type, u64 msg){ int ret; msg &= ~APPLE_RTKIT_MGMT_TYPE; msg |= FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, type); ret = apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false); if (ret) dev_err(rtk->dev, "RTKit: Failed to send management message: %d\n", ret); return ret;} static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg){ u64 reply; int min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg); int max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg); int want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver); dev_dbg(rtk->dev, "RTKit: Min ver %d, max ver %d\n", min_ver, max_ver); if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) { dev_err(rtk->dev, "RTKit: Firmware min version %d is too new\n", min_ver); goto abort_boot; } if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) { dev_err(rtk->dev, "RTKit: Firmware max version %d is too old\n", max_ver); goto abort_boot; } dev_info(rtk->dev, "RTKit: Initializing (protocol version %d)\n", want_ver); rtk->version = want_ver; reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver); reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver); apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_HELLO_REPLY, reply); return; abort_boot: rtk->boot_result = -EINVAL; complete_all(&rtk->epmap_completion);} static void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg){ int i, ep; u64 reply; unsigned long bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg); u32 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg); dev_dbg(rtk->dev, "RTKit: received endpoint bitmap 0x%lx with base 0x%x\n", bitmap, base); for_each_set_bit(i, &bitmap, 32) { ep = 32 * base + i; dev_dbg(rtk->dev, "RTKit: Discovered endpoint 0x%02x\n", ep); set_bit(ep, rtk->endpoints); } reply = FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base); if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST) reply |= APPLE_RTKIT_MGMT_EPMAP_LAST; else reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE; apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_EPMAP_REPLY, reply); if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST)) return; for_each_set_bit(ep, rtk->endpoints, APPLE_RTKIT_APP_ENDPOINT_START) { switch (ep) { /* the management endpoint is started by default */ case APPLE_RTKIT_EP_MGMT: break; /* without starting these RTKit refuses to boot */ case APPLE_RTKIT_EP_SYSLOG: case APPLE_RTKIT_EP_CRASHLOG: case APPLE_RTKIT_EP_DEBUG: case APPLE_RTKIT_EP_IOREPORT: case APPLE_RTKIT_EP_OSLOG: dev_dbg(rtk->dev, "RTKit: Starting system endpoint 0x%02x\n", ep); apple_rtkit_start_ep(rtk, ep); break; default: dev_warn(rtk->dev, "RTKit: Unknown system endpoint: 0x%02x\n", ep); } } rtk->boot_result = 0; complete_all(&rtk->epmap_completion);} static void apple_rtkit_management_rx_iop_pwr_ack(struct apple_rtkit *rtk, u64 msg){ unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); dev_dbg(rtk->dev, "RTKit: IOP power state transition: 0x%x -> 0x%x\n", rtk->iop_power_state, new_state); rtk->iop_power_state = new_state; complete_all(&rtk->iop_pwr_ack_completion);} static void apple_rtkit_management_rx_ap_pwr_ack(struct apple_rtkit *rtk, u64 msg){ unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); dev_dbg(rtk->dev, "RTKit: AP power state transition: 0x%x -> 0x%x\n", rtk->ap_power_state, new_state); rtk->ap_power_state = new_state; complete_all(&rtk->ap_pwr_ack_completion);} static void apple_rtkit_management_rx(struct apple_rtkit *rtk, u64 msg){ u8 type = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg); switch (type) { case APPLE_RTKIT_MGMT_HELLO: apple_rtkit_management_rx_hello(rtk, msg); break; case APPLE_RTKIT_MGMT_EPMAP: apple_rtkit_management_rx_epmap(rtk, msg); break; case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK: apple_rtkit_management_rx_iop_pwr_ack(rtk, msg); break; case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK: apple_rtkit_management_rx_ap_pwr_ack(rtk, msg); break; default: dev_warn( rtk->dev, "RTKit: unknown management message: 0x%llx (type: 0x%02x)\n", msg, type); }} static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, struct apple_rtkit_shmem *buffer, u8 ep, u64 msg){ u64 reply; int err; /* The different size vs. IOVA shifts look odd but are indeed correct this way */ if (ep == APPLE_RTKIT_EP_OSLOG) { buffer->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg); buffer->iova = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg) << 12; } else { buffer->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg) << 12; buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); } buffer->buffer = NULL; buffer->iomem = NULL; buffer->is_mapped = false; dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n", buffer->size, &buffer->iova); if (buffer->iova && !rtk->ops->shmem_setup) { err = -EINVAL; goto error; } if (rtk->ops->shmem_setup) { err = rtk->ops->shmem_setup(rtk->cookie, buffer); if (err) goto error; } else { buffer->buffer = dma_alloc_coherent(rtk->dev, buffer->size, &buffer->iova, GFP_KERNEL); if (!buffer->buffer) { err = -ENOMEM; goto error; } } if (!buffer->is_mapped) { /* oslog uses different fields and needs a shifted IOVA instead of size */ if (ep == APPLE_RTKIT_EP_OSLOG) { reply = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_BUFFER_REQUEST); reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buffer->size); reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA, buffer->iova >> 12); } else { reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, APPLE_RTKIT_BUFFER_REQUEST); reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, buffer->size >> 12); reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buffer->iova); } apple_rtkit_send_message(rtk, ep, reply, NULL, false); } return 0; error: dev_err(rtk->dev, "RTKit: failed buffer request for 0x%zx bytes (%d)\n", buffer->size, err); buffer->buffer = NULL; buffer->iomem = NULL; buffer->iova = 0; buffer->size = 0; buffer->is_mapped = false; return err;} static void apple_rtkit_free_buffer(struct apple_rtkit *rtk, struct apple_rtkit_shmem *bfr){ if (bfr->size == 0) return; if (rtk->ops->shmem_destroy) rtk->ops->shmem_destroy(rtk->cookie, bfr); else if (bfr->buffer) dma_free_coherent(rtk->dev, bfr->size, bfr->buffer, bfr->iova); bfr->buffer = NULL; bfr->iomem = NULL; bfr->iova = 0; bfr->size = 0; bfr->is_mapped = false;} static void apple_rtkit_memcpy(struct apple_rtkit *rtk, void *dst, struct apple_rtkit_shmem *bfr, size_t offset, size_t len){ if (bfr->iomem) memcpy_fromio(dst, bfr->iomem + offset, len); else memcpy(dst, bfr->buffer + offset, len);} static void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg){ u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); u8 *bfr; if (type != APPLE_RTKIT_CRASHLOG_CRASH) { dev_warn(rtk->dev, "RTKit: Unknown crashlog message: %llx\n", msg); return; } if (!rtk->crashlog_buffer.size) { apple_rtkit_common_rx_get_buffer(rtk, &rtk->crashlog_buffer, APPLE_RTKIT_EP_CRASHLOG, msg); return; } dev_err(rtk->dev, "RTKit: co-processor has crashed\n"); /* * create a shadow copy here to make sure the co-processor isn't able * to change the log while we're dumping it. this also ensures * the buffer is in normal memory and not iomem for e.g. the SMC */ bfr = kzalloc(rtk->crashlog_buffer.size, GFP_KERNEL); if (bfr) { apple_rtkit_memcpy(rtk, bfr, &rtk->crashlog_buffer, 0, rtk->crashlog_buffer.size); apple_rtkit_crashlog_dump(rtk, bfr, rtk->crashlog_buffer.size); } else { dev_err(rtk->dev, "RTKit: Couldn't allocate crashlog shadow buffer\n"); } rtk->crashed = true; if (rtk->ops->crashed) rtk->ops->crashed(rtk->cookie, bfr, rtk->crashlog_buffer.size); kfree(bfr);} static void apple_rtkit_ioreport_rx(struct apple_rtkit *rtk, u64 msg){ u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); switch (type) { case APPLE_RTKIT_BUFFER_REQUEST: apple_rtkit_common_rx_get_buffer(rtk, &rtk->ioreport_buffer, APPLE_RTKIT_EP_IOREPORT, msg); break; /* unknown, must be ACKed or the co-processor will hang */ case 0x8: case 0xc: apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_IOREPORT, msg, NULL, false); break; default: dev_warn(rtk->dev, "RTKit: Unknown ioreport message: %llx\n", msg); }} static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg){ rtk->syslog_n_entries = FIELD_GET(APPLE_RTKIT_SYSLOG_N_ENTRIES, msg); rtk->syslog_msg_size = FIELD_GET(APPLE_RTKIT_SYSLOG_MSG_SIZE, msg); rtk->syslog_msg_buffer = kzalloc(rtk->syslog_msg_size, GFP_KERNEL); dev_dbg(rtk->dev, "RTKit: syslog initialized: entries: %zd, msg_size: %zd\n", rtk->syslog_n_entries, rtk->syslog_msg_size);} static bool should_crop_syslog_char(char c){ return c == '\n' || c == '\r' || c == ' ' || c == '\0';} static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg){ u8 idx = msg & 0xff; char log_context[24]; size_t entry_size = 0x20 + rtk->syslog_msg_size; int msglen; if (!rtk->syslog_msg_buffer) { dev_warn( rtk->dev, "RTKit: received syslog message but no syslog_msg_buffer\n"); goto done; } if (!rtk->syslog_buffer.size) { dev_warn( rtk->dev, "RTKit: received syslog message but syslog_buffer.size is zero\n"); goto done; } if (!rtk->syslog_buffer.buffer && !rtk->syslog_buffer.iomem) { dev_warn( rtk->dev, "RTKit: received syslog message but no syslog_buffer.buffer or syslog_buffer.iomem\n"); goto done; } if (idx > rtk->syslog_n_entries) { dev_warn(rtk->dev, "RTKit: syslog index %d out of range\n", idx); goto done; } apple_rtkit_memcpy(rtk, log_context, &rtk->syslog_buffer, idx * entry_size + 8, sizeof(log_context)); apple_rtkit_memcpy(rtk, rtk->syslog_msg_buffer, &rtk->syslog_buffer, idx * entry_size + 8 + sizeof(log_context), rtk->syslog_msg_size); log_context[sizeof(log_context) - 1] = 0; msglen = strnlen(rtk->syslog_msg_buffer, rtk->syslog_msg_size - 1); while (msglen > 0 && should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1])) msglen--; rtk->syslog_msg_buffer[msglen] = 0; dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context, rtk->syslog_msg_buffer); done: apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_SYSLOG, msg, NULL, false);} static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg){ u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); switch (type) { case APPLE_RTKIT_BUFFER_REQUEST: apple_rtkit_common_rx_get_buffer(rtk, &rtk->syslog_buffer, APPLE_RTKIT_EP_SYSLOG, msg); break;Lines 1–500 of 979. Load more
// SPDX-License-Identifier: GPL-2.0-only OR MIT /* * Apple RTKit IPC library * Copyright (C) The Asahi Linux Contributors */ #include "rtkit-internal.h" enum { APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */ APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */ APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */ APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */ APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */ APPLE_RTKIT_PWR_STATE_INIT = 0x220, /* init after starting the coproc */ }; enum { APPLE_RTKIT_EP_MGMT = 0, APPLE_RTKIT_EP_CRASHLOG = 1, APPLE_RTKIT_EP_SYSLOG = 2, APPLE_RTKIT_EP_DEBUG = 3, APPLE_RTKIT_EP_IOREPORT = 4, APPLE_RTKIT_EP_OSLOG = 8, }; #define APPLE_RTKIT_MGMT_TYPE GENMASK_ULL(59, 52) enum { APPLE_RTKIT_MGMT_HELLO = 1, APPLE_RTKIT_MGMT_HELLO_REPLY = 2, APPLE_RTKIT_MGMT_STARTEP = 5, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE = 6, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK = 7, APPLE_RTKIT_MGMT_EPMAP = 8, APPLE_RTKIT_MGMT_EPMAP_REPLY = 8, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE = 0xb, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK = 0xb, }; #define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK_ULL(15, 0) #define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK_ULL(31, 16) #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT_ULL(51) #define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK_ULL(34, 32) #define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK_ULL(31, 0) #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT_ULL(0) #define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK_ULL(39, 32) #define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT_ULL(1) #define APPLE_RTKIT_MGMT_PWR_STATE GENMASK_ULL(15, 0) #define APPLE_RTKIT_CRASHLOG_CRASH 1 #define APPLE_RTKIT_BUFFER_REQUEST 1 #define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44) #define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0) #define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52) #define APPLE_RTKIT_SYSLOG_LOG 5 #define APPLE_RTKIT_SYSLOG_INIT 8 #define APPLE_RTKIT_SYSLOG_N_ENTRIES GENMASK_ULL(7, 0) #define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24) #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56) #define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1 #define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36) #define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0) #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 struct apple_rtkit_rx_work { struct apple_rtkit *rtk; u8 ep; u64 msg; struct work_struct work; }; bool apple_rtkit_is_running(struct apple_rtkit *rtk) { if (rtk->crashed) return false; if ((rtk->iop_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) return false; if ((rtk->ap_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) return false; return true; } EXPORT_SYMBOL_GPL(apple_rtkit_is_running); bool apple_rtkit_is_crashed(struct apple_rtkit *rtk) { return rtk->crashed; } EXPORT_SYMBOL_GPL(apple_rtkit_is_crashed); static int apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type, u64 msg) { int ret; msg &= ~APPLE_RTKIT_MGMT_TYPE; msg |= FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, type); ret = apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false); if (ret) dev_err(rtk->dev, "RTKit: Failed to send management message: %d\n", ret); return ret; } static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg) { u64 reply; int min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg); int max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg); int want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver); dev_dbg(rtk->dev, "RTKit: Min ver %d, max ver %d\n", min_ver, max_ver); if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) { dev_err(rtk->dev, "RTKit: Firmware min version %d is too new\n", min_ver); goto abort_boot; } if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) { dev_err(rtk->dev, "RTKit: Firmware max version %d is too old\n", max_ver); goto abort_boot; } dev_info(rtk->dev, "RTKit: Initializing (protocol version %d)\n", want_ver); rtk->version = want_ver; reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver); reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver); apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_HELLO_REPLY, reply); return; abort_boot: rtk->boot_result = -EINVAL; complete_all(&rtk->epmap_completion); } static void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg) { int i, ep; u64 reply; unsigned long bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg); u32 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg); dev_dbg(rtk->dev, "RTKit: received endpoint bitmap 0x%lx with base 0x%x\n", bitmap, base); for_each_set_bit(i, &bitmap, 32) { ep = 32 * base + i; dev_dbg(rtk->dev, "RTKit: Discovered endpoint 0x%02x\n", ep); set_bit(ep, rtk->endpoints); } reply = FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base); if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST) reply |= APPLE_RTKIT_MGMT_EPMAP_LAST; else reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE; apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_EPMAP_REPLY, reply); if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST)) return; for_each_set_bit(ep, rtk->endpoints, APPLE_RTKIT_APP_ENDPOINT_START) { switch (ep) { /* the management endpoint is started by default */ case APPLE_RTKIT_EP_MGMT: break; /* without starting these RTKit refuses to boot */ case APPLE_RTKIT_EP_SYSLOG: case APPLE_RTKIT_EP_CRASHLOG: case APPLE_RTKIT_EP_DEBUG: case APPLE_RTKIT_EP_IOREPORT: case APPLE_RTKIT_EP_OSLOG: dev_dbg(rtk->dev, "RTKit: Starting system endpoint 0x%02x\n", ep); apple_rtkit_start_ep(rtk, ep); break; default: dev_warn(rtk->dev, "RTKit: Unknown system endpoint: 0x%02x\n", ep); } } rtk->boot_result = 0; complete_all(&rtk->epmap_completion); } static void apple_rtkit_management_rx_iop_pwr_ack(struct apple_rtkit *rtk, u64 msg) { unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); dev_dbg(rtk->dev, "RTKit: IOP power state transition: 0x%x -> 0x%x\n", rtk->iop_power_state, new_state); rtk->iop_power_state = new_state; complete_all(&rtk->iop_pwr_ack_completion); } static void apple_rtkit_management_rx_ap_pwr_ack(struct apple_rtkit *rtk, u64 msg) { unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); dev_dbg(rtk->dev, "RTKit: AP power state transition: 0x%x -> 0x%x\n", rtk->ap_power_state, new_state); rtk->ap_power_state = new_state; complete_all(&rtk->ap_pwr_ack_completion); } static void apple_rtkit_management_rx(struct apple_rtkit *rtk, u64 msg) { u8 type = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg); switch (type) { case APPLE_RTKIT_MGMT_HELLO: apple_rtkit_management_rx_hello(rtk, msg); break; case APPLE_RTKIT_MGMT_EPMAP: apple_rtkit_management_rx_epmap(rtk, msg); break; case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK: apple_rtkit_management_rx_iop_pwr_ack(rtk, msg); break; case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK: apple_rtkit_management_rx_ap_pwr_ack(rtk, msg); break; default: dev_warn( rtk->dev, "RTKit: unknown management message: 0x%llx (type: 0x%02x)\n", msg, type); } } static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, struct apple_rtkit_shmem *buffer, u8 ep, u64 msg) { u64 reply; int err; /* The different size vs. IOVA shifts look odd but are indeed correct this way */ if (ep == APPLE_RTKIT_EP_OSLOG) { buffer->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg); buffer->iova = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg) << 12; } else { buffer->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg) << 12; buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); } buffer->buffer = NULL; buffer->iomem = NULL; buffer->is_mapped = false; dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n", buffer->size, &buffer->iova); if (buffer->iova && !rtk->ops->shmem_setup) { err = -EINVAL; goto error; } if (rtk->ops->shmem_setup) { err = rtk->ops->shmem_setup(rtk->cookie, buffer); if (err) goto error; } else { buffer->buffer = dma_alloc_coherent(rtk->dev, buffer->size, &buffer->iova, GFP_KERNEL); if (!buffer->buffer) { err = -ENOMEM; goto error; } } if (!buffer->is_mapped) { /* oslog uses different fields and needs a shifted IOVA instead of size */ if (ep == APPLE_RTKIT_EP_OSLOG) { reply = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_BUFFER_REQUEST); reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buffer->size); reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA, buffer->iova >> 12); } else { reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, APPLE_RTKIT_BUFFER_REQUEST); reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, buffer->size >> 12); reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buffer->iova); } apple_rtkit_send_message(rtk, ep, reply, NULL, false); } return 0; error: dev_err(rtk->dev, "RTKit: failed buffer request for 0x%zx bytes (%d)\n", buffer->size, err); buffer->buffer = NULL; buffer->iomem = NULL; buffer->iova = 0; buffer->size = 0; buffer->is_mapped = false; return err; } static void apple_rtkit_free_buffer(struct apple_rtkit *rtk, struct apple_rtkit_shmem *bfr) { if (bfr->size == 0) return; if (rtk->ops->shmem_destroy) rtk->ops->shmem_destroy(rtk->cookie, bfr); else if (bfr->buffer) dma_free_coherent(rtk->dev, bfr->size, bfr->buffer, bfr->iova); bfr->buffer = NULL; bfr->iomem = NULL; bfr->iova = 0; bfr->size = 0; bfr->is_mapped = false; } static void apple_rtkit_memcpy(struct apple_rtkit *rtk, void *dst, struct apple_rtkit_shmem *bfr, size_t offset, size_t len) { if (bfr->iomem) memcpy_fromio(dst, bfr->iomem + offset, len); else memcpy(dst, bfr->buffer + offset, len); } static void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg) { u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); u8 *bfr; if (type != APPLE_RTKIT_CRASHLOG_CRASH) { dev_warn(rtk->dev, "RTKit: Unknown crashlog message: %llx\n", msg); return; } if (!rtk->crashlog_buffer.size) { apple_rtkit_common_rx_get_buffer(rtk, &rtk->crashlog_buffer, APPLE_RTKIT_EP_CRASHLOG, msg); return; } dev_err(rtk->dev, "RTKit: co-processor has crashed\n"); /* * create a shadow copy here to make sure the co-processor isn't able * to change the log while we're dumping it. this also ensures * the buffer is in normal memory and not iomem for e.g. the SMC */ bfr = kzalloc(rtk->crashlog_buffer.size, GFP_KERNEL); if (bfr) { apple_rtkit_memcpy(rtk, bfr, &rtk->crashlog_buffer, 0, rtk->crashlog_buffer.size); apple_rtkit_crashlog_dump(rtk, bfr, rtk->crashlog_buffer.size); } else { dev_err(rtk->dev, "RTKit: Couldn't allocate crashlog shadow buffer\n"); } rtk->crashed = true; if (rtk->ops->crashed) rtk->ops->crashed(rtk->cookie, bfr, rtk->crashlog_buffer.size); kfree(bfr); } static void apple_rtkit_ioreport_rx(struct apple_rtkit *rtk, u64 msg) { u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); switch (type) { case APPLE_RTKIT_BUFFER_REQUEST: apple_rtkit_common_rx_get_buffer(rtk, &rtk->ioreport_buffer, APPLE_RTKIT_EP_IOREPORT, msg); break; /* unknown, must be ACKed or the co-processor will hang */ case 0x8: case 0xc: apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_IOREPORT, msg, NULL, false); break; default: dev_warn(rtk->dev, "RTKit: Unknown ioreport message: %llx\n", msg); } } static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg) { rtk->syslog_n_entries = FIELD_GET(APPLE_RTKIT_SYSLOG_N_ENTRIES, msg); rtk->syslog_msg_size = FIELD_GET(APPLE_RTKIT_SYSLOG_MSG_SIZE, msg); rtk->syslog_msg_buffer = kzalloc(rtk->syslog_msg_size, GFP_KERNEL); dev_dbg(rtk->dev, "RTKit: syslog initialized: entries: %zd, msg_size: %zd\n", rtk->syslog_n_entries, rtk->syslog_msg_size); } static bool should_crop_syslog_char(char c) { return c == '\n' || c == '\r' || c == ' ' || c == '\0'; } static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg) { u8 idx = msg & 0xff; char log_context[24]; size_t entry_size = 0x20 + rtk->syslog_msg_size; int msglen; if (!rtk->syslog_msg_buffer) { dev_warn( rtk->dev, "RTKit: received syslog message but no syslog_msg_buffer\n"); goto done; } if (!rtk->syslog_buffer.size) { dev_warn( rtk->dev, "RTKit: received syslog message but syslog_buffer.size is zero\n"); goto done; } if (!rtk->syslog_buffer.buffer && !rtk->syslog_buffer.iomem) { dev_warn( rtk->dev, "RTKit: received syslog message but no syslog_buffer.buffer or syslog_buffer.iomem\n"); goto done; } if (idx > rtk->syslog_n_entries) { dev_warn(rtk->dev, "RTKit: syslog index %d out of range\n", idx); goto done; } apple_rtkit_memcpy(rtk, log_context, &rtk->syslog_buffer, idx * entry_size + 8, sizeof(log_context)); apple_rtkit_memcpy(rtk, rtk->syslog_msg_buffer, &rtk->syslog_buffer, idx * entry_size + 8 + sizeof(log_context), rtk->syslog_msg_size); log_context[sizeof(log_context) - 1] = 0; msglen = strnlen(rtk->syslog_msg_buffer, rtk->syslog_msg_size - 1); while (msglen > 0 && should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1])) msglen--; rtk->syslog_msg_buffer[msglen] = 0; dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context, rtk->syslog_msg_buffer); done: apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_SYSLOG, msg, NULL, false); } static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg) { u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); switch (type) { case APPLE_RTKIT_BUFFER_REQUEST: apple_rtkit_common_rx_get_buffer(rtk, &rtk->syslog_buffer, APPLE_RTKIT_EP_SYSLOG, msg); break;