The NVMe firmware distributed with the macOS 13 developer beta does not
authorkettenis <kettenis@openbsd.org>
Sun, 12 Jun 2022 16:00:12 +0000 (16:00 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 12 Jun 2022 16:00:12 +0000 (16:00 +0000)
like some of the shortcuts we've taken in the code that talks to RTKit.
In particular it does not like our NAK of the request for ioreport buffers.
So allocate the requested buffers and ACK the request instead.

However, the hardware implements a address filter between the coprocessor
that the firmware runs on and main memory.  So we have to add a mapping
into this address filter such that the firmware can access these buffers.
Support for this address filter is implemented in a new aplsart(4) driver.

ok dlg@

sys/arch/arm64/conf/GENERIC
sys/arch/arm64/conf/RAMDISK
sys/arch/arm64/conf/files.arm64
sys/arch/arm64/dev/aplns.c
sys/arch/arm64/dev/aplsart.c [new file with mode: 0644]
sys/arch/arm64/dev/aplsmc.c
sys/arch/arm64/dev/rtkit.c
sys/arch/arm64/dev/rtkit.h

index e49f4d2..cb5632f 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.229 2022/06/02 03:09:39 jmatthew Exp $
+# $OpenBSD: GENERIC,v 1.230 2022/06/12 16:00:12 kettenis Exp $
 #
 # GENERIC machine description file
 #
@@ -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 7e9693f..6da753a 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.172 2022/06/02 03:09:39 jmatthew Exp $
+# $OpenBSD: RAMDISK,v 1.173 2022/06/12 16:00:12 kettenis Exp $
 
 machine                arm64
 maxusers       4
@@ -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 37e1532..920455b 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: files.arm64,v 1.56 2022/02/20 19:25:57 kettenis Exp $
+# $OpenBSD: files.arm64,v 1.57 2022/06/12 16:00:12 kettenis Exp $
 
 maxpartitions  16
 maxusers       2 8 128
@@ -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 ddb085b..c59960b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: aplns.c,v 1.11 2022/04/06 18:59:26 naddy Exp $ */
+/*     $OpenBSD: aplns.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $ */
 /*
  * Copyright (c) 2014, 2021 David Gwynne <dlg@openbsd.org>
  *
@@ -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, struct device *self, void *aux)
                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, struct device *self, void *aux)
 
        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) {
@@ -258,6 +267,14 @@ unmap:
        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
 nvme_ans_q_alloc(struct nvme_softc *sc,
     struct nvme_queue *q)
diff --git a/sys/arch/arm64/dev/aplsart.c b/sys/arch/arm64/dev/aplsart.c
new file mode 100644 (file)
index 0000000..975ee9f
--- /dev/null
@@ -0,0 +1,166 @@
+/*     $OpenBSD: aplsart.c,v 1.1 2022/06/12 16:00:12 kettenis Exp $    */
+/*
+ * Copyright (c) 2022 Mark Kettenis <kettenis@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 b9cb2b5..43ee3bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: aplsmc.c,v 1.11 2022/03/25 15:52:03 kettenis Exp $    */
+/*     $OpenBSD: aplsmc.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $    */
 /*
  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
  *
@@ -194,7 +194,7 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux)
                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 fbf32c3..ef0012e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rtkit.c,v 1.3 2022/01/10 09:07:28 kettenis Exp $      */
+/*     $OpenBSD: rtkit.c,v 1.4 2022/06/12 16:00:12 kettenis Exp $      */
 /*
  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
  *
 #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, uint32_t endpoint,
        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 *state, struct aplmbox_msg *msg)
                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 *state, struct aplmbox_msg *msg)
 
                                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 *state, struct aplmbox_msg *msg)
                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 *state, struct aplmbox_msg *msg)
                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 cdfd7ca..1da40e3 100644 (file)
@@ -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);