Skip to content

Commit

Permalink
Merge pull request seL4#5 from adanis/a15errata
Browse files Browse the repository at this point in the history
arm: Add work around for errata on some Cortex-A15 boards
  • Loading branch information
AdrianDanis committed Jul 18, 2014
2 parents 784a367 + 43e1a21 commit 99b2b25
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 31 deletions.
10 changes: 10 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -376,4 +376,14 @@ menu "Errata"
if code containing ARM/Thumb interworking branch is replaced by different code
at the same virtual address.

config ARM_ERRATA_773022
bool "Enable workaround for 773022 Cortex-A15 (r0p0..r0p4) erratum"
depends on ARCH_ARM
depends on ARM_CORTEX_A15
default y
help
Enables a workaround for the 773022 Cortex-A15 (r0p0..r0p4) erratum. Error occurs
on rare sequences of instructions and results in the loop buffer delivering
incorrect instructions. The work around is to disable the loop buffer

endmenu
32 changes: 32 additions & 0 deletions include/arch/arm/arch/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,38 @@ void setNextPC(tcb_t *thread, word_t v);

/* Architecture specific machine operations */

/** MODIFIES: [*] */
static inline uint32_t getProcessorID(void)
{
uint32_t processor_id;
MRC("p15, 0, %0, c0, c0, 0", processor_id);
return processor_id;
}

static inline uint32_t readSystemControlRegister(void)
{
uint32_t scr;
MRC("p15, 0, %0, c1, c0, 0", scr);
return scr;
}

static inline void writeSystemControlRegister(uint32_t scr)
{
MCR("p15, 0, %0, c1, c0, 0", scr);
}

static inline uint32_t readAuxiliaryControlRegister(void)
{
uint32_t acr;
MRC("p15, 0, %0, c1, c0, 1", acr);
return acr;
}

static inline void writeAuxiliaryControlRegister(uint32_t acr)
{
MCR("p15, 0, %0, c1, c0, 1", acr);
}

/** MODIFIES: [*] */
static inline void clearExMonitor(void)
{
Expand Down
35 changes: 5 additions & 30 deletions src/arch/arm/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -86,36 +86,6 @@ BEGIN_FUNC(_start)
/* Initialise CP15 control register */
mrc p15, 0, r4, c1, c0, 0
ldr r5, =CR_BITS_SET

#ifdef ARM1136_WORKAROUND
/*
* We need to potentially work around arm1136 errata #364296 which
* can cause data cache corruption. The fix involves disabling hit-under-miss
* via an undocumented bit in the aux control register, as well as the
* FI bit in the control register. The result of enabling these two bits
* is for fast interrupts to *not* be enabled, but hit-under-miss to be
* disabled. We only need to do this for a particular revision of the
* arm1136
*/
ldr r6, =ARM1136_R0PX
/* Load processor id */
mrc p15, 0, r7, c0, c0, 0
/* Mask out bottom four part bits */
bic r7, r7, #0xf
teq r7, r6
bne 1f

/* Additionally enable the Fast Interrupts bit in the control register */
ldr r6, =BIT(CONTROL_FI)
orr r5, r5, r6

/* Set undocumented bit 31 in the auxiliary control register */
mrc p15, 0, r6, c1, c0, 1
orr r6, r6, #(1<<31)
mcr p15, 0, r6, c1, c0, 1
1:
#endif /* ARM1136_WORKAROUND */

ldr r6, =CR_BITS_CLEAR
orr r4, r4, r5
bic r4, r4, r6
Expand All @@ -131,6 +101,11 @@ BEGIN_FUNC(_start)
ldr sp, =arm_kernel_stack
add sp, sp, #(PPTR_KERNEL_STACK_TOP - PPTR_KERNEL_STACK)

/* Attempt to workaround any known ARM errata. */
push {r0-r3}
blx arm_errata
pop {r0-r3}

/* Initialise ABORT stack pointer */
cps #PMODE_ABORT
ldr sp, =_breakpoint_stack_top
Expand Down
3 changes: 2 additions & 1 deletion src/arch/arm/machine/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ DIRECTORIES += src/arch/arm/machine

ARCH_C_SOURCES += machine/hardware.c \
machine/registerset.c \
machine/cache.c
machine/cache.c \
machine/errata.c

ifeq ($(CPU), cortex-a9)
ARCH_C_SOURCES += machine/gic_pl390.c
Expand Down
71 changes: 71 additions & 0 deletions src/arch/arm/machine/errata.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

#include <config.h>
#include <api/types.h>
#include <arch/machine.h>
#include <arch/machine/hardware.h>

/* Prototyped here as this is referenced from assembly */
void arm_errata(void);

#ifdef ARM1136_WORKAROUND
/*
* Potentially work around ARM1136 errata #364296, which can cause data
* cache corruption.
*
* The fix involves disabling hit-under-miss via an undocumented bit in
* the aux control register, as well as the FI bit in the control
* register. The result of enabling these two bits is for fast
* interrupts to *not* be enabled, but hit-under-miss to be disabled. We
* only need to do this for a particular revision of the ARM1136.
*/
BOOT_CODE static void
errata_arm1136(void)
{
/* See if we are affected by the errata. */
if ((getProcessorID() & ~0xf) == ARM1136_R0PX) {

/* Enable the Fast Interrupts bit in the control register. */
writeSystemControlRegister(
readSystemControlRegister() | BIT(CONTROL_FI));

/* Set undocumented bit 31 in the auxiliary control register */
writeAuxiliaryControlRegister(
readAuxiliaryControlRegister() | BIT(31));
}
}
#endif

#ifdef CONFIG_ARM_ERRATA_773022
/*
* There is an errata for Cortex-A15 up to r0p4 where the loop buffer
* may deliver incorrect instructions. The work around is to disable
* the loop buffer. Errata is number 773022.
*/
BOOT_CODE static void errata_armA15_773022(void)
{
/* Fetch the processor primary part number. */
uint32_t proc_id = getProcessorID();
uint32_t variant = (proc_id >> 20) & MASK(4);
uint32_t revision = proc_id & MASK(4);
uint32_t part = (proc_id >> 4) & MASK(12);

/* Check that we are running A15 and a revision upto r0p4. */
if (part == 0xc0f && variant == 0 && revision <= 4) {
/* Disable loop buffer in the auxiliary control register */
writeAuxiliaryControlRegister(
readAuxiliaryControlRegister() | BIT(1));
}
}
#endif

BOOT_CODE void __attribute__((externally_visible)) arm_errata(void)
{
#ifdef ARM1136_WORKAROUND
errata_arm1136();
#endif
#ifdef CONFIG_ARM_ERRATA_773022
(void)errata_armA15_773022;
errata_armA15_773022();
#endif
}

0 comments on commit 99b2b25

Please sign in to comment.