From: Andrew Jones <drjones@redhat.com>
To: qemu-devel@nongnu.org, qemu-arm@nongnu.org
Cc: peter.maydell@linaro.org, richard.henderson@linaro.org,
alex.bennee@linaro.org, armbru@redhat.com, eblake@redhat.com,
Dave.Martin@arm.com, abologna@redhat.com
Subject: [PATCH 05/13] target/arm/kvm: Add kvm_arch_get/put_sve
Date: Sun, 12 May 2019 10:36:16 +0200 [thread overview]
Message-ID: <20190512083624.8916-6-drjones@redhat.com> (raw)
In-Reply-To: <20190512083624.8916-1-drjones@redhat.com>
These are the SVE equivalents to kvm_arch_get/put_fpsimd.
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
target/arm/kvm64.c | 127 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 123 insertions(+), 4 deletions(-)
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 61947f3716e1..86362f4cd7d0 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -658,11 +658,12 @@ int kvm_arch_init_vcpu(CPUState *cs)
bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
{
/* Return true if the regidx is a register we should synchronize
- * via the cpreg_tuples array (ie is not a core reg we sync by
- * hand in kvm_arch_get/put_registers())
+ * via the cpreg_tuples array (ie is not a core or sve reg that
+ * we sync by hand in kvm_arch_get/put_registers())
*/
switch (regidx & KVM_REG_ARM_COPROC_MASK) {
case KVM_REG_ARM_CORE:
+ case KVM_REG_ARM64_SVE:
return false;
default:
return true;
@@ -748,6 +749,61 @@ static int kvm_arch_put_fpsimd(CPUState *cs)
return 0;
}
+static int kvm_arch_put_sve(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ struct kvm_one_reg reg;
+ int n, ret;
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; n++) {
+ uint64_t *q = aa64_vfp_qreg(env, n);
+#ifdef HOST_WORDS_BIGENDIAN
+ uint64_t d[ARM_MAX_VQ * 2];
+ int i;
+ for (i = 0; i < cpu->sve_max_vq * 2; i++) {
+ d[i] = q[cpu->sve_max_vq * 2 - 1 - i];
+ }
+ reg.addr = (uintptr_t)d;
+#else
+ reg.addr = (uintptr_t)q;
+#endif
+ reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; n++) {
+ uint64_t *p = &env->vfp.pregs[n].p[0];
+#ifdef HOST_WORDS_BIGENDIAN
+ uint64_t d[ARM_MAX_VQ * 2];
+ int i;
+ for (i = 0; i < cpu->sve_max_vq * 2 / 8; i++) {
+ d[i] = p[cpu->sve_max_vq * 2 / 8 - 1 - i];
+ }
+ reg.addr = (uintptr_t)d;
+#else
+ reg.addr = (uintptr_t)p;
+#endif
+ reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ reg.addr = (uintptr_t)&env->vfp.pregs[FFR_PRED_NUM].p[0];
+ reg.id = KVM_REG_ARM64_SVE_FFR(0);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
int kvm_arch_put_registers(CPUState *cs, int level)
{
struct kvm_one_reg reg;
@@ -842,7 +898,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
}
- ret = kvm_arch_put_fpsimd(cs);
+ if (!cpu_isar_feature(aa64_sve, cpu)) {
+ ret = kvm_arch_put_fpsimd(cs);
+ } else {
+ ret = kvm_arch_put_sve(cs);
+ }
if (ret) {
return ret;
}
@@ -905,6 +965,61 @@ static int kvm_arch_get_fpsimd(CPUState *cs)
return 0;
}
+static int kvm_arch_get_sve(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ struct kvm_one_reg reg;
+ int n, ret;
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; n++) {
+ uint64_t *q = aa64_vfp_qreg(env, n);
+ reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+ reg.addr = (uintptr_t)q;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ } else {
+#ifdef HOST_WORDS_BIGENDIAN
+ int i = 0, j = cpu->sve_max_vq * 2 - 1;
+ while (i < j) {
+ uint64_t t;
+ t = q[i], q[i] = q[j], q[j] = t;
+ ++i, --j;
+ }
+#endif
+ }
+ }
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; n++) {
+ uint64_t *p = &env->vfp.pregs[n].p[0];
+ reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+ reg.addr = (uintptr_t)p;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ } else {
+#ifdef HOST_WORDS_BIGENDIAN
+ int i = 0, j = cpu->sve_max_vq * 2 / 8 - 1;
+ while (i < j) {
+ uint64_t t;
+ t = q[i], q[i] = q[j], q[j] = t;
+ ++i, --j;
+ }
+#endif
+ }
+ }
+
+ reg.addr = (uintptr_t)&env->vfp.pregs[FFR_PRED_NUM].p[0];
+ reg.id = KVM_REG_ARM64_SVE_FFR(0);
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
int kvm_arch_get_registers(CPUState *cs)
{
struct kvm_one_reg reg;
@@ -999,7 +1114,11 @@ int kvm_arch_get_registers(CPUState *cs)
env->spsr = env->banked_spsr[i];
}
- ret = kvm_arch_get_fpsimd(cs);
+ if (!cpu_isar_feature(aa64_sve, cpu)) {
+ ret = kvm_arch_get_fpsimd(cs);
+ } else {
+ ret = kvm_arch_get_sve(cs);
+ }
if (ret) {
return ret;
}
--
2.20.1
WARNING: multiple messages have this Message-ID (diff)
From: Andrew Jones <drjones@redhat.com>
To: qemu-devel@nongnu.org, qemu-arm@nongnu.org
Cc: peter.maydell@linaro.org, richard.henderson@linaro.org,
armbru@redhat.com, abologna@redhat.com, alex.bennee@linaro.org,
Dave.Martin@arm.com
Subject: [Qemu-devel] [PATCH 05/13] target/arm/kvm: Add kvm_arch_get/put_sve
Date: Sun, 12 May 2019 10:36:16 +0200 [thread overview]
Message-ID: <20190512083624.8916-6-drjones@redhat.com> (raw)
In-Reply-To: <20190512083624.8916-1-drjones@redhat.com>
These are the SVE equivalents to kvm_arch_get/put_fpsimd.
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
target/arm/kvm64.c | 127 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 123 insertions(+), 4 deletions(-)
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 61947f3716e1..86362f4cd7d0 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -658,11 +658,12 @@ int kvm_arch_init_vcpu(CPUState *cs)
bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
{
/* Return true if the regidx is a register we should synchronize
- * via the cpreg_tuples array (ie is not a core reg we sync by
- * hand in kvm_arch_get/put_registers())
+ * via the cpreg_tuples array (ie is not a core or sve reg that
+ * we sync by hand in kvm_arch_get/put_registers())
*/
switch (regidx & KVM_REG_ARM_COPROC_MASK) {
case KVM_REG_ARM_CORE:
+ case KVM_REG_ARM64_SVE:
return false;
default:
return true;
@@ -748,6 +749,61 @@ static int kvm_arch_put_fpsimd(CPUState *cs)
return 0;
}
+static int kvm_arch_put_sve(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ struct kvm_one_reg reg;
+ int n, ret;
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; n++) {
+ uint64_t *q = aa64_vfp_qreg(env, n);
+#ifdef HOST_WORDS_BIGENDIAN
+ uint64_t d[ARM_MAX_VQ * 2];
+ int i;
+ for (i = 0; i < cpu->sve_max_vq * 2; i++) {
+ d[i] = q[cpu->sve_max_vq * 2 - 1 - i];
+ }
+ reg.addr = (uintptr_t)d;
+#else
+ reg.addr = (uintptr_t)q;
+#endif
+ reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; n++) {
+ uint64_t *p = &env->vfp.pregs[n].p[0];
+#ifdef HOST_WORDS_BIGENDIAN
+ uint64_t d[ARM_MAX_VQ * 2];
+ int i;
+ for (i = 0; i < cpu->sve_max_vq * 2 / 8; i++) {
+ d[i] = p[cpu->sve_max_vq * 2 / 8 - 1 - i];
+ }
+ reg.addr = (uintptr_t)d;
+#else
+ reg.addr = (uintptr_t)p;
+#endif
+ reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ reg.addr = (uintptr_t)&env->vfp.pregs[FFR_PRED_NUM].p[0];
+ reg.id = KVM_REG_ARM64_SVE_FFR(0);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
int kvm_arch_put_registers(CPUState *cs, int level)
{
struct kvm_one_reg reg;
@@ -842,7 +898,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
}
- ret = kvm_arch_put_fpsimd(cs);
+ if (!cpu_isar_feature(aa64_sve, cpu)) {
+ ret = kvm_arch_put_fpsimd(cs);
+ } else {
+ ret = kvm_arch_put_sve(cs);
+ }
if (ret) {
return ret;
}
@@ -905,6 +965,61 @@ static int kvm_arch_get_fpsimd(CPUState *cs)
return 0;
}
+static int kvm_arch_get_sve(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ struct kvm_one_reg reg;
+ int n, ret;
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; n++) {
+ uint64_t *q = aa64_vfp_qreg(env, n);
+ reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+ reg.addr = (uintptr_t)q;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ } else {
+#ifdef HOST_WORDS_BIGENDIAN
+ int i = 0, j = cpu->sve_max_vq * 2 - 1;
+ while (i < j) {
+ uint64_t t;
+ t = q[i], q[i] = q[j], q[j] = t;
+ ++i, --j;
+ }
+#endif
+ }
+ }
+
+ for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; n++) {
+ uint64_t *p = &env->vfp.pregs[n].p[0];
+ reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+ reg.addr = (uintptr_t)p;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ } else {
+#ifdef HOST_WORDS_BIGENDIAN
+ int i = 0, j = cpu->sve_max_vq * 2 / 8 - 1;
+ while (i < j) {
+ uint64_t t;
+ t = q[i], q[i] = q[j], q[j] = t;
+ ++i, --j;
+ }
+#endif
+ }
+ }
+
+ reg.addr = (uintptr_t)&env->vfp.pregs[FFR_PRED_NUM].p[0];
+ reg.id = KVM_REG_ARM64_SVE_FFR(0);
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
int kvm_arch_get_registers(CPUState *cs)
{
struct kvm_one_reg reg;
@@ -999,7 +1114,11 @@ int kvm_arch_get_registers(CPUState *cs)
env->spsr = env->banked_spsr[i];
}
- ret = kvm_arch_get_fpsimd(cs);
+ if (!cpu_isar_feature(aa64_sve, cpu)) {
+ ret = kvm_arch_get_fpsimd(cs);
+ } else {
+ ret = kvm_arch_get_sve(cs);
+ }
if (ret) {
return ret;
}
--
2.20.1
next prev parent reply other threads:[~2019-05-12 8:36 UTC|newest]
Thread overview: 131+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-12 8:36 [PATCH 00/13] target/arm/kvm: enable SVE in guests Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-12 8:36 ` [PATCH 01/13] target/arm/kvm64: fix error returns Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-06-05 7:20 ` Auger Eric
2019-05-12 8:36 ` [PATCH 02/13] update-linux-headers: Add sve_context.h to asm-arm64 Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-06-05 7:21 ` Auger Eric
2019-06-05 7:30 ` Andrew Jones
2019-06-05 7:30 ` Andrew Jones
2019-05-12 8:36 ` [PATCH 03/13] HACK: linux header update Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-12 8:36 ` [PATCH 04/13] target/arm/kvm: Move the get/put of fpsimd registers out Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-06-05 7:15 ` Auger Eric
2019-06-05 7:27 ` Andrew Jones
2019-06-05 7:27 ` Andrew Jones
2019-05-12 8:36 ` Andrew Jones [this message]
2019-05-12 8:36 ` [Qemu-devel] [PATCH 05/13] target/arm/kvm: Add kvm_arch_get/put_sve Andrew Jones
2019-05-13 12:31 ` Dave Martin
2019-05-13 12:31 ` [Qemu-devel] " Dave Martin
2019-05-13 13:55 ` Andrew Jones
2019-05-13 13:55 ` Andrew Jones
2019-05-13 15:31 ` Dave Martin
2019-05-13 15:31 ` Dave Martin
2019-05-13 15:40 ` Peter Maydell
2019-05-13 15:40 ` Peter Maydell
2019-05-13 16:05 ` Dave Martin
2019-05-13 16:05 ` Dave Martin
2019-05-13 16:40 ` Richard Henderson
2019-05-13 16:40 ` [Qemu-devel] " Richard Henderson
2019-05-13 18:14 ` Andrew Jones
2019-05-13 18:14 ` [Qemu-devel] " Andrew Jones
2019-05-13 18:31 ` Richard Henderson
2019-05-13 18:31 ` [Qemu-devel] " Richard Henderson
2019-05-13 12:43 ` Dave Martin
2019-05-13 12:43 ` [Qemu-devel] " Dave Martin
2019-05-13 14:07 ` Andrew Jones
2019-05-13 14:07 ` Andrew Jones
2019-05-13 14:39 ` Dave Martin
2019-05-13 14:39 ` Dave Martin
2019-05-13 16:58 ` Richard Henderson
2019-05-13 16:58 ` Richard Henderson
2019-05-14 9:10 ` Dave Martin
2019-05-14 9:10 ` Dave Martin
2019-05-12 8:36 ` [PATCH 06/13] target/arm/kvm: max cpu: Enable SVE when available Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-06-05 9:09 ` Auger Eric
2019-06-05 11:04 ` Andrew Jones
2019-06-05 11:04 ` Andrew Jones
2019-05-12 8:36 ` [PATCH 07/13] target/arm/kvm: max cpu: Allow sve max vector length setting Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-13 17:19 ` Richard Henderson
2019-05-13 17:19 ` [Qemu-devel] " Richard Henderson
2019-05-13 18:19 ` Andrew Jones
2019-05-13 18:19 ` Andrew Jones
2019-06-06 8:30 ` Auger Eric
2019-06-06 8:53 ` Andrew Jones
2019-06-06 8:53 ` Andrew Jones
2019-05-12 8:36 ` [PATCH 08/13] target/arm/monitor: Add query-sve-vector-lengths Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-13 16:12 ` Markus Armbruster
2019-05-13 16:12 ` Markus Armbruster
2019-05-13 18:30 ` Andrew Jones
2019-05-13 18:30 ` Andrew Jones
2019-05-14 5:32 ` Markus Armbruster
2019-05-12 8:36 ` [PATCH 09/13] target/arm/kvm: Export kvm_arm_get_sve_vls Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-12 8:36 ` [PATCH 10/13] target/arm/monitor: kvm: only return valid sve vector sets Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-12 8:36 ` [PATCH 11/13] target/arm/cpu64: max cpu: Introduce sve-vls-map Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-13 11:26 ` Dave Martin
2019-05-13 11:26 ` [Qemu-devel] " Dave Martin
2019-05-13 12:30 ` Andrew Jones
2019-05-13 12:30 ` Andrew Jones
2019-05-13 12:41 ` Dave Martin
2019-05-13 12:41 ` Dave Martin
2019-05-13 12:57 ` Andrew Jones
2019-05-13 12:57 ` Andrew Jones
2019-05-13 13:12 ` Dave Martin
2019-05-13 13:12 ` Dave Martin
2019-05-13 13:45 ` Andrew Jones
2019-05-13 13:45 ` Andrew Jones
2019-05-13 14:35 ` Dave Martin
2019-05-13 14:35 ` Dave Martin
2019-05-13 15:25 ` Markus Armbruster
2019-05-13 15:25 ` Markus Armbruster
2019-05-13 18:31 ` Andrew Jones
2019-05-13 18:31 ` Andrew Jones
2019-05-12 8:36 ` [PATCH 12/13] target/arm/kvm: max cpu: Add support for sve-vls-map Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-12 8:36 ` [PATCH 13/13] target/arm/kvm: host " Andrew Jones
2019-05-12 8:36 ` [Qemu-devel] " Andrew Jones
2019-05-13 15:37 ` Markus Armbruster
2019-05-13 15:37 ` Markus Armbruster
2019-05-13 18:33 ` Andrew Jones
2019-05-13 18:33 ` Andrew Jones
2019-05-13 9:32 ` [PATCH 00/13] target/arm/kvm: enable SVE in guests Andrea Bolognani
2019-05-13 9:32 ` [Qemu-devel] " Andrea Bolognani
2019-05-13 11:15 ` Dave Martin
2019-05-13 11:15 ` [Qemu-devel] " Dave Martin
2019-05-13 12:38 ` Andrew Jones
2019-05-13 12:38 ` [Qemu-devel] " Andrew Jones
2019-05-13 12:50 ` Dave Martin
2019-05-13 12:50 ` [Qemu-devel] " Dave Martin
2019-05-13 12:36 ` Andrew Jones
2019-05-13 12:36 ` Andrew Jones
2019-05-14 12:29 ` Andrea Bolognani
2019-05-14 12:29 ` Andrea Bolognani
2019-05-14 12:53 ` Andrew Jones
2019-05-14 16:03 ` Andrea Bolognani
2019-05-14 20:14 ` Richard Henderson
2019-05-15 8:03 ` Andrea Bolognani
2019-05-15 11:14 ` Dave Martin
2019-05-15 11:14 ` Dave Martin
2019-05-15 11:28 ` Andrea Bolognani
2019-05-15 11:28 ` Andrea Bolognani
2019-05-15 12:47 ` Dave Martin
2019-05-15 12:47 ` Dave Martin
2019-05-15 9:15 ` Andrew Jones
2019-05-13 9:52 ` Peter Maydell
2019-05-13 9:52 ` [Qemu-devel] " Peter Maydell
2019-05-13 12:43 ` Andrew Jones
2019-05-13 12:43 ` Andrew Jones
2019-05-13 18:46 ` Richard Henderson
2019-05-13 18:46 ` [Qemu-devel] " Richard Henderson
2019-05-13 19:16 ` Andrew Jones
2019-05-13 19:16 ` [Qemu-devel] " Andrew Jones
2019-05-14 9:05 ` Peter Maydell
2019-05-14 9:05 ` [Qemu-devel] " Peter Maydell
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=20190512083624.8916-6-drjones@redhat.com \
--to=drjones@redhat.com \
--cc=Dave.Martin@arm.com \
--cc=abologna@redhat.com \
--cc=alex.bennee@linaro.org \
--cc=armbru@redhat.com \
--cc=eblake@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
/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.