diff for duplicates of <5de2a378-77cf-4373-b3ae-faeebb931e2d@oss.qualcomm.com> diff --git a/N1/2.bin b/N1/2.bin new file mode 100644 index 0000000..41f00ef --- /dev/null +++ b/N1/2.bin @@ -0,0 +1,201 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + </head> + <body> + <p>Hi jens,<br> + </p> + <div class="moz-cite-prefix">On 4/8/2025 10:19 PM, Jens Wiklander + wrote:<br> + </div> + <blockquote type="cite" +cite="mid:CAHUa44GRBiRr6CsFWxJhyzf1cRSEP66m5K7uFntOv3oYWTHWgQ@mail.gmail.com"> + <pre wrap="" class="moz-quote-pre">Hi Amirreza, + +On Fri, Mar 28, 2025 at 3:48â¯AM Amirreza Zarrabi +<a class="moz-txt-link-rfc2396E" href="mailto:amirreza.zarrabi@oss.qualcomm.com"><amirreza.zarrabi@oss.qualcomm.com></a> wrote: +</pre> + <blockquote type="cite"> + <pre wrap="" class="moz-quote-pre"> +For drivers that can transfer data to the TEE without using shared +memory from client, it is necessary to receive the user address +directly, bypassing any processing by the TEE subsystem. Introduce +TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT/OUTPUT/INOUT to represent +userspace buffers. + +Signed-off-by: Amirreza Zarrabi <a class="moz-txt-link-rfc2396E" href="mailto:amirreza.zarrabi@oss.qualcomm.com"><amirreza.zarrabi@oss.qualcomm.com></a> +--- + drivers/tee/tee_core.c | 33 +++++++++++++++++++++++++++++++++ + include/linux/tee_drv.h | 6 ++++++ + include/uapi/linux/tee.h | 22 ++++++++++++++++------ + 3 files changed, 55 insertions(+), 6 deletions(-) +</pre> + </blockquote> + <pre wrap="" class="moz-quote-pre"> +Is this patch needed now that the QCOMTEE driver supports shared +memory? I prefer keeping changes to the ABI to a minimum. + +Cheers, +Jens</pre> + </blockquote> + <p>Unfortunately, this is still required. QTEE supports two types of + data transfer:<br> + (1) using UBUF and (2) memory objects. Even with memory object + support, some APIs still<br> + expect to receive data using UBUF. For instance, to load a TA, + QTEE offers two interfaces:<br> + one where the TA binary is in UBUF and another where the TA binary + is in a memory object.<br> + <br> + Best Regards,<br> + Amir<br> + </p> + <p><span style="white-space: pre-wrap"> +</span></p> + <blockquote type="cite" +cite="mid:CAHUa44GRBiRr6CsFWxJhyzf1cRSEP66m5K7uFntOv3oYWTHWgQ@mail.gmail.com"> + <pre wrap="" class="moz-quote-pre"> +</pre> + <blockquote type="cite"> + <pre wrap="" class="moz-quote-pre"> +diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c +index 22cc7d624b0c..bc862a11d437 100644 +--- a/drivers/tee/tee_core.c ++++ b/drivers/tee/tee_core.c +@@ -404,6 +404,17 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params, + params[n].u.value.b = ip.b; + params[n].u.value.c = ip.c; + break; ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT: ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: ++ params[n].u.ubuf.uaddr = u64_to_user_ptr(ip.a); ++ params[n].u.ubuf.size = ip.b; ++ ++ if (!access_ok(params[n].u.ubuf.uaddr, ++ params[n].u.ubuf.size)) ++ return -EFAULT; ++ ++ break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: +@@ -472,6 +483,11 @@ static int params_to_user(struct tee_ioctl_param __user *uparams, + put_user(p->u.value.c, &up->c)) + return -EFAULT; + break; ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: ++ if (put_user((u64)p->u.ubuf.size, &up->b)) ++ return -EFAULT; ++ break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + if (put_user((u64)p->u.memref.size, &up->b)) +@@ -672,6 +688,13 @@ static int params_to_supp(struct tee_context *ctx, + ip.b = p->u.value.b; + ip.c = p->u.value.c; + break; ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT: ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: ++ ip.a = (u64)p->u.ubuf.uaddr; ++ ip.b = p->u.ubuf.size; ++ ip.c = 0; ++ break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: +@@ -774,6 +797,16 @@ static int params_from_supp(struct tee_param *params, size_t num_params, + p->u.value.b = ip.b; + p->u.value.c = ip.c; + break; ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: ++ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: ++ p->u.ubuf.uaddr = u64_to_user_ptr(ip.a); ++ p->u.ubuf.size = ip.b; ++ ++ if (!access_ok(params[n].u.ubuf.uaddr, ++ params[n].u.ubuf.size)) ++ return -EFAULT; ++ ++ break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + /* +diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h +index ce23fd42c5d4..d773f91c6bdd 100644 +--- a/include/linux/tee_drv.h ++++ b/include/linux/tee_drv.h +@@ -82,6 +82,11 @@ struct tee_param_memref { + struct tee_shm *shm; + }; + ++struct tee_param_ubuf { ++ void * __user uaddr; ++ size_t size; ++}; ++ + struct tee_param_value { + u64 a; + u64 b; +@@ -92,6 +97,7 @@ struct tee_param { + u64 attr; + union { + struct tee_param_memref memref; ++ struct tee_param_ubuf ubuf; + struct tee_param_value value; + } u; + }; +diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h +index d0430bee8292..3e9b1ec5dfde 100644 +--- a/include/uapi/linux/tee.h ++++ b/include/uapi/linux/tee.h +@@ -151,6 +151,13 @@ struct tee_ioctl_buf_data { + #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 + #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ + ++/* ++ * These defines userspace buffer parameters. ++ */ ++#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT 8 ++#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT 9 ++#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT 10 /* input and output */ ++ + /* + * Mask for the type part of the attribute, leaves room for more types + */ +@@ -186,14 +193,17 @@ struct tee_ioctl_buf_data { + /** + * struct tee_ioctl_param - parameter + * @attr: attributes +- * @a: if a memref, offset into the shared memory object, else a value parameter +- * @b: if a memref, size of the buffer, else a value parameter ++ * @a: if a memref, offset into the shared memory object, ++ * else if a ubuf, address of the user buffer, ++ * else a value parameter ++ * @b: if a memref or ubuf, size of the buffer, else a value parameter + * @c: if a memref, shared memory identifier, else a value parameter + * +- * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in +- * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and +- * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE +- * indicates that none of the members are used. ++ * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, ubuf, or value is ++ * used in the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value, ++ * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, and TEE_PARAM_ATTR_TYPE_UBUF_* ++ * indicates ubuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members ++ * are used. + * + * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an + * identifier representing the shared memory object. A memref can reference + +-- +2.34.1 + +</pre> + </blockquote> + </blockquote> + </body> +</html> diff --git a/N1/2.hdr b/N1/2.hdr new file mode 100644 index 0000000..e9e8314 --- /dev/null +++ b/N1/2.hdr @@ -0,0 +1,2 @@ +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: 8bit diff --git a/a/content_digest b/N1/content_digest index 3e7e15b..0096500 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,8 +1,26 @@ - "ref\0 <CAHUa44GRBiRr6CsFWxJhyzf1cRSEP66m5K7uFntOv3oYWTHWgQ@mail.gmail.com\0" + "ref\020250327-qcom-tee-using-tee-ss-without-mem-obj-v3-0-7f457073282d@oss.qualcomm.com\0" + "ref\020250327-qcom-tee-using-tee-ss-without-mem-obj-v3-3-7f457073282d@oss.qualcomm.com\0" + "ref\0CAHUa44GRBiRr6CsFWxJhyzf1cRSEP66m5K7uFntOv3oYWTHWgQ@mail.gmail.com\0" "From\0Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>\0" "Subject\0Re: [PATCH v3 03/11] tee: add TEE_IOCTL_PARAM_ATTR_TYPE_UBUF\0" - "Date\0Wed, 09 Apr 2025 10:28:19 +1000\0" - "To\0op-tee@lists.trustedfirmware.org\0" + "Date\0Wed, 9 Apr 2025 10:28:19 +1000\0" + "To\0Jens Wiklander <jens.wiklander@linaro.org>\0" + "Cc\0Sumit Garg <sumit.garg@kernel.org>" + Bjorn Andersson <andersson@kernel.org> + Konrad Dybcio <konradybcio@kernel.org> + Bartosz Golaszewski <bartosz.golaszewski@linaro.org> + Apurupa Pattapu <quic_apurupa@quicinc.com> + Kees Cook <kees@kernel.org> + Gustavo A. R. Silva <gustavoars@kernel.org> + Sumit Semwal <sumit.semwal@linaro.org> + " Christian K\303\266nig <christian.koenig@amd.com>" + linux-arm-msm@vger.kernel.org + op-tee@lists.trustedfirmware.org + linux-kernel@vger.kernel.org + linux-hardening@vger.kernel.org + dri-devel@lists.freedesktop.org + linaro-mm-sig@lists.linaro.org + " linux-doc@vger.kernel.org\0" "\01:1\0" "b\0" "Hi jens,\n" @@ -173,5 +191,208 @@ ">> --\n" ">> 2.34.1\n" >> + "\01:2\0" + "b\0" + "<!DOCTYPE html>\n" + "<html>\n" + " <head>\n" + " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" + " </head>\n" + " <body>\n" + " <p>Hi jens,<br>\n" + " </p>\n" + " <div class=\"moz-cite-prefix\">On 4/8/2025 10:19 PM, Jens Wiklander\n" + " wrote:<br>\n" + " </div>\n" + " <blockquote type=\"cite\"\n" + "cite=\"mid:CAHUa44GRBiRr6CsFWxJhyzf1cRSEP66m5K7uFntOv3oYWTHWgQ@mail.gmail.com\">\n" + " <pre wrap=\"\" class=\"moz-quote-pre\">Hi Amirreza,\n" + "\n" + "On Fri, Mar 28, 2025 at 3:48\342\200\257AM Amirreza Zarrabi\n" + "<a class=\"moz-txt-link-rfc2396E\" href=\"mailto:amirreza.zarrabi@oss.qualcomm.com\"><amirreza.zarrabi@oss.qualcomm.com></a> wrote:\n" + "</pre>\n" + " <blockquote type=\"cite\">\n" + " <pre wrap=\"\" class=\"moz-quote-pre\">\n" + "For drivers that can transfer data to the TEE without using shared\n" + "memory from client, it is necessary to receive the user address\n" + "directly, bypassing any processing by the TEE subsystem. Introduce\n" + "TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT/OUTPUT/INOUT to represent\n" + "userspace buffers.\n" + "\n" + "Signed-off-by: Amirreza Zarrabi <a class=\"moz-txt-link-rfc2396E\" href=\"mailto:amirreza.zarrabi@oss.qualcomm.com\"><amirreza.zarrabi@oss.qualcomm.com></a>\n" + "---\n" + " drivers/tee/tee_core.c | 33 +++++++++++++++++++++++++++++++++\n" + " include/linux/tee_drv.h | 6 ++++++\n" + " include/uapi/linux/tee.h | 22 ++++++++++++++++------\n" + " 3 files changed, 55 insertions(+), 6 deletions(-)\n" + "</pre>\n" + " </blockquote>\n" + " <pre wrap=\"\" class=\"moz-quote-pre\">\n" + "Is this patch needed now that the QCOMTEE driver supports shared\n" + "memory? I prefer keeping changes to the ABI to a minimum.\n" + "\n" + "Cheers,\n" + "Jens</pre>\n" + " </blockquote>\n" + " <p>Unfortunately, this is still required. QTEE supports two types of\n" + " data transfer:<br>\n" + " (1) using UBUF and (2) memory objects. Even with memory object\n" + " support, some APIs still<br>\n" + " expect to receive data using UBUF. For instance, to load a TA,\n" + " QTEE offers two interfaces:<br>\n" + " one where the TA binary is in UBUF and another where the TA binary\n" + " is in a memory object.<br>\n" + " <br>\n" + " Best Regards,<br>\n" + " Amir<br>\n" + " </p>\n" + " <p><span style=\"white-space: pre-wrap\">\n" + "</span></p>\n" + " <blockquote type=\"cite\"\n" + "cite=\"mid:CAHUa44GRBiRr6CsFWxJhyzf1cRSEP66m5K7uFntOv3oYWTHWgQ@mail.gmail.com\">\n" + " <pre wrap=\"\" class=\"moz-quote-pre\">\n" + "</pre>\n" + " <blockquote type=\"cite\">\n" + " <pre wrap=\"\" class=\"moz-quote-pre\">\n" + "diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c\n" + "index 22cc7d624b0c..bc862a11d437 100644\n" + "--- a/drivers/tee/tee_core.c\n" + "+++ b/drivers/tee/tee_core.c\n" + "@@ -404,6 +404,17 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,\n" + " params[n].u.value.b = ip.b;\n" + " params[n].u.value.c = ip.c;\n" + " break;\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT:\n" + "+ params[n].u.ubuf.uaddr = u64_to_user_ptr(ip.a);\n" + "+ params[n].u.ubuf.size = ip.b;\n" + "+\n" + "+ if (!access_ok(params[n].u.ubuf.uaddr,\n" + "+ params[n].u.ubuf.size))\n" + "+ return -EFAULT;\n" + "+\n" + "+ break;\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:\n" + "@@ -472,6 +483,11 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,\n" + " put_user(p->u.value.c, &up->c))\n" + " return -EFAULT;\n" + " break;\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT:\n" + "+ if (put_user((u64)p->u.ubuf.size, &up->b))\n" + "+ return -EFAULT;\n" + "+ break;\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:\n" + " if (put_user((u64)p->u.memref.size, &up->b))\n" + "@@ -672,6 +688,13 @@ static int params_to_supp(struct tee_context *ctx,\n" + " ip.b = p->u.value.b;\n" + " ip.c = p->u.value.c;\n" + " break;\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT:\n" + "+ ip.a = (u64)p->u.ubuf.uaddr;\n" + "+ ip.b = p->u.ubuf.size;\n" + "+ ip.c = 0;\n" + "+ break;\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:\n" + "@@ -774,6 +797,16 @@ static int params_from_supp(struct tee_param *params, size_t num_params,\n" + " p->u.value.b = ip.b;\n" + " p->u.value.c = ip.c;\n" + " break;\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:\n" + "+ case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT:\n" + "+ p->u.ubuf.uaddr = u64_to_user_ptr(ip.a);\n" + "+ p->u.ubuf.size = ip.b;\n" + "+\n" + "+ if (!access_ok(params[n].u.ubuf.uaddr,\n" + "+ params[n].u.ubuf.size))\n" + "+ return -EFAULT;\n" + "+\n" + "+ break;\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:\n" + " case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:\n" + " /*\n" + "diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h\n" + "index ce23fd42c5d4..d773f91c6bdd 100644\n" + "--- a/include/linux/tee_drv.h\n" + "+++ b/include/linux/tee_drv.h\n" + "@@ -82,6 +82,11 @@ struct tee_param_memref {\n" + " struct tee_shm *shm;\n" + " };\n" + "\n" + "+struct tee_param_ubuf {\n" + "+ void * __user uaddr;\n" + "+ size_t size;\n" + "+};\n" + "+\n" + " struct tee_param_value {\n" + " u64 a;\n" + " u64 b;\n" + "@@ -92,6 +97,7 @@ struct tee_param {\n" + " u64 attr;\n" + " union {\n" + " struct tee_param_memref memref;\n" + "+ struct tee_param_ubuf ubuf;\n" + " struct tee_param_value value;\n" + " } u;\n" + " };\n" + "diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h\n" + "index d0430bee8292..3e9b1ec5dfde 100644\n" + "--- a/include/uapi/linux/tee.h\n" + "+++ b/include/uapi/linux/tee.h\n" + "@@ -151,6 +151,13 @@ struct tee_ioctl_buf_data {\n" + " #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6\n" + " #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */\n" + "\n" + "+/*\n" + "+ * These defines userspace buffer parameters.\n" + "+ */\n" + "+#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT 8\n" + "+#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT 9\n" + "+#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT 10 /* input and output */\n" + "+\n" + " /*\n" + " * Mask for the type part of the attribute, leaves room for more types\n" + " */\n" + "@@ -186,14 +193,17 @@ struct tee_ioctl_buf_data {\n" + " /**\n" + " * struct tee_ioctl_param - parameter\n" + " * @attr: attributes\n" + "- * @a: if a memref, offset into the shared memory object, else a value parameter\n" + "- * @b: if a memref, size of the buffer, else a value parameter\n" + "+ * @a: if a memref, offset into the shared memory object,\n" + "+ * else if a ubuf, address of the user buffer,\n" + "+ * else a value parameter\n" + "+ * @b: if a memref or ubuf, size of the buffer, else a value parameter\n" + " * @c: if a memref, shared memory identifier, else a value parameter\n" + " *\n" + "- * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in\n" + "- * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and\n" + "- * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE\n" + "- * indicates that none of the members are used.\n" + "+ * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, ubuf, or value is\n" + "+ * used in the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value,\n" + "+ * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, and TEE_PARAM_ATTR_TYPE_UBUF_*\n" + "+ * indicates ubuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members\n" + "+ * are used.\n" + " *\n" + " * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an\n" + " * identifier representing the shared memory object. A memref can reference\n" + "\n" + "--\n" + "2.34.1\n" + "\n" + "</pre>\n" + " </blockquote>\n" + " </blockquote>\n" + " </body>\n" + "</html>\n" -28c5f0d9c762ab2bc4d4b6287717e5920ef4d162c487e263dfa6f8e0997452e2 +5d798944ff13a828219ef115861156a50c63be8b82752f7b8ad9d784b2321735
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.