summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Martin <dave.martin@linaro.org>2012-02-06 18:00:36 -0800
committerDietmar Eggemann <dietmar.eggemann@arm.com>2012-05-23 12:44:35 +0100
commitc13b1a358650170433e068bc6cec9361f4959340 (patch)
tree2187ea8277e3cf96f82e8dcc488a712908ce12ba
parente37385b2dc9ef04d65986ccd2fa36100c72d7564 (diff)
downloadswitcher-c13b1a358650170433e068bc6cec9361f4959340.tar.gz
switcher: Fix invalid use of memcpy() on I/O memory
The size and order etc. of memory accesses performed by memcpy() is undefined, so we can't make valid use of it to save and restore peripheral registers which don't implement full memory-like semantics, except as may be permitted by luck. In praticular, the GIC rejects byte accesses to its registers, whereas it is entirely valid for memcpy() to perform byte accesses. This patch replaces the invalid use of memcpy() for GIC save/restore with trivial dedicated functions which preform volatile word accesses only.
-rw-r--r--big-little/switcher/context/gic.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/big-little/switcher/context/gic.c b/big-little/switcher/context/gic.c
index 5ae13a7..7686feb 100644
--- a/big-little/switcher/context/gic.c
+++ b/big-little/switcher/context/gic.c
@@ -59,6 +59,24 @@ typedef struct {
/* 0x18 */ volatile unsigned const int highest_pending;
} cpu_interface;
+static void wcpymem2io(void volatile *dest, void const *src, size_t count)
+{
+ unsigned long volatile *_dest = dest;
+ unsigned long *_src = src;
+
+ while (count--)
+ *_dest++ = *_src++;
+}
+
+static void wcpyio2mem(void *dest, void volatile const *src, size_t count)
+{
+ unsigned long *_src = src;
+ unsigned long volatile *_dest = dest;
+
+ while (count--)
+ *_dest++ = *_src++;
+}
+
/*
* Saves the GIC CPU interface context
* Requires 3 words of memory
@@ -87,9 +105,9 @@ int save_gic_distributor_private(unsigned int *pointer,
*pointer = id->enable.set[0];
++pointer;
- memcpy((void *)pointer, (const void *)id->priority, 8 << 2);
+ wcpyio2mem(pointer, id->priority, 8);
pointer += 8;
- memcpy((void *)pointer, (const void *)id->target, 8 << 2);
+ wcpyio2mem(pointer, id->target, 8);
pointer += 8;
/* Save just the PPI configurations (SGIs are not configurable) */
@@ -114,14 +132,14 @@ int save_gic_distributor_private(unsigned int *pointer,
* and restoring the set/clear pending registers
*/
ptr = pointer;
- memcpy((void *)pointer, (const void *)id->sgi_set_pending, 4 << 2);
+ wcpyio2mem(pointer, id->sgi_set_pending, 4);
pointer += 8;
/*
* Clear the pending SGIs on this cpuif so that they don't
* interfere with the wfi later on.
*/
- memcpy((void *)id->sgi_clr_pending, (const void *)ptr, 4 << 2);
+ wcpymem2io(id->sgi_clr_pending, ptr, 4);
if (*pointer) {
return -1;
@@ -148,8 +166,7 @@ int save_gic_distributor_shared(unsigned int *pointer,
/* Save rest of GIC configuration */
if (num_spis) {
- memcpy((void *)pointer, (const void *)(id->target + 8),
- (num_spis / 4) << 2);
+ wcpyio2mem(pointer, id->target + 8, num_spis / 4);
pointer += num_spis / 4;
}
@@ -182,9 +199,9 @@ void restore_gic_distributor_private(unsigned int *pointer,
id->enable.set[0] = *pointer;
++pointer;
- memcpy((void *)id->priority, (const void *)pointer, 8 << 2);
+ wcpymem2io(id->priority, pointer, 8);
pointer += 8;
- memcpy((void *)id->target, (const void *)pointer, 8 << 2);
+ wcpymem2io(id->target, pointer, 8);
pointer += 8;
/* Restore just the PPI configurations (SGIs are not configurable) */
@@ -214,7 +231,7 @@ void restore_gic_distributor_private(unsigned int *pointer,
}
}
- memcpy((void *)id->sgi_set_pending, (const void *)pointer, 4 << 2);
+ wcpymem2io(id->sgi_set_pending, pointer, 4);
pointer += 4;
id->pending.set[0] = *pointer;
@@ -242,9 +259,7 @@ void restore_gic_distributor_shared(unsigned int *pointer,
/* Restore rest of GIC configuration */
if (num_spis) {
-
- memcpy((void *)pointer, (const void *)(id->target + 8),
- (num_spis / 4) << 2);
+ wcpyio2mem(pointer, id->target + 8, num_spis / 4);
for (ctr = 0; ctr < num_spis / 4; ctr++) {
if (!pointer[ctr])
@@ -259,8 +274,7 @@ void restore_gic_distributor_shared(unsigned int *pointer,
}
}
- memcpy((void *)(id->target + 8), (const void *)pointer,
- (num_spis / 4) << 2);
+ wcpymem2io(id->target + 8, pointer, num_spis / 4);
}
return;