The macOS 13 beta release apparently comes with new RTKit-based NVMe firmware that doesn't like some of the shortcuts I've taken in the OpenBSD drivers and U-Boot. U-Boot is being fixed and here is a diff that attempts to fix OpenBSD.
* For now, don't update your Apple M1 machines to macOS 13 if you want to keep running OpenBSD on them!!! * The issue is that our code doesn't allocate the memory that RTKit asks for. Instead we effectively NAK the request. This works fine with the current firmware, but apparently not with the new one. The diff below changes this and allocates the requested memory. There is a complication though. The hardware has an address filter to prevent the firmware from accessing arbitrary bits of memory. So we need to program this address filter when we allocate the memory. This is done by a new driver that is called aplsart(4). ok? Index: arch/arm64/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v retrieving revision 1.229 diff -u -p -r1.229 GENERIC --- arch/arm64/conf/GENERIC 2 Jun 2022 03:09:39 -0000 1.229 +++ arch/arm64/conf/GENERIC 11 Jun 2022 19:27:57 -0000 @@ -147,10 +147,13 @@ apliic* at fdt? iic* at apliic? aplintc* at fdt? early 1 aplmbox* at fdt? +aplns* at fdt? # Apple NVME Storage controllers +nvme* at aplns? aplpcie* at fdt? pci* at aplpcie? aplpinctrl* at fdt? early 1 aplpmgr* at fdt? early 1 +aplsart* at fdt? aplsmc* at fdt? aplspi* at fdt? aplhidev* at spi? @@ -161,8 +164,6 @@ wsmouse* at aplms? mux 0 aplspmi* at fdt? aplpmu* at aplspmi? exuart* at fdt? -aplns* at fdt? # Apple NVME Storage controllers -nvme* at aplns? # iMX imxccm* at fdt? early 1 Index: arch/arm64/conf/RAMDISK =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/RAMDISK,v retrieving revision 1.172 diff -u -p -r1.172 RAMDISK --- arch/arm64/conf/RAMDISK 2 Jun 2022 03:09:39 -0000 1.172 +++ arch/arm64/conf/RAMDISK 11 Jun 2022 19:27:57 -0000 @@ -110,10 +110,13 @@ apliic* at fdt? iic* at apliic? aplintc* at fdt? early 1 aplmbox* at fdt? +aplns* at fdt? # Apple NVME Storage controllers +nvme* at aplns? aplpcie* at fdt? pci* at aplpcie? aplpinctrl* at fdt? early 1 aplpmgr* at fdt? early 1 +aplsart* at fdt? aplsmc* at fdt? aplspi* at fdt? aplhidev* at spi? @@ -122,8 +125,6 @@ wskbd* at aplkbd? mux 1 aplspmi* at fdt? aplpmu* at aplspmi? exuart* at fdt? -aplns* at fdt? # Apple NVME Storage controllers -nvme* at aplns? # iMX imxccm* at fdt? early 1 Index: arch/arm64/conf/files.arm64 =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/files.arm64,v retrieving revision 1.56 diff -u -p -r1.56 files.arm64 --- arch/arm64/conf/files.arm64 20 Feb 2022 19:25:57 -0000 1.56 +++ arch/arm64/conf/files.arm64 11 Jun 2022 19:27:57 -0000 @@ -197,6 +197,10 @@ attach aplns at fdt attach nvme at aplns with nvme_ans file arch/arm64/dev/aplns.c aplns | nvme_ans +device aplsart +attach aplsart at fdt +file arch/arm64/dev/aplsart.c aplsart | aplns + device aplsmc attach aplsmc at fdt file arch/arm64/dev/aplsmc.c aplsmc Index: arch/arm64/dev/aplns.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/aplns.c,v retrieving revision 1.11 diff -u -p -r1.11 aplns.c --- arch/arm64/dev/aplns.c 6 Apr 2022 18:59:26 -0000 1.11 +++ arch/arm64/dev/aplns.c 11 Jun 2022 19:27:57 -0000 @@ -93,6 +93,8 @@ struct cfdriver aplns_cd = { NULL, "aplns", DV_DULL }; +int nvme_ans_sart_map(void *, bus_addr_t, bus_size_t); + int aplns_match(struct device *parent, void *match, void *aux) { @@ -117,7 +119,9 @@ struct nvme_ans_softc { bus_space_tag_t asc_iot; bus_space_handle_t asc_ioh; - struct rtkit_state *asc_rtkit; + uint32_t asc_sart; + struct rtkit asc_rtkit; + struct rtkit_state *asc_rtkit_state; struct nvme_dmamem *asc_nvmmu; }; @@ -205,8 +209,13 @@ nvme_ans_attach(struct device *parent, s goto unmap; } - asc->asc_rtkit = rtkit_init(faa->fa_node, NULL); - if (asc->asc_rtkit == NULL) { + asc->asc_sart = OF_getpropint(faa->fa_node, "apple,sart", 0); + asc->asc_rtkit.rk_cookie = asc; + asc->asc_rtkit.rk_dmat = faa->fa_dmat; + asc->asc_rtkit.rk_map = nvme_ans_sart_map; + + asc->asc_rtkit_state = rtkit_init(faa->fa_node, NULL, &asc->asc_rtkit); + if (asc->asc_rtkit_state == NULL) { printf(": can't map mailbox channel\n"); goto disestablish; } @@ -217,7 +226,7 @@ nvme_ans_attach(struct device *parent, s status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS); if (status != ANS_BOOT_STATUS_OK) - rtkit_boot(asc->asc_rtkit); + rtkit_boot(asc->asc_rtkit_state); status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS); if (status != ANS_BOOT_STATUS_OK) { @@ -256,6 +265,14 @@ unmap: bus_space_unmap(asc->asc_iot, asc->asc_ioh, faa->fa_reg[1].size); bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); sc->sc_ios = 0; +} + +int +nvme_ans_sart_map(void *cookie, bus_addr_t addr, bus_size_t size) +{ + struct nvme_ans_softc *asc = cookie; + + return aplsart_map(asc->asc_sart, addr, size); } int Index: arch/arm64/dev/aplsart.c =================================================================== RCS file: arch/arm64/dev/aplsart.c diff -N arch/arm64/dev/aplsart.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm64/dev/aplsart.c 11 Jun 2022 19:27:57 -0000 @@ -0,0 +1,166 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2022 Mark Kettenis <kette...@openbsd.org> + * + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/extent.h> +#include <sys/malloc.h> +#include <sys/mutex.h> + +#include <machine/intr.h> +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/fdt.h> + +#define SART2_CONFIG(idx) (0x0000 + 4 * (idx)) +#define SART2_CONFIG_FLAGS_MASK 0xff000000 +#define SART2_CONFIG_FLAGS_ALLOW 0xff000000 +#define SART2_ADDR(idx) (0x0040 + 4 * (idx)) + +#define SART3_CONFIG(idx) (0x0000 + 4 * (idx)) +#define SART3_CONFIG_FLAGS_MASK 0x000000ff +#define SART3_CONFIG_FLAGS_ALLOW 0x000000ff +#define SART3_ADDR(idx) (0x0040 + 4 * (idx)) +#define SART3_SIZE(idx) (0x0080 + 4 * (idx)) + +#define SART_NUM_ENTRIES 16 +#define SART_ADDR_SHIFT 12 +#define SART_SIZE_SHIFT 12 + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +struct aplsart_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + uint32_t sc_phandle; + int sc_version; +}; + +int aplsart_match(struct device *, void *, void *); +void aplsart_attach(struct device *, struct device *, void *); + +const struct cfattach aplsart_ca = { + sizeof (struct aplsart_softc), aplsart_match, aplsart_attach +}; + +struct cfdriver aplsart_cd = { + NULL, "aplsart", DV_DULL +}; + +int +aplsart_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "apple,sart2") || + OF_is_compatible(faa->fa_node, "apple,sart3"); +} + +void +aplsart_attach(struct device *parent, struct device *self, void *aux) +{ + struct aplsart_softc *sc = (struct aplsart_softc *)self; + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + + sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0); + + if (OF_is_compatible(faa->fa_node, "apple,sart2")) + sc->sc_version = 2; + if (OF_is_compatible(faa->fa_node, "apple,sart3")) + sc->sc_version = 3; + + printf("\n"); +} + +int +aplsart2_map(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size) +{ + uint32_t conf; + int i; + + for (i = 0; i < SART_NUM_ENTRIES; i++) { + conf = HREAD4(sc, SART2_CONFIG(i)); + if (conf & SART2_CONFIG_FLAGS_MASK) + continue; + + HWRITE4(sc, SART2_ADDR(i), addr >> SART_ADDR_SHIFT); + HWRITE4(sc, SART2_CONFIG(i), + size >> SART_SIZE_SHIFT | SART2_CONFIG_FLAGS_ALLOW); + return 0; + } + + return ENOENT; +} + +int +aplsart3_map(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size) +{ + uint32_t conf; + int i; + + for (i = 0; i < SART_NUM_ENTRIES; i++) { + conf = HREAD4(sc, SART3_CONFIG(i)); + if (conf & SART3_CONFIG_FLAGS_MASK) + continue; + + HWRITE4(sc, SART3_ADDR(i), addr >> SART_ADDR_SHIFT); + HWRITE4(sc, SART3_SIZE(i), size >> SART_SIZE_SHIFT); + HWRITE4(sc, SART3_CONFIG(i), SART3_CONFIG_FLAGS_ALLOW); + return 0; + } + + return ENOENT; +} + +int +aplsart_map(uint32_t phandle, bus_addr_t addr, bus_size_t size) +{ + struct aplsart_softc *sc; + int i; + + for (i = 0; i < aplsart_cd.cd_ndevs; i++) { + sc = (struct aplsart_softc *)aplsart_cd.cd_devs[i]; + + if (sc->sc_phandle == phandle) { + if (sc->sc_version == 2) + return aplsart2_map(sc, addr, size); + else + return aplsart3_map(sc, addr, size); + } + } + + return ENXIO; +} Index: arch/arm64/dev/aplsmc.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/aplsmc.c,v retrieving revision 1.11 diff -u -p -r1.11 aplsmc.c --- arch/arm64/dev/aplsmc.c 25 Mar 2022 15:52:03 -0000 1.11 +++ arch/arm64/dev/aplsmc.c 11 Jun 2022 19:27:57 -0000 @@ -194,7 +194,7 @@ aplsmc_attach(struct device *parent, str return; } - sc->sc_rs = rtkit_init(faa->fa_node, NULL); + sc->sc_rs = rtkit_init(faa->fa_node, NULL, NULL); if (sc->sc_rs == NULL) { printf(": can't map mailbox channel\n"); return; Index: arch/arm64/dev/rtkit.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/rtkit.c,v retrieving revision 1.3 diff -u -p -r1.3 rtkit.c --- arch/arm64/dev/rtkit.c 10 Jan 2022 09:07:28 -0000 1.3 +++ arch/arm64/dev/rtkit.c 11 Jun 2022 19:27:57 -0000 @@ -68,12 +68,16 @@ #define RTKIT_BUFFER_SIZE(x) (((x) >> 44) & 0xff) #define RTKIT_BUFFER_SIZE_SHIFT 44 +#define RTKIT_IOREPORT_UNKNOWN1 8 +#define RTKIT_IOREPORT_UNKNOWN2 12 + /* Versions we support. */ #define RTKIT_MINVER 11 #define RTKIT_MAXVER 12 struct rtkit_state { struct mbox_channel *mc; + struct rtkit *rk; int pwrstate; uint64_t epmap; void (*callback[32])(void *, uint64_t); @@ -106,6 +110,19 @@ rtkit_send(struct mbox_channel *mc, uint return mbox_send(mc, &msg, sizeof(msg)); } +bus_addr_t +rtkit_alloc(struct rtkit *rk, bus_size_t size) +{ + bus_dma_segment_t seg; + int nsegs; + + if (bus_dmamem_alloc(rk->rk_dmat, size, 16384, 0, + &seg, 1, &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO)) + return (bus_addr_t)-1; + + return seg.ds_addr; +} + int rtkit_start(struct rtkit_state *state, uint32_t endpoint) { @@ -131,13 +148,13 @@ rtkit_handle_mgmt(struct rtkit_state *st minver = RTKIT_MGMT_HELLO_MINVER(msg->data0); maxver = RTKIT_MGMT_HELLO_MAXVER(msg->data0); if (minver > RTKIT_MAXVER) { - printf("unsupported minimum firmware version %lld\n", - minver); + printf("%s: unsupported minimum firmware version %lld\n", + __func__, minver); return EINVAL; } if (maxver < RTKIT_MINVER) { - printf("unsupported maximum firmware version %lld\n", - maxver); + printf("%s: unsupported maximum firmware version %lld\n", + __func__, maxver); return EINVAL; } ver = min(RTKIT_MAXVER, maxver); @@ -172,18 +189,24 @@ rtkit_handle_mgmt(struct rtkit_state *st switch (endpoint) { case RTKIT_EP_CRASHLOG: + case RTKIT_EP_SYSLOG: case RTKIT_EP_DEBUG: case RTKIT_EP_IOREPORT: error = rtkit_start(state, endpoint); if (error) return error; break; + default: + printf("%s: skipping endpoint %d\n", + __func__, endpoint); + break; } } } break; default: - printf("unhandled management event 0x%016lld\n", msg->data0); + printf("%s: unhandled management event 0x%016lld\n", + __func__, msg->data0); return EIO; } @@ -194,6 +217,7 @@ int rtkit_handle_crashlog(struct rtkit_state *state, struct aplmbox_msg *msg) { struct mbox_channel *mc = state->mc; + struct rtkit *rk = state->rk; bus_addr_t addr; bus_size_t size; int error; @@ -205,13 +229,24 @@ rtkit_handle_crashlog(struct rtkit_state if (addr) break; + if (rk) { + addr = rtkit_alloc(rk, size << PAGE_SHIFT); + if (addr == (bus_addr_t)-1) + return ENOMEM; + error = rk->rk_map(rk->rk_cookie, addr, + size << PAGE_SHIFT); + if (error) + return error; + } + error = rtkit_send(mc, RTKIT_EP_CRASHLOG, RTKIT_BUFFER_REQUEST, - size << RTKIT_BUFFER_SIZE_SHIFT | addr); + (size << RTKIT_BUFFER_SIZE_SHIFT) | addr); if (error) return error; break; default: - printf("unhandled crashlog event 0x%016llx\n", msg->data0); + printf("%s: unhandled crashlog event 0x%016llx\n", + __func__, msg->data0); return EIO; } @@ -222,6 +257,7 @@ int rtkit_handle_ioreport(struct rtkit_state *state, struct aplmbox_msg *msg) { struct mbox_channel *mc = state->mc; + struct rtkit *rk = state->rk; bus_addr_t addr; bus_size_t size; int error; @@ -233,13 +269,32 @@ rtkit_handle_ioreport(struct rtkit_state if (addr) break; + if (rk) { + addr = rtkit_alloc(rk, size << PAGE_SHIFT); + if (addr == (bus_addr_t)-1) + return ENOMEM; + error = rk->rk_map(rk->rk_cookie, addr, + size << PAGE_SHIFT); + if (error) + return error; + } + error = rtkit_send(mc, RTKIT_EP_IOREPORT, RTKIT_BUFFER_REQUEST, - size << RTKIT_BUFFER_SIZE_SHIFT | addr); + (size << RTKIT_BUFFER_SIZE_SHIFT) | addr); + if (error) + return error; + break; + case RTKIT_IOREPORT_UNKNOWN1: + case RTKIT_IOREPORT_UNKNOWN2: + /* These unknown events have to be acked to make progress. */ + error = rtkit_send(mc, RTKIT_EP_IOREPORT, + RTKIT_MGMT_TYPE(msg->data0), msg->data0); if (error) return error; break; default: - printf("unhandled ioreport event 0x%016llx\n", msg->data0); + printf("%s: unhandled ioreport event 0x%016llx\n", + __func__, msg->data0); return EIO; } @@ -286,7 +341,7 @@ rtkit_poll(struct rtkit_state *state) break; } - printf("unhandled endpoint %d\n", msg.data1); + printf("%s: unhandled endpoint %d\n", __func__, msg.data1); return EIO; } @@ -300,7 +355,7 @@ rtkit_rx_callback(void *cookie) } struct rtkit_state * -rtkit_init(int node, const char *name) +rtkit_init(int node, const char *name, struct rtkit *rk) { struct rtkit_state *state; struct mbox_client client; @@ -313,6 +368,7 @@ rtkit_init(int node, const char *name) free(state, M_DEVBUF, sizeof(*state)); return NULL; } + state->rk = rk; return state; } Index: arch/arm64/dev/rtkit.h =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/rtkit.h,v retrieving revision 1.2 diff -u -p -r1.2 rtkit.h --- arch/arm64/dev/rtkit.h 10 Jan 2022 09:07:28 -0000 1.2 +++ arch/arm64/dev/rtkit.h 11 Jun 2022 19:27:57 -0000 @@ -2,9 +2,17 @@ struct rtkit_state; -struct rtkit_state *rtkit_init(int, const char *); +struct rtkit { + void *rk_cookie; + bus_dma_tag_t rk_dmat; + int (*rk_map)(void *, bus_addr_t, bus_size_t); +}; + +struct rtkit_state *rtkit_init(int, const char *, struct rtkit *); int rtkit_boot(struct rtkit_state *); int rtkit_poll(struct rtkit_state *); int rtkit_start_endpoint(struct rtkit_state *, uint32_t, void (*)(void *, uint64_t), void *); int rtkit_send_endpoint(struct rtkit_state *, uint32_t, uint64_t); + +int aplsart_map(uint32_t, bus_addr_t, bus_size_t);