All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] Arm64: introduce __hyp_func_call
@ 2014-08-27 10:28 Arun Chandran
  2014-08-27 10:47 ` Marc Zyngier
  2014-08-27 10:52 ` Marc Zyngier
  0 siblings, 2 replies; 5+ messages in thread
From: Arun Chandran @ 2014-08-27 10:28 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a mechanism to __hyp_stub_vectors to allow a hypercall to
call a function at EL2. It is needed for users who want to
run a part of code with EL2 permissions. The current usecase is for
KVM and kexec.

For kexec we need to move the final CPU up to the mode it started
in before we branch to the new kernel. If we don't do that

* We loose EL2 in the next boot
* Arm64 bootwrapper may not be able to put CPUs at the spin-table
  code. It expects the final jump from kernel to cpu-return-addr to be
  done in EL2.

KVM can use this to set/get VBAR_EL2

Signed-off-by: Arun Chandran <achandran@mvista.com>
---
Idea is from "Mark Rutland <mark.rutland@arm.com>"
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/280026.html
---
 arch/arm64/include/asm/virt.h |   15 +++++++++++++++
 arch/arm64/kernel/hyp-stub.S  |   33 +++++++++++++++++++++------------
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index 7a5df52..910a163 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -34,9 +34,24 @@
  */
 extern u32 __boot_cpu_mode[2];
 
+void *__hyp_func_call(u64 __tmp, phys_addr_t func, ...);
 void __hyp_set_vectors(phys_addr_t phys_vector_base);
 phys_addr_t __hyp_get_vectors(void);
 
+#define __hyp_set_vectors(__vbase)					    \
+({									    \
+	u64 __tmp = 0;							    \
+	__hyp_func_call(__tmp, virt_to_phys(__hyp_set_vectors), __vbase);   \
+})
+
+#define __hyp_get_vectors()						    \
+({									    \
+	u64 __tmp = 0;							    \
+	phys_addr_t ret = (phys_addr_t) __hyp_func_call(__tmp,		    \
+					virt_to_phys(__hyp_get_vectors));   \
+	ret;								    \
+})
+
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
 {
diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
index a272f33..2144a3f 100644
--- a/arch/arm64/kernel/hyp-stub.S
+++ b/arch/arm64/kernel/hyp-stub.S
@@ -53,15 +53,14 @@ ENDPROC(__hyp_stub_vectors)
 	.align 11
 
 el1_sync:
-	mrs	x1, esr_el2
-	lsr	x1, x1, #26
-	cmp	x1, #0x16
+	mrs	x0, esr_el2
+	lsr	x0, x0, #26
+	cmp	x0, #0x16
 	b.ne	2f				// Not an HVC trap
-	cbz	x0, 1f
-	msr	vbar_el2, x0			// Set vbar_el2
-	b	2f
-1:	mrs	x0, vbar_el2			// Return vbar_el2
-2:	eret
+
+1:	blr	x1 				// Jump to the function
+2:	mov	x0, xzr				// esr_el2 not readable <= el2
+	eret
 ENDPROC(el1_sync)
 
 .macro invalid_vector	label
@@ -101,10 +100,20 @@ ENDPROC(\label)
  */
 
 ENTRY(__hyp_get_vectors)
-	mov	x0, xzr
-	// fall through
-ENTRY(__hyp_set_vectors)
-	hvc	#0
+	mrs	x0, vbar_el2			// Return vbar_el2
 	ret
 ENDPROC(__hyp_get_vectors)
+
+ENTRY(__hyp_set_vectors)
+	msr	vbar_el2, x2
+	ret
 ENDPROC(__hyp_set_vectors)
+
+/* Call a function @x1 */
+ENTRY(__hyp_func_call)
+	/* Save lr here */
+	msr	elr_el1, x30
+	hvc	#0
+	mrs	x30, elr_el1
+	ret
+ENDPROC(__hyp_func_call)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH] Arm64: introduce __hyp_func_call
  2014-08-27 10:28 [RFC PATCH] Arm64: introduce __hyp_func_call Arun Chandran
@ 2014-08-27 10:47 ` Marc Zyngier
  2014-08-27 10:52 ` Marc Zyngier
  1 sibling, 0 replies; 5+ messages in thread
From: Marc Zyngier @ 2014-08-27 10:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 27 2014 at 11:28:34 am BST, Arun Chandran <achandran@mvista.com> wrote:
> This adds a mechanism to __hyp_stub_vectors to allow a hypercall to
> call a function at EL2. It is needed for users who want to
> run a part of code with EL2 permissions. The current usecase is for
> KVM and kexec.
>
> For kexec we need to move the final CPU up to the mode it started
> in before we branch to the new kernel. If we don't do that
>
> * We loose EL2 in the next boot
> * Arm64 bootwrapper may not be able to put CPUs at the spin-table
>   code. It expects the final jump from kernel to cpu-return-addr to be
>   done in EL2.
>
> KVM can use this to set/get VBAR_EL2

So you've now broken KVM on arm64, since this patch doesn't address the
callers. But if you do so, you also break KVM on 32bit ARM, as we share
the calling code.

So you'll have to work a bit more before this can be an acceptable
solution.

Thanks,

	M.

> Signed-off-by: Arun Chandran <achandran@mvista.com>
> ---
> Idea is from "Mark Rutland <mark.rutland@arm.com>"
> http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/280026.html
> ---
>  arch/arm64/include/asm/virt.h |   15 +++++++++++++++
>  arch/arm64/kernel/hyp-stub.S  |   33 +++++++++++++++++++++------------
>  2 files changed, 36 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 7a5df52..910a163 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -34,9 +34,24 @@
>   */
>  extern u32 __boot_cpu_mode[2];
>  
> +void *__hyp_func_call(u64 __tmp, phys_addr_t func, ...);
>  void __hyp_set_vectors(phys_addr_t phys_vector_base);
>  phys_addr_t __hyp_get_vectors(void);
>  
> +#define __hyp_set_vectors(__vbase)					    \
> +({									    \
> +	u64 __tmp = 0;							    \
> +	__hyp_func_call(__tmp, virt_to_phys(__hyp_set_vectors), __vbase);   \
> +})
> +
> +#define __hyp_get_vectors()						    \
> +({									    \
> +	u64 __tmp = 0;							    \
> +	phys_addr_t ret = (phys_addr_t) __hyp_func_call(__tmp,		    \
> +					virt_to_phys(__hyp_get_vectors));   \
> +	ret;								    \
> +})
> +
>  /* Reports the availability of HYP mode */
>  static inline bool is_hyp_mode_available(void)
>  {
> diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
> index a272f33..2144a3f 100644
> --- a/arch/arm64/kernel/hyp-stub.S
> +++ b/arch/arm64/kernel/hyp-stub.S
> @@ -53,15 +53,14 @@ ENDPROC(__hyp_stub_vectors)
>  	.align 11
>  
>  el1_sync:
> -	mrs	x1, esr_el2
> -	lsr	x1, x1, #26
> -	cmp	x1, #0x16
> +	mrs	x0, esr_el2
> +	lsr	x0, x0, #26
> +	cmp	x0, #0x16
>  	b.ne	2f				// Not an HVC trap
> -	cbz	x0, 1f
> -	msr	vbar_el2, x0			// Set vbar_el2
> -	b	2f
> -1:	mrs	x0, vbar_el2			// Return vbar_el2
> -2:	eret
> +
> +1:	blr	x1 				// Jump to the function
> +2:	mov	x0, xzr				// esr_el2 not readable <= el2
> +	eret
>  ENDPROC(el1_sync)
>  
>  .macro invalid_vector	label
> @@ -101,10 +100,20 @@ ENDPROC(\label)
>   */
>  
>  ENTRY(__hyp_get_vectors)
> -	mov	x0, xzr
> -	// fall through
> -ENTRY(__hyp_set_vectors)
> -	hvc	#0
> +	mrs	x0, vbar_el2			// Return vbar_el2
>  	ret
>  ENDPROC(__hyp_get_vectors)
> +
> +ENTRY(__hyp_set_vectors)
> +	msr	vbar_el2, x2
> +	ret
>  ENDPROC(__hyp_set_vectors)
> +
> +/* Call a function @x1 */
> +ENTRY(__hyp_func_call)
> +	/* Save lr here */
> +	msr	elr_el1, x30
> +	hvc	#0
> +	mrs	x30, elr_el1
> +	ret
> +ENDPROC(__hyp_func_call)

-- 
Jazz is not dead. It just smells funny.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC PATCH] Arm64: introduce __hyp_func_call
  2014-08-27 10:28 [RFC PATCH] Arm64: introduce __hyp_func_call Arun Chandran
  2014-08-27 10:47 ` Marc Zyngier
@ 2014-08-27 10:52 ` Marc Zyngier
  2014-08-30 10:32   ` Arun Chandran
  1 sibling, 1 reply; 5+ messages in thread
From: Marc Zyngier @ 2014-08-27 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 27/08/14 11:28, Arun Chandran wrote:
> This adds a mechanism to __hyp_stub_vectors to allow a hypercall to
> call a function at EL2. It is needed for users who want to
> run a part of code with EL2 permissions. The current usecase is for
> KVM and kexec.
> 
> For kexec we need to move the final CPU up to the mode it started
> in before we branch to the new kernel. If we don't do that
> 
> * We loose EL2 in the next boot
> * Arm64 bootwrapper may not be able to put CPUs at the spin-table
>   code. It expects the final jump from kernel to cpu-return-addr to be
>   done in EL2.
> 
> KVM can use this to set/get VBAR_EL2

Ah, looking at this a bit more, I see what you've done (missed the
#define trickery below).

> Signed-off-by: Arun Chandran <achandran@mvista.com>
> ---
> Idea is from "Mark Rutland <mark.rutland@arm.com>"
> http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/280026.html
> ---
>  arch/arm64/include/asm/virt.h |   15 +++++++++++++++
>  arch/arm64/kernel/hyp-stub.S  |   33 +++++++++++++++++++++------------
>  2 files changed, 36 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 7a5df52..910a163 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -34,9 +34,24 @@
>   */
>  extern u32 __boot_cpu_mode[2];
>  
> +void *__hyp_func_call(u64 __tmp, phys_addr_t func, ...);
>  void __hyp_set_vectors(phys_addr_t phys_vector_base);
>  phys_addr_t __hyp_get_vectors(void);
>  
> +#define __hyp_set_vectors(__vbase)					    \
> +({									    \
> +	u64 __tmp = 0;							    \
> +	__hyp_func_call(__tmp, virt_to_phys(__hyp_set_vectors), __vbase);   \
> +})
> +
> +#define __hyp_get_vectors()						    \
> +({									    \
> +	u64 __tmp = 0;							    \
> +	phys_addr_t ret = (phys_addr_t) __hyp_func_call(__tmp,		    \
> +					virt_to_phys(__hyp_get_vectors));   \
> +	ret;								    \
> +})
> +

This is what has thrown me off the wrong path. Don't do that, this is
horrid. Just rename the assembly entry points, it will make things a lot
clearer.

Thanks,

	M.

>  /* Reports the availability of HYP mode */
>  static inline bool is_hyp_mode_available(void)
>  {
> diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
> index a272f33..2144a3f 100644
> --- a/arch/arm64/kernel/hyp-stub.S
> +++ b/arch/arm64/kernel/hyp-stub.S
> @@ -53,15 +53,14 @@ ENDPROC(__hyp_stub_vectors)
>  	.align 11
>  
>  el1_sync:
> -	mrs	x1, esr_el2
> -	lsr	x1, x1, #26
> -	cmp	x1, #0x16
> +	mrs	x0, esr_el2
> +	lsr	x0, x0, #26
> +	cmp	x0, #0x16
>  	b.ne	2f				// Not an HVC trap
> -	cbz	x0, 1f
> -	msr	vbar_el2, x0			// Set vbar_el2
> -	b	2f
> -1:	mrs	x0, vbar_el2			// Return vbar_el2
> -2:	eret
> +
> +1:	blr	x1 				// Jump to the function
> +2:	mov	x0, xzr				// esr_el2 not readable <= el2
> +	eret
>  ENDPROC(el1_sync)
>  
>  .macro invalid_vector	label
> @@ -101,10 +100,20 @@ ENDPROC(\label)
>   */
>  
>  ENTRY(__hyp_get_vectors)
> -	mov	x0, xzr
> -	// fall through
> -ENTRY(__hyp_set_vectors)
> -	hvc	#0
> +	mrs	x0, vbar_el2			// Return vbar_el2
>  	ret
>  ENDPROC(__hyp_get_vectors)
> +
> +ENTRY(__hyp_set_vectors)
> +	msr	vbar_el2, x2
> +	ret
>  ENDPROC(__hyp_set_vectors)
> +
> +/* Call a function @x1 */
> +ENTRY(__hyp_func_call)
> +	/* Save lr here */
> +	msr	elr_el1, x30
> +	hvc	#0
> +	mrs	x30, elr_el1
> +	ret
> +ENDPROC(__hyp_func_call)
> 


-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC PATCH] Arm64: introduce __hyp_func_call
  2014-08-27 10:52 ` Marc Zyngier
@ 2014-08-30 10:32   ` Arun Chandran
  2014-09-01  8:28     ` Marc Zyngier
  0 siblings, 1 reply; 5+ messages in thread
From: Arun Chandran @ 2014-08-30 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On Wed, Aug 27, 2014 at 4:22 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 27/08/14 11:28, Arun Chandran wrote:
>> This adds a mechanism to __hyp_stub_vectors to allow a hypercall to
>> call a function at EL2. It is needed for users who want to
>> run a part of code with EL2 permissions. The current usecase is for
>> KVM and kexec.
>>
>> For kexec we need to move the final CPU up to the mode it started
>> in before we branch to the new kernel. If we don't do that
>>
>> * We loose EL2 in the next boot
>> * Arm64 bootwrapper may not be able to put CPUs at the spin-table
>>   code. It expects the final jump from kernel to cpu-return-addr to be
>>   done in EL2.
>>
>> KVM can use this to set/get VBAR_EL2
>
> Ah, looking at this a bit more, I see what you've done (missed the
> #define trickery below).
>
>> Signed-off-by: Arun Chandran <achandran@mvista.com>
>> ---
>> Idea is from "Mark Rutland <mark.rutland@arm.com>"
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/280026.html
>> ---
>>  arch/arm64/include/asm/virt.h |   15 +++++++++++++++
>>  arch/arm64/kernel/hyp-stub.S  |   33 +++++++++++++++++++++------------
>>  2 files changed, 36 insertions(+), 12 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
>> index 7a5df52..910a163 100644
>> --- a/arch/arm64/include/asm/virt.h
>> +++ b/arch/arm64/include/asm/virt.h
>> @@ -34,9 +34,24 @@
>>   */
>>  extern u32 __boot_cpu_mode[2];
>>
>> +void *__hyp_func_call(u64 __tmp, phys_addr_t func, ...);
>>  void __hyp_set_vectors(phys_addr_t phys_vector_base);
>>  phys_addr_t __hyp_get_vectors(void);
>>
>> +#define __hyp_set_vectors(__vbase)                                       \
>> +({                                                                       \
>> +     u64 __tmp = 0;                                                      \
>> +     __hyp_func_call(__tmp, virt_to_phys(__hyp_set_vectors), __vbase);   \
>> +})
>> +
>> +#define __hyp_get_vectors()                                              \
>> +({                                                                       \
>> +     u64 __tmp = 0;                                                      \
>> +     phys_addr_t ret = (phys_addr_t) __hyp_func_call(__tmp,              \
>> +                                     virt_to_phys(__hyp_get_vectors));   \
>> +     ret;                                                                \
>> +})
>> +
>
> This is what has thrown me off the wrong path. Don't do that, this is
> horrid. Just rename the assembly entry points, it will make things a lot
> clearer.
>

Ok. I will post another one.

--Arun


> Thanks,
>
>         M.
>
>>  /* Reports the availability of HYP mode */
>>  static inline bool is_hyp_mode_available(void)
>>  {
>> diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
>> index a272f33..2144a3f 100644
>> --- a/arch/arm64/kernel/hyp-stub.S
>> +++ b/arch/arm64/kernel/hyp-stub.S
>> @@ -53,15 +53,14 @@ ENDPROC(__hyp_stub_vectors)
>>       .align 11
>>
>>  el1_sync:
>> -     mrs     x1, esr_el2
>> -     lsr     x1, x1, #26
>> -     cmp     x1, #0x16
>> +     mrs     x0, esr_el2
>> +     lsr     x0, x0, #26
>> +     cmp     x0, #0x16
>>       b.ne    2f                              // Not an HVC trap
>> -     cbz     x0, 1f
>> -     msr     vbar_el2, x0                    // Set vbar_el2
>> -     b       2f
>> -1:   mrs     x0, vbar_el2                    // Return vbar_el2
>> -2:   eret
>> +
>> +1:   blr     x1                              // Jump to the function
>> +2:   mov     x0, xzr                         // esr_el2 not readable <= el2
>> +     eret
>>  ENDPROC(el1_sync)
>>
>>  .macro invalid_vector        label
>> @@ -101,10 +100,20 @@ ENDPROC(\label)
>>   */
>>
>>  ENTRY(__hyp_get_vectors)
>> -     mov     x0, xzr
>> -     // fall through
>> -ENTRY(__hyp_set_vectors)
>> -     hvc     #0
>> +     mrs     x0, vbar_el2                    // Return vbar_el2
>>       ret
>>  ENDPROC(__hyp_get_vectors)
>> +
>> +ENTRY(__hyp_set_vectors)
>> +     msr     vbar_el2, x2
>> +     ret
>>  ENDPROC(__hyp_set_vectors)
>> +
>> +/* Call a function @x1 */
>> +ENTRY(__hyp_func_call)
>> +     /* Save lr here */
>> +     msr     elr_el1, x30
>> +     hvc     #0
>> +     mrs     x30, elr_el1
>> +     ret
>> +ENDPROC(__hyp_func_call)
>>
>
>
> --
> Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC PATCH] Arm64: introduce __hyp_func_call
  2014-08-30 10:32   ` Arun Chandran
@ 2014-09-01  8:28     ` Marc Zyngier
  0 siblings, 0 replies; 5+ messages in thread
From: Marc Zyngier @ 2014-09-01  8:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 30/08/14 11:32, Arun Chandran wrote:
> Hi Marc,
> 
> On Wed, Aug 27, 2014 at 4:22 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On 27/08/14 11:28, Arun Chandran wrote:
>>> This adds a mechanism to __hyp_stub_vectors to allow a hypercall to
>>> call a function at EL2. It is needed for users who want to
>>> run a part of code with EL2 permissions. The current usecase is for
>>> KVM and kexec.
>>>
>>> For kexec we need to move the final CPU up to the mode it started
>>> in before we branch to the new kernel. If we don't do that
>>>
>>> * We loose EL2 in the next boot
>>> * Arm64 bootwrapper may not be able to put CPUs at the spin-table
>>>   code. It expects the final jump from kernel to cpu-return-addr to be
>>>   done in EL2.
>>>
>>> KVM can use this to set/get VBAR_EL2
>>
>> Ah, looking at this a bit more, I see what you've done (missed the
>> #define trickery below).
>>
>>> Signed-off-by: Arun Chandran <achandran@mvista.com>
>>> ---
>>> Idea is from "Mark Rutland <mark.rutland@arm.com>"
>>> http://lists.infradead.org/pipermail/linux-arm-kernel/2014-August/280026.html
>>> ---
>>>  arch/arm64/include/asm/virt.h |   15 +++++++++++++++
>>>  arch/arm64/kernel/hyp-stub.S  |   33 +++++++++++++++++++++------------
>>>  2 files changed, 36 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
>>> index 7a5df52..910a163 100644
>>> --- a/arch/arm64/include/asm/virt.h
>>> +++ b/arch/arm64/include/asm/virt.h
>>> @@ -34,9 +34,24 @@
>>>   */
>>>  extern u32 __boot_cpu_mode[2];
>>>
>>> +void *__hyp_func_call(u64 __tmp, phys_addr_t func, ...);
>>>  void __hyp_set_vectors(phys_addr_t phys_vector_base);
>>>  phys_addr_t __hyp_get_vectors(void);
>>>
>>> +#define __hyp_set_vectors(__vbase)                                       \
>>> +({                                                                       \
>>> +     u64 __tmp = 0;                                                      \
>>> +     __hyp_func_call(__tmp, virt_to_phys(__hyp_set_vectors), __vbase);   \
>>> +})
>>> +
>>> +#define __hyp_get_vectors()                                              \
>>> +({                                                                       \
>>> +     u64 __tmp = 0;                                                      \
>>> +     phys_addr_t ret = (phys_addr_t) __hyp_func_call(__tmp,              \
>>> +                                     virt_to_phys(__hyp_get_vectors));   \
>>> +     ret;                                                                \
>>> +})
>>> +
>>
>> This is what has thrown me off the wrong path. Don't do that, this is
>> horrid. Just rename the assembly entry points, it will make things a lot
>> clearer.
>>
> 
> Ok. I will post another one.

Hold on, there are more problems.

You've changed the case that works when KVM is *not* running. But if you
look at the KVM code, you'll see that it has its own implementation of
__hyp_get_vectors. What will happen when KVM calls this version of
__hyp_get_vectors (on a CPU hotplug event, for example)? The code isn't
mapped in KVM's HYP code, so it will simply burst into flames.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-09-01  8:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-27 10:28 [RFC PATCH] Arm64: introduce __hyp_func_call Arun Chandran
2014-08-27 10:47 ` Marc Zyngier
2014-08-27 10:52 ` Marc Zyngier
2014-08-30 10:32   ` Arun Chandran
2014-09-01  8:28     ` Marc Zyngier

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.