All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
To: Alan Previn <alan.previn.teres.alexis@intel.com>, uma.shankar@intel.com
Cc: igt-dev@lists.freedesktop.org
Subject: Re: [igt-dev] [PATCH i-g-t 17/17] tests/i915_pxp: CRC validation for display tests.
Date: Fri, 4 Jun 2021 10:40:55 -0400	[thread overview]
Message-ID: <YLo7d2H3IM7ioEcq@intel.com> (raw)
In-Reply-To: <20210518103344.2264397-18-alan.previn.teres.alexis@intel.com>

On Tue, May 18, 2021 at 03:33:44AM -0700, Alan Previn wrote:
> From: Karthik B S <karthik.b.s@intel.com>
> 
> Added subtests to validate pxp using CRC validation.
> 
> Signed-off-by: Karthik B S <karthik.b.s@intel.com>
Cc: Uma Shankar <uma.shankar@intel.com>

> ---
>  tests/i915/gem_pxp.c | 286 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 283 insertions(+), 3 deletions(-)
> 
> diff --git a/tests/i915/gem_pxp.c b/tests/i915/gem_pxp.c
> index 179fb742..728c925a 100644
> --- a/tests/i915/gem_pxp.c
> +++ b/tests/i915/gem_pxp.c
> @@ -435,6 +435,7 @@ static uint32_t alloc_and_fill_dest_buff(int i915, bool protected, uint32_t size
>  #define TSTSURF_INITCOLOR1  0x12341234
>  #define TSTSURF_INITCOLOR2  0x56785678
>  #define TSTSURF_INITCOLOR3  0xabcdabcd
> +#define TSTSURF_GREENCOLOR  0xFF00FF00
>  
>  static void test_render_baseline(int i915)
>  {
> @@ -906,7 +907,7 @@ static void test_pxp_pwrcycle_staleasset_execution(int i915, struct powermgt_dat
>  	trigger_powermgt_suspend_cycle(i915, pm);
>  
>  	igt_assert_f(!is_context_valid(i915, data[0].ctx),
> -				       "RESET_STATS missed INVAL bit on stale pxp context\n");
> +		     "RESET_STATS missed INVAL bit on stale pxp context\n");
>  	ret = gem_execbuf_flush_store_dw(i915, data[0].ibb, data[0].ctx, data[0].fencebuf);
>  	igt_assert_f((ret == -EACCES), "Executing stale pxp context didn't fail with -EACCES\n");
>  
> @@ -916,7 +917,7 @@ static void test_pxp_pwrcycle_staleasset_execution(int i915, struct powermgt_dat
>  	 * invalidated bo (not context)
>  	 */
>  	igt_assert_f(!is_context_valid(i915, data[1].ctx),
> -				       "RESET_STATS missed INVAL bit on stale pxp context\n");
> +		     "RESET_STATS missed INVAL bit on stale pxp context\n");
>  	ret = create_ctx_with_params(i915, true, true, true, false, &ctx2);
>  	igt_assert_eq(ret, 0);
>  	igt_assert_eq(get_ctx_protected_param(i915, ctx2), 1);
> @@ -928,7 +929,7 @@ static void test_pxp_pwrcycle_staleasset_execution(int i915, struct powermgt_dat
>  	igt_assert_f((ret == -ENOEXEC), "Executing stale pxp buffer didn't fail with -ENOEXEC\n");
>  
>  	igt_assert_f(is_context_valid(i915, data[2].ctx),
> -				       "RESET_STATS false-hit on opt-out context\n");
> +		     "RESET_STATS false-hit on opt-out context\n");
>  	ret = gem_execbuf_flush_store_dw(i915, data[2].ibb, data[2].ctx, data[2].fencebuf);
>  	igt_assert_f((ret == 0), "Opt-out-execution with stale pxp buffer didn't succeed\n");
>  
> @@ -937,6 +938,266 @@ static void test_pxp_pwrcycle_staleasset_execution(int i915, struct powermgt_dat
>  	free_exec_assets(i915, &data[2]);
>  }
>  
> +static void setup_protected_fb(int i915, int width, int height, igt_fb_t *fb, uint32_t ctx)
> +{
> +	int err;
> +	uint32_t srcbo;
> +	struct intel_buf *srcbuf, *dstbuf;
> +	struct buf_ops *bops;
> +	struct intel_bb *ibb;
> +	uint32_t devid;
> +	igt_render_copyfunc_t rendercopy;
> +
> +	devid = intel_get_drm_devid(i915);
> +	igt_assert(devid);
> +
> +	rendercopy = igt_get_render_copyfunc(devid);
> +	igt_assert(rendercopy);
> +
> +	bops = buf_ops_create(i915);
> +	igt_assert(bops);
> +
> +	igt_init_fb(fb, i915, width, height, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
> +		    IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
> +
> +	igt_calc_fb_size(i915, width, height, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
> +			 &fb->size, &fb->strides[0]);
> +
> +	err = create_bo_ext(i915, fb->size, true, &(fb->gem_handle));
> +	igt_assert_eq(err, 0);
> +	igt_assert(fb->gem_handle);
> +
> +	err = __gem_set_tiling(i915, fb->gem_handle, igt_fb_mod_to_tiling(fb->modifier),
> +			       fb->strides[0]);
> +	igt_assert(err == 0 || err == -EOPNOTSUPP);
> +
> +	do_or_die(__kms_addfb(fb->fd, fb->gem_handle, fb->width, fb->height, fb->drm_format,
> +			      fb->modifier, fb->strides, fb->offsets, fb->num_planes,
> +			      LOCAL_DRM_MODE_FB_MODIFIERS, &fb->fb_id));
> +
> +	dstbuf = intel_buf_create_using_handle(bops, fb->gem_handle, fb->width, fb->height,
> +					       fb->plane_bpp[0], 0,
> +					       igt_fb_mod_to_tiling(fb->modifier), 0);
> +	dstbuf->is_protected = true;
> +
> +	srcbo = alloc_and_fill_dest_buff(i915, false, fb->size, TSTSURF_GREENCOLOR);
> +	srcbuf = intel_buf_create_using_handle(bops, srcbo, fb->width, fb->height,
> +					       fb->plane_bpp[0], 0,
> +					       igt_fb_mod_to_tiling(fb->modifier), 0);
> +
> +	ibb = intel_bb_create_with_context(i915, ctx, 4096);
> +	igt_assert(ibb);
> +
> +	ibb->pxp.enabled = true;
> +	ibb->pxp.apptype = DISPLAY_APPTYPE;
> +	ibb->pxp.appid = I915_PROTECTED_CONTENT_DEFAULT_SESSION;
> +
> +	gen12_render_copyfunc(ibb, srcbuf, 0, 0, fb->width, fb->height, dstbuf, 0, 0);
> +
> +	gem_sync(i915, fb->gem_handle);
> +	assert_bo_content_check(i915, fb->gem_handle, COMPARE_COLOR_UNREADIBLE, fb->size,
> +				TSTSURF_GREENCOLOR, NULL, 0);
> +
> +	intel_bb_destroy(ibb);
> +	intel_buf_destroy(srcbuf);
> +	gem_close(i915, srcbo);
> +}
> +
> +static void __debugfs_read(int fd, const char *param, char *buf, int len)
> +{
> +	len = igt_debugfs_simple_read(fd, param, buf, len);
> +	if (len < 0)
> +		igt_assert_eq(len, -ENODEV);
> +}
> +
> +#define debugfs_read(fd, p, arr) __debugfs_read(fd, p, arr, sizeof(arr))
> +#define MAX_SINK_HDCP_CAP_BUF_LEN	5000
> +
> +#define CP_UNDESIRED				0
> +#define CP_DESIRED				1
> +#define CP_ENABLED				2
> +
> +#define KERNEL_AUTH_TIME_ALLOWED_MSEC		(3 *  6 * 1000)
> +#define KERNEL_DISABLE_TIME_ALLOWED_MSEC	(1 * 1000)
> +
> +static bool
> +wait_for_prop_value(igt_output_t *output, uint64_t expected,
> +		    uint32_t timeout_mSec)
> +{
> +	uint64_t val;
> +	int i;
> +
> +	for (i = 0; i < timeout_mSec; i++) {
> +		val = igt_output_get_prop(output, IGT_CONNECTOR_CONTENT_PROTECTION);
> +		if (val == expected)
> +			return true;
> +		usleep(1000);
> +	}
> +
> +	igt_info("prop_value mismatch %" PRId64 " != %" PRId64 "\n", val, expected);
> +
> +	return false;
> +}
> +
> +static bool sink_hdcp_capable(int i915, igt_output_t *output)
> +{
> +	char buf[MAX_SINK_HDCP_CAP_BUF_LEN];
> +	int fd;
> +
> +	fd = igt_debugfs_connector_dir(i915, output->name, O_RDONLY);
> +	if (fd < 0)
> +		return false;
> +
> +	if (is_i915_device(i915))
> +		debugfs_read(fd, "i915_hdcp_sink_capability", buf);
> +	else
> +		debugfs_read(fd, "hdcp_sink_capability", buf);
> +
> +	close(fd);
> +
> +	igt_debug("Sink capability: %s\n", buf);
> +
> +	return strstr(buf, "HDCP1.4");
> +}
> +
> +static bool output_hdcp_capable(int i915, igt_output_t *output, bool content_type)
> +{
> +	if (!output->props[IGT_CONNECTOR_CONTENT_PROTECTION])
> +		return false;
> +	if (!output->props[IGT_CONNECTOR_HDCP_CONTENT_TYPE] && content_type)
> +		return false;
> +	if (!sink_hdcp_capable(i915, output))
> +		return false;
> +
> +	return true;
> +}
> +
> +static void test_display_protected_crc(int i915, igt_display_t *display, bool hdcp)
> +{
> +	igt_output_t *output;
> +	drmModeModeInfo *mode;
> +	igt_fb_t ref_fb, protected_fb;
> +	igt_plane_t *plane;
> +	igt_pipe_t *pipe;
> +	igt_pipe_crc_t *pipe_crc;
> +	igt_crc_t ref_crc, new_crc;
> +	int width = 0, height = 0, i = 0, ret, count, valid_outputs = 0;
> +	uint32_t ctx;
> +	igt_output_t *hdcp_output[IGT_MAX_PIPES];
> +
> +	ret = create_ctx_with_params(i915, true, true, true, false, &ctx);
> +	igt_assert_eq(ret, 0);
> +
> +	for_each_connected_output(display, output) {
> +		mode = igt_output_get_mode(output);
> +
> +		width = max(width, mode->hdisplay);
> +		height = max(height, mode->vdisplay);
> +
> +		if (!output_hdcp_capable(i915, output, 0))
> +			continue;
> +
> +		hdcp_output[valid_outputs++] = output;
> +	}
> +
> +	if (hdcp)
> +		igt_require_f(valid_outputs > 0, "No HDCP capable connector found\n");
> +
> +	igt_create_color_fb(i915, width, height, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
> +			    0, 1, 0, &ref_fb);
> +
> +	/* Do a modeset on all outputs */
> +	for_each_connected_output(display, output) {
> +		mode = igt_output_get_mode(output);
> +		pipe = &display->pipes[i];
> +		plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> +		igt_require(igt_pipe_connector_valid(i, output));
> +		igt_output_set_pipe(output, i);
> +
> +		igt_plane_set_fb(plane, &ref_fb);
> +		igt_fb_set_size(&ref_fb, plane, mode->hdisplay, mode->vdisplay);
> +		igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> +
> +		igt_display_commit2(display, COMMIT_ATOMIC);
> +		i++;
> +	}
> +
> +	if (hdcp) {
> +		/* Enable HDCP on all the valid connectors */
> +		for (count = 0; count < valid_outputs; count++) {
> +			igt_output_set_prop_value(hdcp_output[count],
> +						  IGT_CONNECTOR_CONTENT_PROTECTION, CP_DESIRED);
> +			if (output->props[IGT_CONNECTOR_HDCP_CONTENT_TYPE])
> +				igt_output_set_prop_value(hdcp_output[count],
> +							  IGT_CONNECTOR_HDCP_CONTENT_TYPE, 0);
> +		}
> +
> +		igt_display_commit2(display, COMMIT_ATOMIC);
> +
> +		/*Verify that HDCP is enabled on all valid connectors */
> +		for (count = 0; count < valid_outputs; count++) {
> +			ret = wait_for_prop_value(hdcp_output[count], CP_ENABLED,
> +						  KERNEL_AUTH_TIME_ALLOWED_MSEC);
> +			igt_assert_f(ret, "Content Protection not enabled on %s\n",
> +				     hdcp_output[count]->name);
> +		}
> +	}
> +
> +	setup_protected_fb(i915, width, height, &protected_fb, ctx);
> +
> +	for_each_connected_output(display, output) {
> +		mode = igt_output_get_mode(output);
> +		pipe = &display->pipes[output->pending_pipe];
> +		pipe_crc = igt_pipe_crc_new(i915, pipe->pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
> +		plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> +		igt_require(igt_pipe_connector_valid(pipe->pipe, output));
> +		igt_output_set_pipe(output, pipe->pipe);
> +
> +		igt_plane_set_fb(plane, &ref_fb);
> +		igt_fb_set_size(&ref_fb, plane, mode->hdisplay, mode->vdisplay);
> +		igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> +
> +		igt_display_commit2(display, COMMIT_ATOMIC);
> +		igt_pipe_crc_collect_crc(pipe_crc, &ref_crc);
> +
> +		igt_plane_set_fb(plane, &protected_fb);
> +		igt_fb_set_size(&protected_fb, plane, mode->hdisplay, mode->vdisplay);
> +		igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> +
> +		igt_display_commit2(display, COMMIT_ATOMIC);
> +		igt_pipe_crc_collect_crc(pipe_crc, &new_crc);
> +		igt_assert_crc_equal(&ref_crc, &new_crc);
> +
> +		if (hdcp) {
> +			/* Disable HDCP and collect CRC */
> +			igt_output_set_prop_value(hdcp_output[0], IGT_CONNECTOR_CONTENT_PROTECTION,
> +						  CP_UNDESIRED);
> +			igt_display_commit2(display, COMMIT_ATOMIC);
> +			ret = wait_for_prop_value(hdcp_output[0], CP_UNDESIRED,
> +						  KERNEL_DISABLE_TIME_ALLOWED_MSEC);
> +			igt_assert_f(ret, "Content Protection not cleared\n");
> +
> +			igt_plane_set_fb(plane, &protected_fb);
> +			igt_fb_set_size(&protected_fb, plane, mode->hdisplay, mode->vdisplay);
> +			igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> +
> +			igt_display_commit2(display, COMMIT_ATOMIC);
> +			igt_pipe_crc_collect_crc(pipe_crc, &new_crc);
> +			igt_assert_f(!igt_check_crc_equal(&ref_crc, &new_crc),
> +				    "CRC's expected to be different after HDCP is disabled\n");

The CRC is at the pipe level, but I believe it is right to expect that
after disabling the HDCP we will get different CRC.

+Uma to help me to confirm this.

But also, I'm asking myself if this test case here is really bringing
any value to PXP itself. To me, it looks like it is only testing
HDCP disable scenario... nothing to do with the PXP flow.

With the HDCP removed, or with Uma confirming my assumption is right
and that I'm wrong about the value-added, feel free to use:

Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

> +		}
> +		/*
> +		 * Testing with one pipe-output combination is sufficient.
> +		 * So break the loop.
> +		 */
> +		break;
> +	}
> +
> +	gem_context_destroy(i915, ctx);
> +	igt_remove_fb(i915, &ref_fb);
> +	igt_remove_fb(i915, &protected_fb);
> +}
> +
>  igt_main
>  {
>  	int i915 = -1;
> @@ -944,6 +1205,7 @@ igt_main
>  	struct powermgt_data pm = {0};
>  	igt_render_copyfunc_t rendercopy = NULL;
>  	uint32_t devid = 0;
> +	igt_display_t display;
>  
>  	igt_fixture
>  	{
> @@ -1031,6 +1293,24 @@ igt_main
>  		igt_subtest("verify-pxp-execution-behavior-after-suspend-resume")
>  			test_pxp_pwrcycle_staleasset_execution(i915, &pm);
>  	}
> +	igt_subtest_group {
> +		igt_fixture {
> +			igt_require(pxp_supported);
> +			devid = intel_get_drm_devid(i915);
> +			igt_assert(devid);
> +			rendercopy = igt_get_render_copyfunc(devid);
> +			igt_require(rendercopy);
> +
> +			igt_require_pipe_crc(i915);
> +			igt_display_require(&display, i915);
> +		}
> +		igt_describe("Test the display CRC");
> +		igt_subtest("display-protected-crc-without-hdcp")
> +			test_display_protected_crc(i915, &display, 0);
> +		igt_subtest("display-protected-crc-with-hdcp")
> +			test_display_protected_crc(i915, &display, 1);
> +	}
> +
>  
>  	igt_fixture {
>  		close(i915);
> -- 
> 2.25.1
> 
> _______________________________________________
> igt-dev mailing list
> igt-dev@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/igt-dev
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

  reply	other threads:[~2021-06-04 14:41 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-18 10:33 [igt-dev] [PATCH i-g-t 00/17] Introduce PXP Test Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 01/17] Sync i915_drm.h UAPI from kernel Alan Previn
2021-06-02 20:07   ` Rodrigo Vivi
2021-06-03  0:15     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 02/17] Add PXP UAPI support in i915_drm.h Alan Previn
2021-06-02 20:10   ` Rodrigo Vivi
2021-06-03  0:50     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 03/17] Update IOCTL wrapper with DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT Alan Previn
2021-06-02 20:10   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 04/17] Add basic PXP testing of buffer and context alloc Alan Previn
2021-06-02 20:23   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 05/17] Perform a regular 3d copy as a control checkpoint Alan Previn
2021-06-02 21:37   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 06/17] Add PXP attribute support in batchbuffer and buffer_ops libs Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 07/17] Add MI_SET_APPID instruction definition Alan Previn
2021-06-02 21:40   ` Rodrigo Vivi
2021-06-03  0:54     ` Teres Alexis, Alan Previn
2021-06-03 15:06       ` Rodrigo Vivi
2021-06-03  8:52   ` Michal Wajdeczko
2021-06-03 15:22     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 08/17] Enable protected session cmd in gen12_render_copyfunc Alan Previn
2021-06-04 13:16   ` Rodrigo Vivi
2021-06-10 17:36     ` Teres Alexis, Alan Previn
2021-06-10 19:55       ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 09/17] Add subtest to copy raw source to protected dest Alan Previn
2021-06-04 13:22   ` Rodrigo Vivi
2021-06-05  1:30     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 10/17] Add test where both src and dest are protected Alan Previn
2021-06-04 13:31   ` Rodrigo Vivi
2021-06-05  1:38     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 11/17] Verify PXP teardown occurred through suspend-resume Alan Previn
2021-06-03 21:40   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 12/17] Verify execbuf fails with stale PXP context after teardown Alan Previn
2021-06-04 13:38   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 13/17] Verify execbuf fails with stale PXP buffer " Alan Previn
2021-06-03 21:41   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 14/17] Verify execbuf ok with stale prot-buff and regular context Alan Previn
2021-06-04 13:56   ` Rodrigo Vivi
2021-06-05  0:27     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 15/17] Ensure RESET_STATS reports invalidated protected context Alan Previn
2021-06-03 21:43   ` Rodrigo Vivi
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 16/17] Verify protected surfaces are dma buffer sharable Alan Previn
2021-06-04 14:18   ` Rodrigo Vivi
2021-06-05  0:45     ` Teres Alexis, Alan Previn
2021-05-18 10:33 ` [igt-dev] [PATCH i-g-t 17/17] tests/i915_pxp: CRC validation for display tests Alan Previn
2021-06-04 14:40   ` Rodrigo Vivi [this message]
2021-06-05  1:07     ` Teres Alexis, Alan Previn
2021-06-10 13:00       ` Shankar, Uma
2021-06-10 14:17         ` Rodrigo Vivi
2021-05-18 11:30 ` [igt-dev] ✓ Fi.CI.BAT: success for Introduce PXP Test (rev5) Patchwork
2021-05-18 18:19 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
2021-06-02 21:44   ` Rodrigo Vivi
2021-06-03 18:09     ` Teres Alexis, Alan Previn
2021-06-03 18:13       ` Rodrigo Vivi
  -- strict thread matches above, loose matches on Subject: below --
2021-05-15 23:01 [igt-dev] [PATCH i-g-t 00/17] Introduce PXP Test Alan Previn
2021-05-15 23:01 ` [igt-dev] [PATCH i-g-t 17/17] tests/i915_pxp: CRC validation for display tests Alan Previn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YLo7d2H3IM7ioEcq@intel.com \
    --to=rodrigo.vivi@intel.com \
    --cc=alan.previn.teres.alexis@intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=uma.shankar@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.