ARMv8 Trusted Firmware release v0.2

This commit is contained in:
Achin Gupta 2013-10-25 09:08:21 +01:00 committed by James Morrissey
commit 4f6ad66ae9
98 changed files with 17582 additions and 0 deletions

169
Makefile Normal file
View File

@ -0,0 +1,169 @@
#
# Copyright (c) 2013, ARM Limited. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of ARM nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Decrease the verbosity of the make script
# can be made verbose by passing V=1 at the make command line
ifdef V
KBUILD_VERBOSE = $(V)
else
KBUILD_VERBOSE = 0
endif
ifeq "$(KBUILD_VERBOSE)" "0"
Q=@
else
Q=
endif
DEBUG ?= 0
BL_COMMON_OBJS = misc_helpers.o cache_helpers.o tlb_helpers.o \
semihosting_call.o mmio.o pl011.o semihosting.o \
std.o bl_common.o platform_helpers.o sysreg_helpers.o
ARCH := aarch64
all: $(patsubst %,%.bin,bl1 bl2 bl31) ;
#$(info $(filter bl2.%, $(MAKECMDGOALS)))
#$(info $(filter bl1.%, $(MAKECMDGOALS)))
#$(info $(MAKECMDGOALS))
$(info Including bl1.mk)
include bl1/bl1.mk
$(info Including bl2.mk)
include bl2/bl2.mk
$(info Including bl31.mk)
include bl31/bl31.mk
OBJS += $(BL_COMMON_OBJS)
INCLUDES += -Ilib/include/ -Iinclude/aarch64/ -Iinclude/ \
-Idrivers/arm/interconnect/cci-400/ \
-Idrivers/arm/peripherals/pl011/ \
-Iplat/fvp -Idrivers/power \
-Iarch/system/gic -Icommon/psci
ASFLAGS += -D__ASSEMBLY__ $(INCLUDES)
CFLAGS := -Wall -std=c99 -c -Os -DDEBUG=$(DEBUG) $(INCLUDES) ${CFLAGS}
LDFLAGS += -O1
BL1_LDFLAGS := -Map=$(BL1_MAPFILE) --script $(BL1_LINKERFILE) --entry=$(BL1_ENTRY_POINT)
BL2_LDFLAGS := -Map=$(BL2_MAPFILE) --script $(BL2_LINKERFILE) --entry=$(BL2_ENTRY_POINT)
BL31_LDFLAGS := -Map=$(BL31_MAPFILE) --script $(BL31_LINKERFILE) --entry=$(BL31_ENTRY_POINT)
vpath %.ld.S bl1:bl2:bl31
vpath %.c bl1:bl2:bl31
vpath %.c bl1/${ARCH}:bl2/${ARCH}:bl31/${ARCH}
vpath %.S bl1/${ARCH}:bl2/${ARCH}:bl31/${ARCH}
ifneq ($(DEBUG), 0)
#CFLAGS += -g -O0
CFLAGS += -g
# -save-temps -fverbose-asm
ASFLAGS += -g -Wa,--gdwarf-2
endif
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)cpp
AS = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OC = $(CROSS_COMPILE)objcopy
OD = $(CROSS_COMPILE)objdump
NM = $(CROSS_COMPILE)nm
PP = $(CROSS_COMPILE)gcc -E $(CFLAGS)
distclean: clean
@echo " DISTCLEAN"
$(Q)rm -rf *.zi
$(Q)rm -rf *.dump
$(Q)rm -rf *.bin
$(Q)rm -f *.axf
$(Q)rm -f *.i *.s
$(Q)rm -f *.ar
$(Q)rm -f *.map
$(Q)rm -f *.scf
$(Q)rm -f *.txt
$(Q)rm -f *.elf
$(Q)rm -rf *.bin
$(Q)rm -f $(LISTFILE)
clean:
@echo " CLEAN"
$(Q)rm -f *.o *.ld
.PHONY: dump
dump:
@echo " OBJDUMP"
$(OD) -d bl1.elf > bl1.dump
$(OD) -d bl2.elf > bl2.dump
$(OD) -d bl31.elf > bl31.dump
%.o: %.S
@echo " AS $<"
$(Q)$(AS) $(ASFLAGS) -c $< -o $@
%.o: %.c
@echo " CC $<"
$(Q)$(CC) $(CFLAGS) -c $< -o $@
%.ld: %.ld.S
@echo " LDS $<"
$(Q)$(AS) $(ASFLAGS) -P -E $< -o $@
bl1.elf: $(OBJS) $(BL1_OBJS) bl1.ld
@echo " LD $@"
$(Q)$(LD) -o $@ $(LDFLAGS) $(BL1_LDFLAGS) $(OBJS) $(BL1_OBJS)
@echo "Built $@ successfully"
@echo
bl2.elf: $(OBJS) $(BL2_OBJS) bl2.ld
@echo " LD $@"
$(Q)$(LD) -o $@ $(LDFLAGS) $(BL2_LDFLAGS) $(OBJS) $(BL2_OBJS)
@echo "Built $@ successfully"
@echo
bl31.elf: $(OBJS) $(BL31_OBJS) bl31.ld
@echo " LD $@"
$(Q)$(LD) -o $@ $(LDFLAGS) $(BL31_LDFLAGS) $(OBJS) $(BL31_OBJS)
@echo "Built $@ successfully"
@echo
%.bin: %.elf
$(OC) -O binary $< $@

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
.weak cpu_reset_handler
.section aarch64_code, "ax"; .align 3
cpu_reset_handler:; .type cpu_reset_handler, %function
mov x19, x30 // lr
/* ---------------------------------------------
* As a bare minimal enable the SMP bit and the
* I$ for all aarch64 processors. Also set the
* exception vector to something sane.
* ---------------------------------------------
*/
adr x0, early_exceptions
bl write_vbar
bl read_midr
lsr x0, x0, #MIDR_PN_SHIFT
and x0, x0, #MIDR_PN_MASK
cmp x0, #MIDR_PN_A57
b.eq smp_setup_begin
cmp x0, #MIDR_PN_A53
b.ne smp_setup_end
smp_setup_begin:
bl read_cpuectlr
orr x0, x0, #CPUECTLR_SMP_BIT
bl write_cpuectlr
smp_setup_end:
bl read_sctlr
orr x0, x0, #SCTLR_I_BIT
bl write_sctlr
ret x19

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
.globl read_icc_sre_el1
.globl read_icc_sre_el2
.globl read_icc_sre_el3
.globl write_icc_sre_el1
.globl write_icc_sre_el2
.globl write_icc_sre_el3
.globl write_icc_pmr_el1
/*
* Register definitions used by GCC for GICv3 access.
* These are defined by ARMCC, so keep them in the GCC specific code for now.
*/
#define ICC_SRE_EL1 S3_0_C12_C12_5
#define ICC_SRE_EL2 S3_4_C12_C9_5
#define ICC_SRE_EL3 S3_6_C12_C12_5
#define ICC_CTLR_EL1 S3_0_C12_C12_4
#define ICC_CTLR_EL3 S3_6_C12_C12_4
#define ICC_PMR_EL1 S3_0_C4_C6_0
.section platform_code, "ax"; .align 3
read_icc_sre_el1:; .type read_icc_sre_el1, %function
mrs x0, ICC_SRE_EL1
ret
read_icc_sre_el2:; .type read_icc_sre_el2, %function
mrs x0, ICC_SRE_EL2
ret
read_icc_sre_el3:; .type read_icc_sre_el3, %function
mrs x0, ICC_SRE_EL3
ret
write_icc_sre_el1:; .type write_icc_sre_el1, %function
msr ICC_SRE_EL1, x0
isb
ret
write_icc_sre_el2:; .type write_icc_sre_el2, %function
msr ICC_SRE_EL2, x0
isb
ret
write_icc_sre_el3:; .type write_icc_sre_el3, %function
msr ICC_SRE_EL3, x0
isb
ret
write_icc_pmr_el1:; .type write_icc_pmr_el1, %function
msr ICC_PMR_EL1, x0
isb
ret

217
arch/system/gic/gic.h Normal file
View File

@ -0,0 +1,217 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GIC_H__
#define __GIC_H__
#define MAX_SPIS 480
#define MAX_PPIS 14
#define MAX_SGIS 16
#define GRP0 0
#define GRP1 1
#define MAX_PRI_VAL 0xff
#define ENABLE_GRP0 (1 << 0)
#define ENABLE_GRP1 (1 << 1)
/* Distributor interface definitions */
#define GICD_CTLR 0x0
#define GICD_TYPER 0x4
#define GICD_IGROUPR 0x80
#define GICD_ISENABLER 0x100
#define GICD_ICENABLER 0x180
#define GICD_ISPENDR 0x200
#define GICD_ICPENDR 0x280
#define GICD_ISACTIVER 0x300
#define GICD_ICACTIVER 0x380
#define GICD_IPRIORITYR 0x400
#define GICD_ITARGETSR 0x800
#define GICD_ICFGR 0xC00
#define GICD_SGIR 0xF00
#define GICD_CPENDSGIR 0xF10
#define GICD_SPENDSGIR 0xF20
#define IGROUPR_SHIFT 5
#define ISENABLER_SHIFT 5
#define ICENABLER_SHIFT ISENABLER_SHIFT
#define ISPENDR_SHIFT 5
#define ICPENDR_SHIFT ISPENDR_SHIFT
#define ISACTIVER_SHIFT 5
#define ICACTIVER_SHIFT ISACTIVER_SHIFT
#define IPRIORITYR_SHIFT 2
#define ITARGETSR_SHIFT 2
#define ICFGR_SHIFT 4
#define CPENDSGIR_SHIFT 2
#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
/* GICD_TYPER bit definitions */
#define IT_LINES_NO_MASK 0x1f
/* Physical CPU Interface registers */
#define GICC_CTLR 0x0
#define GICC_PMR 0x4
#define GICC_BPR 0x8
#define GICC_IAR 0xC
#define GICC_EOIR 0x10
#define GICC_RPR 0x14
#define GICC_HPPIR 0x18
#define GICC_IIDR 0xFC
#define GICC_DIR 0x1000
#define GICC_PRIODROP GICC_EOIR
/* GICC_CTLR bit definitions */
#define EOI_MODE_NS (1 << 10)
#define EOI_MODE_S (1 << 9)
#define IRQ_BYP_DIS_GRP1 (1 << 8)
#define FIQ_BYP_DIS_GRP1 (1 << 7)
#define IRQ_BYP_DIS_GRP0 (1 << 6)
#define FIQ_BYP_DIS_GRP0 (1 << 5)
#define CBPR (1 << 4)
#define FIQ_EN (1 << 3)
#define ACK_CTL (1 << 2)
/* GICC_IIDR bit masks and shifts */
#define GICC_IIDR_PID_SHIFT 20
#define GICC_IIDR_ARCH_SHIFT 16
#define GICC_IIDR_REV_SHIFT 12
#define GICC_IIDR_IMP_SHIFT 0
#define GICC_IIDR_PID_MASK 0xfff
#define GICC_IIDR_ARCH_MASK 0xf
#define GICC_IIDR_REV_MASK 0xf
#define GICC_IIDR_IMP_MASK 0xfff
/* HYP view virtual CPU Interface registers */
#define GICH_CTL 0x0
#define GICH_VTR 0x4
#define GICH_ELRSR0 0x30
#define GICH_ELRSR1 0x34
#define GICH_APR0 0xF0
#define GICH_LR_BASE 0x100
/* Virtual CPU Interface registers */
#define GICV_CTL 0x0
#define GICV_PRIMASK 0x4
#define GICV_BP 0x8
#define GICV_INTACK 0xC
#define GICV_EOI 0x10
#define GICV_RUNNINGPRI 0x14
#define GICV_HIGHESTPEND 0x18
#define GICV_DEACTIVATE 0x1000
/* GICv3 Re-distributor interface registers & shifts */
#define GICR_PCPUBASE_SHIFT 0x11
#define GICR_WAKER 0x14
/* GICR_WAKER bit definitions */
#define WAKER_CA (1UL << 2)
#define WAKER_PS (1UL << 1)
/* GICv3 ICC_SRE register bit definitions*/
#define ICC_SRE_EN (1UL << 3)
#define ICC_SRE_SRE (1UL << 0)
#ifndef __ASSEMBLY__
/*******************************************************************************
* Function prototypes
******************************************************************************/
extern inline unsigned int gicd_read_typer(unsigned int);
extern inline unsigned int gicd_read_ctlr(unsigned int);
extern unsigned int gicd_read_igroupr(unsigned int, unsigned int);
extern unsigned int gicd_read_isenabler(unsigned int, unsigned int);
extern unsigned int gicd_read_icenabler(unsigned int, unsigned int);
extern unsigned int gicd_read_ispendr(unsigned int, unsigned int);
extern unsigned int gicd_read_icpendr(unsigned int, unsigned int);
extern unsigned int gicd_read_isactiver(unsigned int, unsigned int);
extern unsigned int gicd_read_icactiver(unsigned int, unsigned int);
extern unsigned int gicd_read_ipriorityr(unsigned int, unsigned int);
extern unsigned int gicd_read_itargetsr(unsigned int, unsigned int);
extern unsigned int gicd_read_icfgr(unsigned int, unsigned int);
extern unsigned int gicd_read_sgir(unsigned int);
extern unsigned int gicd_read_cpendsgir(unsigned int, unsigned int);
extern unsigned int gicd_read_spendsgir(unsigned int, unsigned int);
extern inline void gicd_write_ctlr(unsigned int, unsigned int);
extern void gicd_write_igroupr(unsigned int, unsigned int, unsigned int);
extern void gicd_write_isenabler(unsigned int, unsigned int, unsigned int);
extern void gicd_write_icenabler(unsigned int, unsigned int, unsigned int);
extern void gicd_write_ispendr(unsigned int, unsigned int, unsigned int);
extern void gicd_write_icpendr(unsigned int, unsigned int, unsigned int);
extern void gicd_write_isactiver(unsigned int, unsigned int, unsigned int);
extern void gicd_write_icactiver(unsigned int, unsigned int, unsigned int);
extern void gicd_write_ipriorityr(unsigned int, unsigned int, unsigned int);
extern void gicd_write_itargetsr(unsigned int, unsigned int, unsigned int);
extern void gicd_write_icfgr(unsigned int, unsigned int, unsigned int);
extern void gicd_write_sgir(unsigned int, unsigned int);
extern void gicd_write_cpendsgir(unsigned int, unsigned int, unsigned int);
extern void gicd_write_spendsgir(unsigned int, unsigned int, unsigned int);
extern unsigned int gicd_get_igroupr(unsigned int, unsigned int);
extern void gicd_set_igroupr(unsigned int, unsigned int);
extern void gicd_clr_igroupr(unsigned int, unsigned int);
extern void gicd_set_isenabler(unsigned int, unsigned int);
extern void gicd_set_icenabler(unsigned int, unsigned int);
extern void gicd_set_ispendr(unsigned int, unsigned int);
extern void gicd_set_icpendr(unsigned int, unsigned int);
extern void gicd_set_isactiver(unsigned int, unsigned int);
extern void gicd_set_icactiver(unsigned int, unsigned int);
extern void gicd_set_ipriorityr(unsigned int, unsigned int, unsigned int);
extern void gicd_set_itargetsr(unsigned int, unsigned int, unsigned int);
extern inline unsigned int gicc_read_ctlr(unsigned int);
extern inline unsigned int gicc_read_pmr(unsigned int);
extern inline unsigned int gicc_read_BPR(unsigned int);
extern inline unsigned int gicc_read_IAR(unsigned int);
extern inline unsigned int gicc_read_EOIR(unsigned int);
extern inline unsigned int gicc_read_hppir(unsigned int);
extern inline unsigned int gicc_read_iidr(unsigned int);
extern inline unsigned int gicc_read_dir(unsigned int);
extern inline void gicc_write_ctlr(unsigned int, unsigned int);
extern inline void gicc_write_pmr(unsigned int, unsigned int);
extern inline void gicc_write_BPR(unsigned int, unsigned int);
extern inline void gicc_write_IAR(unsigned int, unsigned int);
extern inline void gicc_write_EOIR(unsigned int, unsigned int);
extern inline void gicc_write_hppir(unsigned int, unsigned int);
extern inline void gicc_write_dir(unsigned int, unsigned int);
/* GICv3 functions */
extern inline unsigned int gicr_read_waker(unsigned int);
extern inline void gicr_write_waker(unsigned int, unsigned int);
extern unsigned int read_icc_sre_el1(void);
extern unsigned int read_icc_sre_el2(void);
extern unsigned int read_icc_sre_el3(void);
extern void write_icc_sre_el1(unsigned int);
extern void write_icc_sre_el2(unsigned int);
extern void write_icc_sre_el3(unsigned int);
extern void write_icc_pmr_el1(unsigned int);
#endif /*__ASSEMBLY__*/
#endif /* __GIC_H__ */

426
arch/system/gic/gic_v2.c Normal file
View File

@ -0,0 +1,426 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <gic.h>
#include <mmio.h>
/*******************************************************************************
* GIC Distributor interface accessesors for reading entire registers
******************************************************************************/
inline unsigned int gicd_read_ctlr(unsigned int base)
{
return mmio_read_32(base + GICD_CTLR);
}
inline unsigned int gicd_read_typer(unsigned int base)
{
return mmio_read_32(base + GICD_TYPER);
}
unsigned int gicd_read_igroupr(unsigned int base, unsigned int id)
{
unsigned n = id >> IGROUPR_SHIFT;
return mmio_read_32(base + GICD_IGROUPR + (n << 2));
}
unsigned int gicd_read_isenabler(unsigned int base, unsigned int id)
{
unsigned n = id >> ISENABLER_SHIFT;
return mmio_read_32(base + GICD_ISENABLER + (n << 2));
}
unsigned int gicd_read_icenabler(unsigned int base, unsigned int id)
{
unsigned n = id >> ICENABLER_SHIFT;
return mmio_read_32(base + GICD_ICENABLER + (n << 2));
}
unsigned int gicd_read_ispendr(unsigned int base, unsigned int id)
{
unsigned n = id >> ISPENDR_SHIFT;
return mmio_read_32(base + GICD_ISPENDR + (n << 2));
}
unsigned int gicd_read_icpendr(unsigned int base, unsigned int id)
{
unsigned n = id >> ICPENDR_SHIFT;
return mmio_read_32(base + GICD_ICPENDR + (n << 2));
}
unsigned int gicd_read_isactiver(unsigned int base, unsigned int id)
{
unsigned n = id >> ISACTIVER_SHIFT;
return mmio_read_32(base + GICD_ISACTIVER + (n << 2));
}
unsigned int gicd_read_icactiver(unsigned int base, unsigned int id)
{
unsigned n = id >> ICACTIVER_SHIFT;
return mmio_read_32(base + GICD_ICACTIVER + (n << 2));
}
unsigned int gicd_read_ipriorityr(unsigned int base, unsigned int id)
{
unsigned n = id >> IPRIORITYR_SHIFT;
return mmio_read_32(base + GICD_IPRIORITYR + (n << 2));
}
unsigned int gicd_read_itargetsr(unsigned int base, unsigned int id)
{
unsigned n = id >> ITARGETSR_SHIFT;
return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
}
unsigned int gicd_read_icfgr(unsigned int base, unsigned int id)
{
unsigned n = id >> ICFGR_SHIFT;
return mmio_read_32(base + GICD_ICFGR + (n << 2));
}
unsigned int gicd_read_sgir(unsigned int base)
{
return mmio_read_32(base + GICD_SGIR);
}
unsigned int gicd_read_cpendsgir(unsigned int base, unsigned int id)
{
unsigned n = id >> CPENDSGIR_SHIFT;
return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
}
unsigned int gicd_read_spendsgir(unsigned int base, unsigned int id)
{
unsigned n = id >> SPENDSGIR_SHIFT;
return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
}
/*******************************************************************************
* GIC Distributor interface accessesors for writing entire registers
******************************************************************************/
inline void gicd_write_ctlr(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICD_CTLR, val);
return;
}
void gicd_write_igroupr(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> IGROUPR_SHIFT;
mmio_write_32(base + GICD_IGROUPR + (n << 2), val);
return;
}
void gicd_write_isenabler(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ISENABLER_SHIFT;
mmio_write_32(base + GICD_ISENABLER + (n << 2), val);
return;
}
void gicd_write_icenabler(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ICENABLER_SHIFT;
mmio_write_32(base + GICD_ICENABLER + (n << 2), val);
return;
}
void gicd_write_ispendr(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ISPENDR_SHIFT;
mmio_write_32(base + GICD_ISPENDR + (n << 2), val);
return;
}
void gicd_write_icpendr(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ICPENDR_SHIFT;
mmio_write_32(base + GICD_ICPENDR + (n << 2), val);
return;
}
void gicd_write_isactiver(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ISACTIVER_SHIFT;
mmio_write_32(base + GICD_ISACTIVER + (n << 2), val);
return;
}
void gicd_write_icactiver(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ICACTIVER_SHIFT;
mmio_write_32(base + GICD_ICACTIVER + (n << 2), val);
return;
}
void gicd_write_ipriorityr(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> IPRIORITYR_SHIFT;
mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val);
return;
}
void gicd_write_itargetsr(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ITARGETSR_SHIFT;
mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
return;
}
void gicd_write_icfgr(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> ICFGR_SHIFT;
mmio_write_32(base + GICD_ICFGR + (n << 2), val);
return;
}
void gicd_write_sgir(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICD_SGIR, val);
return;
}
void gicd_write_cpendsgir(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> CPENDSGIR_SHIFT;
mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
return;
}
void gicd_write_spendsgir(unsigned int base, unsigned int id, unsigned int val)
{
unsigned n = id >> SPENDSGIR_SHIFT;
mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
return;
}
/*******************************************************************************
* GIC Distributor interface accessesors for individual interrupt manipulation
******************************************************************************/
unsigned int gicd_get_igroupr(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
unsigned int reg_val = gicd_read_igroupr(base, id);
return (reg_val >> bit_num) & 0x1;
}
void gicd_set_igroupr(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
unsigned int reg_val = gicd_read_igroupr(base, id);
gicd_write_igroupr(base, id, reg_val | (1 << bit_num));
return;
}
void gicd_clr_igroupr(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
unsigned int reg_val = gicd_read_igroupr(base, id);
gicd_write_igroupr(base, id, reg_val & ~(1 << bit_num));
return;
}
void gicd_set_isenabler(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);
unsigned int reg_val = gicd_read_isenabler(base, id);
gicd_write_isenabler(base, id, reg_val | (1 << bit_num));
return;
}
void gicd_set_icenabler(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1);
unsigned int reg_val = gicd_read_icenabler(base, id);
gicd_write_icenabler(base, id, reg_val & ~(1 << bit_num));
return;
}
void gicd_set_ispendr(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);
unsigned int reg_val = gicd_read_ispendr(base, id);
gicd_write_ispendr(base, id, reg_val | (1 << bit_num));
return;
}
void gicd_set_icpendr(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);
unsigned int reg_val = gicd_read_icpendr(base, id);
gicd_write_icpendr(base, id, reg_val & ~(1 << bit_num));
return;
}
void gicd_set_isactiver(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
unsigned int reg_val = gicd_read_isactiver(base, id);
gicd_write_isactiver(base, id, reg_val | (1 << bit_num));
return;
}
void gicd_set_icactiver(unsigned int base, unsigned int id)
{
unsigned bit_num = id & ((1 << ICACTIVER_SHIFT) - 1);
unsigned int reg_val = gicd_read_icactiver(base, id);
gicd_write_icactiver(base, id, reg_val & ~(1 << bit_num));
return;
}
/*
* Make sure that the interrupt's group is set before expecting
* this function to do its job correctly.
*/
void gicd_set_ipriorityr(unsigned int base, unsigned int id, unsigned int pri)
{
unsigned byte_off = id & ((1 << ICACTIVER_SHIFT) - 1);
unsigned int reg_val = gicd_read_icactiver(base, id);
/*
* Enforce ARM recommendation to manage priority values such
* that group1 interrupts always have a lower priority than
* group0 interrupts
*/
if (gicd_get_igroupr(base, id) == GRP1)
pri |= 1 << 7;
else
pri &= ~(1 << 7);
gicd_write_icactiver(base, id, reg_val & ~(pri << (byte_off << 3)));
return;
}
void gicd_set_itargetsr(unsigned int base, unsigned int id, unsigned int iface)
{
unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
unsigned int reg_val = gicd_read_itargetsr(base, id);
gicd_write_itargetsr(base, id, reg_val |
(1 << iface) << (byte_off << 3));
return;
}
/*******************************************************************************
* GIC CPU interface accessesors for reading entire registers
******************************************************************************/
inline unsigned int gicc_read_ctlr(unsigned int base)
{
return mmio_read_32(base + GICC_CTLR);
}
inline unsigned int gicc_read_pmr(unsigned int base)
{
return mmio_read_32(base + GICC_PMR);
}
inline unsigned int gicc_read_BPR(unsigned int base)
{
return mmio_read_32(base + GICC_BPR);
}
inline unsigned int gicc_read_IAR(unsigned int base)
{
return mmio_read_32(base + GICC_IAR);
}
inline unsigned int gicc_read_EOIR(unsigned int base)
{
return mmio_read_32(base + GICC_EOIR);
}
inline unsigned int gicc_read_hppir(unsigned int base)
{
return mmio_read_32(base + GICC_HPPIR);
}
inline unsigned int gicc_read_dir(unsigned int base)
{
return mmio_read_32(base + GICC_DIR);
}
inline unsigned int gicc_read_iidr(unsigned int base)
{
return mmio_read_32(base + GICC_IIDR);
}
/*******************************************************************************
* GIC CPU interface accessesors for writing entire registers
******************************************************************************/
inline void gicc_write_ctlr(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_CTLR, val);
return;
}
inline void gicc_write_pmr(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_PMR, val);
return;
}
inline void gicc_write_BPR(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_BPR, val);
return;
}
inline void gicc_write_IAR(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_IAR, val);
return;
}
inline void gicc_write_EOIR(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_EOIR, val);
return;
}
inline void gicc_write_hppir(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_HPPIR, val);
return;
}
inline void gicc_write_dir(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICC_DIR, val);
return;
}

46
arch/system/gic/gic_v3.c Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <gic.h>
#include <mmio.h>
/*******************************************************************************
* GIC Redistributor interface accessesors
******************************************************************************/
inline unsigned int gicr_read_waker(unsigned int base)
{
return mmio_read_32(base + GICR_WAKER);
}
inline void gicr_write_waker(unsigned int base, unsigned int val)
{
mmio_write_32(base + GICR_WAKER, val);
return;
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
#include <platform.h>
#include <assert.h>
/*******************************************************************************
* Function that does the first bit of architectural setup that affects
* execution in the non-secure address space.
******************************************************************************/
void bl1_arch_setup(void)
{
unsigned long tmp_reg = 0;
unsigned int counter_base_frequency;
/* Enable alignment checks and set the exception endianess to LE */
tmp_reg = read_sctlr();
tmp_reg |= (SCTLR_A_BIT | SCTLR_SA_BIT);
tmp_reg &= ~SCTLR_EE_BIT;
write_sctlr(tmp_reg);
/*
* Enable HVCs, route FIQs to EL3, set the next EL to be aarch64
*/
tmp_reg = SCR_RES1_BITS | SCR_RW_BIT | SCR_HCE_BIT | SCR_FIQ_BIT;
write_scr(tmp_reg);
/* Do not trap coprocessor accesses from lower ELs to EL3 */
write_cptr_el3(0);
/* Read the frequency from Frequency modes table */
counter_base_frequency = mmio_read_32(SYS_CNTCTL_BASE + CNTFID_OFF);
/* The first entry of the frequency modes table must not be 0 */
assert(counter_base_frequency != 0);
/* Program the counter frequency */
write_cntfrq_el0(counter_base_frequency);
return;
}
/*******************************************************************************
* Set the Secure EL1 required architectural state
******************************************************************************/
void bl1_arch_next_el_setup(void) {
unsigned long current_sctlr, next_sctlr;
/* Use the same endianness than the current BL */
current_sctlr = read_sctlr();
next_sctlr = (current_sctlr & SCTLR_EE_BIT);
/* Set SCTLR Secure EL1 */
next_sctlr |= SCTLR_EL1_RES1;
write_sctlr_el1(next_sctlr);
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
.globl reset_handler
.section reset_code, "ax"; .align 3
/* -----------------------------------------------------
* reset_handler() is the entry point into the trusted
* firmware code when a cpu is released from warm or
* cold reset.
* -----------------------------------------------------
*/
reset_handler:; .type reset_handler, %function
/* ---------------------------------------------
* Perform any processor specific actions upon
* reset e.g. cache, tlb invalidations etc.
* ---------------------------------------------
*/
bl cpu_reset_handler
_wait_for_entrypoint:
/* ---------------------------------------------
* Find the type of reset and jump to handler
* if present. If the handler is null then it is
* a cold boot. The primary cpu will set up the
* platform while the secondaries wait for
* their turn to be woken up
* ---------------------------------------------
*/
bl read_mpidr
bl platform_get_entrypoint
cbnz x0, _do_warm_boot
bl read_mpidr
bl platform_is_primary_cpu
cbnz x0, _do_cold_boot
/* ---------------------------------------------
* Perform any platform specific secondary cpu
* actions
* ---------------------------------------------
*/
bl plat_secondary_cold_boot_setup
b _wait_for_entrypoint
_do_cold_boot:
/* ---------------------------------------------
* Initialize platform and jump to our c-entry
* point for this type of reset
* ---------------------------------------------
*/
adr x0, bl1_main
bl platform_cold_boot_init
b _panic
_do_warm_boot:
/* ---------------------------------------------
* Jump to BL31 for all warm boot init.
* ---------------------------------------------
*/
blr x0
_panic:
b _panic

View File

@ -0,0 +1,216 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <bl_common.h>
#include <bl1.h>
#include <platform.h>
#include <runtime_svc.h>
.globl early_exceptions
.section .text, "ax"; .align 11
/* -----------------------------------------------------
* Very simple exception handlers used by BL1 and BL2.
* Apart from one SMC exception all other traps loop
* endlessly.
* -----------------------------------------------------
*/
.align 7
early_exceptions:
/* -----------------------------------------------------
* Current EL with SP0 : 0x0 - 0x180
* -----------------------------------------------------
*/
SynchronousExceptionSP0:
mov x0, #SYNC_EXCEPTION_SP_EL0
bl plat_report_exception
b SynchronousExceptionSP0
.align 7
IrqSP0:
mov x0, #IRQ_SP_EL0
bl plat_report_exception
b IrqSP0
.align 7
FiqSP0:
mov x0, #FIQ_SP_EL0
bl plat_report_exception
b FiqSP0
.align 7
SErrorSP0:
mov x0, #SERROR_SP_EL0
bl plat_report_exception
b SErrorSP0
/* -----------------------------------------------------
* Current EL with SPx: 0x200 - 0x380
* -----------------------------------------------------
*/
.align 7
SynchronousExceptionSPx:
mov x0, #SYNC_EXCEPTION_SP_ELX
bl plat_report_exception
b SynchronousExceptionSPx
.align 7
IrqSPx:
mov x0, #IRQ_SP_ELX
bl plat_report_exception
b IrqSPx
.align 7
FiqSPx:
mov x0, #FIQ_SP_ELX
bl plat_report_exception
b FiqSPx
.align 7
SErrorSPx:
mov x0, #SERROR_SP_ELX
bl plat_report_exception
b SErrorSPx
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x580
* -----------------------------------------------------
*/
.align 7
SynchronousExceptionA64:
/* ---------------------------------------------
* Only a single SMC exception from BL2 to ask
* BL1 to pass EL3 control to BL31 is expected
* here.
* ---------------------------------------------
*/
sub sp, sp, #0x40
stp x0, x1, [sp, #0x0]
stp x2, x3, [sp, #0x10]
stp x4, x5, [sp, #0x20]
stp x6, x7, [sp, #0x30]
mov x19, x0
mov x20, x1
mov x21, x2
mov x0, #SYNC_EXCEPTION_AARCH64
bl plat_report_exception
bl read_esr
ubfx x1, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH
cmp x1, #EC_AARCH64_SMC
b.ne panic
mov x1, #RUN_IMAGE
cmp x19, x1
b.ne panic
mov x0, x20
mov x1, x21
mov x2, x3
mov x3, x4
bl display_boot_progress
mov x0, x20
bl write_elr
mov x0, x21
bl write_spsr
ubfx x0, x21, #MODE_EL_SHIFT, #2
cmp x0, #MODE_EL3
b.ne skip_mmu_teardown
/* ---------------------------------------------
* If BL31 is to be executed in EL3 as well
* then turn off the MMU so that it can perform
* its own setup. TODO: Assuming flat mapped
* translations here. Also all should go into a
* separate MMU teardown function
* ---------------------------------------------
*/
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
bl read_sctlr
bic x0, x0, x1
bl write_sctlr
mov x0, #DCCISW
bl dcsw_op_all
bl tlbialle3
skip_mmu_teardown:
ldp x6, x7, [sp, #0x30]
ldp x4, x5, [sp, #0x20]
ldp x2, x3, [sp, #0x10]
ldp x0, x1, [sp, #0x0]
add sp, sp, #0x40
eret
panic:
b panic
.align 7
IrqA64:
mov x0, #IRQ_AARCH64
bl plat_report_exception
b IrqA64
.align 7
FiqA64:
mov x0, #FIQ_AARCH64
bl plat_report_exception
b FiqA64
.align 7
SErrorA64:
mov x0, #SERROR_AARCH64
bl plat_report_exception
b SErrorA64
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x0 - 0x180
* -----------------------------------------------------
*/
.align 7
SynchronousExceptionA32:
mov x0, #SYNC_EXCEPTION_AARCH32
bl plat_report_exception
b SynchronousExceptionA32
.align 7
IrqA32:
mov x0, #IRQ_AARCH32
bl plat_report_exception
b IrqA32
.align 7
FiqA32:
mov x0, #FIQ_AARCH32
bl plat_report_exception
b FiqA32
.align 7
SErrorA32:
mov x0, #SERROR_AARCH32
bl plat_report_exception
b SErrorA32

90
bl1/bl1.ld.S Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <platform.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
MEMORY {
/* ROM is read-only and executable */
ROM (rx): ORIGIN = TZROM_BASE, LENGTH = TZROM_SIZE
/* RAM is read/write and Initialised */
RAM (rwx): ORIGIN = TZRAM_BASE, LENGTH = TZRAM_SIZE
}
SECTIONS
{
FIRMWARE_ROM : {
*(reset_code)
*(.text)
*(.rodata)
} >ROM
.bss : {
__BSS_RAM_START__ = .;
*(.bss)
*(COMMON)
__BSS_RAM_STOP__ = .;
} >RAM AT>ROM
.data : {
__DATA_RAM_START__ = .;
*(.data)
__DATA_RAM_STOP__ = .;
} >RAM AT>ROM
FIRMWARE_RAM_STACKS ALIGN (PLATFORM_CACHE_LINE_SIZE) : {
. += 0x1000;
*(tzfw_normal_stacks)
. = ALIGN(4096);
} >RAM AT>ROM
FIRMWARE_RAM_COHERENT ALIGN (4096): {
*(tzfw_coherent_mem)
/* . += 0x1000;*/
/* Do we need to make sure this is at least 4k? */
. = ALIGN(4096);
} >RAM
__FIRMWARE_ROM_START__ = LOADADDR(FIRMWARE_ROM);
__FIRMWARE_ROM_SIZE__ = SIZEOF(FIRMWARE_ROM);
__FIRMWARE_DATA_START__ = LOADADDR(.data);
__FIRMWARE_DATA_SIZE__ = SIZEOF(.data);
__FIRMWARE_BSS_START__ = LOADADDR(.bss);
__FIRMWARE_BSS_SIZE__ = SIZEOF(.bss);
__FIRMWARE_RAM_STACKS_START__ = LOADADDR(FIRMWARE_RAM_STACKS);
__FIRMWARE_RAM_STACKS_SIZE__ = SIZEOF(FIRMWARE_RAM_STACKS);
__FIRMWARE_RAM_COHERENT_START__ = LOADADDR(FIRMWARE_RAM_COHERENT);
__FIRMWARE_RAM_COHERENT_SIZE__ = SIZEOF(FIRMWARE_RAM_COHERENT);
}

46
bl1/bl1.mk Normal file
View File

@ -0,0 +1,46 @@
#
# Copyright (c) 2013, ARM Limited. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of ARM nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
vpath %.c drivers/arm/interconnect/cci-400/ plat/fvp \
plat/fvp/${ARCH} drivers/arm/peripherals/pl011 common/ lib/ \
lib/semihosting arch/aarch64/ lib/non-semihosting
vpath %.S arch/${ARCH}/cpu plat/common/aarch64 \
plat/fvp/${ARCH} lib/semihosting/aarch64 \
include/ lib/arch/aarch64
BL1_ASM_OBJS := bl1_entrypoint.o bl1_plat_helpers.o cpu_helpers.o
BL1_C_OBJS := bl1_main.o cci400.o bl1_plat_setup.o bl1_arch_setup.o \
fvp_common.o fvp_helpers.o early_exceptions.o
BL1_ENTRY_POINT := reset_handler
BL1_MAPFILE := bl1.map
BL1_LINKERFILE := bl1.ld
BL1_OBJS := $(BL1_C_OBJS) $(BL1_ASM_OBJS)

132
bl1/bl1_main.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <platform.h>
#include <semihosting.h>
#include <bl1.h>
void bl1_arch_next_el_setup(void);
/*******************************************************************************
* Function to perform late architectural and platform specific initialization.
* It also locates and loads the BL2 raw binary image in the trusted DRAM. Only
* called by the primary cpu after a cold boot.
* TODO: Add support for alternative image load mechanism e.g using virtio/elf
* loader etc.
******************************************************************************/
void bl1_main(void)
{
unsigned long sctlr_el3 = read_sctlr();
unsigned long bl2_base;
unsigned int load_type = TOP_LOAD, spsr;
meminfo bl1_tzram_layout, *bl2_tzram_layout = 0x0;
/*
* Ensure that MMU/Caches and coherency are turned on
*/
assert(sctlr_el3 | SCTLR_M_BIT);
assert(sctlr_el3 | SCTLR_C_BIT);
assert(sctlr_el3 | SCTLR_I_BIT);
/* Perform remaining generic architectural setup from EL3 */
bl1_arch_setup();
/* Perform platform setup in BL1. */
bl1_platform_setup();
/* Announce our arrival */
printf(FIRMWARE_WELCOME_STR);
printf("Built : %s, %s\n\r", __TIME__, __DATE__);
/*
* Find out how much free trusted ram remains after BL1 load
* & load the BL2 image at its top
*/
bl1_tzram_layout = bl1_get_sec_mem_layout();
bl2_base = load_image(&bl1_tzram_layout,
(const char *) BL2_IMAGE_NAME,
load_type, BL2_BASE);
/*
* Create a new layout of memory for BL2 as seen by BL1 i.e.
* tell it the amount of total and free memory available.
* This layout is created at the first free address visible
* to BL2. BL2 will read the memory layout before using its
* memory for other purposes.
*/
bl2_tzram_layout = (meminfo *) bl1_tzram_layout.free_base;
init_bl2_mem_layout(&bl1_tzram_layout,
bl2_tzram_layout,
load_type,
bl2_base);
if (bl2_base) {
bl1_arch_next_el_setup();
spsr = make_spsr(MODE_EL1, MODE_SP_ELX, MODE_RW_64);
printf("Booting trusted firmware boot loader stage 2\n\r");
#if DEBUG
printf("BL2 address = 0x%llx \n\r", (unsigned long long) bl2_base);
printf("BL2 cpsr = 0x%x \n\r", spsr);
printf("BL2 memory layout address = 0x%llx \n\r",
(unsigned long long) bl2_tzram_layout);
#endif
run_image(bl2_base, spsr, SECURE, bl2_tzram_layout, 0);
}
/*
* TODO: print failure to load BL2 but also add a tzwdog timer
* which will reset the system eventually.
*/
printf("Failed to load boot loader stage 2 (BL2) firmware.\n\r");
return;
}
/*******************************************************************************
* Temporary function to print the fact that BL2 has done its job and BL31 is
* about to be loaded. This is needed as long as printfs cannot be used
******************************************************************************/
void display_boot_progress(unsigned long entrypoint,
unsigned long spsr,
unsigned long mem_layout,
unsigned long ns_image_info)
{
printf("Booting trusted firmware boot loader stage 3\n\r");
#if DEBUG
printf("BL31 address = 0x%llx \n\r", (unsigned long long) entrypoint);
printf("BL31 cpsr = 0x%llx \n\r", (unsigned long long)spsr);
printf("BL31 memory layout address = 0x%llx \n\r", (unsigned long long)mem_layout);
printf("BL31 non-trusted image info address = 0x%llx\n\r", (unsigned long long)ns_image_info);
#endif
return;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
#include <platform.h>
/*******************************************************************************
* Place holder function to perform any S-EL1 specific architectural setup. At
* the moment there is nothing to do.
******************************************************************************/
void bl2_arch_setup(void)
{
/* Give access to FP/SIMD registers */
write_cpacr(CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bl_common.h>
.globl bl2_entrypoint
.section entry_code, "ax"; .align 3
bl2_entrypoint:; .type bl2_entrypoint, %function
/*---------------------------------------------
* Store the extents of the tzram available to
* BL2 for future use. Use the opcode param to
* allow implement other functions if needed.
* ---------------------------------------------
*/
mov x20, x0
mov x21, x1
mov x22, x2
/* ---------------------------------------------
* This is BL2 which is expected to be executed
* only by the primary cpu (at least for now).
* So, make sure no secondary has lost its way.
* ---------------------------------------------
*/
bl read_mpidr
mov x19, x0
bl platform_is_primary_cpu
cbz x0, _panic
/* --------------------------------------------
* Give ourselves a small coherent stack to
* ease the pain of initializing the MMU
* --------------------------------------------
*/
mov x0, x19
bl platform_set_coherent_stack
/* ---------------------------------------------
* Perform early platform setup & platform
* specific early arch. setup e.g. mmu setup
* ---------------------------------------------
*/
mov x0, x21
mov x1, x22
bl bl2_early_platform_setup
bl bl2_plat_arch_setup
/* ---------------------------------------------
* Give ourselves a stack allocated in Normal
* -IS-WBWA memory
* ---------------------------------------------
*/
mov x0, x19
bl platform_set_stack
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
_panic:
b _panic

85
bl2/bl2.ld.S Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <platform.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
MEMORY {
/* RAM is read/write and Initialised */
RAM (rwx): ORIGIN = TZRAM_BASE, LENGTH = TZRAM_SIZE
}
SECTIONS
{
. = BL2_BASE;
BL2_RO NEXT (4096): {
*(entry_code)
*(.text .rodata)
} >RAM
BL2_STACKS NEXT (4096): {
*(tzfw_normal_stacks)
} >RAM
BL2_COHERENT_RAM NEXT (4096): {
*(tzfw_coherent_mem)
/* . += 0x1000;*/
/* Do we need to ensure at least 4k here? */
. = NEXT(4096);
} >RAM
__BL2_DATA_START__ = .;
.bss NEXT (4096): {
*(SORT_BY_ALIGNMENT(.bss))
*(COMMON)
} >RAM
.data : {
*(.data)
} >RAM
__BL2_DATA_STOP__ = .;
__BL2_RO_BASE__ = LOADADDR(BL2_RO);
__BL2_RO_SIZE__ = SIZEOF(BL2_RO);
__BL2_STACKS_BASE__ = LOADADDR(BL2_STACKS);
__BL2_STACKS_SIZE__ = SIZEOF(BL2_STACKS);
__BL2_COHERENT_RAM_BASE__ = LOADADDR(BL2_COHERENT_RAM);
__BL2_COHERENT_RAM_SIZE__ = SIZEOF(BL2_COHERENT_RAM);
__BL2_RW_BASE__ = __BL2_DATA_START__;
__BL2_RW_SIZE__ = __BL2_DATA_STOP__ - __BL2_DATA_START__;
}

48
bl2/bl2.mk Normal file
View File

@ -0,0 +1,48 @@
#
# Copyright (c) 2013, ARM Limited. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of ARM nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
vpath %.c common/ drivers/arm/interconnect/cci-400/ \
drivers/arm/peripherals/pl011 common/ lib/ \
plat/fvp plat/fvp/${ARCH} lib/semihosting arch/aarch64/ \
lib/non-semihosting
vpath %.S lib/arch/aarch64 \
lib/semihosting/aarch64 \
include lib/sync/locks/exclusive
BL2_ASM_OBJS := bl2_entrypoint.o spinlock.o
BL2_C_OBJS := bl2_main.o bl2_plat_setup.o bl2_arch_setup.o fvp_common.o \
early_exceptions.o
BL2_ENTRY_POINT := bl2_entrypoint
BL2_MAPFILE := bl2.map
BL2_LINKERFILE := bl2.ld
BL2_OBJS := $(BL2_C_OBJS) $(BL2_ASM_OBJS)
CFLAGS += $(DEFINES)

143
bl2/bl2_main.c Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <semihosting.h>
#include <bl_common.h>
#include <bl2.h>
/*******************************************************************************
* The only thing to do in BL2 is to load further images and pass control to
* BL31. The memory occupied by BL2 will be reclaimed by BL3_x stages. BL2 runs
* entirely in S-EL1. Since arm standard c libraries are not PIC, printf et al
* are not available. We rely on assertions to signal error conditions
******************************************************************************/
void bl2_main(void)
{
meminfo bl2_tzram_layout, *bl31_tzram_layout;
el_change_info *ns_image_info;
unsigned long bl31_base, el_status;
unsigned int bl2_load, bl31_load, mode;
/* Perform remaining generic architectural setup in S-El1 */
bl2_arch_setup();
/* Perform platform setup in BL1 */
bl2_platform_setup();
#if defined (__GNUC__)
printf("BL2 Built : %s, %s\n\r", __TIME__, __DATE__);
#endif
/* Find out how much free trusted ram remains after BL2 load */
bl2_tzram_layout = bl2_get_sec_mem_layout();
/*
* Load BL31. BL1 tells BL2 whether it has been TOP or BOTTOM loaded.
* To avoid fragmentation of trusted SRAM memory, BL31 is always
* loaded opposite to BL2. This allows BL31 to reclaim BL2 memory
* while maintaining its free space in one contiguous chunk.
*/
bl2_load = bl2_tzram_layout.attr & LOAD_MASK;
assert((bl2_load == TOP_LOAD) || (bl2_load == BOT_LOAD));
bl31_load = (bl2_load == TOP_LOAD) ? BOT_LOAD : TOP_LOAD;
bl31_base = load_image(&bl2_tzram_layout, BL31_IMAGE_NAME,
bl31_load, BL31_BASE);
/* Assert if it has not been possible to load BL31 */
assert(bl31_base != 0);
/*
* Create a new layout of memory for BL31 as seen by BL2. This
* will gobble up all the BL2 memory.
*/
bl31_tzram_layout = (meminfo *) get_el_change_mem_ptr();
init_bl31_mem_layout(&bl2_tzram_layout, bl31_tzram_layout, bl31_load);
/*
* BL2 also needs to tell BL31 where the non-trusted software image
* has been loaded. Place this info right after the BL31 memory layout
*/
ns_image_info = (el_change_info *) ((unsigned char *) bl31_tzram_layout
+ sizeof(meminfo));
/*
* Assume that the non-secure bootloader has already been
* loaded to its platform-specific location.
*/
ns_image_info->entrypoint = plat_get_ns_image_entrypoint();
/* Figure out what mode we enter the non-secure world in */
el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
el_status &= ID_AA64PFR0_ELX_MASK;
if (el_status)
mode = MODE_EL2;
else
mode = MODE_EL1;
ns_image_info->spsr = make_spsr(mode, MODE_SP_ELX, MODE_RW_64);
ns_image_info->security_state = NON_SECURE;
flush_dcache_range((unsigned long) ns_image_info,
sizeof(el_change_info));
/*
* Run BL31 via an SMC to BL1. Information on how to pass control to
* the non-trusted software image will be passed to BL31 in x2.
*/
if (bl31_base)
run_image(bl31_base,
make_spsr(MODE_EL3, MODE_SP_ELX, MODE_RW_64),
SECURE,
bl31_tzram_layout,
(void *) ns_image_info);
/* There is no valid reason for run_image() to return */
assert(0);
}
/*******************************************************************************
* BL1 has this function to print the fact that BL2 has done its job and BL31 is
* about to be loaded. Since BL2 re-uses BL1's exception table, it needs to
* define this function as well.
* TODO: Remove this function from BL2.
******************************************************************************/
void display_boot_progress(unsigned long entrypoint,
unsigned long spsr,
unsigned long mem_layout,
unsigned long ns_image_info)
{
return;
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
#include <platform.h>
#include <assert.h>
/*******************************************************************************
* This duplicates what the primary cpu did after a cold boot in BL1. The same
* needs to be done when a cpu is hotplugged in. This function could also over-
* ride any EL3 setup done by BL1 as this code resides in rw memory.
******************************************************************************/
void bl31_arch_setup(void)
{
unsigned long tmp_reg = 0;
unsigned int counter_base_frequency;
/* Enable alignment checks and set the exception endianness to LE */
tmp_reg = read_sctlr();
tmp_reg |= (SCTLR_A_BIT | SCTLR_SA_BIT);
tmp_reg &= ~SCTLR_EE_BIT;
write_sctlr(tmp_reg);
/*
* Enable HVCs, allow NS to mask CPSR.A, route FIQs to EL3, set the
* next EL to be aarch64
*/
tmp_reg = SCR_RES1_BITS | SCR_RW_BIT | SCR_HCE_BIT | SCR_FIQ_BIT;
write_scr(tmp_reg);
/* Do not trap coprocessor accesses from lower ELs to EL3 */
write_cptr_el3(0);
/* Read the frequency from Frequency modes table */
counter_base_frequency = mmio_read_32(SYS_CNTCTL_BASE + CNTFID_OFF);
/* The first entry of the frequency modes table must not be 0 */
assert(counter_base_frequency != 0);
/* Program the counter frequency */
write_cntfrq_el0(counter_base_frequency);
return;
}
/*******************************************************************************
* Detect what is the next Non-Secure EL and setup the required architectural
* state
******************************************************************************/
void bl31_arch_next_el_setup(void) {
unsigned long id_aa64pfr0 = read_id_aa64pfr0_el1();
unsigned long current_sctlr, next_sctlr;
unsigned long el_status;
unsigned long scr = read_scr();
/* Use the same endianness than the current BL */
current_sctlr = read_sctlr();
next_sctlr = (current_sctlr & SCTLR_EE_BIT);
/* Find out which EL we are going to */
el_status = (id_aa64pfr0 >> ID_AA64PFR0_EL2_SHIFT) & ID_AA64PFR0_ELX_MASK;
/* Check what if EL2 is supported */
if (el_status && (scr & SCR_HCE_BIT)) {
/* Set SCTLR EL2 */
next_sctlr |= SCTLR_EL2_RES1;
write_sctlr_el2(next_sctlr);
} else {
/* Set SCTLR Non-Secure EL1 */
next_sctlr |= SCTLR_EL1_RES1;
write_sctlr_el1(next_sctlr);
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bl1.h>
#include <bl_common.h>
#include <platform.h>
.globl bl31_entrypoint
.section entry_code, "ax"; .align 3
/* -----------------------------------------------------
* bl31_entrypoint() is the cold boot entrypoint,
* executed only by the primary cpu.
* -----------------------------------------------------
*/
bl31_entrypoint:; .type bl31_entrypoint, %function
/* ---------------------------------------------
* BL2 has populated x0,x3,x4 with the opcode
* indicating BL31 should be run, memory layout
* of the trusted SRAM available to BL31 and
* information about running the non-trusted
* software already loaded by BL2. Check the
* opcode out of paranoia.
* ---------------------------------------------
*/
mov x19, #RUN_IMAGE
cmp x0, x19
b.ne _panic
mov x20, x3
mov x21, x4
/* ---------------------------------------------
* This is BL31 which is expected to be executed
* only by the primary cpu (at least for now).
* So, make sure no secondary has lost its way.
* ---------------------------------------------
*/
bl read_mpidr
mov x19, x0
bl platform_is_primary_cpu
cbz x0, _panic
/* --------------------------------------------
* Give ourselves a small coherent stack to
* ease the pain of initializing the MMU
* --------------------------------------------
*/
mov x0, x19
bl platform_set_coherent_stack
/* ---------------------------------------------
* Perform platform specific early arch. setup
* ---------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x19
bl bl31_early_platform_setup
bl bl31_plat_arch_setup
/* ---------------------------------------------
* Give ourselves a stack allocated in Normal
* -IS-WBWA memory
* ---------------------------------------------
*/
mov x0, x19
bl platform_set_stack
/* ---------------------------------------------
* Use SP_EL0 to initialize BL31. It allows us
* to jump to the next image without having to
* come back here to ensure all of the stack's
* been popped out. run_image() is not nice
* enough to reset the stack pointer before
* handing control to the next stage.
* ---------------------------------------------
*/
mov x0, sp
msr sp_el0, x0
msr spsel, #0
isb
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl31_main
_panic:
b _panic

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
#include <platform.h>
#include <bl_common.h>
#include <bl31.h>
#include <psci.h>
#include <assert.h>
#include <runtime_svc.h>
/*******************************************************************************
* This function checks whether this is a valid smc e.g.
* the function id is correct, top word of args are zeroed
* when aarch64 makes an aarch32 call etc.
******************************************************************************/
int validate_smc(gp_regs *regs)
{
unsigned int rw = GET_RW(regs->spsr);
unsigned int cc = GET_SMC_CC(regs->x0);
/* Check if there is a difference in the caller RW and SMC CC */
if (rw == cc) {
/* Check whether the caller has chosen the right func. id */
if (cc == SMC_64) {
regs->x0 = SMC_UNK;
return SMC_UNK;
}
/*
* Paranoid check to zero the top word of passed args
* irrespective of caller's register width.
*
* TODO: Check if this needed if the caller is aarch32
*/
regs->x0 &= (unsigned int) 0xFFFFFFFF;
regs->x1 &= (unsigned int) 0xFFFFFFFF;
regs->x2 &= (unsigned int) 0xFFFFFFFF;
regs->x3 &= (unsigned int) 0xFFFFFFFF;
regs->x4 &= (unsigned int) 0xFFFFFFFF;
regs->x5 &= (unsigned int) 0xFFFFFFFF;
regs->x6 &= (unsigned int) 0xFFFFFFFF;
}
return 0;
}
/* TODO: Break down the SMC handler into fast and standard SMC handlers. */
void smc_handler(unsigned type, unsigned long esr, gp_regs *regs)
{
/* Check if the SMC has been correctly called */
if (validate_smc(regs) != 0)
return;
switch (regs->x0) {
case PSCI_VERSION:
regs->x0 = psci_version();
break;
case PSCI_CPU_OFF:
regs->x0 = __psci_cpu_off();
break;
case PSCI_CPU_SUSPEND_AARCH64:
case PSCI_CPU_SUSPEND_AARCH32:
regs->x0 = __psci_cpu_suspend(regs->x1, regs->x2, regs->x3);
break;
case PSCI_CPU_ON_AARCH64:
case PSCI_CPU_ON_AARCH32:
regs->x0 = psci_cpu_on(regs->x1, regs->x2, regs->x3);
break;
case PSCI_AFFINITY_INFO_AARCH32:
case PSCI_AFFINITY_INFO_AARCH64:
regs->x0 = psci_affinity_info(regs->x1, regs->x2);
break;
default:
regs->x0 = SMC_UNK;
}
return;
}
void irq_handler(unsigned type, unsigned long esr, gp_regs *regs)
{
plat_report_exception(type);
assert(0);
}
void fiq_handler(unsigned type, unsigned long esr, gp_regs *regs)
{
plat_report_exception(type);
assert(0);
}
void serror_handler(unsigned type, unsigned long esr, gp_regs *regs)
{
plat_report_exception(type);
assert(0);
}
void sync_exception_handler(unsigned type, gp_regs *regs)
{
unsigned long esr = read_esr();
unsigned int ec = EC_BITS(esr);
switch (ec) {
case EC_AARCH32_SMC:
case EC_AARCH64_SMC:
smc_handler(type, esr, regs);
break;
default:
plat_report_exception(type);
assert(0);
}
return;
}
void async_exception_handler(unsigned type, gp_regs *regs)
{
unsigned long esr = read_esr();
switch (type) {
case IRQ_SP_EL0:
case IRQ_SP_ELX:
case IRQ_AARCH64:
case IRQ_AARCH32:
irq_handler(type, esr, regs);
break;
case FIQ_SP_EL0:
case FIQ_SP_ELX:
case FIQ_AARCH64:
case FIQ_AARCH32:
fiq_handler(type, esr, regs);
break;
case SERROR_SP_EL0:
case SERROR_SP_ELX:
case SERROR_AARCH64:
case SERROR_AARCH32:
serror_handler(type, esr, regs);
break;
default:
plat_report_exception(type);
assert(0);
}
return;
}

View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <runtime_svc.h>
.globl runtime_exceptions
#include <asm_macros.S>
.section aarch64_code, "ax"; .align 11
.align 7
runtime_exceptions:
/* -----------------------------------------------------
* Current EL with _sp_el0 : 0x0 - 0x180
* -----------------------------------------------------
*/
sync_exception_sp_el0:
exception_entry save_regs
mov x0, #SYNC_EXCEPTION_SP_EL0
mov x1, sp
bl sync_exception_handler
exception_exit restore_regs
eret
.align 7
irq_sp_el0:
exception_entry save_regs
mov x0, #IRQ_SP_EL0
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
fiq_sp_el0:
exception_entry save_regs
mov x0, #FIQ_SP_EL0
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
serror_sp_el0:
exception_entry save_regs
mov x0, #SERROR_SP_EL0
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
/* -----------------------------------------------------
* Current EL with SPx: 0x200 - 0x380
* -----------------------------------------------------
*/
.align 7
sync_exception_sp_elx:
exception_entry save_regs
mov x0, #SYNC_EXCEPTION_SP_ELX
mov x1, sp
bl sync_exception_handler
exception_exit restore_regs
eret
.align 7
irq_sp_elx:
exception_entry save_regs
mov x0, #IRQ_SP_ELX
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
fiq_sp_elx:
exception_entry save_regs
mov x0, #FIQ_SP_ELX
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
serror_sp_elx:
exception_entry save_regs
mov x0, #SERROR_SP_ELX
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x580
* -----------------------------------------------------
*/
.align 7
sync_exception_aarch64:
exception_entry save_regs
mov x0, #SYNC_EXCEPTION_AARCH64
mov x1, sp
bl sync_exception_handler
exception_exit restore_regs
eret
.align 7
irq_aarch64:
exception_entry save_regs
mov x0, #IRQ_AARCH64
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
fiq_aarch64:
exception_entry save_regs
mov x0, #FIQ_AARCH64
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
serror_aarch64:
exception_entry save_regs
mov x0, #IRQ_AARCH32
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x780
* -----------------------------------------------------
*/
.align 7
sync_exception_aarch32:
exception_entry save_regs
mov x0, #SYNC_EXCEPTION_AARCH32
mov x1, sp
bl sync_exception_handler
exception_exit restore_regs
eret
.align 7
irq_aarch32:
exception_entry save_regs
mov x0, #IRQ_AARCH32
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
fiq_aarch32:
exception_entry save_regs
mov x0, #FIQ_AARCH32
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
serror_aarch32:
exception_entry save_regs
mov x0, #SERROR_AARCH32
mov x1, sp
bl async_exception_handler
exception_exit restore_regs
eret
.align 7
save_regs:; .type save_regs, %function
sub sp, sp, #0x100
stp x0, x1, [sp, #0x0]
stp x2, x3, [sp, #0x10]
stp x4, x5, [sp, #0x20]
stp x6, x7, [sp, #0x30]
stp x8, x9, [sp, #0x40]
stp x10, x11, [sp, #0x50]
stp x12, x13, [sp, #0x60]
stp x14, x15, [sp, #0x70]
stp x16, x17, [sp, #0x80]
stp x18, x19, [sp, #0x90]
stp x20, x21, [sp, #0xa0]
stp x22, x23, [sp, #0xb0]
stp x24, x25, [sp, #0xc0]
stp x26, x27, [sp, #0xd0]
mrs x0, sp_el0
stp x28, x0, [sp, #0xe0]
mrs x0, spsr_el3
str x0, [sp, #0xf0]
ret
restore_regs:; .type restore_regs, %function
ldr x9, [sp, #0xf0]
msr spsr_el3, x9
ldp x28, x9, [sp, #0xe0]
msr sp_el0, x9
ldp x26, x27, [sp, #0xd0]
ldp x24, x25, [sp, #0xc0]
ldp x22, x23, [sp, #0xb0]
ldp x20, x21, [sp, #0xa0]
ldp x18, x19, [sp, #0x90]
ldp x16, x17, [sp, #0x80]
ldp x14, x15, [sp, #0x70]
ldp x12, x13, [sp, #0x60]
ldp x10, x11, [sp, #0x50]
ldp x8, x9, [sp, #0x40]
ldp x6, x7, [sp, #0x30]
ldp x4, x5, [sp, #0x20]
ldp x2, x3, [sp, #0x10]
ldp x0, x1, [sp, #0x0]
add sp, sp, #0x100
ret

88
bl31/bl31.ld.S Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <platform.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
MEMORY {
/* RAM is read/write and Initialised */
RAM (rwx): ORIGIN = TZRAM_BASE, LENGTH = TZRAM_SIZE
}
SECTIONS
{
. = BL31_BASE;
BL31_RO ALIGN (4096): {
*(entry_code)
*(.text)
*(.rodata)
} >RAM
BL31_STACKS ALIGN (4096): {
. += 0x1000;
*(tzfw_normal_stacks)
} >RAM
BL31_COHERENT_RAM ALIGN (4096): {
*(tzfw_coherent_mem)
/* . += 0x1000;*/
/* Do we need to ensure at least 4k here? */
. = ALIGN(4096);
} >RAM
__BL31_DATA_START__ = .;
.bss ALIGN (4096): {
*(.bss)
*(COMMON)
} >RAM
.data : {
*(.data)
} >RAM
__BL31_DATA_STOP__ = .;
__BL31_RO_BASE__ = LOADADDR(BL31_RO);
__BL31_RO_SIZE__ = SIZEOF(BL31_RO);
__BL31_STACKS_BASE__ = LOADADDR(BL31_STACKS);
__BL31_STACKS_SIZE__ = SIZEOF(BL31_STACKS);
__BL31_COHERENT_RAM_BASE__ = LOADADDR(BL31_COHERENT_RAM);
__BL31_COHERENT_RAM_SIZE__ = SIZEOF(BL31_COHERENT_RAM);
__BL31_RW_BASE__ = __BL31_DATA_START__;
__BL31_RW_SIZE__ = __BL31_DATA_STOP__ - __BL31_DATA_START__;
}

55
bl31/bl31.mk Normal file
View File

@ -0,0 +1,55 @@
#
# Copyright (c) 2013, ARM Limited. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of ARM nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
vpath %.c drivers/arm/interconnect/cci-400/ common/ lib/ \
drivers/arm/peripherals/pl011 plat/fvp common/psci \
lib/semihosting arch/aarch64/ lib/non-semihosting \
lib/sync/locks/bakery/ drivers/power/ arch/system/gic/ \
plat/fvp/aarch64/
vpath %.S lib/arch/aarch64 common/psci \
lib/semihosting/aarch64 include/ plat/fvp/${ARCH} \
lib/sync/locks/exclusive plat/common/aarch64/ \
arch/system/gic/${ARCH}
BL31_ASM_OBJS := bl31_entrypoint.o runtime_exceptions.o psci_entry.o \
spinlock.o gic_v3_sysregs.o fvp_helpers.o
BL31_C_OBJS := bl31_main.o bl31_plat_setup.o bl31_arch_setup.o \
exception_handlers.o bakery_lock.o cci400.o \
fvp_common.o fvp_pm.o fvp_pwrc.o fvp_topology.o \
runtime_svc.o gic_v3.o gic_v2.o psci_setup.o \
psci_common.o psci_afflvl_on.o psci_main.o \
psci_afflvl_off.o psci_afflvl_suspend.o
BL31_ENTRY_POINT := bl31_entrypoint
BL31_MAPFILE := bl31.map
BL31_LINKERFILE := bl31.ld
BL31_OBJS := $(BL31_C_OBJS) $(BL31_ASM_OBJS)

76
bl31/bl31_main.c Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <semihosting.h>
#include <bl_common.h>
#include <bl31.h>
#include <runtime_svc.h>
void bl31_arch_next_el_setup(void);
/*******************************************************************************
* BL31 is responsible for setting up the runtime services for the primary cpu
* before passing control to the bootloader (UEFI) or Linux.
******************************************************************************/
void bl31_main(void)
{
el_change_info *image_info;
unsigned long mpidr = read_mpidr();
/* Perform remaining generic architectural setup from EL3 */
bl31_arch_setup();
/* Perform platform setup in BL1 */
bl31_platform_setup();
#if defined (__GNUC__)
printf("BL31 Built : %s, %s\n\r", __TIME__, __DATE__);
#endif
/* Initialize the runtime services e.g. psci */
runtime_svc_init(mpidr);
/* Clean caches before re-entering normal world */
dcsw_op_all(DCCSW);
image_info = bl31_get_next_image_info(mpidr);
bl31_arch_next_el_setup();
change_el(image_info);
/* There is no valid reason for change_el() to return */
assert(0);
}

516
common/bl_common.c Normal file
View File

@ -0,0 +1,516 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <semihosting.h>
#include <bl_common.h>
#include <bl1.h>
/***********************************************************
* Memory for sharing data while changing exception levels.
* Only used by the primary core.
**********************************************************/
unsigned char bl2_el_change_mem_ptr[EL_CHANGE_MEM_SIZE];
unsigned long *get_el_change_mem_ptr(void)
{
return (unsigned long *) bl2_el_change_mem_ptr;
}
unsigned long page_align(unsigned long value, unsigned dir)
{
unsigned long page_size = 1 << FOUR_KB_SHIFT;
/* Round up the limit to the next page boundary */
if (value & (page_size - 1)) {
value &= ~(page_size - 1);
if (dir == UP)
value += page_size;
}
return value;
}
static inline unsigned int is_page_aligned (unsigned long addr) {
const unsigned long page_size = 1 << FOUR_KB_SHIFT;
return (addr & (page_size - 1)) == 0;
}
void change_security_state(unsigned int target_security_state)
{
unsigned long scr = read_scr();
if (target_security_state == SECURE)
scr &= ~SCR_NS_BIT;
else if (target_security_state == NON_SECURE)
scr |= SCR_NS_BIT;
else
assert(0);
write_scr(scr);
}
int drop_el(aapcs64_params *args,
unsigned long spsr,
unsigned long entrypoint)
{
write_spsr(spsr);
write_elr(entrypoint);
eret(args->arg0,
args->arg1,
args->arg2,
args->arg3,
args->arg4,
args->arg5,
args->arg6,
args->arg7);
return -EINVAL;
}
long raise_el(aapcs64_params *args)
{
return smc(args->arg0,
args->arg1,
args->arg2,
args->arg3,
args->arg4,
args->arg5,
args->arg6,
args->arg7);
}
/*
* TODO: If we are not EL3 then currently we only issue an SMC.
* Add support for dropping into EL0 etc. Consider adding support
* for switching from S-EL1 to S-EL0/1 etc.
*/
long change_el(el_change_info *info)
{
unsigned long current_el = read_current_el();
if (GET_EL(current_el) == MODE_EL3) {
/*
* We can go anywhere from EL3. So find where.
* TODO: Lots to do if we are going non-secure.
* Flip the NS bit. Restore NS registers etc.
* Just doing the bare minimal for now.
*/
if (info->security_state == NON_SECURE)
change_security_state(info->security_state);
return drop_el(&info->args, info->spsr, info->entrypoint);
} else
return raise_el(&info->args);
}
/* TODO: add a parameter for DAIF. not needed right now */
unsigned long make_spsr(unsigned long target_el,
unsigned long target_sp,
unsigned long target_rw)
{
unsigned long spsr;
/* Disable all exceptions & setup the EL */
spsr = (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
<< PSR_DAIF_SHIFT;
spsr |= PSR_MODE(target_rw, target_el, target_sp);
return spsr;
}
/*******************************************************************************
* The next two functions are the weak definitions. Platform specific
* code can override them if it wishes to.
******************************************************************************/
/*******************************************************************************
* Function that takes a memory layout into which BL31 has been either top or
* bottom loaded. Using this information, it populates bl31_mem_layout to tell
* BL31 how much memory it has access to and how much is available for use. It
* does not need the address where BL31 has been loaded as BL31 will reclaim
* all the memory used by BL2.
* TODO: Revisit if this and init_bl2_mem_layout can be replaced by a single
* routine.
******************************************************************************/
void init_bl31_mem_layout(const meminfo *bl2_mem_layout,
meminfo *bl31_mem_layout,
unsigned int load_type)
{
if (load_type == BOT_LOAD) {
/*
* ------------ ^
* | BL2 | |
* |----------| ^ | BL2
* | | | BL2 free | total
* | | | size | size
* |----------| BL2 free base v |
* | BL31 | |
* ------------ BL2 total base v
*/
unsigned long bl31_size;
bl31_mem_layout->free_base = bl2_mem_layout->free_base;
bl31_size = bl2_mem_layout->free_base - bl2_mem_layout->total_base;
bl31_mem_layout->free_size = bl2_mem_layout->total_size - bl31_size;
} else {
/*
* ------------ ^
* | BL31 | |
* |----------| ^ | BL2
* | | | BL2 free | total
* | | | size | size
* |----------| BL2 free base v |
* | BL2 | |
* ------------ BL2 total base v
*/
unsigned long bl2_size;
bl31_mem_layout->free_base = bl2_mem_layout->total_base;
bl2_size = bl2_mem_layout->free_base - bl2_mem_layout->total_base;
bl31_mem_layout->free_size = bl2_mem_layout->free_size + bl2_size;
}
bl31_mem_layout->total_base = bl2_mem_layout->total_base;
bl31_mem_layout->total_size = bl2_mem_layout->total_size;
bl31_mem_layout->attr = load_type;
flush_dcache_range((unsigned long) bl31_mem_layout, sizeof(meminfo));
return;
}
/*******************************************************************************
* Function that takes a memory layout into which BL2 has been either top or
* bottom loaded along with the address where BL2 has been loaded in it. Using
* this information, it populates bl2_mem_layout to tell BL2 how much memory
* it has access to and how much is available for use.
******************************************************************************/
void init_bl2_mem_layout(meminfo *bl1_mem_layout,
meminfo *bl2_mem_layout,
unsigned int load_type,
unsigned long bl2_base)
{
unsigned tmp;
if (load_type == BOT_LOAD) {
bl2_mem_layout->total_base = bl2_base;
tmp = bl1_mem_layout->free_base - bl2_base;
bl2_mem_layout->total_size = bl1_mem_layout->free_size + tmp;
} else {
bl2_mem_layout->total_base = bl1_mem_layout->free_base;
tmp = bl1_mem_layout->total_base + bl1_mem_layout->total_size;
bl2_mem_layout->total_size = tmp - bl1_mem_layout->free_base;
}
bl2_mem_layout->free_base = bl1_mem_layout->free_base;
bl2_mem_layout->free_size = bl1_mem_layout->free_size;
bl2_mem_layout->attr = load_type;
flush_dcache_range((unsigned long) bl2_mem_layout, sizeof(meminfo));
return;
}
static void dump_load_info(unsigned long image_load_addr,
unsigned long image_size,
const meminfo *mem_layout)
{
#if DEBUG
printf("Trying to load image at address 0x%lx, size = 0x%lx\r\n",
image_load_addr, image_size);
printf("Current memory layout:\r\n");
printf(" total region = [0x%lx, 0x%lx]\r\n", mem_layout->total_base,
mem_layout->total_base + mem_layout->total_size);
printf(" free region = [0x%lx, 0x%lx]\r\n", mem_layout->free_base,
mem_layout->free_base + mem_layout->free_size);
#endif
}
/*******************************************************************************
* Generic function to load an image into the trusted RAM using semihosting
* given a name, extents of free memory & whether the image should be loaded at
* the bottom or top of the free memory. It updates the memory layout if the
* load is successful.
******************************************************************************/
unsigned long load_image(meminfo *mem_layout,
const char *image_name,
unsigned int load_type,
unsigned long fixed_addr)
{
unsigned long temp_image_base, image_base;
long offset;
int image_flen;
/* Find the size of the image */
image_flen = semihosting_get_flen(image_name);
if (image_flen < 0) {
printf("ERROR: Cannot access '%s' file (%i).\r\n",
image_name, image_flen);
return 0;
}
/* See if we have enough space */
if (image_flen > mem_layout->free_size) {
printf("ERROR: Cannot load '%s' file: Not enough space.\r\n",
image_name);
dump_load_info(0, image_flen, mem_layout);
return 0;
}
switch (load_type) {
case TOP_LOAD:
/* Load the image in the top of free memory */
temp_image_base = mem_layout->free_base + mem_layout->free_size;
temp_image_base -= image_flen;
/* Page align base address and check whether the image still fits */
image_base = page_align(temp_image_base, DOWN);
assert(image_base <= temp_image_base);
if (image_base < mem_layout->free_base) {
printf("ERROR: Cannot load '%s' file: Not enough space.\r\n",
image_name);
dump_load_info(image_base, image_flen, mem_layout);
return 0;
}
/* Calculate the amount of extra memory used due to alignment */
offset = temp_image_base - image_base;
break;
case BOT_LOAD:
/* Load the BL2 image in the bottom of free memory */
temp_image_base = mem_layout->free_base;
image_base = page_align(temp_image_base, UP);
assert(image_base >= temp_image_base);
/* Page align base address and check whether the image still fits */
if (image_base + image_flen >
mem_layout->free_base + mem_layout->free_size) {
printf("ERROR: Cannot load '%s' file: Not enough space.\r\n",
image_name);
dump_load_info(image_base, image_flen, mem_layout);
return 0;
}
/* Calculate the amount of extra memory used due to alignment */
offset = image_base - temp_image_base;
break;
default:
assert(0);
}
/*
* Some images must be loaded at a fixed address, not a dynamic one.
*
* This has been implemented as a hack on top of the existing dynamic
* loading mechanism, for the time being. If the 'fixed_addr' function
* argument is different from zero, then it will force the load address.
* So we still have this principle of top/bottom loading but the code
* determining the load address is bypassed and the load address is
* forced to the fixed one.
*
* This can result in quite a lot of wasted space because we still use
* 1 sole meminfo structure to represent the extents of free memory,
* where we should use some sort of linked list.
*
* E.g. we want to load BL2 at address 0x04020000, the resulting memory
* layout should look as follows:
* ------------ 0x04040000
* | | <- Free space (1)
* |----------|
* | BL2 |
* |----------| 0x04020000
* | | <- Free space (2)
* |----------|
* | BL1 |
* ------------ 0x04000000
*
* But in the current hacky implementation, we'll need to specify
* whether BL2 is loaded at the top or bottom of the free memory.
* E.g. if BL2 is considered as top-loaded, the meminfo structure
* will give the following view of the memory, hiding the chunk of
* free memory above BL2:
* ------------ 0x04040000
* | |
* | |
* | BL2 |
* |----------| 0x04020000
* | | <- Free space (2)
* |----------|
* | BL1 |
* ------------ 0x04000000
*/
if (fixed_addr != 0) {
/* Load the image at the given address. */
image_base = fixed_addr;
/* Check whether the image fits. */
if ((image_base < mem_layout->free_base) ||
(image_base + image_flen >
mem_layout->free_base + mem_layout->free_size)) {
printf("ERROR: Cannot load '%s' file: Not enough space.\r\n",
image_name);
dump_load_info(image_base, image_flen, mem_layout);
return 0;
}
/* Check whether the fixed load address is page-aligned. */
if (!is_page_aligned(image_base)) {
printf("ERROR: Cannot load '%s' file at unaligned address 0x%lx.\r\n",
image_name, fixed_addr);
return 0;
}
/*
* Calculate the amount of extra memory used due to fixed
* loading.
*/
if (load_type == TOP_LOAD) {
unsigned long max_addr, space_used;
/*
* ------------ max_addr
* | /wasted/ | | offset
* |..........|..............................
* | image | | image_flen
* |----------| fixed_addr
* | |
* | |
* ------------ total_base
*/
max_addr = mem_layout->total_base + mem_layout->total_size;
/*
* Compute the amount of memory used by the image.
* Corresponds to all space above the image load
* address.
*/
space_used = max_addr - fixed_addr;
/*
* Calculate the amount of wasted memory within the
* amount of memory used by the image.
*/
offset = space_used - image_flen;
} else /* BOT_LOAD */
/*
* ------------
* | |
* | |
* |----------|
* | image |
* |..........| fixed_addr
* | /wasted/ | | offset
* ------------ total_base
*/
offset = fixed_addr - mem_layout->total_base;
}
/* We have enough space so load the image now */
image_flen = semihosting_download_file(image_name,
image_flen,
(void *) image_base);
if (image_flen <= 0) {
printf("ERROR: Failed to load '%s' file from semihosting (%i).\r\n",
image_name, image_flen);
return 0;
}
/*
* File has been successfully loaded. Update the free memory
* data structure & flush the contents of the TZRAM so that
* the next EL can see it.
*/
/* Update the memory contents */
flush_dcache_range(image_base, image_flen);
mem_layout->free_size -= image_flen + offset;
/* Update the base of free memory since its moved up */
if (load_type == BOT_LOAD)
mem_layout->free_base += offset + image_flen;
return image_base;
}
/*******************************************************************************
* Run a loaded image from the given entry point. This could result in either
* dropping into a lower exception level or jumping to a higher exception level.
* The only way of doing the latter is through an SMC. In either case, setup the
* parameters for the EL change request correctly.
******************************************************************************/
int run_image(unsigned long entrypoint,
unsigned long spsr,
unsigned long target_security_state,
meminfo *mem_layout,
void *data)
{
el_change_info run_image_info;
unsigned long current_el = read_current_el();
/* Tell next EL what we want done */
run_image_info.args.arg0 = RUN_IMAGE;
run_image_info.entrypoint = entrypoint;
run_image_info.spsr = spsr;
run_image_info.security_state = target_security_state;
run_image_info.next = 0;
/*
* If we are EL3 then only an eret can take us to the desired
* exception level. Else for the time being assume that we have
* to jump to a higher EL and issue an SMC. Contents of argY
* will go into the general purpose register xY e.g. arg0->x0
*/
if (GET_EL(current_el) == MODE_EL3) {
run_image_info.args.arg1 = (unsigned long) mem_layout;
run_image_info.args.arg2 = (unsigned long) data;
} else {
run_image_info.args.arg1 = entrypoint;
run_image_info.args.arg2 = spsr;
run_image_info.args.arg3 = (unsigned long) mem_layout;
run_image_info.args.arg4 = (unsigned long) data;
}
return change_el(&run_image_info);
}

View File

@ -0,0 +1,265 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <psci.h>
#include <psci_private.h>
typedef int (*afflvl_off_handler)(unsigned long, aff_map_node *);
/*******************************************************************************
* The next three functions implement a handler for each supported affinity
* level which is called when that affinity level is turned off.
******************************************************************************/
static int psci_afflvl0_off(unsigned long mpidr, aff_map_node *cpu_node)
{
unsigned int index, plat_state;
int rc = PSCI_E_SUCCESS;
unsigned long sctlr = read_sctlr();
assert(cpu_node->level == MPIDR_AFFLVL0);
/*
* Generic management: Get the index for clearing any
* lingering re-entry information
*/
index = cpu_node->data;
memset(&psci_ns_entry_info[index], 0, sizeof(psci_ns_entry_info[index]));
/*
* Arch. management. Perform the necessary steps to flush all
* cpu caches.
*
* TODO: This power down sequence varies across cpus so it needs to be
* abstracted out on the basis of the MIDR like in cpu_reset_handler().
* Do the bare minimal for the time being. Fix this before porting to
* Cortex models.
*/
sctlr &= ~SCTLR_C_BIT;
write_sctlr(sctlr);
/*
* CAUTION: This flush to the level of unification makes an assumption
* about the cache hierarchy at affinity level 0 (cpu) in the platform.
* Ideally the platform should tell psci which levels to flush to exit
* coherency.
*/
dcsw_op_louis(DCCISW);
/*
* Plat. management: Perform platform specific actions to turn this
* cpu off e.g. exit cpu coherency, program the power controller etc.
*/
if (psci_plat_pm_ops->affinst_off) {
/* Get the current physical state of this cpu */
plat_state = psci_get_aff_phys_state(cpu_node);
rc = psci_plat_pm_ops->affinst_off(mpidr,
cpu_node->level,
plat_state);
}
/*
* The only error cpu_off can return is E_DENIED. So check if that's
* indeed the case. The caller will simply 'eret' in case of an error.
*/
if (rc != PSCI_E_SUCCESS)
assert(rc == PSCI_E_DENIED);
return rc;
}
static int psci_afflvl1_off(unsigned long mpidr, aff_map_node *cluster_node)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
/* Sanity check the cluster level */
assert(cluster_node->level == MPIDR_AFFLVL1);
/*
* Keep the physical state of this cluster handy to decide
* what action needs to be taken
*/
plat_state = psci_get_aff_phys_state(cluster_node);
/*
* Arch. Management. Flush all levels of caches to PoC if
* the cluster is to be shutdown
*/
if (plat_state == PSCI_STATE_OFF)
dcsw_op_all(DCCISW);
/*
* Plat. Management. Allow the platform to do it's cluster
* specific bookeeping e.g. turn off interconnect coherency,
* program the power controller etc.
*/
if (psci_plat_pm_ops->affinst_off)
rc = psci_plat_pm_ops->affinst_off(mpidr,
cluster_node->level,
plat_state);
return rc;
}
static int psci_afflvl2_off(unsigned long mpidr, aff_map_node *system_node)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
/* Cannot go beyond this level */
assert(system_node->level == MPIDR_AFFLVL2);
/*
* Keep the physical state of the system handy to decide what
* action needs to be taken
*/
plat_state = psci_get_aff_phys_state(system_node);
/* No arch. and generic bookeeping to do here currently */
/*
* Plat. Management : Allow the platform to do it's bookeeping
* at this affinity level
*/
if (psci_plat_pm_ops->affinst_off)
rc = psci_plat_pm_ops->affinst_off(mpidr,
system_node->level,
plat_state);
return rc;
}
static const afflvl_off_handler psci_afflvl_off_handlers[] = {
psci_afflvl0_off,
psci_afflvl1_off,
psci_afflvl2_off,
};
/*******************************************************************************
* This function implements the core of the processing required to turn a cpu
* off. It's assumed that along with turning the cpu off, higher affinity levels
* will be turned off as far as possible. We first need to determine the new
* state off all the affinity instances in the mpidr corresponding to the target
* cpu. Action will be taken on the basis of this new state. To do the state
* change we first need to acquire the locks for all the implemented affinity
* level to be able to snapshot the system state. Then we need to start turning
* affinity levels off from the lowest to the highest (e.g. a cpu needs to be
* off before a cluster can be turned off). To achieve this flow, we start
* acquiring the locks from the highest to the lowest affinity level. Once we
* reach affinity level 0, we do the state change followed by the actions
* corresponding to the new state for affinity level 0. Actions as per the
* updated state for higher affinity levels are performed as we unwind back to
* highest affinity level.
******************************************************************************/
int psci_afflvl_off(unsigned long mpidr,
int cur_afflvl,
int tgt_afflvl)
{
int rc = PSCI_E_SUCCESS, level;
unsigned int next_state, prev_state;
aff_map_node *aff_node;
mpidr &= MPIDR_AFFINITY_MASK;;
/*
* Some affinity instances at levels between the current and
* target levels could be absent in the mpidr. Skip them and
* start from the first present instance.
*/
level = psci_get_first_present_afflvl(mpidr,
cur_afflvl,
tgt_afflvl,
&aff_node);
/*
* Return if there are no more affinity instances beyond this
* level to process. Else ensure that the returned affinity
* node makes sense.
*/
if (aff_node == NULL)
return rc;
assert(level == aff_node->level);
/*
* This function acquires the lock corresponding to each
* affinity level so that state management can be done safely.
*/
bakery_lock_get(mpidr, &aff_node->lock);
/* Keep the old state and the next one handy */
prev_state = psci_get_state(aff_node->state);
next_state = PSCI_STATE_OFF;
/*
* We start from the highest affinity level and work our way
* downwards to the lowest i.e. MPIDR_AFFLVL0.
*/
if (aff_node->level == tgt_afflvl) {
psci_change_state(mpidr,
tgt_afflvl,
get_max_afflvl(),
next_state);
} else {
rc = psci_afflvl_off(mpidr, level - 1, tgt_afflvl);
if (rc != PSCI_E_SUCCESS) {
psci_set_state(aff_node->state, prev_state);
goto exit;
}
}
/*
* Perform generic, architecture and platform specific
* handling
*/
rc = psci_afflvl_off_handlers[level](mpidr, aff_node);
if (rc != PSCI_E_SUCCESS) {
psci_set_state(aff_node->state, prev_state);
goto exit;
}
/*
* If all has gone as per plan then this cpu should be
* marked as OFF
*/
if (level == MPIDR_AFFLVL0) {
next_state = psci_get_state(aff_node->state);
assert(next_state == PSCI_STATE_OFF);
}
exit:
bakery_lock_release(mpidr, &aff_node->lock);
return rc;
}

View File

@ -0,0 +1,416 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <psci.h>
#include <psci_private.h>
typedef int (*afflvl_on_handler)(unsigned long,
aff_map_node *,
unsigned long,
unsigned long);
/*******************************************************************************
* This function checks whether a cpu which has been requested to be turned on
* is OFF to begin with.
******************************************************************************/
static int cpu_on_validate_state(unsigned int state)
{
unsigned int psci_state;
/* Get the raw psci state */
psci_state = psci_get_state(state);
if (psci_state == PSCI_STATE_ON || psci_state == PSCI_STATE_SUSPEND)
return PSCI_E_ALREADY_ON;
if (psci_state == PSCI_STATE_ON_PENDING)
return PSCI_E_ON_PENDING;
assert(psci_state == PSCI_STATE_OFF);
return PSCI_E_SUCCESS;
}
/*******************************************************************************
* Handler routine to turn a cpu on. It takes care of any generic, architectural
* or platform specific setup required.
* TODO: Split this code across separate handlers for each type of setup?
******************************************************************************/
static int psci_afflvl0_on(unsigned long target_cpu,
aff_map_node *cpu_node,
unsigned long ns_entrypoint,
unsigned long context_id)
{
unsigned int index, plat_state;
unsigned long psci_entrypoint;
int rc;
/* Sanity check to safeguard against data corruption */
assert(cpu_node->level == MPIDR_AFFLVL0);
/*
* Generic management: Ensure that the cpu is off to be
* turned on
*/
rc = cpu_on_validate_state(cpu_node->state);
if (rc != PSCI_E_SUCCESS)
return rc;
/*
* Arch. management: Derive the re-entry information for
* the non-secure world from the non-secure state from
* where this call originated.
*/
index = cpu_node->data;
rc = psci_set_ns_entry_info(index, ns_entrypoint, context_id);
if (rc != PSCI_E_SUCCESS)
return rc;
/* Set the secure world (EL3) re-entry point after BL1 */
psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
/*
* Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary
* steps to power on.
*/
if (psci_plat_pm_ops->affinst_on) {
/* Get the current physical state of this cpu */
plat_state = psci_get_aff_phys_state(cpu_node);
rc = psci_plat_pm_ops->affinst_on(target_cpu,
psci_entrypoint,
ns_entrypoint,
cpu_node->level,
plat_state);
}
return rc;
}
/*******************************************************************************
* Handler routine to turn a cluster on. It takes care or any generic, arch.
* or platform specific setup required.
* TODO: Split this code across separate handlers for each type of setup?
******************************************************************************/
static int psci_afflvl1_on(unsigned long target_cpu,
aff_map_node *cluster_node,
unsigned long ns_entrypoint,
unsigned long context_id)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
unsigned long psci_entrypoint;
assert(cluster_node->level == MPIDR_AFFLVL1);
/*
* There is no generic and arch. specific cluster
* management required
*/
/*
* Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary
* steps to power on.
*/
if (psci_plat_pm_ops->affinst_on) {
plat_state = psci_get_aff_phys_state(cluster_node);
psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
rc = psci_plat_pm_ops->affinst_on(target_cpu,
psci_entrypoint,
ns_entrypoint,
cluster_node->level,
plat_state);
}
return rc;
}
/*******************************************************************************
* Handler routine to turn a cluster of clusters on. It takes care or any
* generic, arch. or platform specific setup required.
* TODO: Split this code across separate handlers for each type of setup?
******************************************************************************/
static int psci_afflvl2_on(unsigned long target_cpu,
aff_map_node *system_node,
unsigned long ns_entrypoint,
unsigned long context_id)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
unsigned long psci_entrypoint;
/* Cannot go beyond affinity level 2 in this psci imp. */
assert(system_node->level == MPIDR_AFFLVL2);
/*
* There is no generic and arch. specific system management
* required
*/
/*
* Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary
* steps to power on.
*/
if (psci_plat_pm_ops->affinst_on) {
plat_state = psci_get_aff_phys_state(system_node);
psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
rc = psci_plat_pm_ops->affinst_on(target_cpu,
psci_entrypoint,
ns_entrypoint,
system_node->level,
plat_state);
}
return rc;
}
/* Private data structure to make this handlers accessible through indexing */
static const afflvl_on_handler psci_afflvl_on_handlers[] = {
psci_afflvl0_on,
psci_afflvl1_on,
psci_afflvl2_on,
};
/*******************************************************************************
* This function implements the core of the processing required to turn a cpu
* on. It avoids recursion to traverse from the lowest to the highest affinity
* level unlike the off/suspend/pon_finisher functions. It does ensure that the
* locks are picked in the same order as the order routines to avoid deadlocks.
* The flow is: Take all the locks until the highest affinity level, Call the
* handlers for turning an affinity level on & finally change the state of the
* affinity level.
******************************************************************************/
int psci_afflvl_on(unsigned long target_cpu,
unsigned long entrypoint,
unsigned long context_id,
int current_afflvl,
int target_afflvl)
{
unsigned int prev_state, next_state;
int rc = PSCI_E_SUCCESS, level;
aff_map_node *aff_node;
unsigned long mpidr = read_mpidr() & MPIDR_AFFINITY_MASK;
/*
* This loop acquires the lock corresponding to each
* affinity level so that by the time we hit the lowest
* affinity level, the system topology is snapshot and
* state management can be done safely.
*/
for (level = current_afflvl; level >= target_afflvl; level--) {
aff_node = psci_get_aff_map_node(target_cpu, level);
if (aff_node)
bakery_lock_get(mpidr, &aff_node->lock);
}
/*
* Perform generic, architecture and platform specific
* handling
*/
for (level = current_afflvl; level >= target_afflvl; level--) {
/* Grab the node for each affinity level once again */
aff_node = psci_get_aff_map_node(target_cpu, level);
if (aff_node) {
/* Keep the old state and the next one handy */
prev_state = psci_get_state(aff_node->state);
rc = psci_afflvl_on_handlers[level](target_cpu,
aff_node,
entrypoint,
context_id);
if (rc != PSCI_E_SUCCESS) {
psci_set_state(aff_node->state, prev_state);
goto exit;
}
}
}
/*
* State management: Update the states since this is the
* target affinity level requested.
*/
psci_change_state(target_cpu,
target_afflvl,
get_max_afflvl(),
PSCI_STATE_ON_PENDING);
exit:
/*
* This loop releases the lock corresponding to each affinity level
* in the reverse order. It also checks the final state of the cpu.
*/
for (level = target_afflvl; level <= current_afflvl; level++) {
aff_node = psci_get_aff_map_node(target_cpu, level);
if (aff_node) {
if (level == MPIDR_AFFLVL0) {
next_state = psci_get_state(aff_node->state);
assert(next_state == PSCI_STATE_ON_PENDING);
}
bakery_lock_release(mpidr, &aff_node->lock);
}
}
return rc;
}
/*******************************************************************************
* The following functions finish an earlier affinity power on request. They
* are called by the common finisher routine in psci_common.c.
******************************************************************************/
static unsigned int psci_afflvl0_on_finish(unsigned long mpidr,
aff_map_node *cpu_node,
unsigned int prev_state)
{
unsigned int index, plat_state, rc = PSCI_E_SUCCESS;
assert(cpu_node->level == MPIDR_AFFLVL0);
/*
* Plat. management: Perform the platform specific actions
* for this cpu e.g. enabling the gic or zeroing the mailbox
* register. The actual state of this cpu has already been
* changed.
*/
if (psci_plat_pm_ops->affinst_on_finish) {
/* Get the previous physical state of this cpu */
plat_state = psci_get_phys_state(prev_state);
rc = psci_plat_pm_ops->affinst_on_finish(mpidr,
cpu_node->level,
plat_state);
assert(rc == PSCI_E_SUCCESS);
}
/*
* Arch. management: Turn on mmu & restore architectural state
*/
write_vbar((unsigned long) runtime_exceptions);
enable_mmu();
/*
* All the platform specific actions for turning this cpu
* on have completed. Perform enough arch.initialization
* to run in the non-secure address space.
*/
bl31_arch_setup();
/*
* Generic management: Now we just need to retrieve the
* information that we had stashed away during the cpu_on
* call to set this cpu on it's way. First get the index
* for restoring the re-entry info
*/
index = cpu_node->data;
rc = psci_get_ns_entry_info(index);
/* Clean caches before re-entering normal world */
dcsw_op_louis(DCCSW);
return rc;
}
static unsigned int psci_afflvl1_on_finish(unsigned long mpidr,
aff_map_node *cluster_node,
unsigned int prev_state)
{
unsigned int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
assert(cluster_node->level == MPIDR_AFFLVL1);
/*
* Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling
* coherency at the interconnect depends upon the state with
* which this cluster was powered up. If anything goes wrong
* then assert as there is no way to recover from this
* situation.
*/
if (psci_plat_pm_ops->affinst_on_finish) {
plat_state = psci_get_phys_state(prev_state);
rc = psci_plat_pm_ops->affinst_on_finish(mpidr,
cluster_node->level,
plat_state);
assert(rc == PSCI_E_SUCCESS);
}
return rc;
}
static unsigned int psci_afflvl2_on_finish(unsigned long mpidr,
aff_map_node *system_node,
unsigned int prev_state)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
/* Cannot go beyond this affinity level */
assert(system_node->level == MPIDR_AFFLVL2);
/*
* Currently, there are no architectural actions to perform
* at the system level.
*/
/*
* Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling
* coherency at the interconnect depends upon the state with
* which this cluster was powered up. If anything goes wrong
* then assert as there is no way to recover from this
* situation.
*/
if (psci_plat_pm_ops->affinst_on_finish) {
plat_state = psci_get_phys_state(system_node->state);
rc = psci_plat_pm_ops->affinst_on_finish(mpidr,
system_node->level,
plat_state);
assert(rc == PSCI_E_SUCCESS);
}
return rc;
}
const afflvl_power_on_finisher psci_afflvl_on_finishers[] = {
psci_afflvl0_on_finish,
psci_afflvl1_on_finish,
psci_afflvl2_on_finish,
};

View File

@ -0,0 +1,465 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <psci.h>
#include <psci_private.h>
typedef int (*afflvl_suspend_handler)(unsigned long,
aff_map_node *,
unsigned long,
unsigned long,
unsigned int);
/*******************************************************************************
* The next three functions implement a handler for each supported affinity
* level which is called when that affinity level is about to be suspended.
******************************************************************************/
static int psci_afflvl0_suspend(unsigned long mpidr,
aff_map_node *cpu_node,
unsigned long ns_entrypoint,
unsigned long context_id,
unsigned int power_state)
{
unsigned int index, plat_state;
unsigned long psci_entrypoint, sctlr = read_sctlr();
int rc = PSCI_E_SUCCESS;
/* Sanity check to safeguard against data corruption */
assert(cpu_node->level == MPIDR_AFFLVL0);
/*
* Generic management: Store the re-entry information for the
* non-secure world
*/
index = cpu_node->data;
rc = psci_set_ns_entry_info(index, ns_entrypoint, context_id);
if (rc != PSCI_E_SUCCESS)
return rc;
/*
* Arch. management: Save the secure context, flush the
* L1 caches and exit intra-cluster coherency et al
*/
psci_secure_context[index].sctlr = read_sctlr();
psci_secure_context[index].scr = read_scr();
psci_secure_context[index].cptr = read_cptr();
psci_secure_context[index].cpacr = read_cpacr();
psci_secure_context[index].cntfrq = read_cntfrq_el0();
psci_secure_context[index].mair = read_mair();
psci_secure_context[index].tcr = read_tcr();
psci_secure_context[index].ttbr = read_ttbr0();
psci_secure_context[index].vbar = read_vbar();
/* Set the secure world (EL3) re-entry point after BL1 */
psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
/*
* Arch. management. Perform the necessary steps to flush all
* cpu caches.
*
* TODO: This power down sequence varies across cpus so it needs to be
* abstracted out on the basis of the MIDR like in cpu_reset_handler().
* Do the bare minimal for the time being. Fix this before porting to
* Cortex models.
*/
sctlr &= ~SCTLR_C_BIT;
write_sctlr(sctlr);
/*
* CAUTION: This flush to the level of unification makes an assumption
* about the cache hierarchy at affinity level 0 (cpu) in the platform.
* Ideally the platform should tell psci which levels to flush to exit
* coherency.
*/
dcsw_op_louis(DCCISW);
/*
* Plat. management: Allow the platform to perform the
* necessary actions to turn off this cpu e.g. set the
* platform defined mailbox with the psci entrypoint,
* program the power controller etc.
*/
if (psci_plat_pm_ops->affinst_suspend) {
plat_state = psci_get_aff_phys_state(cpu_node);
rc = psci_plat_pm_ops->affinst_suspend(mpidr,
psci_entrypoint,
ns_entrypoint,
cpu_node->level,
plat_state);
}
return rc;
}
static int psci_afflvl1_suspend(unsigned long mpidr,
aff_map_node *cluster_node,
unsigned long ns_entrypoint,
unsigned long context_id,
unsigned int power_state)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
unsigned long psci_entrypoint;
/* Sanity check the cluster level */
assert(cluster_node->level == MPIDR_AFFLVL1);
/*
* Keep the physical state of this cluster handy to decide
* what action needs to be taken
*/
plat_state = psci_get_aff_phys_state(cluster_node);
/*
* Arch. management: Flush all levels of caches to PoC if the
* cluster is to be shutdown
*/
if (plat_state == PSCI_STATE_OFF)
dcsw_op_all(DCCISW);
/*
* Plat. Management. Allow the platform to do it's cluster
* specific bookeeping e.g. turn off interconnect coherency,
* program the power controller etc.
*/
if (psci_plat_pm_ops->affinst_suspend) {
/*
* Sending the psci entrypoint is currently redundant
* beyond affinity level 0 but one never knows what a
* platform might do. Also it allows us to keep the
* platform handler prototype the same.
*/
psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
rc = psci_plat_pm_ops->affinst_suspend(mpidr,
psci_entrypoint,
ns_entrypoint,
cluster_node->level,
plat_state);
}
return rc;
}
static int psci_afflvl2_suspend(unsigned long mpidr,
aff_map_node *system_node,
unsigned long ns_entrypoint,
unsigned long context_id,
unsigned int power_state)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
unsigned long psci_entrypoint;
/* Cannot go beyond this */
assert(system_node->level == MPIDR_AFFLVL2);
/*
* Keep the physical state of the system handy to decide what
* action needs to be taken
*/
plat_state = psci_get_aff_phys_state(system_node);
/*
* Plat. Management : Allow the platform to do it's bookeeping
* at this affinity level
*/
if (psci_plat_pm_ops->affinst_suspend) {
/*
* Sending the psci entrypoint is currently redundant
* beyond affinity level 0 but one never knows what a
* platform might do. Also it allows us to keep the
* platform handler prototype the same.
*/
psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
rc = psci_plat_pm_ops->affinst_suspend(mpidr,
psci_entrypoint,
ns_entrypoint,
system_node->level,
plat_state);
}
return rc;
}
static const afflvl_suspend_handler psci_afflvl_suspend_handlers[] = {
psci_afflvl0_suspend,
psci_afflvl1_suspend,
psci_afflvl2_suspend,
};
/*******************************************************************************
* This function implements the core of the processing required to suspend a cpu
* It'S assumed that along with suspending the cpu, higher affinity levels will
* be suspended as far as possible. Suspending a cpu is equivalent to physically
* powering it down, but the cpu is still available to the OS for scheduling.
* We first need to determine the new state off all the affinity instances in
* the mpidr corresponding to the target cpu. Action will be taken on the basis
* of this new state. To do the state change we first need to acquire the locks
* for all the implemented affinity level to be able to snapshot the system
* state. Then we need to start suspending affinity levels from the lowest to
* the highest (e.g. a cpu needs to be suspended before a cluster can be). To
* achieve this flow, we start acquiring the locks from the highest to the
* lowest affinity level. Once we reach affinity level 0, we do the state change
* followed by the actions corresponding to the new state for affinity level 0.
* Actions as per the updated state for higher affinity levels are performed as
* we unwind back to highest affinity level.
******************************************************************************/
int psci_afflvl_suspend(unsigned long mpidr,
unsigned long entrypoint,
unsigned long context_id,
unsigned int power_state,
int cur_afflvl,
int tgt_afflvl)
{
int rc = PSCI_E_SUCCESS, level;
unsigned int prev_state, next_state;
aff_map_node *aff_node;
mpidr &= MPIDR_AFFINITY_MASK;
/*
* Some affinity instances at levels between the current and
* target levels could be absent in the mpidr. Skip them and
* start from the first present instance.
*/
level = psci_get_first_present_afflvl(mpidr,
cur_afflvl,
tgt_afflvl,
&aff_node);
/*
* Return if there are no more affinity instances beyond this
* level to process. Else ensure that the returned affinity
* node makes sense.
*/
if (aff_node == NULL)
return rc;
assert(level == aff_node->level);
/*
* This function acquires the lock corresponding to each
* affinity level so that state management can be done safely.
*/
bakery_lock_get(mpidr, &aff_node->lock);
/* Keep the old state and the next one handy */
prev_state = psci_get_state(aff_node->state);
next_state = PSCI_STATE_SUSPEND;
/*
* We start from the highest affinity level and work our way
* downwards to the lowest i.e. MPIDR_AFFLVL0.
*/
if (aff_node->level == tgt_afflvl) {
psci_change_state(mpidr,
tgt_afflvl,
get_max_afflvl(),
next_state);
} else {
rc = psci_afflvl_suspend(mpidr,
entrypoint,
context_id,
power_state,
level - 1,
tgt_afflvl);
if (rc != PSCI_E_SUCCESS) {
psci_set_state(aff_node->state, prev_state);
goto exit;
}
}
/*
* Perform generic, architecture and platform specific
* handling
*/
rc = psci_afflvl_suspend_handlers[level](mpidr,
aff_node,
entrypoint,
context_id,
power_state);
if (rc != PSCI_E_SUCCESS) {
psci_set_state(aff_node->state, prev_state);
goto exit;
}
/*
* If all has gone as per plan then this cpu should be
* marked as OFF
*/
if (level == MPIDR_AFFLVL0) {
next_state = psci_get_state(aff_node->state);
assert(next_state == PSCI_STATE_SUSPEND);
}
exit:
bakery_lock_release(mpidr, &aff_node->lock);
return rc;
}
/*******************************************************************************
* The following functions finish an earlier affinity suspend request. They
* are called by the common finisher routine in psci_common.c.
******************************************************************************/
static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr,
aff_map_node *cpu_node,
unsigned int prev_state)
{
unsigned int index, plat_state, rc = 0;
assert(cpu_node->level == MPIDR_AFFLVL0);
/*
* Plat. management: Perform the platform specific actions
* before we change the state of the cpu e.g. enabling the
* gic or zeroing the mailbox register. If anything goes
* wrong then assert as there is no way to recover from this
* situation.
*/
if (psci_plat_pm_ops->affinst_suspend_finish) {
plat_state = psci_get_phys_state(prev_state);
rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
cpu_node->level,
plat_state);
assert(rc == PSCI_E_SUCCESS);
}
/* Get the index for restoring the re-entry information */
index = cpu_node->data;
/*
* Arch. management: Restore the stashed secure architectural
* context in the right order.
*/
write_vbar(psci_secure_context[index].vbar);
write_mair(psci_secure_context[index].mair);
write_tcr(psci_secure_context[index].tcr);
write_ttbr0(psci_secure_context[index].ttbr);
write_sctlr(psci_secure_context[index].sctlr);
/* MMU and coherency should be enabled by now */
write_scr(psci_secure_context[index].scr);
write_cptr(psci_secure_context[index].cptr);
write_cpacr(psci_secure_context[index].cpacr);
write_cntfrq_el0(psci_secure_context[index].cntfrq);
/*
* Generic management: Now we just need to retrieve the
* information that we had stashed away during the suspend
* call to set this cpu on it's way.
*/
rc = psci_get_ns_entry_info(index);
/* Clean caches before re-entering normal world */
dcsw_op_louis(DCCSW);
return rc;
}
static unsigned int psci_afflvl1_suspend_finish(unsigned long mpidr,
aff_map_node *cluster_node,
unsigned int prev_state)
{
unsigned int rc = 0;
unsigned int plat_state;
assert(cluster_node->level == MPIDR_AFFLVL1);
/*
* Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling
* coherency at the interconnect depends upon the state with
* which this cluster was powered up. If anything goes wrong
* then assert as there is no way to recover from this
* situation.
*/
if (psci_plat_pm_ops->affinst_suspend_finish) {
plat_state = psci_get_phys_state(prev_state);
rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
cluster_node->level,
plat_state);
assert(rc == PSCI_E_SUCCESS);
}
return rc;
}
static unsigned int psci_afflvl2_suspend_finish(unsigned long mpidr,
aff_map_node *system_node,
unsigned int target_afflvl)
{
int rc = PSCI_E_SUCCESS;
unsigned int plat_state;
/* Cannot go beyond this affinity level */
assert(system_node->level == MPIDR_AFFLVL2);
/*
* Currently, there are no architectural actions to perform
* at the system level.
*/
/*
* Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling
* coherency at the interconnect depends upon the state with
* which this cluster was powered up. If anything goes wrong
* then assert as there is no way to recover from this
* situation.
*/
if (psci_plat_pm_ops->affinst_suspend_finish) {
plat_state = psci_get_phys_state(system_node->state);
rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
system_node->level,
plat_state);
assert(rc == PSCI_E_SUCCESS);
}
return rc;
}
const afflvl_power_on_finisher psci_afflvl_suspend_finishers[] = {
psci_afflvl0_suspend_finish,
psci_afflvl1_suspend_finish,
psci_afflvl2_suspend_finish,
};

520
common/psci/psci_common.c Normal file
View File

@ -0,0 +1,520 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <psci.h>
#include <psci_private.h>
/*******************************************************************************
* Arrays that contains information needs to resume a cpu's execution when woken
* out of suspend or off states. 'psci_ns_einfo_idx' keeps track of the next
* free index in the 'psci_ns_entry_info' & 'psci_secure_context' arrays. Each
* cpu is allocated a single entry in each array during startup.
******************************************************************************/
secure_context psci_secure_context[PSCI_NUM_AFFS];
ns_entry_info psci_ns_entry_info[PSCI_NUM_AFFS];
unsigned int psci_ns_einfo_idx;
/*******************************************************************************
* Grand array that holds the platform's topology information for state
* management of affinity instances. Each node (aff_map_node) in the array
* corresponds to an affinity instance e.g. cluster, cpu within an mpidr
******************************************************************************/
aff_map_node psci_aff_map[PSCI_NUM_AFFS]
__attribute__ ((section("tzfw_coherent_mem")));
/*******************************************************************************
* In a system, a certain number of affinity instances are present at an
* affinity level. The cumulative number of instances across all levels are
* stored in 'psci_aff_map'. The topology tree has been flattenned into this
* array. To retrieve nodes, information about the extents of each affinity
* level i.e. start index and end index needs to be present. 'psci_aff_limits'
* stores this information.
******************************************************************************/
aff_limits_node psci_aff_limits[MPIDR_MAX_AFFLVL + 1];
/*******************************************************************************
* Pointer to functions exported by the platform to complete power mgmt. ops
******************************************************************************/
plat_pm_ops *psci_plat_pm_ops;
/*******************************************************************************
* Simple routine to retrieve the maximum affinity level supported by the
* platform and check that it makes sense.
******************************************************************************/
int get_max_afflvl()
{
int aff_lvl;
aff_lvl = plat_get_max_afflvl();
assert(aff_lvl <= MPIDR_MAX_AFFLVL && aff_lvl >= MPIDR_AFFLVL0);
return aff_lvl;
}
/*******************************************************************************
* Simple routine to set the id of an affinity instance at a given level in the
* mpidr.
******************************************************************************/
unsigned long mpidr_set_aff_inst(unsigned long mpidr,
unsigned char aff_inst,
int aff_lvl)
{
unsigned long aff_shift;
assert(aff_lvl <= MPIDR_AFFLVL3);
/*
* Decide the number of bits to shift by depending upon
* the affinity level
*/
aff_shift = get_afflvl_shift(aff_lvl);
/* Clear the existing affinity instance & set the new one*/
mpidr &= ~(MPIDR_AFFLVL_MASK << aff_shift);
mpidr |= aff_inst << aff_shift;
return mpidr;
}
/*******************************************************************************
* Simple routine to determine whether an affinity instance at a given level
* in an mpidr exists or not.
******************************************************************************/
int psci_validate_mpidr(unsigned long mpidr, int level)
{
aff_map_node *node;
node = psci_get_aff_map_node(mpidr, level);
if (node && (node->state & PSCI_AFF_PRESENT))
return PSCI_E_SUCCESS;
else
return PSCI_E_INVALID_PARAMS;
}
/*******************************************************************************
* Simple routine to determine the first affinity level instance that is present
* between the start and end affinity levels. This helps to skip handling of
* absent affinity levels while performing psci operations.
* The start level can be > or <= to the end level depending upon whether this
* routine is expected to search top down or bottom up.
******************************************************************************/
int psci_get_first_present_afflvl(unsigned long mpidr,
int start_afflvl,
int end_afflvl,
aff_map_node **node)
{
int level;
/* Check whether we have to search up or down */
if (start_afflvl <= end_afflvl) {
for (level = start_afflvl; level <= end_afflvl; level++) {
*node = psci_get_aff_map_node(mpidr, level);
if (*node && ((*node)->state & PSCI_AFF_PRESENT))
break;
}
} else {
for (level = start_afflvl; level >= end_afflvl; level--) {
*node = psci_get_aff_map_node(mpidr, level);
if (*node && ((*node)->state & PSCI_AFF_PRESENT))
break;
}
}
return level;
}
/*******************************************************************************
* Recursively change the affinity state between the current and target affinity
* levels. The target state matters only if we are starting from affinity level
* 0 i.e. a cpu otherwise the state depends upon the state of the lower affinity
* levels.
******************************************************************************/
int psci_change_state(unsigned long mpidr,
int cur_afflvl,
int tgt_afflvl,
unsigned int tgt_state)
{
int rc = PSCI_E_SUCCESS;
unsigned int state;
aff_map_node *aff_node;
/* Sanity check the affinity levels */
assert(tgt_afflvl >= cur_afflvl);
aff_node = psci_get_aff_map_node(mpidr, cur_afflvl);
assert(aff_node);
/* TODO: Check whether the affinity level is present or absent*/
if (cur_afflvl == MPIDR_AFFLVL0) {
psci_set_state(aff_node->state, tgt_state);
} else {
state = psci_calculate_affinity_state(aff_node);
psci_set_state(aff_node->state, state);
}
if (cur_afflvl != tgt_afflvl)
psci_change_state(mpidr, cur_afflvl + 1, tgt_afflvl, tgt_state);
return rc;
}
/*******************************************************************************
* This routine does the heavy lifting for psci_change_state(). It examines the
* state of each affinity instance at the next lower affinity level and decides
* it's final state accordingly. If a lower affinity instance is ON then the
* higher affinity instance is ON. If all the lower affinity instances are OFF
* then the higher affinity instance is OFF. If atleast one lower affinity
* instance is SUSPENDED then the higher affinity instance is SUSPENDED. If only
* a single lower affinity instance is ON_PENDING then the higher affinity
* instance in ON_PENDING as well.
******************************************************************************/
unsigned int psci_calculate_affinity_state(aff_map_node *aff_node)
{
int ctr;
unsigned int aff_count, hi_aff_state;
unsigned long tempidr;
aff_map_node *lo_aff_node;
/* Cannot calculate lowest affinity state. It's simply assigned */
assert(aff_node->level > MPIDR_AFFLVL0);
/*
* Find the number of affinity instances at level X-1 e.g. number of
* cpus in a cluster. The level X state depends upon the state of each
* instance at level X-1
*/
hi_aff_state = PSCI_STATE_OFF;
aff_count = plat_get_aff_count(aff_node->level - 1, aff_node->mpidr);
for (ctr = 0; ctr < aff_count; ctr++) {
/*
* Create a mpidr for each lower affinity level (X-1). Use their
* states to influence the higher affinity state (X).
*/
tempidr = mpidr_set_aff_inst(aff_node->mpidr,
ctr,
aff_node->level - 1);
lo_aff_node = psci_get_aff_map_node(tempidr,
aff_node->level - 1);
assert(lo_aff_node);
/* Continue only if the cpu exists within the cluster */
if (!(lo_aff_node->state & PSCI_AFF_PRESENT))
continue;
switch (psci_get_state(lo_aff_node->state)) {
/*
* If any lower affinity is on within the cluster, then
* the higher affinity is on.
*/
case PSCI_STATE_ON:
return PSCI_STATE_ON;
/*
* At least one X-1 needs to be suspended for X to be suspended
* but it's effectively on for the affinity_info call.
* SUSPEND > ON_PENDING > OFF.
*/
case PSCI_STATE_SUSPEND:
hi_aff_state = PSCI_STATE_SUSPEND;
continue;
/*
* Atleast one X-1 needs to be on_pending & the rest off for X
* to be on_pending. ON_PENDING > OFF.
*/
case PSCI_STATE_ON_PENDING:
if (hi_aff_state != PSCI_STATE_SUSPEND)
hi_aff_state = PSCI_STATE_ON_PENDING;
continue;
/* Higher affinity is off if all lower affinities are off. */
case PSCI_STATE_OFF:
continue;
default:
assert(0);
}
}
return hi_aff_state;
}
/*******************************************************************************
* This function retrieves all the stashed information needed to correctly
* resume a cpu's execution in the non-secure state after it has been physically
* powered on i.e. turned ON or resumed from SUSPEND
******************************************************************************/
unsigned int psci_get_ns_entry_info(unsigned int index)
{
unsigned long sctlr = 0, scr, el_status, id_aa64pfr0;
scr = read_scr();
/* Switch to the non-secure view of the registers */
write_scr(scr | SCR_NS_BIT);
/* Find out which EL we are going to */
id_aa64pfr0 = read_id_aa64pfr0_el1();
el_status = (id_aa64pfr0 >> ID_AA64PFR0_EL2_SHIFT) &
ID_AA64PFR0_ELX_MASK;
/* Restore endianess */
if (psci_ns_entry_info[index].sctlr & SCTLR_EE_BIT)
sctlr |= SCTLR_EE_BIT;
else
sctlr &= ~SCTLR_EE_BIT;
/* Turn off MMU and Caching */
sctlr &= ~(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_M_BIT);
/* Set the register width */
if (psci_ns_entry_info[index].scr & SCR_RW_BIT)
scr |= SCR_RW_BIT;
else
scr &= ~SCR_RW_BIT;
scr |= SCR_NS_BIT;
if (el_status)
write_sctlr_el2(sctlr);
else
write_sctlr_el1(sctlr);
/* Fulfill the cpu_on entry reqs. as per the psci spec */
write_scr(scr);
write_spsr(psci_ns_entry_info[index].eret_info.spsr);
write_elr(psci_ns_entry_info[index].eret_info.entrypoint);
return psci_ns_entry_info[index].context_id;
}
/*******************************************************************************
* This function retrieves and stashes all the information needed to correctly
* resume a cpu's execution in the non-secure state after it has been physically
* powered on i.e. turned ON or resumed from SUSPEND. This is done prior to
* turning it on or before suspending it.
******************************************************************************/
int psci_set_ns_entry_info(unsigned int index,
unsigned long entrypoint,
unsigned long context_id)
{
int rc = PSCI_E_SUCCESS;
unsigned int rw, mode, ee, spsr = 0;
unsigned long id_aa64pfr0 = read_id_aa64pfr0_el1(), scr = read_scr();
unsigned long el_status;
/* Figure out what mode do we enter the non-secure world in */
el_status = (id_aa64pfr0 >> ID_AA64PFR0_EL2_SHIFT) &
ID_AA64PFR0_ELX_MASK;
/*
* Figure out whether the cpu enters the non-secure address space
* in aarch32 or aarch64
*/
rw = scr & SCR_RW_BIT;
if (rw) {
/*
* Check whether a Thumb entry point has been provided for an
* aarch64 EL
*/
if (entrypoint & 0x1)
return PSCI_E_INVALID_PARAMS;
if (el_status && (scr & SCR_HCE_BIT)) {
mode = MODE_EL2;
ee = read_sctlr_el2() & SCTLR_EE_BIT;
} else {
mode = MODE_EL1;
ee = read_sctlr_el1() & SCTLR_EE_BIT;
}
spsr = DAIF_DBG_BIT | DAIF_ABT_BIT;
spsr |= DAIF_IRQ_BIT | DAIF_FIQ_BIT;
spsr <<= PSR_DAIF_SHIFT;
spsr |= make_spsr(mode, MODE_SP_ELX, !rw);
psci_ns_entry_info[index].sctlr |= ee;
psci_ns_entry_info[index].scr |= SCR_RW_BIT;
} else {
/* Check whether aarch32 has to be entered in Thumb mode */
if (entrypoint & 0x1)
spsr = SPSR32_T_BIT;
if (el_status && (scr & SCR_HCE_BIT)) {
mode = AARCH32_MODE_HYP;
ee = read_sctlr_el2() & SCTLR_EE_BIT;
} else {
mode = AARCH32_MODE_SVC;
ee = read_sctlr_el1() & SCTLR_EE_BIT;
}
/*
* TODO: Choose async. exception bits if HYP mode is not
* implemented according to the values of SCR.{AW, FW} bits
*/
spsr |= DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
spsr <<= PSR_DAIF_SHIFT;
if(ee)
spsr |= SPSR32_EE_BIT;
spsr |= mode;
/* Ensure that the CSPR.E and SCTLR.EE bits match */
psci_ns_entry_info[index].sctlr |= ee;
psci_ns_entry_info[index].scr &= ~SCR_RW_BIT;
}
psci_ns_entry_info[index].eret_info.entrypoint = entrypoint;
psci_ns_entry_info[index].eret_info.spsr = spsr;
psci_ns_entry_info[index].context_id = context_id;
return rc;
}
/*******************************************************************************
* An affinity level could be on, on_pending, suspended or off. These are the
* logical states it can be in. Physically either it's off or on. When it's in
* the state on_pending then it's about to be turned on. It's not possible to
* tell whether that's actually happenned or not. So we err on the side of
* caution & treat the affinity level as being turned off.
******************************************************************************/
inline unsigned int psci_get_phys_state(unsigned int aff_state)
{
return (aff_state != PSCI_STATE_ON ? PSCI_STATE_OFF : PSCI_STATE_ON);
}
unsigned int psci_get_aff_phys_state(aff_map_node *aff_node)
{
unsigned int aff_state;
aff_state = psci_get_state(aff_node->state);
return psci_get_phys_state(aff_state);
}
/*******************************************************************************
* Generic handler which is called when a cpu is physically powered on. It
* recurses through all the affinity levels performing generic, architectural,
* platform setup and state management e.g. for a cluster that's been powered
* on, it will call the platform specific code which will enable coherency at
* the interconnect level. For a cpu it could mean turning on the MMU etc.
*
* This function traverses from the lowest to the highest affinity level
* implemented by the platform. Since it's recursive, for each call the
* 'cur_afflvl' & 'tgt_afflvl' parameters keep track of which level we are at
* and which level we need to get to respectively. Locks are picked up along the
* way so that when the lowest affinity level is hit, state management can be
* safely done. Prior to this, each affinity level does it's bookeeping as per
* the state out of reset.
*
* CAUTION: This function is called with coherent stacks so that coherency and
* the mmu can be turned on safely.
******************************************************************************/
unsigned int psci_afflvl_power_on_finish(unsigned long mpidr,
int cur_afflvl,
int tgt_afflvl,
afflvl_power_on_finisher *pon_handlers)
{
unsigned int prev_state, next_state, rc = PSCI_E_SUCCESS;
aff_map_node *aff_node;
int level;
mpidr &= MPIDR_AFFINITY_MASK;;
/*
* Some affinity instances at levels between the current and
* target levels could be absent in the mpidr. Skip them and
* start from the first present instance.
*/
level = psci_get_first_present_afflvl(mpidr,
cur_afflvl,
tgt_afflvl,
&aff_node);
/*
* Return if there are no more affinity instances beyond this
* level to process. Else ensure that the returned affinity
* node makes sense.
*/
if (aff_node == NULL)
return rc;
assert(level == aff_node->level);
/*
* This function acquires the lock corresponding to each
* affinity level so that by the time we hit the highest
* affinity level, the system topology is snapshot and state
* management can be done safely.
*/
bakery_lock_get(mpidr, &aff_node->lock);
/* Keep the old and new state handy */
prev_state = psci_get_state(aff_node->state);
next_state = PSCI_STATE_ON;
/* Perform generic, architecture and platform specific handling */
rc = pon_handlers[level](mpidr, aff_node, prev_state);
if (rc != PSCI_E_SUCCESS) {
psci_set_state(aff_node->state, prev_state);
goto exit;
}
/*
* State management: Update the states if this is the highest
* affinity level requested else pass the job to the next level.
*/
if (aff_node->level != tgt_afflvl) {
rc = psci_afflvl_power_on_finish(mpidr,
level + 1,
tgt_afflvl,
pon_handlers);
} else {
psci_change_state(mpidr, MPIDR_AFFLVL0, tgt_afflvl, next_state);
}
/* If all has gone as per plan then this cpu should be marked as ON */
if (level == MPIDR_AFFLVL0) {
next_state = psci_get_state(aff_node->state);
assert(next_state == PSCI_STATE_ON);
}
exit:
bakery_lock_release(mpidr, &aff_node->lock);
return rc;
}

159
common/psci/psci_entry.S Normal file
View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <platform.h>
#include <psci.h>
#include <psci_private.h>
#include <asm_macros.S>
.globl psci_aff_on_finish_entry
.globl psci_aff_suspend_finish_entry
.globl __psci_cpu_off
.globl __psci_cpu_suspend
.section platform_code, "ax"; .align 3
/* -----------------------------------------------------
* This cpu has been physically powered up. Depending
* upon whether it was resumed from suspend or simply
* turned on, call the common power on finisher with
* the handlers (chosen depending upon original state).
* For ease, the finisher is called with coherent
* stacks. This allows the cluster/cpu finishers to
* enter coherency and enable the mmu without running
* into issues. We switch back to normal stacks once
* all this is done.
* -----------------------------------------------------
*/
psci_aff_on_finish_entry:
adr x23, psci_afflvl_on_finishers
b psci_aff_common_finish_entry
psci_aff_suspend_finish_entry:
adr x23, psci_afflvl_suspend_finishers
psci_aff_common_finish_entry:
adr x22, psci_afflvl_power_on_finish
bl read_mpidr
mov x19, x0
bl platform_set_coherent_stack
/* ---------------------------------------------
* Call the finishers starting from affinity
* level 0.
* ---------------------------------------------
*/
bl get_max_afflvl
mov x3, x23
mov x2, x0
mov x0, x19
mov x1, #MPIDR_AFFLVL0
blr x22
mov x21, x0
/* --------------------------------------------
* Give ourselves a stack allocated in Normal
* -IS-WBWA memory
* --------------------------------------------
*/
mov x0, x19
bl platform_set_stack
/* --------------------------------------------
* Restore the context id. value
* --------------------------------------------
*/
mov x0, x21
/* --------------------------------------------
* Jump back to the non-secure world assuming
* that the elr and spsr setup has been done
* by the finishers
* --------------------------------------------
*/
eret
_panic:
b _panic
/* -----------------------------------------------------
* The following two stubs give the calling cpu a
* coherent stack to allow flushing of caches without
* suffering from stack coherency issues
* -----------------------------------------------------
*/
__psci_cpu_off:
func_prologue
sub sp, sp, #0x10
stp x19, x20, [sp, #0]
mov x19, sp
bl read_mpidr
bl platform_set_coherent_stack
bl psci_cpu_off
mov x1, #PSCI_E_SUCCESS
cmp x0, x1
b.eq final_wfi
mov sp, x19
ldp x19, x20, [sp,#0]
add sp, sp, #0x10
func_epilogue
ret
__psci_cpu_suspend:
func_prologue
sub sp, sp, #0x20
stp x19, x20, [sp, #0]
stp x21, x22, [sp, #0x10]
mov x19, sp
mov x20, x0
mov x21, x1
mov x22, x2
bl read_mpidr
bl platform_set_coherent_stack
mov x0, x20
mov x1, x21
mov x2, x22
bl psci_cpu_suspend
mov x1, #PSCI_E_SUCCESS
cmp x0, x1
b.eq final_wfi
mov sp, x19
ldp x21, x22, [sp,#0x10]
ldp x19, x20, [sp,#0]
add sp, sp, #0x20
func_epilogue
ret
final_wfi:
dsb sy
wfi
wfi_spill:
b wfi_spill

190
common/psci/psci_main.c Normal file
View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <psci_private.h>
/*******************************************************************************
* PSCI frontend api for servicing SMCs. Described in the PSCI spec.
******************************************************************************/
int psci_cpu_on(unsigned long target_cpu,
unsigned long entrypoint,
unsigned long context_id)
{
int rc;
unsigned int start_afflvl, target_afflvl;
/* Determine if the cpu exists of not */
rc = psci_validate_mpidr(target_cpu, MPIDR_AFFLVL0);
if (rc != PSCI_E_SUCCESS) {
goto exit;
}
start_afflvl = get_max_afflvl();
target_afflvl = MPIDR_AFFLVL0;
rc = psci_afflvl_on(target_cpu,
entrypoint,
context_id,
start_afflvl,
target_afflvl);
exit:
return rc;
}
unsigned int psci_version(void)
{
return PSCI_MAJOR_VER | PSCI_MINOR_VER;
}
int psci_cpu_suspend(unsigned int power_state,
unsigned long entrypoint,
unsigned long context_id)
{
int rc;
unsigned long mpidr;
unsigned int tgt_afflvl, pstate_type;
/* TODO: Standby states are not supported at the moment */
pstate_type = psci_get_pstate_type(power_state);
if (pstate_type == 0) {
rc = PSCI_E_INVALID_PARAMS;
goto exit;
}
/* Sanity check the requested state */
tgt_afflvl = psci_get_pstate_afflvl(power_state);
if (tgt_afflvl > MPIDR_MAX_AFFLVL) {
rc = PSCI_E_INVALID_PARAMS;
goto exit;
}
mpidr = read_mpidr();
rc = psci_afflvl_suspend(mpidr,
entrypoint,
context_id,
power_state,
tgt_afflvl,
MPIDR_AFFLVL0);
exit:
if (rc != PSCI_E_SUCCESS)
assert(rc == PSCI_E_INVALID_PARAMS);
return rc;
}
int psci_cpu_off(void)
{
int rc;
unsigned long mpidr;
int target_afflvl = get_max_afflvl();
mpidr = read_mpidr();
/*
* Traverse from the highest to the lowest affinity level. When the
* lowest affinity level is hit, all the locks are acquired. State
* management is done immediately followed by cpu, cluster ...
* ..target_afflvl specific actions as this function unwinds back.
*/
rc = psci_afflvl_off(mpidr, target_afflvl, MPIDR_AFFLVL0);
if (rc != PSCI_E_SUCCESS) {
assert(rc == PSCI_E_DENIED);
}
return rc;
}
int psci_affinity_info(unsigned long target_affinity,
unsigned int lowest_affinity_level)
{
int rc = PSCI_E_INVALID_PARAMS;
unsigned int aff_state;
aff_map_node *node;
if (lowest_affinity_level > get_max_afflvl()) {
goto exit;
}
node = psci_get_aff_map_node(target_affinity, lowest_affinity_level);
if (node && (node->state & PSCI_AFF_PRESENT)) {
aff_state = psci_get_state(node->state);
/* A suspended cpu is available & on for the OS */
if (aff_state == PSCI_STATE_SUSPEND) {
aff_state = PSCI_STATE_ON;
}
rc = aff_state;
}
exit:
return rc;
}
/* Unimplemented */
int psci_migrate(unsigned int target_cpu)
{
return PSCI_E_NOT_SUPPORTED;
}
/* Unimplemented */
unsigned int psci_migrate_info_type(void)
{
return PSCI_TOS_NOT_PRESENT;
}
unsigned long psci_migrate_info_up_cpu(void)
{
/*
* Return value of this currently unsupported call depends upon
* what psci_migrate_info_type() returns.
*/
return PSCI_E_SUCCESS;
}
/* Unimplemented */
void psci_system_off(void)
{
assert(0);
}
/* Unimplemented */
void psci_system_reset(void)
{
assert(0);
}

147
common/psci/psci_private.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PSCI_PRIVATE_H__
#define __PSCI_PRIVATE_H__
#include <bakery_lock.h>
#ifndef __ASSEMBLY__
/*******************************************************************************
* The following two data structures hold the generic information to bringup
* a suspended/hotplugged out cpu
******************************************************************************/
typedef struct {
unsigned long entrypoint;
unsigned long spsr;
} eret_params;
typedef struct {
eret_params eret_info;
unsigned long context_id;
unsigned int scr;
unsigned int sctlr;
} ns_entry_info;
/*******************************************************************************
*
*
******************************************************************************/
typedef struct {
unsigned long sctlr;
unsigned long scr;
unsigned long cptr;
unsigned long cpacr;
unsigned long cntfrq;
unsigned long mair;
unsigned long tcr;
unsigned long ttbr;
unsigned long vbar;
} secure_context;
/*******************************************************************************
* The following two data structures hold the topology tree which in turn tracks
* the state of the all the affinity instances supported by the platform.
******************************************************************************/
typedef struct {
unsigned long mpidr;
unsigned char state;
char level;
unsigned int data;
bakery_lock lock;
} aff_map_node;
typedef struct {
int min;
int max;
} aff_limits_node;
typedef unsigned int (*afflvl_power_on_finisher)(unsigned long,
aff_map_node *,
unsigned int);
/*******************************************************************************
* Data prototypes
******************************************************************************/
extern secure_context psci_secure_context[PSCI_NUM_AFFS];
extern ns_entry_info psci_ns_entry_info[PSCI_NUM_AFFS];
extern unsigned int psci_ns_einfo_idx;
extern aff_limits_node psci_aff_limits[MPIDR_MAX_AFFLVL + 1];
extern plat_pm_ops *psci_plat_pm_ops;
extern aff_map_node psci_aff_map[PSCI_NUM_AFFS];
extern afflvl_power_on_finisher psci_afflvl_off_finish_handlers[];
extern afflvl_power_on_finisher psci_afflvl_sus_finish_handlers[];
/*******************************************************************************
* Function prototypes
******************************************************************************/
/* Private exported functions from psci_common.c */
extern int get_max_afflvl(void);
extern unsigned int psci_get_phys_state(unsigned int);
extern unsigned int psci_get_aff_phys_state(aff_map_node *);
extern unsigned int psci_calculate_affinity_state(aff_map_node *);
extern unsigned int psci_get_ns_entry_info(unsigned int index);
extern unsigned long mpidr_set_aff_inst(unsigned long,unsigned char, int);
extern int psci_change_state(unsigned long, int, int, unsigned int);
extern int psci_validate_mpidr(unsigned long, int);
extern unsigned int psci_afflvl_power_on_finish(unsigned long,
int,
int,
afflvl_power_on_finisher *);
extern int psci_set_ns_entry_info(unsigned int index,
unsigned long entrypoint,
unsigned long context_id);
extern int psci_get_first_present_afflvl(unsigned long,
int, int,
aff_map_node **);
/* Private exported functions from psci_setup.c */
extern aff_map_node *psci_get_aff_map_node(unsigned long, int);
/* Private exported functions from psci_affinity_on.c */
extern int psci_afflvl_on(unsigned long,
unsigned long,
unsigned long,
int,
int);
/* Private exported functions from psci_affinity_off.c */
extern int psci_afflvl_off(unsigned long, int, int);
/* Private exported functions from psci_affinity_suspend.c */
extern int psci_afflvl_suspend(unsigned long,
unsigned long,
unsigned long,
unsigned int,
int,
int);
extern unsigned int psci_afflvl_suspend_finish(unsigned long, int, int);
#endif /*__ASSEMBLY__*/
#endif /* __PSCI_PRIVATE_H__ */

268
common/psci/psci_setup.c Normal file
View File

@ -0,0 +1,268 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <psci_private.h>
/*******************************************************************************
* Routines for retrieving the node corresponding to an affinity level instance
* in the mpidr. The first one uses binary search to find the node corresponding
* to the mpidr (key) at a particular affinity level. The second routine decides
* extents of the binary search at each affinity level.
******************************************************************************/
static int psci_aff_map_get_idx(unsigned long key,
int min_idx,
int max_idx)
{
int mid;
/*
* Terminating condition: If the max and min indices have crossed paths
* during the binary search then the key has not been found.
*/
if (max_idx < min_idx)
return PSCI_E_INVALID_PARAMS;
/*
* Bisect the array around 'mid' and then recurse into the array chunk
* where the key is likely to be found. The mpidrs in each node in the
* 'psci_aff_map' for a given affinity level are stored in an ascending
* order which makes the binary search possible.
*/
mid = min_idx + ((max_idx - min_idx) >> 1); /* Divide by 2 */
if (psci_aff_map[mid].mpidr > key)
return psci_aff_map_get_idx(key, min_idx, mid - 1);
else if (psci_aff_map[mid].mpidr < key)
return psci_aff_map_get_idx(key, mid + 1, max_idx);
else
return mid;
}
aff_map_node *psci_get_aff_map_node(unsigned long mpidr, int aff_lvl)
{
int rc;
/* Right shift the mpidr to the required affinity level */
mpidr = mpidr_mask_lower_afflvls(mpidr, aff_lvl);
rc = psci_aff_map_get_idx(mpidr,
psci_aff_limits[aff_lvl].min,
psci_aff_limits[aff_lvl].max);
if (rc >= 0)
return &psci_aff_map[rc];
else
return NULL;
}
/*******************************************************************************
* Function which initializes the 'aff_map_node' corresponding to an affinity
* level instance. Each node has a unique mpidr, level and bakery lock. The data
* field is opaque and holds affinity level specific data e.g. for affinity
* level 0 it contains the index into arrays that hold the secure/non-secure
* state for a cpu that's been turned on/off
******************************************************************************/
static void psci_init_aff_map_node(unsigned long mpidr,
int level,
unsigned int idx)
{
unsigned char state;
psci_aff_map[idx].mpidr = mpidr;
psci_aff_map[idx].level = level;
bakery_lock_init(&psci_aff_map[idx].lock);
/*
* If an affinity instance is present then mark it as OFF to begin with.
*/
state = plat_get_aff_state(level, mpidr);
psci_aff_map[idx].state = state;
if (state & PSCI_AFF_PRESENT) {
psci_set_state(psci_aff_map[idx].state, PSCI_STATE_OFF);
}
if (level == MPIDR_AFFLVL0) {
/* Ensure that we have not overflowed the psci_ns_einfo array */
assert(psci_ns_einfo_idx < PSCI_NUM_AFFS);
psci_aff_map[idx].data = psci_ns_einfo_idx;
psci_ns_einfo_idx++;
}
return;
}
/*******************************************************************************
* Core routine used by the Breadth-First-Search algorithm to populate the
* affinity tree. Each level in the tree corresponds to an affinity level. This
* routine's aim is to traverse to the target affinity level and populate nodes
* in the 'psci_aff_map' for all the siblings at that level. It uses the current
* affinity level to keep track of how many levels from the root of the tree
* have been traversed. If the current affinity level != target affinity level,
* then the platform is asked to return the number of children that each
* affinity instance has at the current affinity level. Traversal is then done
* for each child at the next lower level i.e. current affinity level - 1.
*
* CAUTION: This routine assumes that affinity instance ids are allocated in a
* monotonically increasing manner at each affinity level in a mpidr starting
* from 0. If the platform breaks this assumption then this code will have to
* be reworked accordingly.
******************************************************************************/
static unsigned int psci_init_aff_map(unsigned long mpidr,
unsigned int affmap_idx,
int cur_afflvl,
int tgt_afflvl)
{
unsigned int ctr, aff_count;
assert(cur_afflvl >= tgt_afflvl);
/*
* Find the number of siblings at the current affinity level &
* assert if there are none 'cause then we have been invoked with
* an invalid mpidr.
*/
aff_count = plat_get_aff_count(cur_afflvl, mpidr);
assert(aff_count);
if (tgt_afflvl < cur_afflvl) {
for (ctr = 0; ctr < aff_count; ctr++) {
mpidr = mpidr_set_aff_inst(mpidr, ctr, cur_afflvl);
affmap_idx = psci_init_aff_map(mpidr,
affmap_idx,
cur_afflvl - 1,
tgt_afflvl);
}
} else {
for (ctr = 0; ctr < aff_count; ctr++, affmap_idx++) {
mpidr = mpidr_set_aff_inst(mpidr, ctr, cur_afflvl);
psci_init_aff_map_node(mpidr, cur_afflvl, affmap_idx);
}
/* affmap_idx is 1 greater than the max index of cur_afflvl */
psci_aff_limits[cur_afflvl].max = affmap_idx - 1;
}
return affmap_idx;
}
/*******************************************************************************
* This function initializes the topology tree by querying the platform. To do
* so, it's helper routines implement a Breadth-First-Search. At each affinity
* level the platform conveys the number of affinity instances that exist i.e.
* the affinity count. The algorithm populates the psci_aff_map recursively
* using this information. On a platform that implements two clusters of 4 cpus
* each, the populated aff_map_array would look like this:
*
* <- cpus cluster0 -><- cpus cluster1 ->
* ---------------------------------------------------
* | 0 | 1 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 |
* ---------------------------------------------------
* ^ ^
* cluster __| cpu __|
* limit limit
*
* The first 2 entries are of the cluster nodes. The next 4 entries are of cpus
* within cluster 0. The last 4 entries are of cpus within cluster 1.
* The 'psci_aff_limits' array contains the max & min index of each affinity
* level within the 'psci_aff_map' array. This allows restricting search of a
* node at an affinity level between the indices in the limits array.
******************************************************************************/
void psci_setup(unsigned long mpidr)
{
int afflvl, affmap_idx, rc, max_afflvl;
aff_map_node *node;
/* Initialize psci's internal state */
memset(psci_aff_map, 0, sizeof(psci_aff_map));
memset(psci_aff_limits, 0, sizeof(psci_aff_limits));
memset(psci_ns_entry_info, 0, sizeof(psci_ns_entry_info));
psci_ns_einfo_idx = 0;
psci_plat_pm_ops = NULL;
/* Find out the maximum affinity level that the platform implements */
max_afflvl = get_max_afflvl();
assert(max_afflvl <= MPIDR_MAX_AFFLVL);
/*
* This call traverses the topology tree with help from the platform and
* populates the affinity map using a breadth-first-search recursively.
* We assume that the platform allocates affinity instance ids from 0
* onwards at each affinity level in the mpidr. FIRST_MPIDR = 0.0.0.0
*/
affmap_idx = 0;
for (afflvl = max_afflvl; afflvl >= MPIDR_AFFLVL0; afflvl--) {
affmap_idx = psci_init_aff_map(FIRST_MPIDR,
affmap_idx,
max_afflvl,
afflvl);
}
/*
* Set the bounds for the affinity counts of each level in the map. Also
* flush out the entire array so that it's visible to subsequent power
* management operations. The 'psci_aff_map' array is allocated in
* coherent memory so does not need flushing. The 'psci_aff_limits'
* array is allocated in normal memory. It will be accessed when the mmu
* is off e.g. after reset. Hence it needs to be flushed.
*/
for (afflvl = MPIDR_AFFLVL0; afflvl < max_afflvl; afflvl++) {
psci_aff_limits[afflvl].min =
psci_aff_limits[afflvl + 1].max + 1;
}
flush_dcache_range((unsigned long) psci_aff_limits,
sizeof(psci_aff_limits));
/*
* Mark the affinity instances in our mpidr as ON. No need to lock as
* this is the primary cpu.
*/
mpidr &= MPIDR_AFFINITY_MASK;
for (afflvl = max_afflvl; afflvl >= MPIDR_AFFLVL0; afflvl--) {
node = psci_get_aff_map_node(mpidr, afflvl);
assert(node);
/* Mark each present node as ON. */
if (node->state & PSCI_AFF_PRESENT) {
psci_set_state(node->state, PSCI_STATE_ON);
}
}
rc = platform_setup_pm(&psci_plat_pm_ops);
assert(rc == 0);
assert(psci_plat_pm_ops);
return;
}

50
common/runtime_svc.c Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <semihosting.h>
#include <bl_common.h>
#include <psci.h>
/*******************************************************************************
* Perform initialization of runtime services possibly across exception levels
* in the secure address space e.g. psci & interrupt handling.
******************************************************************************/
void runtime_svc_init(unsigned long mpidr)
{
psci_setup(mpidr);
return;
}

76
docs/change-log.md Normal file
View File

@ -0,0 +1,76 @@
ARM Trusted Firmware - version 0.2
==================================
New features
------------
* First source release.
* Code for the PSCI suspend feature is supplied, although this is not enabled
by default since there are known issues (see below).
Issues resolved since last release
----------------------------------
* The "psci" nodes in the FDTs provided in this release now fully comply
with the recommendations made in the PSCI specification.
Known issues
------------
The following is a list of issues which are expected to be fixed in the future
releases of the ARM Trusted Firmware.
* The TrustZone Address Space Controller (TZC-400) is not being programmed
yet. Use of model parameter `-C bp.secure_memory=1` is not supported.
* No support yet for secure world interrupt handling or for switching context
between secure and normal worlds in EL3.
* GICv3 support is experimental. The Linux kernel patches to support this are
not widely available. There are known issues with GICv3 initialization in
the ARM Trusted Firmware.
* Dynamic image loading is not available yet. The current image loader
implementation (used to load BL2 and all subsequent images) has some
limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead
to loading errors, even if the images should theoretically fit in memory.
* Although support for PSCI `CPU_SUSPEND` is present, it is not yet stable
and ready for use.
* PSCI api calls `AFFINITY_INFO` & `PSCI_VERSION` are implemented but have not
been tested.
* The ARM Trusted Firmware make files result in all build artifacts being
placed in the root of the project. These should be placed in appropriate
sub-directories.
* The compilation of ARM Trusted Firmware is not free from compilation
warnings. Some of these warnings have not been investigated yet so they
could mask real bugs.
* The ARM Trusted Firmware currently uses toolchain/system include files like
stdio.h. It should provide versions of these within the project to maintain
compatibility between toolchains/systems.
* The PSCI code takes some locks in an incorrect sequence. This may cause
problems with suspend and hotplug in certain conditions.
* The Linux kernel used in this release is based on version 3.12-rc4. Using
this kernel with the ARM Trusted Firmware fails to start the file-system as
a RAM-disk. It fails to execute user-space `init` from the RAM-disk. As an
alternative, the VirtioBlock mechanism can be used to provide a file-system
to the kernel.
Detailed changes since last release
-----------------------------------
First source release not applicable.
- - - - - - - - - - - - - - - - - - - - - - - - - -
_Copyright (c) 2013 ARM Ltd. All rights reserved._

939
docs/porting-guide.md Normal file
View File

@ -0,0 +1,939 @@
ARM Trusted Firmware Porting Guide
==================================
Contents
--------
1. Introduction
2. Common Modifications
* Common mandatory modifications
* Common optional modifications
3. Boot Loader stage specific modifications
* Boot Loader stage 1 (BL1)
* Boot Loader stage 2 (BL2)
* Boot Loader stage 3-1 (BL3-1)
* PSCI implementation (in BL3-1)
- - - - - - - - - - - - - - - - - -
1. Introduction
----------------
Porting the ARM Trusted Firmware to a new platform involves making some
mandatory and optional modifications for both the cold and warm boot paths.
Modifications consist of:
* Implementing a platform-specific function or variable,
* Setting up the execution context in a certain way, or
* Defining certain constants (for example #defines).
The firmware provides a default implementation of variables and functions to
fulfill the optional requirements. These implementations are all weakly defined;
they are provided to ease the porting effort. Each platform port can override
them with its own implementation if the default implementation is inadequate.
Some modifications are common to all Boot Loader (BL) stages. Section 2
discusses these in detail. The subsequent sections discuss the remaining
modifications for each BL stage in detail.
This document should be read in conjunction with the ARM Trusted Firmware
[User Guide].
2. Common modifications
------------------------
This section covers the modifications that should be made by the platform for
each BL stage to correctly port the firmware stack. They are categorized as
either mandatory or optional.
2.1 Common mandatory modifications
----------------------------------
A platform port must enable the Memory Management Unit (MMU) with identity
mapped page tables, and enable both the instruction and data caches for each BL
stage. In the ARM FVP port, each BL stage configures the MMU in its platform-
specific architecture setup function, for example `blX_plat_arch_setup()`.
Each platform must allocate a block of identity mapped secure memory with
Device-nGnRE attributes aligned to page boundary (4K) for each BL stage. This
memory is identified by the section name `tzfw_coherent_mem` so that its
possible for the firmware to place variables in it using the following C code
directive:
__attribute__ ((section("tzfw_coherent_mem")))
Or alternatively the following assembler code directive:
.section tzfw_coherent_mem
The `tzfw_coherent_mem` section is used to allocate any data structures that are
accessed both when a CPU is executing with its MMU and caches enabled, and when
it's running with its MMU and caches disabled. Examples are given below.
The following variables, functions and constants must be defined by the platform
for the firmware to work correctly.
### File : platform.h [mandatory]
Each platform must export a header file of this name with the following
constants defined. In the ARM FVP port, this file is found in
[../plat/fvp/platform.h].
* ** #define : PLATFORM_LINKER_FORMAT **
Defines the linker format used by the platform, for example
`elf64-littleaarch64` used by the FVP.
* ** #define : PLATFORM_LINKER_ARCH **
Defines the processor architecture for the linker by the platform, for
example `aarch64` used by the FVP.
* ** #define : PLATFORM_STACK_SIZE **
Defines the normal stack memory available to each CPU. This constant is used
by `platform_set_stack()`.
* ** #define : FIRMWARE_WELCOME_STR **
Defines the character string printed by BL1 upon entry into the `bl1_main()`
function.
* ** #define : BL2_IMAGE_NAME **
Name of the BL2 binary image on the host file-system. This name is used by
BL1 to load BL2 into secure memory using semi-hosting.
* ** #define : PLATFORM_CACHE_LINE_SIZE **
Defines the size (in bytes) of the largest cache line across all the cache
levels in the platform.
* ** #define : PLATFORM_CLUSTER_COUNT **
Defines the total number of clusters implemented by the platform in the
system.
* ** #define : PLATFORM_CORE_COUNT **
Defines the total number of CPUs implemented by the platform across all
clusters in the system.
* ** #define : PLATFORM_MAX_CPUS_PER_CLUSTER **
Defines the maximum number of CPUs that can be implemented within a cluster
on the platform.
* ** #define : PRIMARY_CPU **
Defines the `MPIDR` of the primary CPU on the platform. This value is used
after a cold boot to distinguish between primary and secondary CPUs.
* ** #define : TZROM_BASE **
Defines the base address of secure ROM on the platform, where the BL1 binary
is loaded. This constant is used by the linker scripts to ensure that the
BL1 image fits into the available memory.
* ** #define : TZROM_SIZE **
Defines the size of secure ROM on the platform. This constant is used by the
linker scripts to ensure that the BL1 image fits into the available memory.
* ** #define : TZRAM_BASE **
Defines the base address of the secure RAM on platform, where the data
section of the BL1 binary is loaded. The BL2 and BL3-1 images are also
loaded in this secure RAM region. This constant is used by the linker
scripts to ensure that the BL1 data section and BL2/BL3-1 binary images fit
into the available memory.
* ** #define : TZRAM_SIZE **
Defines the size of the secure RAM on the platform. This constant is used by
the linker scripts to ensure that the BL1 data section and BL2/BL3-1 binary
images fit into the available memory.
* ** #define : SYS_CNTCTL_BASE **
Defines the base address of the `CNTCTLBase` frame of the memory mapped
counter and timer in the system level implementation of the generic timer.
* ** #define : BL2_BASE **
Defines the base address in secure RAM where BL1 loads the BL2 binary image.
* ** #define : BL31_BASE **
Defines the base address in secure RAM where BL2 loads the BL3-1 binary
image.
### Other mandatory modifications
The following following mandatory modifications may be implemented in any file
the implementer chooses. In the ARM FVP port, they are implemented in
[../plat/fvp/aarch64/fvp_common.c].
* ** Variable : unsigned char platform_normal_stacks[X][Y] **
where X = PLATFORM_STACK_SIZE
and Y = PLATFORM_CORE_COUNT
Each platform must allocate a block of memory with Normal Cacheable, Write
back, Write allocate and Inner Shareable attributes aligned to the size (in
bytes) of the largest cache line amongst all caches implemented in the
system. A pointer to this memory should be exported with the name
`platform_normal_stacks`. This pointer is used by the common platform helper
function `platform_set_stack()` to allocate a stack to each CPU in the
platform (see [../plat/common/aarch64/platform_helpers.S]).
2.2 Common optional modifications
---------------------------------
The following are helper functions implemented by the firmware that perform
common platform-specific tasks. A platform may choose to override these
definitions.
### Function : platform_get_core_pos()
Argument : unsigned long
Return : int
A platform may need to convert the `MPIDR` of a CPU to an absolute number, which
can be used as a CPU-specific linear index into blocks of memory (for example
while allocating per-CPU stacks). This routine contains a simple mechanism
to perform this conversion, using the assumption that each cluster contains a
maximum of 4 CPUs:
linear index = cpu_id + (cluster_id * 4)
cpu_id = 8-bit value in MPIDR at affinity level 0
cluster_id = 8-bit value in MPIDR at affinity level 1
### Function : platform_set_coherent_stack()
Argument : unsigned long
Return : void
A platform may need stack memory that is coherent with main memory to perform
certain operations like:
* Turning the MMU on, or
* Flushing caches prior to powering down a CPU or cluster.
Each BL stage allocates this coherent stack memory for each CPU in the
`tzfw_coherent_mem` section. A pointer to this memory (`pcpu_dv_mem_stack`) is
used by this function to allocate a coherent stack for each CPU. A CPU is
identified by its `MPIDR`, which is passed as an argument to this function.
The size of the stack allocated to each CPU is specified by the constant
`PCPU_DV_MEM_STACK_SIZE`.
### Function : platform_is_primary_cpu()
Argument : unsigned long
Return : unsigned int
This function identifies a CPU by its `MPIDR`, which is passed as the argument,
to determine whether this CPU is the primary CPU or a secondary CPU. A return
value of zero indicates that the CPU is not the primary CPU, while a non-zero
return value indicates that the CPU is the primary CPU.
### Function : platform_set_stack()
Argument : unsigned long
Return : void
This function uses the `platform_normal_stacks` pointer variable to allocate
stacks to each CPU. Further details are given in the description of the
`platform_normal_stacks` variable below. A CPU is identified by its `MPIDR`,
which is passed as the argument.
The size of the stack allocated to each CPU is specified by the platform defined
constant `PLATFORM_STACK_SIZE`.
### Function : plat_report_exception()
Argument : unsigned int
Return : void
A platform may need to report various information about its status when an
exception is taken, for example the current exception level, the CPU security
state (secure/non-secure), the exception type, and so on. This function is
called in the following circumstances:
* In BL1, whenever an exception is taken.
* In BL2, whenever an exception is taken.
* In BL3-1, whenever an asynchronous exception or a synchronous exception
other than an SMC32/SMC64 exception is taken.
The default implementation doesn't do anything, to avoid making assumptions
about the way the platform displays its status information.
This function receives the exception type as its argument. Possible values for
exceptions types are listed in the [../include/runtime_svc.h] header file. Note
that these constants are not related to any architectural exception code; they
are just an ARM Trusted Firmware convention.
3. Modifications specific to a Boot Loader stage
-------------------------------------------------
3.1 Boot Loader Stage 1 (BL1)
-----------------------------
BL1 implements the reset vector where execution starts from after a cold or
warm boot. For each CPU, BL1 is responsible for the following tasks:
1. Distinguishing between a cold boot and a warm boot.
2. In the case of a cold boot and the CPU being the primary CPU, ensuring that
only this CPU executes the remaining BL1 code, including loading and passing
control to the BL2 stage.
3. In the case of a cold boot and the CPU being a secondary CPU, ensuring that
the CPU is placed in a platform-specific state until the primary CPU
performs the necessary steps to remove it from this state.
4. In the case of a warm boot, ensuring that the CPU jumps to a platform-
specific address in the BL3-1 image in the same processor mode as it was
when released from reset.
5. Loading the BL2 image in secure memory using semi-hosting at the
address specified by the platform defined constant `BL2_BASE`.
6. Populating a `meminfo` structure with the following information in memory,
accessible by BL2 immediately upon entry.
meminfo.total_base = Base address of secure RAM visible to BL2
meminfo.total_size = Size of secure RAM visible to BL2
meminfo.free_base = Base address of secure RAM available for
allocation to BL2
meminfo.free_size = Size of secure RAM available for allocation to BL2
BL1 places this `meminfo` structure at the beginning of the free memory
available for its use. Since BL1 cannot allocate memory dynamically at the
moment, its free memory will be available for BL2's use as-is. However, this
means that BL2 must read the `meminfo` structure before it starts using its
free memory (this is discussed in Section 3.2).
In future releases of the ARM Trusted Firmware it will be possible for
the platform to decide where it wants to place the `meminfo` structure for
BL2.
BL1 implements the `init_bl2_mem_layout()` function to populate the
BL2 `meminfo` structure. The platform may override this implementation, for
example if the platform wants to restrict the amount of memory visible to
BL2. Details of how to do this are given below.
The following functions need to be implemented by the platform port to enable
BL1 to perform the above tasks.
### Function : platform_get_entrypoint() [mandatory]
Argument : unsigned long
Return : unsigned int
This function is called with the `SCTLR.M` and `SCTLR.C` bits disabled. The CPU
is identified by its `MPIDR`, which is passed as the argument. The function is
responsible for distinguishing between a warm and cold reset using platform-
specific means. If it's a warm reset then it returns the entrypoint into the
BL3-1 image that the CPU must jump to. If it's a cold reset then this function
must return zero.
This function is also responsible for implementing a platform-specific mechanism
to handle the condition where the CPU has been warm reset but there is no
entrypoint to jump to.
This function does not follow the Procedure Call Standard used by the
Application Binary Interface for the ARM 64-bit architecture. The caller should
not assume that callee saved registers are preserved across a call to this
function.
This function fulfills requirement 1 listed above.
### Function : plat_secondary_cold_boot_setup() [mandatory]
Argument : void
Return : void
This function is called with the MMU and data caches disabled. It is responsible
for placing the executing secondary CPU in a platform-specific state until the
primary CPU performs the necessary actions to bring it out of that state and
allow entry into the OS.
In the ARM FVP port, each secondary CPU powers itself off. The primary CPU is
responsible for powering up the secondary CPU when normal world software
requires them.
This function fulfills requirement 3 above.
### Function : platform_cold_boot_init() [mandatory]
Argument : unsigned long
Return : unsigned int
This function executes with the MMU and data caches disabled. It is only called
by the primary CPU. The argument to this function is the address of the
`bl1_main()` routine where the generic BL1-specific actions are performed.
This function performs any platform-specific and architectural setup that the
platform requires to make execution of `bl1_main()` possible.
The platform must enable the MMU with identity mapped page tables and enable
caches by setting the `SCTLR.I` and `SCTLR.C` bits.
Platform-specific setup might include configuration of memory controllers,
configuration of the interconnect to allow the cluster to service cache snoop
requests from another cluster, zeroing of the ZI section, and so on.
In the ARM FVP port, this function enables CCI snoops into the cluster that the
primary CPU is part of. It also enables the MMU and initializes the ZI section
in the BL1 image through the use of linker defined symbols.
This function helps fulfill requirement 2 above.
### Function : bl1_platform_setup() [mandatory]
Argument : void
Return : void
This function executes with the MMU and data caches enabled. It is responsible
for performing any remaining platform-specific setup that can occur after the
MMU and data cache have been enabled.
In the ARM FVP port, it zeros out the ZI section, enables the system level
implementation of the generic timer counter and initializes the console.
This function helps fulfill requirement 5 above.
### Function : bl1_get_sec_mem_layout() [mandatory]
Argument : void
Return : meminfo
This function executes with the MMU and data caches enabled. The `meminfo`
structure returned by this function must contain the extents and availability of
secure RAM for the BL1 stage.
meminfo.total_base = Base address of secure RAM visible to BL1
meminfo.total_size = Size of secure RAM visible to BL1
meminfo.free_base = Base address of secure RAM available for allocation
to BL1
meminfo.free_size = Size of secure RAM available for allocation to BL1
This information is used by BL1 to load the BL2 image in secure RAM. BL1 also
populates a similar structure to tell BL2 the extents of memory available for
its own use.
This function helps fulfill requirement 5 above.
### Function : init_bl2_mem_layout() [optional]
Argument : meminfo *, meminfo *, unsigned int, unsigned long
Return : void
Each BL stage needs to tell the next stage the amount of secure RAM available
for it to use. For example, as part of handing control to BL2, BL1 informs BL2
of the extents of secure RAM available for BL2 to use. BL2 must do the same when
passing control to BL3-1. This information is populated in a `meminfo`
structure.
Depending upon where BL2 has been loaded in secure RAM (determined by
`BL2_BASE`), BL1 calculates the amount of free memory available for BL2 to use.
BL1 also ensures that its data sections resident in secure RAM are not visible
to BL2. An illustration of how this is done in the ARM FVP port is given in the
[User Guide], in the Section "Memory layout on Base FVP".
3.2 Boot Loader Stage 2 (BL2)
-----------------------------
The BL2 stage is executed only by the primary CPU, which is determined in BL1
using the `platform_is_primary_cpu()` function. BL1 passed control to BL2 at
`BL2_BASE`. BL2 executes in Secure EL1 and is responsible for:
1. Loading the BL3-1 binary image in secure RAM using semi-hosting. To load the
BL3-1 image, BL2 makes use of the `meminfo` structure passed to it by BL1.
This structure allows BL2 to calculate how much secure RAM is available for
its use. The platform also defines the address in secure RAM where BL3-1 is
loaded through the constant `BL31_BASE`. BL2 uses this information to
determine if there is enough memory to load the BL3-1 image.
2. Arranging to pass control to a normal world BL image that has been
pre-loaded at a platform-specific address. This address is determined using
the `plat_get_ns_image_entrypoint()` function described below.
BL2 populates an `el_change_info` structure in memory provided by the
platform with information about how BL3-1 should pass control to the normal
world BL image.
3. Populating a `meminfo` structure with the following information in
memory that is accessible by BL3-1 immediately upon entry.
meminfo.total_base = Base address of secure RAM visible to BL3-1
meminfo.total_size = Size of secure RAM visible to BL3-1
meminfo.free_base = Base address of secure RAM available for allocation
to BL3-1
meminfo.free_size = Size of secure RAM available for allocation to
BL3-1
BL2 places this `meminfo` structure in memory provided by the
platform (`bl2_el_change_mem_ptr`). BL2 implements the
`init_bl31_mem_layout()` function to populate the BL3-1 meminfo structure
described above. The platform may override this implementation, for example
if the platform wants to restrict the amount of memory visible to BL3-1.
Details of this function are given below.
The following functions must be implemented by the platform port to enable BL2
to perform the above tasks.
### Function : bl2_early_platform_setup() [mandatory]
Argument : meminfo *, void *
Return : void
This function executes with the MMU and data caches disabled. It is only called
by the primary CPU. The arguments to this function are:
* The address of the `meminfo` structure populated by BL1
* An opaque pointer that the platform may use as needed.
The platform must copy the contents of the `meminfo` structure into a private
variable as the original memory may be subsequently overwritten by BL2. The
copied structure is made available to all BL2 code through the
`bl2_get_sec_mem_layout()` function.
### Function : bl2_plat_arch_setup() [mandatory]
Argument : void
Return : void
This function executes with the MMU and data caches disabled. It is only called
by the primary CPU.
The purpose of this function is to perform any architectural initialization
that varies across platforms, for example enabling the MMU (since the memory
map differs across platforms).
### Function : bl2_platform_setup() [mandatory]
Argument : void
Return : void
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initialization in `bl2_plat_arch_setup()`. It is only
called by the primary CPU.
The purpose of this function is to perform any platform initialization specific
to BL2. This function must initialize a pointer to memory
(`bl2_el_change_mem_ptr`), which can then be used to populate an
`el_change_info` structure. The underlying requirement is that the platform must
initialize this pointer before the `get_el_change_mem_ptr()` function
accesses it in `bl2_main()`.
The ARM FVP port initializes this pointer to the base address of Secure DRAM
(`0x06000000`).
### Variable : unsigned char bl2_el_change_mem_ptr[EL_CHANGE_MEM_SIZE] [mandatory]
As mentioned in the description of `bl2_platform_setup()`, this pointer is
initialized by the platform to point to memory where an `el_change_info`
structure can be populated.
### Function : bl2_get_sec_mem_layout() [mandatory]
Argument : void
Return : meminfo
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initialization in `bl2_plat_arch_setup()`. It is only
called by the primary CPU.
The purpose of this function is to return a `meminfo` structure populated with
the extents of secure RAM available for BL2 to use. See
`bl2_early_platform_setup()` above.
### Function : init_bl31_mem_layout() [optional]
Argument : meminfo *, meminfo *, unsigned int
Return : void
Each BL stage needs to tell the next stage the amount of secure RAM that is
available for it to use. For example, as part of handing control to BL2, BL1
must inform BL2 about the extents of secure RAM that is available for BL2 to
use. BL2 must do the same when passing control to BL3-1. This information is
populated in a `meminfo` structure.
Depending upon where BL3-1 has been loaded in secure RAM (determined by
`BL31_BASE`), BL2 calculates the amount of free memory available for BL3-1 to
use. BL2 also ensures that BL3-1 is able reclaim memory occupied by BL2. This
is done because BL2 never executes again after passing control to BL3-1.
An illustration of how this is done in the ARM FVP port is given in the
[User Guide], in the section "Memory layout on Base FVP".
### Function : plat_get_ns_image_entrypoint() [mandatory]
Argument : void
Return : unsigned long
As previously described, BL2 is responsible for arranging for control to be
passed to a normal world BL image through BL3-1. This function returns the
entrypoint of that image, which BL3-1 uses to jump to it.
The ARM FVP port assumes that flash memory has been pre-loaded with the UEFI
image, and so returns the base address of flash memory.
3.2 Boot Loader Stage 3-1 (BL3-1)
---------------------------------
During cold boot, the BL3-1 stage is executed only by the primary CPU. This is
determined in BL1 using the `platform_is_primary_cpu()` function. BL1 passes
control to BL3-1 at `BL31_BASE`. During warm boot, BL3-1 is executed by all
CPUs. BL3-1 executes at EL3 and is responsible for:
1. Re-initializing all architectural and platform state. Although BL1 performs
some of this initialization, BL3-1 remains resident in EL3 and must ensure
that EL3 architectural and platform state is completely initialized. It
should make no assumptions about the system state when it receives control.
2. Passing control to a normal world BL image, pre-loaded at a platform-
specific address by BL2. BL3-1 uses the `el_change_info` structure that BL2
populated in memory to do this.
3. Providing runtime firmware services. Currently, BL3-1 only implements a
subset of the Power State Coordination Interface (PSCI) API as a runtime
service. See Section 3.3 below for details of porting the PSCI
implementation.
The following functions must be implemented by the platform port to enable BL3-1
to perform the above tasks.
### Function : bl31_early_platform_setup() [mandatory]
Argument : meminfo *, void *, unsigned long
Return : void
This function executes with the MMU and data caches disabled. It is only called
by the primary CPU. The arguments to this function are:
* The address of the `meminfo` structure populated by BL2.
* An opaque pointer that the platform may use as needed.
* The `MPIDR` of the primary CPU.
The platform must copy the contents of the `meminfo` structure into a private
variable as the original memory may be subsequently overwritten by BL3-1. The
copied structure is made available to all BL3-1 code through the
`bl31_get_sec_mem_layout()` function.
### Function : bl31_plat_arch_setup() [mandatory]
Argument : void
Return : void
This function executes with the MMU and data caches disabled. It is only called
by the primary CPU.
The purpose of this function is to perform any architectural initialization
that varies across platforms, for example enabling the MMU (since the memory
map differs across platforms).
### Function : bl31_platform_setup() [mandatory]
Argument : void
Return : void
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initialization in `bl31_plat_arch_setup()`. It is only
called by the primary CPU.
The purpose of this function is to complete platform initialization so that both
BL3-1 runtime services and normal world software can function correctly.
The ARM FVP port does the following:
* Initializes the generic interrupt controller.
* Configures the CLCD controller.
* Grants access to the system counter timer module
* Initializes the FVP power controller device
* Detects the system topology.
### Function : bl31_get_next_image_info() [mandatory]
Argument : unsigned long
Return : el_change_info *
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `bl31_plat_arch_setup()`.
This function is called by `bl31_main()` to retrieve information provided by
BL2, so that BL3-1 can pass control to the normal world software image. This
function must return a pointer to the `el_change_info` structure (that was
copied during `bl31_early_platform_setup()`).
### Function : bl31_get_sec_mem_layout() [mandatory]
Argument : void
Return : meminfo
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
called by the primary CPU.
The purpose of this function is to return a `meminfo` structure populated with
the extents of secure RAM available for BL3-1 to use. See
`bl31_early_platform_setup()` above.
3.3 Power State Coordination Interface (in BL3-1)
------------------------------------------------
The ARM Trusted Firmware's implementation of the PSCI API is based around the
concept of an _affinity instance_. Each _affinity instance_ can be uniquely
identified in a system by a CPU ID (the processor `MPIDR` is used in the PSCI
interface) and an _affinity level_. A processing element (for example, a
CPU) is at level 0. If the CPUs in the system are described in a tree where the
node above a CPU is a logical grouping of CPUs that share some state, then
affinity level 1 is that group of CPUs (for example, a cluster), and affinity
level 2 is a group of clusters (for example, the system). The implementation
assumes that the affinity level 1 ID can be computed from the affinity level 0
ID (for example, a unique cluster ID can be computed from the CPU ID). The
current implementation computes this on the basis of the recommended use of
`MPIDR` affinity fields in the ARM Architecture Reference Manual.
BL3-1's platform initialization code exports a pointer to the platform-specific
power management operations required for the PSCI implementation to function
correctly. This information is populated in the `plat_pm_ops` structure. The
PSCI implementation calls members of the `plat_pm_ops` structure for performing
power management operations for each affinity instance. For example, the target
CPU is specified by its `MPIDR` in a PSCI `CPU_ON` call. The `affinst_on()`
handler (if present) is called for each affinity instance as the PSCI
implementation powers up each affinity level implemented in the `MPIDR` (for
example, CPU, cluster and system).
The following functions must be implemented to initialize PSCI functionality in
the ARM Trusted Firmware.
### Function : plat_get_aff_count() [mandatory]
Argument : unsigned int, unsigned long
Return : unsigned int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
called by the primary CPU.
This function is called by the PSCI initialization code to detect the system
topology. Its purpose is to return the number of affinity instances implemented
at a given `affinity level` (specified by the first argument) and a given
`MPIDR` (specified by the second argument). For example, on a dual-cluster
system where first cluster implements 2 CPUs and the second cluster implements 4
CPUs, a call to this function with an `MPIDR` corresponding to the first cluster
(`0x0`) and affinity level 0, would return 2. A call to this function with an
`MPIDR` corresponding to the second cluster (`0x100`) and affinity level 0,
would return 4.
### Function : plat_get_aff_state() [mandatory]
Argument : unsigned int, unsigned long
Return : unsigned int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
called by the primary CPU.
This function is called by the PSCI initialization code. Its purpose is to
return the state of an affinity instance. The affinity instance is determined by
the affinity ID at a given `affinity level` (specified by the first argument)
and an `MPIDR` (specified by the second argument). The state can be one of
`PSCI_AFF_PRESENT` or `PSCI_AFF_ABSENT`. The latter state is used to cater for
system topologies where certain affinity instances are unimplemented. For
example, consider a platform that implements a single cluster with 4 CPUs and
another CPU implemented directly on the interconnect with the cluster. The
`MPIDR`s of the cluster would range from `0x0-0x3`. The `MPIDR` of the single
CPU would be 0x100 to indicate that it does not belong to cluster 0. Cluster 1
is missing but needs to be accounted for to reach this single CPU in the
topology tree. Hence it is marked as `PSCI_AFF_ABSENT`.
### Function : plat_get_max_afflvl() [mandatory]
Argument : void
Return : int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
called by the primary CPU.
This function is called by the PSCI implementation both during cold and warm
boot, to determine the maximum affinity level that the power management
operations should apply to. ARMv8 has support for 4 affinity levels. It is
likely that hardware will implement fewer affinity levels. This function allows
the PSCI implementation to consider only those affinity levels in the system
that the platform implements. For example, the Base AEM FVP implements two
clusters with a configurable number of CPUs. It reports the maximum affinity
level as 1, resulting in PSCI power control up to the cluster level.
### Function : platform_setup_pm() [mandatory]
Argument : plat_pm_ops **
Return : int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `bl31_plat_arch_setup()`. It is only
called by the primary CPU.
This function is called by PSCI initialization code. Its purpose is to export
handler routines for platform-specific power management actions by populating
the passed pointer with a pointer to BL3-1's private `plat_pm_ops` structure.
A description of each member of this structure is given below. Please refer to
the ARM FVP specific implementation of these handlers in [../plat/fvp/fvp_pm.c]
as an example. A platform port may choose not implement some of the power
management operations. For example, the ARM FVP port does not implement the
`affinst_standby()` function.
#### plat_pm_ops.affinst_standby()
Perform the platform-specific setup to enter the standby state indicated by the
passed argument.
#### plat_pm_ops.affinst_on()
Perform the platform specific setup to power on an affinity instance, specified
by the `MPIDR` (first argument) and `affinity level` (fourth argument). The
`state` (fifth argument) contains the current state of that affinity instance
(ON or OFF). This is useful to determine whether any action must be taken. For
example, while powering on a CPU, the cluster that contains this CPU might
already be in the ON state. The platform decides what actions must be taken to
transition from the current state to the target state (indicated by the power
management operation).
#### plat_pm_ops.affinst_off()
Perform the platform specific setup to power off an affinity instance in the
`MPIDR` of the calling CPU. It is called by the PSCI `CPU_OFF` API
implementation.
The `MPIDR` (first argument), `affinity level` (second argument) and `state`
(third argument) have a similar meaning as described in the `affinst_on()`
operation. They are used to identify the affinity instance on which the call
is made and its current state. This gives the platform port an indication of the
state transition it must make to perform the requested action. For example, if
the calling CPU is the last powered on CPU in the cluster, after powering down
affinity level 0 (CPU), the platform port should power down affinity level 1
(the cluster) as well.
This function is called with coherent stacks. This allows the PSCI
implementation to flush caches at a given affinity level without running into
stale stack state after turning off the caches. On ARMv8 cache hits do not occur
after the cache has been turned off.
#### plat_pm_ops.affinst_suspend()
Perform the platform specific setup to power off an affinity instance in the
`MPIDR` of the calling CPU. It is called by the PSCI `CPU_SUSPEND` API
implementation.
The `MPIDR` (first argument), `affinity level` (third argument) and `state`
(fifth argument) have a similar meaning as described in the `affinst_on()`
operation. They are used to identify the affinity instance on which the call
is made and its current state. This gives the platform port an indication of the
state transition it must make to perform the requested action. For example, if
the calling CPU is the last powered on CPU in the cluster, after powering down
affinity level 0 (CPU), the platform port should power down affinity level 1
(the cluster) as well.
The difference between turning an affinity instance off versus suspending it
is that in the former case, the affinity instance is expected to re-initialize
its state when its next powered on (see `affinst_on_finish()`). In the latter
case, the affinity instance is expected to save enough state so that it can
resume execution by restoring this state when its powered on (see
`affinst_suspend_finish()`).
This function is called with coherent stacks. This allows the PSCI
implementation to flush caches at a given affinity level without running into
stale stack state after turning off the caches. On ARMv8 cache hits do not occur
after the cache has been turned off.
#### plat_pm_ops.affinst_on_finish()
This function is called by the PSCI implementation after the calling CPU is
powered on and released from reset in response to an earlier PSCI `CPU_ON` call.
It performs the platform-specific setup required to initialize enough state for
this CPU to enter the normal world and also provide secure runtime firmware
services.
The `MPIDR` (first argument), `affinity level` (second argument) and `state`
(third argument) have a similar meaning as described in the previous operations.
This function is called with coherent stacks. This allows the PSCI
implementation to flush caches at a given affinity level without running into
stale stack state after turning off the caches. On ARMv8 cache hits do not occur
after the cache has been turned off.
#### plat_pm_ops.affinst_on_suspend()
This function is called by the PSCI implementation after the calling CPU is
powered on and released from reset in response to an asynchronous wakeup
event, for example a timer interrupt that was programmed by the CPU during the
`CPU_SUSPEND` call. It performs the platform-specific setup required to
restore the saved state for this CPU to resume execution in the normal world
and also provide secure runtime firmware services.
The `MPIDR` (first argument), `affinity level` (second argument) and `state`
(third argument) have a similar meaning as described in the previous operations.
This function is called with coherent stacks. This allows the PSCI
implementation to flush caches at a given affinity level without running into
stale stack state after turning off the caches. On ARMv8 cache hits do not occur
after the cache has been turned off.
BL3-1 platform initialization code must also detect the system topology and
the state of each affinity instance in the topology. This information is
critical for the PSCI runtime service to function correctly. More details are
provided in the description of the `plat_get_aff_count()` and
`plat_get_aff_state()` functions above.
- - - - - - - - - - - - - - - - - - - - - - - - - -
_Copyright (c) 2013 ARM Ltd. All rights reserved._
[User Guide]: user-guide.md
[../plat/common/aarch64/platform_helpers.S]: ../plat/common/aarch64/platform_helpers.S
[../plat/fvp/platform.h]: ../plat/fvp/platform.h
[../plat/fvp/aarch64/fvp_common.c]: ../plat/fvp/aarch64/fvp_common.c
[../plat/fvp/fvp_pm.c]: ../plat/fvp/fvp_pm.c
[../include/runtime_svc.h]: ../include/runtime_svc.h

961
docs/user-guide.md Normal file
View File

@ -0,0 +1,961 @@
ARM Trusted Firmware User Guide
===============================
Contents :
1. Introduction
2. Using the Software
3. Firmware Design
4. References
1. Introduction
----------------
The ARM Trusted Firmware implements a subset of the Trusted Board Boot
Requirements (TBBR) Platform Design Document (PDD) [1] for ARM reference
platforms. The TBB sequence starts when the platform is powered on and runs up
to the stage where it hands-off control to firmware running in the normal
world in DRAM. This is the cold boot path.
The ARM Trusted Firmware also implements the Power State Coordination Interface
([PSCI]) PDD [2] as a runtime service. PSCI is the interface from normal world
software to firmware implementing power management use-cases (for example,
secondary CPU boot, hotplug and idle). Normal world software can access ARM
Trusted Firmware runtime services via the ARM SMC (Secure Monitor Call)
instruction. The SMC instruction must be used as mandated by the [SMC Calling
Convention PDD][SMCCC] [3].
2. Using the Software
----------------------
### Host machine requirements
The minimum recommended machine specification is an Intel Core2Duo clocking at
2.6GHz or above, and 12GB RAM. For best performance, use a machine with Intel
Core i7 (SandyBridge) and 16GB of RAM.
### Tools
The following tools are required to use the ARM Trusted Firmware:
* Ubuntu desktop OS. The software has been tested on Ubuntu 12.04.02 (64-bit).
The following packages are also needed:
* `ia32-libs` package.
* `make` and `uuid-dev` packages for building UEFI.
* `bc` and `ncurses-dev` packages for building Linux.
* Baremetal GNU GCC tools. Verified packages can be downloaded from [Linaro]
[Linaro Toolchain]. The rest of this document assumes that the
`gcc-linaro-aarch64-none-elf-4.8-2013.09-01_linux.tar.xz` tools are used.
wget http://releases.linaro.org/13.09/components/toolchain/binaries/gcc-linaro-aarch64-none-elf-4.8-2013.09-01_linux.tar.xz
tar -xf gcc-linaro-aarch64-none-elf-4.8-2013.09-01_linux.tar.xz
* The Device Tree Compiler (DTC) included with Linux kernel 3.12-rc4 is used
to build the Flattened Device Tree (FDT) source files (`.dts` files)
provided with this release.
* (Optional) For debugging, ARM [Development Studio 5 (DS-5)][DS-5] v5.16.
### Building the Trusted Firmware
To build the software for the Base FVPs, follow these steps:
1. Clone the ARM Trusted Firmware repository from Github:
git clone https://github.com/ARM-software/arm-trusted-firmware.git
2. Change to the trusted firmware directory:
cd arm-trusted-firmware
3. Set the compiler path and build:
CROSS_COMPILE=<path/to>/aarch64-none-elf- make
By default this produces a release version of the build. To produce a debug
version instead, refer to the "Debugging options" section below.
The build creates ELF and raw binary files in the current directory. It
generates the following boot loader binary files from the ELF files:
* `bl1.bin`
* `bl2.bin`
* `bl31.bin`
4. Copy the above 3 boot loader binary files to the directory where the FVPs
are launched from. Symbolic links of the same names may be created instead.
5. (Optional) To clean the build directory use
make distclean
#### Debugging options
To compile a debug version and make the build more verbose use
CROSS_COMPILE=<path/to>/aarch64-none-elf- make DEBUG=1 V=1
AArch64 GCC uses DWARF version 4 debugging symbols by default. Some tools (for
example DS-5) might not support this and may need an older version of DWARF
symbols to be emitted by GCC. This can be achieved by using the
`-gdwarf-<version>` flag, with the version being set to 2 or 3. Setting the
version to 2 is recommended for DS-5 versions older than 5.16.
When debugging logic problems it might also be useful to disable all compiler
optimizations by using `-O0`.
NOTE: Using `-O0` could cause output images to be larger and base addresses
might need to be recalculated (see the later memory layout section).
Extra debug options can be passed to the build system by setting `CFLAGS`:
CFLAGS='-O0 -gdwarf-2' CROSS_COMPILE=<path/to>/aarch64-none-elf- make DEBUG=1 V=1
### Obtaining the normal world software
#### Obtaining UEFI
Download an archive of the [EDK2 (EFI Development Kit 2) source code][EDK2]
supporting the Base FVPs. EDK2 is an open source implementation of the UEFI
specification:
wget http://sourceforge.net/projects/edk2/files/ARM/aarch64-uefi-rev14582.tgz/download -O aarch64-uefi-rev14582.tgz
tar -xf aarch64-uefi-rev14582.tgz
To build the software for the Base FVPs, follow these steps:
1. Change into the unpacked EDK2 source directory
cd uefi
2. Copy build config templates to local workspace
export EDK_TOOLS_PATH=$(pwd)/BaseTools
. edksetup.sh $(pwd)/BaseTools/
3. Rebuild EDK2 host tools
make -C "$EDK_TOOLS_PATH" clean
make -C "$EDK_TOOLS_PATH"
4. Build the software
AARCH64GCC_TOOLS_PATH=<full-path-to-aarch64-gcc>/bin/ \
build -v -d3 -a AARCH64 -t ARMGCC \
-p ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc
The EDK2 binary for use with the ARM Trusted Firmware can then be found
here:
Build/ArmVExpress-FVP-AArch64/DEBUG_ARMGCC/FV/FVP_AARCH64_EFI.fd
This will build EDK2 for the default settings as used by the FVPs.
To boot Linux using a VirtioBlock file-system, the command line passed from EDK2
to the Linux kernel must be modified as described in the "Obtaining a
File-system" section below.
If legacy GICv2 locations are used, the EDK2 platform description must be
updated. This is required as EDK2 does not support probing for the GIC location.
To do this, open the `ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc`
file for editing and make the modifications as below. Rebuild EDK2 after doing a
`clean`.
gArmTokenSpaceGuid.PcdGicDistributorBase|0x2C001000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000
The EDK2 binary `FVP_AARCH64_EFI.fd` should be loaded into FVP FLASH0 via model
parameters as described in the "Running the Software" section below.
#### Obtaining a Linux kernel
The software has been verified using Linux kernel version 3.12-rc4. Patches
have been applied to the kernel in order to enable CPU hotplug.
Preparing a Linux kernel for use on the FVPs with hotplug support can
be done as follows (GICv2 support only):
1. Clone Linux:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
The CPU hotplug features are not yet included in the mainline kernel. To use
these, add the patches from Mark Rutland's kernel, based on Linux 3.12-rc4:
cd linux
git remote add -f --tags markr git://linux-arm.org/linux-mr.git
git checkout -b hotplug arm64-cpu-hotplug-20131023
2. Build with the Linaro GCC tools.
# in linux/
make mrproper
make ARCH=arm64 defconfig
# Enable Hotplug
make ARCH=arm64 menuconfig
# Kernel Features ---> [*] Support for hot-pluggable CPUs
CROSS_COMPILE=/path/to/aarch64-none-elf- make -j6 ARCH=arm64
3. Copy the Linux image `arch/arm64/boot/Image` to the working directory from
where the FVP is launched. A symbolic link may also be created instead.
#### Obtaining the Flattened Device Trees
Depending on the FVP configuration and Linux configuration used, different
FDT files are required. FDTs for the Base FVP can be found in the Trusted
Firmware source directory under `fdts`.
* `fvp-base-gicv2-psci.dtb`
(Default) For use with both AEMv8 and Cortex-A57-A53 Base FVPs with
default memory map configuration.
* `fvp-base-gicv2legacy-psci.dtb`
For use with both AEMv8 and Cortex-A57-A53 Base FVPs with legacy GICv2
memory map configuration.
* `fvp-base-gicv3-psci.dtb`
For use with AEMv8 Base FVP with default memory map configuration and
Linux GICv3 support.
Copy the chosen FDT blob as `fdt.dtb` to the directory from which the FVP
is launched. A symbolic link may also be created instead.
#### Obtaining a File-system
To prepare a Linaro LAMP based Open Embedded file-system, the following
instructions can be used as a guide. The file-system can be provided to Linux
via VirtioBlock or as a RAM-disk. Both methods are described below.
##### Prepare VirtioBlock
To prepare a VirtioBlock file-system, do the following:
1. Download and unpack the disk image.
NOTE: The unpacked disk image grows to 2 GiB in size.
wget http://releases.linaro.org/13.09/openembedded/aarch64/vexpress64-openembedded_lamp-armv8_20130927-7.img.gz
gunzip vexpress64-openembedded_lamp-armv8_20130927-7.img.gz
2. Make sure the Linux kernel has Virtio support enabled using
`make ARCH=arm64 menuconfig`.
Device Drivers ---> Virtio drivers ---> <*> Platform bus driver for memory mapped virtio devices
Device Drivers ---> [*] Block devices ---> <*> Virtio block driver
File systems ---> <*> The Extended 4 (ext4) filesystem
If some of these configurations are missing, enable them, save the kernel
configuration, then rebuild the kernel image using the instructions provided
in the section "Obtaining a Linux kernel".
3. Change the Kernel command line to include `root=/dev/vda2`. This can either
be done in the EDK2 boot menu or in the platform file. Editing the platform
file and rebuilding EDK2 will make the change persist. To do this:
1. In EDK, edit the following file:
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-FVP-AArch64.dsc
2. Add `root=/dev/vda2` to:
gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|"<Other default options>"
3. Remove the entry:
gArmPlatformTokenSpaceGuid.PcdDefaultBootInitrdPath|""
4. Rebuild EDK2 (see "Obtaining UEFI" section above).
4. The file-system image file should be provided to the model environment by
passing it the correct command line option. In the Base FVP the following
option should be provided in addition to the ones described in the
"Running the software" section below.
NOTE: A symbolic link to this file cannot be used with the FVP; the path
to the real file must be provided.
-C bp.virtioblockdevice.image_path="<path/to/>vexpress64-openembedded_lamp-armv8_20130927-7.img"
5. Ensure that the FVP doesn't output any error messages. If the following
error message is displayed:
ERROR: BlockDevice: Failed to open "vexpress64-openembedded_lamp-armv8_20130927-7.img"!
then make sure the path to the file-system image in the model parameter is
correct and that read permission is correctly set on the file-system image
file.
##### Prepare RAM-disk
NOTE: The RAM-disk option does not currently work with the Linux kernel version
described above; use the VirtioBlock method instead. For further information
please see the "Known issues" section in the [Change Log].
To Prepare a RAM-disk file-system, do the following:
1. Download the file-system image:
wget http://releases.linaro.org/13.09/openembedded/aarch64/linaro-image-lamp-genericarmv8-20130912-487.rootfs.tar.gz
2. Modify the Linaro image:
# Prepare for use as RAM-disk. Normally use MMC, NFS or VirtioBlock.
# Be careful, otherwise you could damage your host file-system.
mkdir tmp; cd tmp
sudo sh -c "zcat ../linaro-image-lamp-genericarmv8-20130912-487.rootfs.tar.gz | cpio -id"
sudo ln -s sbin/init .
sudo ln -s S35mountall.sh etc/rcS.d/S03mountall.sh
sudo sh -c "echo 'devtmpfs /dev devtmpfs mode=0755,nosuid 0 0' >> etc/fstab"
sudo sh -c "find . | cpio --quiet -H newc -o | gzip -3 -n > ../filesystem.cpio.gz"
cd ..
3. Copy the resultant `filesystem.cpio.gz` to the directory where the FVP is
launched from. A symbolic link may also be created instead.
### Running the software
This release of the ARM Trusted Firmware has been tested on the following ARM
FVPs (64-bit versions only).
* `FVP_Base_AEMv8A-AEMv8A` (Version 5.1 build 8)
* `FVP_Base_Cortex-A57x4-A53x4` (Version 5.1 build 8)
Please refer to the FVP documentation for a detailed description of the model
parameter options. A brief description of the important ones that affect the
ARM Trusted Firmware and normal world software behavior is provided below.
#### Running on the AEMv8 Base FVP
The following `FVP_Base_AEMv8A-AEMv8A` parameters should be used to boot Linux
with 8 CPUs using the ARM Trusted Firmware.
NOTE: Using `cache_state_modelled=1` makes booting very slow. The software will
still work (and run much faster) without this option but this will hide any
cache maintenance defects in the software.
NOTE: Using the `-C bp.virtioblockdevice.image_path` parameter is not necessary
if a Linux RAM-disk file-system is used (see the "Obtaining a File-system"
section above).
FVP_Base_AEMv8A-AEMv8A \
-C pctl.startup=0.0.0.0 \
-C bp.secure_memory=0 \
-C cluster0.NUM_CORES=4 \
-C cluster1.NUM_CORES=4 \
-C cache_state_modelled=1 \
-C bp.pl011_uart0.untimed_fifos=1 \
-C bp.secureflashloader.fname=<path to bl1.bin> \
-C bp.flashloader0.fname=<path to UEFI binary> \
-C bp.virtioblockdevice.image_path="<path/to/>vexpress64-openembedded_lamp-armv8_20130927-7.img"
#### Running on the Cortex-A57-A53 Base FVP
The following `FVP_Base_Cortex-A57x4-A53x4` model parameters should be used to
boot Linux with 8 CPUs using the ARM Trusted Firmware.
NOTE: Using `cache_state_modelled=1` makes booting very slow. The software will
still work (and run much faster) without this option but this will hide any
cache maintenance defects in the software.
NOTE: Using the `-C bp.virtioblockdevice.image_path` parameter is not necessary
if a Linux RAM-disk file-system is used (see the "Obtaining a File-system"
section above).
FVP_Base_Cortex-A57x4-A53x4 \
-C pctl.startup=0.0.0.0 \
-C bp.secure_memory=0 \
-C cache_state_modelled=1 \
-C bp.pl011_uart0.untimed_fifos=1 \
-C bp.secureflashloader.fname=<path to bl1.bin> \
-C bp.flashloader0.fname=<path to UEFI binary> \
-C bp.virtioblockdevice.image_path="<path/to/>vexpress64-openembedded_lamp-armv8_20130927-7.img"
### Configuring the GICv2 memory map
The Base FVP models support GICv2 with the default model parameters at the
following addresses.
GICv2 Distributor Interface 0x2f000000
GICv2 CPU Interface 0x2c000000
GICv2 Virtual CPU Interface 0x2c010000
GICv2 Hypervisor Interface 0x2c02f000
The models can be configured to support GICv2 at addresses corresponding to the
legacy (Versatile Express) memory map as follows.
GICv2 Distributor Interface 0x2c001000
GICv2 CPU Interface 0x2c002000
GICv2 Virtual CPU Interface 0x2c004000
GICv2 Hypervisor Interface 0x2c006000
The choice of memory map is reflected in the build field (bits[15:12]) in the
`SYS_ID` register (Offset `0x0`) in the Versatile Express System registers
memory map (`0x1c010000`).
* `SYS_ID.Build[15:12]`
`0x1` corresponds to the presence of the default GICv2 memory map. This is
the default value.
* `SYS_ID.Build[15:12]`
`0x0` corresponds to the presence of the Legacy VE GICv2 memory map. This
value can be configured as described in the next section.
NOTE: If the legacy VE GICv2 memory map is used, then the corresponding FDT and
UEFI images should be used.
#### Configuring AEMv8 Base FVP for legacy VE memory map
The following parameters configure the GICv2 memory map in legacy VE mode:
NOTE: Using the `-C bp.virtioblockdevice.image_path` parameter is not necessary
if a Linux RAM-disk file-system is used (see the "Obtaining a File-system"
section above).
FVP_Base_AEMv8A-AEMv8A \
-C cluster0.gic.GICD-offset=0x1000 \
-C cluster0.gic.GICC-offset=0x2000 \
-C cluster0.gic.GICH-offset=0x4000 \
-C cluster0.gic.GICH-other-CPU-offset=0x5000 \
-C cluster0.gic.GICV-offset=0x6000 \
-C cluster0.gic.PERIPH-size=0x8000 \
-C cluster1.gic.GICD-offset=0x1000 \
-C cluster1.gic.GICC-offset=0x2000 \
-C cluster1.gic.GICH-offset=0x4000 \
-C cluster1.gic.GICH-other-CPU-offset=0x5000 \
-C cluster1.gic.GICV-offset=0x6000 \
-C cluster1.gic.PERIPH-size=0x8000 \
-C gic_distributor.GICD-alias=0x2c001000 \
-C bp.variant=0x0 \
-C bp.virtioblockdevice.image_path="<path/to/>vexpress64-openembedded_lamp-armv8_20130927-7.img"
The last parameter sets the build variant field of the `SYS_ID` register to
`0x0`. This allows the ARM Trusted Firmware to detect the legacy VE memory map
while configuring the GIC.
#### Configuring Cortex-A57-A53 Base FVP for legacy VE memory map
Configuration of the GICv2 as per the legacy VE memory map is controlled by
the following parameter. In this case, separate configuration of the `SYS_ID`
register is not required.
NOTE: Using the `-C bp.virtioblockdevice.image_path` parameter is not necessary
if a Linux RAM-disk file-system is used (see the "Obtaining a File-system"
section above).
FVP_Base_Cortex-A57x4-A53x4 \
-C legacy_gicv2_map=1 \
-C bp.virtioblockdevice.image_path="<path/to/>vexpress64-openembedded_lamp-armv8_20130927-7.img"
3. Firmware Design
-------------------
The cold boot path starts when the platform is physically turned on. One of
the CPUs released from reset is chosen as the primary CPU, and the remaining
CPUs are considered secondary CPUs. The primary CPU is chosen through
platform-specific means. The cold boot path is mainly executed by the primary
CPU, other than essential CPU initialization executed by all CPUs. The
secondary CPUs are kept in a safe platform-specific state until the primary
CPU has performed enough initialization to boot them.
The cold boot path in this implementation of the ARM Trusted Firmware is divided
into three stages (in order of execution):
* Boot Loader stage 1 (BL1)
* Boot Loader stage 2 (BL2)
* Boot Loader stage 3 (BL3-1). The '1' distinguishes this from other 3rd level
boot loader stages.
The ARM Fixed Virtual Platforms (FVPs) provide trusted ROM, trusted SRAM and
trusted DRAM regions. Each boot loader stage uses one or more of these
memories for its code and data.
### BL1
This stage begins execution from the platform's reset vector in trusted ROM at
EL3. BL1 code starts at `0x00000000` (trusted ROM) in the FVP memory map. The
BL1 data section is placed at the start of trusted SRAM, `0x04000000`. The
functionality implemented by this stage is as follows.
#### Determination of boot path
Whenever a CPU is released from reset, BL1 needs to distinguish between a warm
boot and a cold boot. This is done using a platform-specific mechanism. The
ARM FVPs implement a simple power controller at `0x1c100000`. The `PSYS`
register (`0x10`) is used to distinguish between a cold and warm boot. This
information is contained in the `PSYS.WK[25:24]` field. Additionally, a
per-CPU mailbox is maintained in trusted DRAM (`0x00600000`), to which BL1
writes an entrypoint. Each CPU jumps to this entrypoint upon warm boot. During
cold boot, BL1 places the secondary CPUs in a safe platform-specific state while
the primary CPU executes the remaining cold boot path as described in the
following sections.
#### Architectural initialization
BL1 performs minimal architectural initialization as follows.
* Exception vectors
BL1 sets up simple exception vectors for both synchronous and asynchronous
exceptions. The default behavior upon receiving an exception is to set a
status code. In the case of the FVP this code is written to the Versatile
Express System LED register in the following format:
SYS_LED[0] - Security state (Secure=0/Non-Secure=1)
SYS_LED[2:1] - Exception Level (EL3=0x3, EL2=0x2, EL1=0x1, EL0=0x0)
SYS_LED[7:3] - Exception Class (Sync/Async & origin). The values for
each exception class are:
0x0 : Synchronous exception from Current EL with SP_EL0
0x1 : IRQ exception from Current EL with SP_EL0
0x2 : FIQ exception from Current EL with SP_EL0
0x3 : System Error exception from Current EL with SP_EL0
0x4 : Synchronous exception from Current EL with SP_ELx
0x5 : IRQ exception from Current EL with SP_ELx
0x6 : FIQ exception from Current EL with SP_ELx
0x7 : System Error exception from Current EL with SP_ELx
0x8 : Synchronous exception from Lower EL using aarch64
0x9 : IRQ exception from Lower EL using aarch64
0xa : FIQ exception from Lower EL using aarch64
0xb : System Error exception from Lower EL using aarch64
0xc : Synchronous exception from Lower EL using aarch32
0xd : IRQ exception from Lower EL using aarch32
0xe : FIQ exception from Lower EL using aarch32
0xf : System Error exception from Lower EL using aarch32
A write to the LED register reflects in the System LEDs (S6LED0..7) in the
CLCD window of the FVP. This behavior is because this boot loader stage
does not expect to receive any exceptions other than the SMC exception.
For the latter, BL1 installs a simple stub. The stub expects to receive
only a single type of SMC (determined by its function ID in the general
purpose register `X0`). This SMC is raised by BL2 to make BL1 pass control
to BL3-1 (loaded by BL2) at EL3. Any other SMC leads to an assertion
failure.
* MMU setup
BL1 sets up EL3 memory translation by creating page tables to cover the
first 4GB of physical address space. This covers all the memories and
peripherals needed by BL1.
* Control register setup
- `SCTLR_EL3`. Instruction cache is enabled by setting the `SCTLR_EL3.I`
bit. Alignment and stack alignment checking is enabled by setting the
`SCTLR_EL3.A` and `SCTLR_EL3.SA` bits. Exception endianness is set to
little-endian by clearing the `SCTLR_EL3.EE` bit.
- `CPUECTLR`. When the FVP includes a model of a specific ARM processor
implementation (for example A57 or A53), then intra-cluster coherency is
enabled by setting the `CPUECTLR.SMPEN` bit. The AEMv8 Base FVP is
inherently coherent so does not implement `CPUECTLR`.
- `SCR`. Use of the HVC instruction from EL1 is enabled by setting the
`SCR.HCE` bit. FIQ exceptions are configured to be taken in EL3 by
setting the `SCR.FIQ` bit. The register width of the next lower
exception level is set to AArch64 by setting the `SCR.RW` bit.
- `CPTR_EL3`. Accesses to the `CPACR` from EL1 or EL2, or the `CPTR_EL2`
from EL2 are configured to not trap to EL3 by clearing the
`CPTR_EL3.TCPAC` bit. Instructions that access the registers associated
with Floating Point and Advanced SIMD execution are configured to not
trap to EL3 by clearing the `CPTR_EL3.TFP` bit.
- `CNTFRQ_EL0`. The `CNTFRQ_EL0` register is programmed with the base
frequency of the system counter, which is retrieved from the first entry
in the frequency modes table.
- Generic Timer. The system level implementation of the generic timer is
enabled through the memory mapped interface.
#### Platform initialization
BL1 enables issuing of snoop and DVM (Distributed Virtual Memory) requests from
the CCI-400 slave interface corresponding to the cluster that includes the
primary CPU. BL1 also initializes UART0 (PL011 console), which enables access to
the `printf` family of functions.
#### BL2 image load and execution
BL1 execution continues as follows:
1. BL1 determines the amount of free trusted SRAM memory available by
calculating the extent of its own data section, which also resides in
trusted SRAM. BL1 loads a BL2 raw binary image through semi-hosting, at a
platform-specific base address. The filename of the BL2 raw binary image on
the host file system must be `bl2.bin`. If the BL2 image file is not present
or if there is not enough free trusted SRAM the following error message
is printed:
"Failed to load boot loader stage 2 (BL2) firmware."
If the load is successful, BL1 updates the limits of the remaining free
trusted SRAM. It also populates information about the amount of trusted
SRAM used by the BL2 image. The exact load location of the image is
provided as a base address in the platform header. Further description of
the memory layout can be found later in this document.
2. BL1 prints the following string from the primary CPU to indicate successful
execution of the BL1 stage:
"Booting trusted firmware boot loader stage 1"
3. BL1 passes control to the BL2 image at Secure EL1, starting from its load
address.
4. BL1 also passes information about the amount of trusted SRAM used and
available for use. This information is populated at a platform-specific
memory address.
### BL2
BL1 loads and passes control to BL2 at Secure EL1. BL2 is linked against and
loaded at a platform-specific base address (more information can found later
in this document). The functionality implemented by BL2 is as follows.
#### Architectural initialization
BL2 performs minimal architectural initialization required for subsequent
stages of the ARM Trusted Firmware and normal world software. It sets up
Secure EL1 memory translation by creating page tables to address the first 4GB
of the physical address space in a similar way to BL1. EL1 and EL0 are given
access to Floating Point & Advanced SIMD registers by clearing the `CPACR.FPEN`
bits.
#### Platform initialization
BL2 does not perform any platform initialization that affects subsequent
stages of the ARM Trusted Firmware or normal world software. It copies the
information regarding the trusted SRAM populated by BL1 using a
platform-specific mechanism. It also calculates the limits of DRAM (main memory)
to determine whether there is enough space to load the normal world software
images. A platform defined base address is used to specify the load address for
the BL3-1 image.
#### Normal world image load
BL2 loads a rich boot firmware image (UEFI). The image executes in the normal
world. BL2 relies on BL3-1 to pass control to the normal world software image it
loads. Hence, BL2 populates a platform-specific area of memory with the
entrypoint and Current Program Status Register (`CPSR`) of the normal world
software image. The entrypoint is the load address of the normal world software
image. The `CPSR` is determined as specified in Section 5.13 of the [PSCI PDD]
[PSCI]. This information is passed to BL3-1.
##### UEFI firmware load
By default, BL2 assumes the UEFI image is present at the base of NOR flash0
(`0x08000000`), and arranges for BL3-1 to pass control to that location. As
mentioned earlier, BL2 populates platform-specific memory with the entrypoint
and `CPSR` of the UEFI image.
#### BL3-1 image load and execution
BL2 execution continues as follows:
1. BL2 loads the BL3-1 image into a platform-specific address in trusted SRAM.
This is done using semi-hosting. The image is identified by the file
`bl31.bin` on the host file-system. If there is not enough memory to load
the image or the image is missing it leads to an assertion failure. If the
BL3-1 image loads successfully, BL1 updates the amount of trusted SRAM used
and available for use by BL3-1. This information is populated at a
platform-specific memory address.
2. BL2 passes control back to BL1 by raising an SMC, providing BL1 with the
BL3-1 entrypoint. The exception is handled by the SMC exception handler
installed by BL1.
3. BL1 turns off the MMU and flushes the caches. It clears the
`SCTLR_EL3.M/I/C` bits, flushes the data cache to the point of coherency
and invalidates the TLBs.
4. BL1 passes control to BL3-1 at the specified entrypoint at EL3.
### BL3-1
The image for this stage is loaded by BL2 and BL1 passes control to BL3-1 at
EL3. BL3-1 executes solely in trusted SRAM. BL3-1 is linked against and
loaded at a platform-specific base address (more information can found later
in this document). The functionality implemented by BL3-1 is as follows.
#### Architectural initialization
Currently, BL3-1 performs a similar architectural initialization to BL1 as
far as system register settings are concerned. Since BL1 code resides in ROM,
architectural initialization in BL3-1 allows override of any previous
initialization done by BL1. BL3-1 creates page tables to address the first
4GB of physical address space and initializes the MMU accordingly. It replaces
the exception vectors populated by BL1 with its own. BL3-1 exception vectors
signal error conditions in the same way as BL1 does if an unexpected
exception is raised. They implement more elaborate support for handling SMCs
since this is the only mechanism to access the runtime services implemented by
BL3-1 (PSCI for example). BL3-1 checks each SMC for validity as specified by
the [SMC calling convention PDD][SMCCC] before passing control to the required
SMC handler routine.
#### Platform initialization
BL3-1 performs detailed platform initialization, which enables normal world
software to function correctly. It also retrieves entrypoint information for
the normal world software image loaded by BL2 from the platform defined
memory address populated by BL2.
* GICv2 initialization:
- Enable group0 interrupts in the GIC CPU interface.
- Configure group0 interrupts to be asserted as FIQs.
- Disable the legacy interrupt bypass mechanism.
- Configure the priority mask register to allow interrupts of all
priorities to be signaled to the CPU interface.
- Mark SGIs 8-15, the secure physical timer interrupt (#29) and the
trusted watchdog interrupt (#56) as group0 (secure).
- Target the trusted watchdog interrupt to CPU0.
- Enable these group0 interrupts in the GIC distributor.
- Configure all other interrupts as group1 (non-secure).
- Enable signaling of group0 interrupts in the GIC distributor.
* GICv3 initialization:
If a GICv3 implementation is available in the platform, BL3-1 initializes
the GICv3 in GICv2 emulation mode with settings as described for GICv2
above.
* Power management initialization:
BL3-1 implements a state machine to track CPU and cluster state. The state
can be one of `OFF`, `ON_PENDING`, `SUSPEND` or `ON`. All secondary CPUs are
initially in the `OFF` state. The cluster that the primary CPU belongs to is
`ON`; any other cluster is `OFF`. BL3-1 initializes the data structures that
implement the state machine, including the locks that protect them. BL3-1
accesses the state of a CPU or cluster immediately after reset and before
the MMU is enabled in the warm boot path. It is not currently possible to
use 'exclusive' based spinlocks, therefore BL3-1 uses locks based on
Lamport's Bakery algorithm instead. BL3-1 allocates these locks in device
memory. They are accessible irrespective of MMU state.
* Runtime services initialization:
The only runtime service implemented by BL3-1 is PSCI. The complete PSCI API
is not yet implemented. The following functions are currently implemented:
- `PSCI_VERSION`
- `CPU_OFF`
- `CPU_ON`
- `AFFINITY_INFO`
The `CPU_ON` and `CPU_OFF` functions implement the warm boot path in ARM
Trusted Firmware. These are the only functions which have been tested.
`AFFINITY_INFO` & `PSCI_VERSION` are present but completely untested in
this release.
Unsupported PSCI functions that can return, return the `NOT_SUPPORTED`
(`-1`) error code. Other unsupported PSCI functions that don't return,
signal an assertion failure.
BL3-1 returns the error code `-1` if an SMC is raised for any other runtime
service. This behavior is mandated by the [SMC calling convention PDD]
[SMCCC].
### Normal world software execution
BL3-1 uses the entrypoint information provided by BL2 to jump to the normal
world software image at the highest available Exception Level (EL2 if
available, otherwise EL1).
### Memory layout on Base FVP ###
The current implementation of the image loader has some limitations. It is
designed to load images dynamically, at a load address chosen to minimize memory
fragmentation. The chosen image location can be either at the top or the bottom
of free memory. However, until this feature is fully functional, the code also
contains support for loading images at a link-time fixed address. The code that
dynamically calculates the load address is bypassed and the load address is
specified statically by the platform.
BL1 is always loaded at address `0x0`. BL2 and BL3-1 are loaded at specified
locations in Trusted SRAM. The lack of dynamic image loader support means these
load addresses must currently be adjusted as the code grows. The individual
images must be linked against their ultimate runtime locations.
BL2 is loaded near the top of the Trusted SRAM. BL3-1 is loaded between BL1
and BL2. As a general rule, the following constraints must always be enforced:
1. `BL2_MAX_ADDR <= (<Top of Trusted SRAM>)`
2. `BL31_BASE >= BL1_MAX_ADDR`
3. `BL2_BASE >= BL31_MAX_ADDR`
Constraint 1 is enforced by BL2's linker script. If it is violated then the
linker will report an error while building BL2 to indicate that it doesn't
fit. For example:
aarch64-none-elf-ld: address 0x40400c8 of bl2.elf section `.bss' is not
within region `RAM'
This error means that the BL2 base address needs to be moved down. Be sure that
the new BL2 load address still obeys constraint 3.
Constraints 2 & 3 must currently be checked by hand. To ensure they are
enforced, first determine the maximum addresses used by BL1 and BL3-1. This can
be deduced from the link map files of the different images.
The BL1 link map file (`bl1.map`) gives these 2 values:
* `FIRMWARE_RAM_COHERENT_START`
* `FIRMWARE_RAM_COHERENT_SIZE`
The maximum address used by BL1 can then be easily determined:
BL1_MAX_ADDR = FIRMWARE_RAM_COHERENT_START + FIRMWARE_RAM_COHERENT_SIZE
The BL3-1 link map file (`bl31.map`) gives the following value:
* `BL31_DATA_STOP`. This is the the maximum address used by BL3-1.
The current implementation can result in wasted space because a simplified
`meminfo` structure represents the extents of free memory. For example, to load
BL2 at address `0x04020000`, the resulting memory layout should be as follows:
------------ 0x04040000
| | <- Free space (1)
|----------|
| BL2 |
|----------| BL2_BASE (0x0402D000)
| | <- Free space (2)
|----------|
| BL1 |
------------ 0x04000000
In the current implementation, we need to specify whether BL2 is loaded at the
top or bottom of the free memory. BL2 is top-loaded so in the example above,
the free space (1) above BL2 is hidden, resulting in the following view of
memory:
------------ 0x04040000
| |
| |
| BL2 |
|----------| BL2_BASE (0x0402D000)
| | <- Free space (2)
|----------|
| BL1 |
------------ 0x04000000
BL3-1 is bottom-loaded above BL1. For example, if BL3-1 is bottom-loaded at
`0x0400E000`, the memory layout should look like this:
------------ 0x04040000
| |
| |
| BL2 |
|----------| BL2_BASE (0x0402D000)
| | <- Free space (2)
| |
|----------|
| |
| BL31 |
|----------| BL31_BASE (0x0400E000)
| | <- Free space (3)
|----------|
| BL1 |
------------ 0x04000000
But the free space (3) between BL1 and BL3-1 is wasted, resulting in the
following view:
------------ 0x04040000
| |
| |
| BL2 |
|----------| BL2_BASE (0x0402D000)
| | <- Free space (2)
| |
|----------|
| |
| |
| BL31 | BL31_BASE (0x0400E000)
| |
|----------|
| BL1 |
------------ 0x04000000
### Code Structure ###
Trusted Firmware code is logically divided between the three boot loader
stages mentioned in the previous sections. The code is also divided into the
following categories (present as directories in the source code):
* **Architecture specific.** This could be AArch32 or AArch64.
* **Platform specific.** Choice of architecture specific code depends upon
the platform.
* **Common code.** This is platform and architecture agnostic code.
* **Library code.** This code comprises of functionality commonly used by all
other code.
* **Stage specific.** Code specific to a boot stage.
* **Drivers.**
Each boot loader stage uses code from one or more of the above mentioned
categories. Based upon the above, the code layout looks like this:
Directory Used by BL1? Used by BL2? Used by BL3?
bl1 Yes No No
bl2 No Yes No
bl31 No No Yes
arch Yes Yes Yes
plat Yes Yes Yes
drivers Yes No Yes
common Yes Yes Yes
lib Yes Yes Yes
All assembler files have the `.S` extension. The linker files for each boot
stage has the `.ld.S` extension. These are processed by GCC to create the
resultant `.ld` files used for linking.
FDTs provide a description of the hardware platform and is used by the Linux
kernel at boot time. These can be found in the `fdts` directory.
4. References
--------------
1. Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
under NDA through your ARM account representative.
2. [Power State Coordination Interface PDD (ARM DEN 0022B.b)][PSCI].
3. [SMC Calling Convention PDD (ARM DEN 0028A)][SMCCC].
- - - - - - - - - - - - - - - - - - - - - - - - - -
_Copyright (c) 2013 ARM Ltd. All rights reserved._
[Change Log]: change-log.md
[Linaro Toolchain]: http://releases.linaro.org/13.09/components/toolchain/binaries/
[EDK2]: http://sourceforge.net/projects/edk2/files/ARM/aarch64-uefi-rev14582.tgz/download
[DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022b/index.html "Power State Coordination Interface PDD (ARM DEN 0022B.b)"
[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <platform.h>
#include <cci400.h>
static inline unsigned long get_slave_iface_base(unsigned long mpidr)
{
return CCI400_BASE + SLAVE_IFACE_OFFSET(CCI400_SL_IFACE_INDEX(mpidr));
}
void cci_enable_coherency(unsigned long mpidr)
{
/* Enable Snoops and DVM messages */
mmio_write_32(get_slave_iface_base(mpidr) + SNOOP_CTRL_REG,
DVM_EN_BIT | SNOOP_EN_BIT);
/* Wait for the dust to settle down */
while (mmio_read_32(CCI400_BASE + STATUS_REG) & CHANGE_PENDING_BIT);
}
void cci_disable_coherency(unsigned long mpidr)
{
/* Disable Snoops and DVM messages */
mmio_write_32(get_slave_iface_base(mpidr) + SNOOP_CTRL_REG,
~(DVM_EN_BIT | SNOOP_EN_BIT));
/* Wait for the dust to settle down */
while (mmio_read_32(CCI400_BASE + STATUS_REG) & CHANGE_PENDING_BIT);
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __CCI_400_H__
#define __CCI_400_H__
/* Slave interface offsets from PERIPHBASE */
#define SLAVE_IFACE4_OFFSET 0x5000
#define SLAVE_IFACE3_OFFSET 0x4000
#define SLAVE_IFACE2_OFFSET 0x3000
#define SLAVE_IFACE1_OFFSET 0x2000
#define SLAVE_IFACE0_OFFSET 0x1000
#define SLAVE_IFACE_OFFSET(index) SLAVE_IFACE0_OFFSET + (0x1000 * index)
/* Control and ID register offsets */
#define CTRL_OVERRIDE_REG 0x0
#define SPEC_CTRL_REG 0x4
#define SECURE_ACCESS_REG 0x8
#define STATUS_REG 0xc
#define IMPRECISE_ERR_REG 0x10
#define PERFMON_CTRL_REG 0x100
/* Slave interface register offsets */
#define SNOOP_CTRL_REG 0x0
#define SH_OVERRIDE_REG 0x4
#define READ_CHNL_QOS_VAL_OVERRIDE_REG 0x100
#define WRITE_CHNL_QOS_VAL_OVERRIDE_REG 0x104
#define QOS_CTRL_REG 0x10c
#define MAX_OT_REG 0x110
#define TARGET_LATENCY_REG 0x130
#define LATENCY_REGULATION_REG 0x134
#define QOS_RANGE_REG 0x138
/* Snoop Control register bit definitions */
#define DVM_EN_BIT (1 << 1)
#define SNOOP_EN_BIT (1 << 0)
/* Status register bit definitions */
#define CHANGE_PENDING_BIT (1 << 0)
/* Function declarations */
extern void cci_enable_coherency(unsigned long mpidr);
extern void cci_disable_coherency(unsigned long mpidr);
#endif /* __CCI_400_H__ */

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
void console_init(void);
int console_putc(int c);
int console_getc(void);
#endif /* __CONSOLE_H__ */

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <console.h>
#include <platform.h>
#include <pl011.h>
/*
* TODO: Console init functions shoule be in a console.c. This file should
* only contain the pl011 accessors.
*/
void console_init(void)
{
unsigned int divisor;
/* Baud Rate */
#if defined(PL011_INTEGER) && defined(PL011_FRACTIONAL)
mmio_write_32(PL011_BASE + UARTIBRD, PL011_INTEGER);
mmio_write_32(PL011_BASE + UARTFBRD, PL011_FRACTIONAL);
#else
divisor = (PL011_CLK_IN_HZ * 4) / PL011_BAUDRATE;
mmio_write_32(PL011_BASE + UARTIBRD, divisor >> 6);
mmio_write_32(PL011_BASE + UARTFBRD, divisor & 0x3F);
#endif
mmio_write_32(PL011_BASE + UARTLCR_H, PL011_LINE_CONTROL);
/* Clear any pending errors */
mmio_write_32(PL011_BASE + UARTECR, 0);
/* Enable tx, rx, and uart overall */
mmio_write_32(PL011_BASE + UARTCR,
PL011_UARTCR_RXE | PL011_UARTCR_TXE |
PL011_UARTCR_UARTEN);
}
int console_putc(int c)
{
if (c == '\n') {
console_putc('\r');
}
while ((mmio_read_32(PL011_BASE + UARTFR) & PL011_UARTFR_TXFE)
== 0) ;
mmio_write_32(PL011_BASE + UARTDR, c);
return c;
}
int console_getc(void)
{
while ((mmio_read_32(PL011_BASE + UARTFR) & PL011_UARTFR_RXFE)
!= 0) ;
return mmio_read_32(PL011_BASE + UARTDR);
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PL011_H__
#define __PL011_H__
/* PL011 Registers */
#define UARTDR 0x000
#define UARTRSR 0x004
#define UARTECR 0x004
#define UARTFR 0x018
#define UARTILPR 0x020
#define UARTIBRD 0x024
#define UARTFBRD 0x028
#define UARTLCR_H 0x02C
#define UARTCR 0x030
#define UARTIFLS 0x034
#define UARTIMSC 0x038
#define UARTRIS 0x03C
#define UARTMIS 0x040
#define UARTICR 0x044
#define UARTDMACR 0x048
/* Data status bits */
#define UART_DATA_ERROR_MASK 0x0F00
/* Status reg bits */
#define UART_STATUS_ERROR_MASK 0x0F
/* Flag reg bits */
#define PL011_UARTFR_RI (1 << 8) /* Ring indicator */
#define PL011_UARTFR_TXFE (1 << 7) /* Transmit FIFO empty */
#define PL011_UARTFR_RXFF (1 << 6) /* Receive FIFO full */
#define PL011_UARTFR_TXFF (1 << 5) /* Transmit FIFO full */
#define PL011_UARTFR_RXFE (1 << 4) /* Receive FIFO empty */
#define PL011_UARTFR_BUSY (1 << 3) /* UART busy */
#define PL011_UARTFR_DCD (1 << 2) /* Data carrier detect */
#define PL011_UARTFR_DSR (1 << 1) /* Data set ready */
#define PL011_UARTFR_CTS (1 << 0) /* Clear to send */
/* Control reg bits */
#define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */
#define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */
#define PL011_UARTCR_RTS (1 << 11) /* Request to send */
#define PL011_UARTCR_DTR (1 << 10) /* Data transmit ready. */
#define PL011_UARTCR_RXE (1 << 9) /* Receive enable */
#define PL011_UARTCR_TXE (1 << 8) /* Transmit enable */
#define PL011_UARTCR_LBE (1 << 7) /* Loopback enable */
#define PL011_UARTCR_UARTEN (1 << 0) /* UART Enable */
#if !defined(PL011_BASE)
#error "The PL011_BASE macro must be defined."
#endif
#if !defined(PL011_BAUDRATE)
#define PL011_BAUDRATE 115200
#endif
#if !defined(PL011_CLK_IN_HZ)
#define PL011_CLK_IN_HZ 24000000
#endif
#if !defined(PL011_LINE_CONTROL)
/* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */
#define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8)
#endif
/* Line Control Register Bits */
#define PL011_UARTLCR_H_SPS (1 << 7) /* Stick parity select */
#define PL011_UARTLCR_H_WLEN_8 (3 << 5)
#define PL011_UARTLCR_H_WLEN_7 (2 << 5)
#define PL011_UARTLCR_H_WLEN_6 (1 << 5)
#define PL011_UARTLCR_H_WLEN_5 (0 << 5)
#define PL011_UARTLCR_H_FEN (1 << 4) /* FIFOs Enable */
#define PL011_UARTLCR_H_STP2 (1 << 3) /* Two stop bits select */
#define PL011_UARTLCR_H_EPS (1 << 2) /* Even parity select */
#define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */
#define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */
#endif /* __PL011_H__ */

103
drivers/power/fvp_pwrc.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <arch_helpers.h>
#include <platform.h>
#include <fvp_pwrc.h>
#include <bakery_lock.h>
/*
* TODO: Someday there will be a generic power controller api. At the moment
* each platform has its own pwrc so just exporting functions is fine.
*/
static bakery_lock pwrc_lock __attribute__ ((section("tzfw_coherent_mem")));
unsigned int fvp_pwrc_get_cpu_wkr(unsigned long mpidr)
{
unsigned int rc = 0;
bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr);
rc = PSYSR_WK(mmio_read_32(PWRC_BASE + PSYSR_OFF));
bakery_lock_release(mpidr, &pwrc_lock);
return rc;
}
unsigned int fvp_pwrc_read_psysr(unsigned long mpidr)
{
unsigned int rc = 0;
bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr);
rc = mmio_read_32(PWRC_BASE + PSYSR_OFF);
bakery_lock_release(mpidr, &pwrc_lock);
return rc;
}
void fvp_pwrc_write_pponr(unsigned long mpidr)
{
bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PPONR_OFF, (unsigned int) mpidr);
bakery_lock_release(mpidr, &pwrc_lock);
}
void fvp_pwrc_write_ppoffr(unsigned long mpidr)
{
bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PPOFFR_OFF, (unsigned int) mpidr);
bakery_lock_release(mpidr, &pwrc_lock);
}
void fvp_pwrc_write_pwkupr(unsigned long mpidr)
{
bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PWKUPR_OFF,
(unsigned int) (PWKUPR_WEN | mpidr));
bakery_lock_release(mpidr, &pwrc_lock);
}
void fvp_pwrc_write_pcoffr(unsigned long mpidr)
{
bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PCOFFR_OFF, (unsigned int) mpidr);
bakery_lock_release(mpidr, &pwrc_lock);
}
/* Nothing else to do here apart from initializing the lock */
int fvp_pwrc_setup(void)
{
bakery_lock_init(&pwrc_lock);
return 0;
}

76
drivers/power/fvp_pwrc.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FVP_PWRC_H__
#define __FVP_PWRC_H__
/* FVP Power controller register offset etc */
#define PPOFFR_OFF 0x0
#define PPONR_OFF 0x4
#define PCOFFR_OFF 0x8
#define PWKUPR_OFF 0xc
#define PSYSR_OFF 0x10
#define PWKUPR_WEN (1ull << 31)
#define PSYSR_AFF_L2 (1 << 31)
#define PSYSR_AFF_L1 (1 << 30)
#define PSYSR_AFF_L0 (1 << 29)
#define PSYSR_WEN (1 << 28)
#define PSYSR_PC (1 << 27)
#define PSYSR_PP (1 << 26)
#define PSYSR_WK_SHIFT 24
#define PSYSR_WK_MASK 0x3
#define PSYSR_WK(x) (x >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK
#define WKUP_COLD 0x0
#define WKUP_RESET 0x1
#define WKUP_PPONR 0x2
#define WKUP_GICREQ 0x3
#define PSYSR_INVALID 0xffffffff
#ifndef __ASSEMBLY__
/*******************************************************************************
* Function & variable prototypes
******************************************************************************/
extern int fvp_pwrc_setup(void);
extern void fvp_pwrc_write_pcoffr(unsigned long);
extern void fvp_pwrc_write_ppoffr(unsigned long);
extern void fvp_pwrc_write_pponr(unsigned long);
extern void fvp_pwrc_write_pwkupr(unsigned long);
extern unsigned int fvp_pwrc_read_psysr(unsigned long);
extern unsigned int fvp_pwrc_get_cpu_wkr(unsigned long);
#endif /*__ASSEMBLY__*/
#endif /* __FVP_PWRC_H__ */

Binary file not shown.

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/dts-v1/;
/memreserve/ 0x80000000 0x00010000;
/ {
};
/ {
model = "FVP Base";
compatible = "arm,vfp-base", "arm,vexpress";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
chosen { };
aliases {
serial0 = &v2m_serial0;
serial1 = &v2m_serial1;
serial2 = &v2m_serial2;
serial3 = &v2m_serial3;
};
psci {
compatible = "arm,psci";
method = "smc";
cpu_suspend = <0xc4000001>;
cpu_off = <0x84000002>;
cpu_on = <0xc4000003>;
};
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
};
cpu@1 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
};
cpu@2 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
};
cpu@3 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
};
cpu@100 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x100>;
enable-method = "psci";
};
cpu@101 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x101>;
enable-method = "psci";
};
cpu@102 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x102>;
enable-method = "psci";
};
cpu@103 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x103>;
enable-method = "psci";
};
};
memory@80000000 {
device_type = "memory";
reg = <0x00000000 0x80000000 0 0x80000000>;
/*
<0x00000008 0x80000000 0 0x80000000>;
*/
};
gic: interrupt-controller@2f000000 {
compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
reg = <0x0 0x2f000000 0 0x10000>,
<0x0 0x2c000000 0 0x2000>,
<0x0 0x2c010000 0 0x2000>,
<0x0 0x2c02F000 0 0x2000>;
interrupts = <1 9 0xf04>;
};
timer {
compatible = "arm,armv8-timer";
interrupts = <1 13 0xff01>,
<1 14 0xff01>,
<1 11 0xff01>,
<1 10 0xff01>;
clock-frequency = <100000000>;
};
timer@2a810000 {
compatible = "arm,armv7-timer-mem";
reg = <0x0 0x2a810000 0x0 0x10000>;
clock-frequency = <100000000>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
frame@2a820000 {
frame-number = <0>;
interrupts = <0 25 4>;
reg = <0x0 0x2a820000 0x0 0x10000>;
};
};
pmu {
compatible = "arm,armv8-pmuv3";
interrupts = <0 60 4>,
<0 61 4>,
<0 62 4>,
<0 63 4>;
};
smb {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0 0x08000000 0x04000000>,
<1 0 0 0x14000000 0x04000000>,
<2 0 0 0x18000000 0x04000000>,
<3 0 0 0x1c000000 0x04000000>,
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 63>;
interrupt-map = <0 0 0 &gic 0 0 4>,
<0 0 1 &gic 0 1 4>,
<0 0 2 &gic 0 2 4>,
<0 0 3 &gic 0 3 4>,
<0 0 4 &gic 0 4 4>,
<0 0 5 &gic 0 5 4>,
<0 0 6 &gic 0 6 4>,
<0 0 7 &gic 0 7 4>,
<0 0 8 &gic 0 8 4>,
<0 0 9 &gic 0 9 4>,
<0 0 10 &gic 0 10 4>,
<0 0 11 &gic 0 11 4>,
<0 0 12 &gic 0 12 4>,
<0 0 13 &gic 0 13 4>,
<0 0 14 &gic 0 14 4>,
<0 0 15 &gic 0 15 4>,
<0 0 16 &gic 0 16 4>,
<0 0 17 &gic 0 17 4>,
<0 0 18 &gic 0 18 4>,
<0 0 19 &gic 0 19 4>,
<0 0 20 &gic 0 20 4>,
<0 0 21 &gic 0 21 4>,
<0 0 22 &gic 0 22 4>,
<0 0 23 &gic 0 23 4>,
<0 0 24 &gic 0 24 4>,
<0 0 25 &gic 0 25 4>,
<0 0 26 &gic 0 26 4>,
<0 0 27 &gic 0 27 4>,
<0 0 28 &gic 0 28 4>,
<0 0 29 &gic 0 29 4>,
<0 0 30 &gic 0 30 4>,
<0 0 31 &gic 0 31 4>,
<0 0 32 &gic 0 32 4>,
<0 0 33 &gic 0 33 4>,
<0 0 34 &gic 0 34 4>,
<0 0 35 &gic 0 35 4>,
<0 0 36 &gic 0 36 4>,
<0 0 37 &gic 0 37 4>,
<0 0 38 &gic 0 38 4>,
<0 0 39 &gic 0 39 4>,
<0 0 40 &gic 0 40 4>,
<0 0 41 &gic 0 41 4>,
<0 0 42 &gic 0 42 4>;
/include/ "rtsm_ve-motherboard.dtsi"
};
panels {
panel@0 {
compatible = "panel";
mode = "XVGA";
refresh = <60>;
xres = <1024>;
yres = <768>;
pixclock = <15748>;
left_margin = <152>;
right_margin = <48>;
upper_margin = <23>;
lower_margin = <3>;
hsync_len = <104>;
vsync_len = <4>;
sync = <0>;
vmode = "FB_VMODE_NONINTERLACED";
tim2 = "TIM2_BCD", "TIM2_IPC";
cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
bpp = <16>;
};
};
};

Binary file not shown.

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/dts-v1/;
/memreserve/ 0x80000000 0x00010000;
/ {
};
/ {
model = "FVP Base";
compatible = "arm,vfp-base", "arm,vexpress";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
chosen { };
aliases {
serial0 = &v2m_serial0;
serial1 = &v2m_serial1;
serial2 = &v2m_serial2;
serial3 = &v2m_serial3;
};
psci {
compatible = "arm,psci";
method = "smc";
cpu_suspend = <0xc4000001>;
cpu_off = <0x84000002>;
cpu_on = <0xc4000003>;
};
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
};
cpu@1 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
};
cpu@2 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
};
cpu@3 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
};
cpu@100 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x100>;
enable-method = "psci";
};
cpu@101 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x101>;
enable-method = "psci";
};
cpu@102 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x102>;
enable-method = "psci";
};
cpu@103 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x103>;
enable-method = "psci";
};
};
memory@80000000 {
device_type = "memory";
reg = <0x00000000 0x80000000 0 0x80000000>;
/*
<0x00000008 0x80000000 0 0x80000000>;
*/
};
gic: interrupt-controller@2c001000 {
compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
reg = <0x0 0x2c001000 0 0x1000>,
<0x0 0x2c002000 0 0x1000>,
<0x0 0x2c004000 0 0x2000>,
<0x0 0x2c006000 0 0x2000>;
interrupts = <1 9 0xf04>;
};
timer {
compatible = "arm,armv8-timer";
interrupts = <1 13 0xff01>,
<1 14 0xff01>,
<1 11 0xff01>,
<1 10 0xff01>;
clock-frequency = <100000000>;
};
timer@2a810000 {
compatible = "arm,armv7-timer-mem";
reg = <0x0 0x2a810000 0x0 0x10000>;
clock-frequency = <100000000>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
frame@2a820000 {
frame-number = <0>;
interrupts = <0 25 4>;
reg = <0x0 0x2a820000 0x0 0x10000>;
};
};
pmu {
compatible = "arm,armv8-pmuv3";
interrupts = <0 60 4>,
<0 61 4>,
<0 62 4>,
<0 63 4>;
};
smb {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0 0x08000000 0x04000000>,
<1 0 0 0x14000000 0x04000000>,
<2 0 0 0x18000000 0x04000000>,
<3 0 0 0x1c000000 0x04000000>,
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 63>;
interrupt-map = <0 0 0 &gic 0 0 4>,
<0 0 1 &gic 0 1 4>,
<0 0 2 &gic 0 2 4>,
<0 0 3 &gic 0 3 4>,
<0 0 4 &gic 0 4 4>,
<0 0 5 &gic 0 5 4>,
<0 0 6 &gic 0 6 4>,
<0 0 7 &gic 0 7 4>,
<0 0 8 &gic 0 8 4>,
<0 0 9 &gic 0 9 4>,
<0 0 10 &gic 0 10 4>,
<0 0 11 &gic 0 11 4>,
<0 0 12 &gic 0 12 4>,
<0 0 13 &gic 0 13 4>,
<0 0 14 &gic 0 14 4>,
<0 0 15 &gic 0 15 4>,
<0 0 16 &gic 0 16 4>,
<0 0 17 &gic 0 17 4>,
<0 0 18 &gic 0 18 4>,
<0 0 19 &gic 0 19 4>,
<0 0 20 &gic 0 20 4>,
<0 0 21 &gic 0 21 4>,
<0 0 22 &gic 0 22 4>,
<0 0 23 &gic 0 23 4>,
<0 0 24 &gic 0 24 4>,
<0 0 25 &gic 0 25 4>,
<0 0 26 &gic 0 26 4>,
<0 0 27 &gic 0 27 4>,
<0 0 28 &gic 0 28 4>,
<0 0 29 &gic 0 29 4>,
<0 0 30 &gic 0 30 4>,
<0 0 31 &gic 0 31 4>,
<0 0 32 &gic 0 32 4>,
<0 0 33 &gic 0 33 4>,
<0 0 34 &gic 0 34 4>,
<0 0 35 &gic 0 35 4>,
<0 0 36 &gic 0 36 4>,
<0 0 37 &gic 0 37 4>,
<0 0 38 &gic 0 38 4>,
<0 0 39 &gic 0 39 4>,
<0 0 40 &gic 0 40 4>,
<0 0 41 &gic 0 41 4>,
<0 0 42 &gic 0 42 4>;
/include/ "rtsm_ve-motherboard.dtsi"
};
panels {
panel@0 {
compatible = "panel";
mode = "XVGA";
refresh = <60>;
xres = <1024>;
yres = <768>;
pixclock = <15748>;
left_margin = <152>;
right_margin = <48>;
upper_margin = <23>;
lower_margin = <3>;
hsync_len = <104>;
vsync_len = <4>;
sync = <0>;
vmode = "FB_VMODE_NONINTERLACED";
tim2 = "TIM2_BCD", "TIM2_IPC";
cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
bpp = <16>;
};
};
};

Binary file not shown.

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/dts-v1/;
/memreserve/ 0x80000000 0x00010000;
/ {
};
/ {
model = "FVP Base";
compatible = "arm,vfp-base", "arm,vexpress";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
chosen { };
aliases {
serial0 = &v2m_serial0;
serial1 = &v2m_serial1;
serial2 = &v2m_serial2;
serial3 = &v2m_serial3;
};
psci {
compatible = "arm,psci";
method = "smc";
cpu_suspend = <0xc4000001>;
cpu_off = <0x84000002>;
cpu_on = <0xc4000003>;
};
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
};
cpu@1 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
};
cpu@2 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
};
cpu@3 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
};
cpu@100 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x100>;
enable-method = "psci";
};
cpu@101 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x101>;
enable-method = "psci";
};
cpu@102 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x102>;
enable-method = "psci";
};
cpu@103 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <0x0 0x103>;
enable-method = "psci";
};
};
memory@80000000 {
device_type = "memory";
reg = <0x00000000 0x80000000 0 0x80000000>;
/*
<0x00000008 0x80000000 0 0x80000000>;
*/
};
gic: interrupt-controller@2cf00000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x0 0x2f000000 0 0x10000>, // GICD
<0x0 0x2f100000 0 0x200000>, // GICR
<0x0 0x2c000000 0 0x2000>, // GICC
<0x0 0x2c010000 0 0x2000>, // GICH
<0x0 0x2c02F000 0 0x2000>; // GICV
interrupts = <1 9 4>;
};
timer {
compatible = "arm,armv8-timer";
interrupts = <1 13 0xff01>,
<1 14 0xff01>,
<1 11 0xff01>,
<1 10 0xff01>;
clock-frequency = <100000000>;
};
timer@2a810000 {
compatible = "arm,armv7-timer-mem";
reg = <0x0 0x2a810000 0x0 0x10000>;
clock-frequency = <100000000>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
frame@2a820000 {
frame-number = <0>;
interrupts = <0 25 4>;
reg = <0x0 0x2a820000 0x0 0x10000>;
};
};
pmu {
compatible = "arm,armv8-pmuv3";
interrupts = <0 60 4>,
<0 61 4>,
<0 62 4>,
<0 63 4>;
};
smb {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0 0x08000000 0x04000000>,
<1 0 0 0x14000000 0x04000000>,
<2 0 0 0x18000000 0x04000000>,
<3 0 0 0x1c000000 0x04000000>,
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 63>;
interrupt-map = <0 0 0 &gic 0 0 4>,
<0 0 1 &gic 0 1 4>,
<0 0 2 &gic 0 2 4>,
<0 0 3 &gic 0 3 4>,
<0 0 4 &gic 0 4 4>,
<0 0 5 &gic 0 5 4>,
<0 0 6 &gic 0 6 4>,
<0 0 7 &gic 0 7 4>,
<0 0 8 &gic 0 8 4>,
<0 0 9 &gic 0 9 4>,
<0 0 10 &gic 0 10 4>,
<0 0 11 &gic 0 11 4>,
<0 0 12 &gic 0 12 4>,
<0 0 13 &gic 0 13 4>,
<0 0 14 &gic 0 14 4>,
<0 0 15 &gic 0 15 4>,
<0 0 16 &gic 0 16 4>,
<0 0 17 &gic 0 17 4>,
<0 0 18 &gic 0 18 4>,
<0 0 19 &gic 0 19 4>,
<0 0 20 &gic 0 20 4>,
<0 0 21 &gic 0 21 4>,
<0 0 22 &gic 0 22 4>,
<0 0 23 &gic 0 23 4>,
<0 0 24 &gic 0 24 4>,
<0 0 25 &gic 0 25 4>,
<0 0 26 &gic 0 26 4>,
<0 0 27 &gic 0 27 4>,
<0 0 28 &gic 0 28 4>,
<0 0 29 &gic 0 29 4>,
<0 0 30 &gic 0 30 4>,
<0 0 31 &gic 0 31 4>,
<0 0 32 &gic 0 32 4>,
<0 0 33 &gic 0 33 4>,
<0 0 34 &gic 0 34 4>,
<0 0 35 &gic 0 35 4>,
<0 0 36 &gic 0 36 4>,
<0 0 37 &gic 0 37 4>,
<0 0 38 &gic 0 38 4>,
<0 0 39 &gic 0 39 4>,
<0 0 40 &gic 0 40 4>,
<0 0 41 &gic 0 41 4>,
<0 0 42 &gic 0 42 4>;
/include/ "rtsm_ve-motherboard.dtsi"
};
panels {
panel@0 {
compatible = "panel";
mode = "XVGA";
refresh = <60>;
xres = <1024>;
yres = <768>;
pixclock = <15748>;
left_margin = <152>;
right_margin = <48>;
upper_margin = <23>;
lower_margin = <3>;
hsync_len = <104>;
vsync_len = <4>;
sync = <0>;
vmode = "FB_VMODE_NONINTERLACED";
tim2 = "TIM2_BCD", "TIM2_IPC";
cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
bpp = <16>;
};
};
};

View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
motherboard {
arm,v2m-memory-map = "rs1";
compatible = "arm,vexpress,v2m-p1", "simple-bus";
#address-cells = <2>; /* SMB chipselect number and offset */
#size-cells = <1>;
#interrupt-cells = <1>;
ranges;
flash@0,00000000 {
compatible = "arm,vexpress-flash", "cfi-flash";
reg = <0 0x00000000 0x04000000>,
<4 0x00000000 0x04000000>;
bank-width = <4>;
};
vram@2,00000000 {
compatible = "arm,vexpress-vram";
reg = <2 0x00000000 0x00800000>;
};
ethernet@2,02000000 {
compatible = "smsc,lan91c111";
reg = <2 0x02000000 0x10000>;
interrupts = <15>;
};
v2m_clk24mhz: clk24mhz {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
clock-output-names = "v2m:clk24mhz";
};
v2m_refclk1mhz: refclk1mhz {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000>;
clock-output-names = "v2m:refclk1mhz";
};
v2m_refclk32khz: refclk32khz {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
clock-output-names = "v2m:refclk32khz";
};
iofpga@3,00000000 {
compatible = "arm,amba-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 3 0 0x200000>;
v2m_sysreg: sysreg@010000 {
compatible = "arm,vexpress-sysreg";
reg = <0x010000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
};
v2m_sysctl: sysctl@020000 {
compatible = "arm,sp810", "arm,primecell";
reg = <0x020000 0x1000>;
clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
clock-names = "refclk", "timclk", "apb_pclk";
#clock-cells = <1>;
clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
};
aaci@040000 {
compatible = "arm,pl041", "arm,primecell";
reg = <0x040000 0x1000>;
interrupts = <11>;
clocks = <&v2m_clk24mhz>;
clock-names = "apb_pclk";
};
mmci@050000 {
compatible = "arm,pl180", "arm,primecell";
reg = <0x050000 0x1000>;
interrupts = <9 10>;
cd-gpios = <&v2m_sysreg 0 0>;
wp-gpios = <&v2m_sysreg 1 0>;
max-frequency = <12000000>;
vmmc-supply = <&v2m_fixed_3v3>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "mclk", "apb_pclk";
};
kmi@060000 {
compatible = "arm,pl050", "arm,primecell";
reg = <0x060000 0x1000>;
interrupts = <12>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "KMIREFCLK", "apb_pclk";
};
kmi@070000 {
compatible = "arm,pl050", "arm,primecell";
reg = <0x070000 0x1000>;
interrupts = <13>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "KMIREFCLK", "apb_pclk";
};
v2m_serial0: uart@090000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x090000 0x1000>;
interrupts = <5>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
v2m_serial1: uart@0a0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0a0000 0x1000>;
interrupts = <6>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
v2m_serial2: uart@0b0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0b0000 0x1000>;
interrupts = <7>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
v2m_serial3: uart@0c0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0c0000 0x1000>;
interrupts = <8>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
wdt@0f0000 {
compatible = "arm,sp805", "arm,primecell";
reg = <0x0f0000 0x1000>;
interrupts = <0>;
clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
clock-names = "wdogclk", "apb_pclk";
};
v2m_timer01: timer@110000 {
compatible = "arm,sp804", "arm,primecell";
reg = <0x110000 0x1000>;
interrupts = <2>;
clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
clock-names = "timclken1", "timclken2", "apb_pclk";
};
v2m_timer23: timer@120000 {
compatible = "arm,sp804", "arm,primecell";
reg = <0x120000 0x1000>;
interrupts = <3>;
clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
clock-names = "timclken1", "timclken2", "apb_pclk";
};
rtc@170000 {
compatible = "arm,pl031", "arm,primecell";
reg = <0x170000 0x1000>;
interrupts = <4>;
clocks = <&v2m_clk24mhz>;
clock-names = "apb_pclk";
};
clcd@1f0000 {
compatible = "arm,pl111", "arm,primecell";
reg = <0x1f0000 0x1000>;
interrupts = <14>;
clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
clock-names = "clcdclk", "apb_pclk";
mode = "XVGA";
use_dma = <0>;
framebuffer = <0x18000000 0x00180000>;
};
virtio_block@0130000 {
compatible = "virtio,mmio";
reg = <0x130000 0x1000>;
interrupts = <0x2a>;
};
};
v2m_fixed_3v3: fixedregulator@0 {
compatible = "regulator-fixed";
regulator-name = "3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
mcc {
compatible = "arm,vexpress,config-bus", "simple-bus";
arm,vexpress,config-bridge = <&v2m_sysreg>;
v2m_oscclk1: osc@1 {
/* CLCD clock */
compatible = "arm,vexpress-osc";
arm,vexpress-sysreg,func = <1 1>;
freq-range = <23750000 63500000>;
#clock-cells = <0>;
clock-output-names = "v2m:oscclk1";
};
reset@0 {
compatible = "arm,vexpress-reset";
arm,vexpress-sysreg,func = <5 0>;
};
muxfpga@0 {
compatible = "arm,vexpress-muxfpga";
arm,vexpress-sysreg,func = <7 0>;
};
shutdown@0 {
compatible = "arm,vexpress-shutdown";
arm,vexpress-sysreg,func = <8 0>;
};
reboot@0 {
compatible = "arm,vexpress-reboot";
arm,vexpress-sysreg,func = <9 0>;
};
dvimode@0 {
compatible = "arm,vexpress-dvimode";
arm,vexpress-sysreg,func = <11 0>;
};
};
};

315
include/aarch64/arch.h Normal file
View File

@ -0,0 +1,315 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_H__
#define __ARCH_H__
#include <bl_common.h>
/*******************************************************************************
* MIDR bit definitions
******************************************************************************/
#define MIDR_PN_MASK 0xfff
#define MIDR_PN_SHIFT 0x4
#define MIDR_PN_AEM 0xd0f
#define MIDR_PN_A57 0xd07
#define MIDR_PN_A53 0xd03
/*******************************************************************************
* MPIDR macros
******************************************************************************/
#define MPIDR_CPU_MASK MPIDR_AFFLVL_MASK
#define MPIDR_CLUSTER_MASK MPIDR_AFFLVL_MASK << MPIDR_AFFINITY_BITS
#define MPIDR_AFFINITY_BITS 8
#define MPIDR_AFFLVL_MASK 0xff
#define MPIDR_AFF0_SHIFT 0
#define MPIDR_AFF1_SHIFT 8
#define MPIDR_AFF2_SHIFT 16
#define MPIDR_AFF3_SHIFT 32
#define MPIDR_AFFINITY_MASK 0xff00ffffff
#define MPIDR_AFFLVL_SHIFT 3
#define MPIDR_AFFLVL0 0
#define MPIDR_AFFLVL1 1
#define MPIDR_AFFLVL2 2
#define MPIDR_AFFLVL3 3
/* TODO: Support only the first 3 affinity levels for now */
#define MPIDR_MAX_AFFLVL 2
/* Constant to highlight the assumption that MPIDR allocation starts from 0 */
#define FIRST_MPIDR 0
/*******************************************************************************
* Implementation defined sysreg encodings
******************************************************************************/
#define CPUECTLR_EL1 S3_1_C15_C2_1
/*******************************************************************************
* System register bit definitions
******************************************************************************/
/* CLIDR definitions */
#define LOUIS_SHIFT 21
#define LOC_SHIFT 24
#define CLIDR_FIELD_WIDTH 3
/* CSSELR definitions */
#define LEVEL_SHIFT 1
/* D$ set/way op type defines */
#define DCISW 0x0
#define DCCISW 0x1
#define DCCSW 0x2
/* ID_AA64PFR0_EL1 definitions */
#define ID_AA64PFR0_EL0_SHIFT 0
#define ID_AA64PFR0_EL1_SHIFT 4
#define ID_AA64PFR0_EL2_SHIFT 8
#define ID_AA64PFR0_EL3_SHIFT 12
#define ID_AA64PFR0_ELX_MASK 0xf
/* ID_PFR1_EL1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT 12
#define ID_PFR1_VIRTEXT_MASK 0xf
#define GET_VIRT_EXT(id) ((id >> ID_PFR1_VIRTEXT_SHIFT) \
& ID_PFR1_VIRTEXT_MASK)
/* SCTLR definitions */
#define SCTLR_EL2_RES1 ((1 << 29) | (1 << 28) | (1 << 23) | (1 << 22) | \
(1 << 18) | (1 << 16) | (1 << 11) | (1 << 5) | \
(1 << 4))
#define SCTLR_EL1_RES1 ((1 << 29) | (1 << 28) | (1 << 23) | (1 << 22) | \
(1 << 11))
#define SCTLR_M_BIT (1 << 0)
#define SCTLR_A_BIT (1 << 1)
#define SCTLR_C_BIT (1 << 2)
#define SCTLR_SA_BIT (1 << 3)
#define SCTLR_B_BIT (1 << 7)
#define SCTLR_Z_BIT (1 << 11)
#define SCTLR_I_BIT (1 << 12)
#define SCTLR_WXN_BIT (1 << 19)
#define SCTLR_EXCEPTION_BITS (0x3 << 6)
#define SCTLR_EE_BIT (1 << 25)
/* CPUECTLR definitions */
#define CPUECTLR_SMP_BIT (1 << 6)
/* CPACR_El1 definitions */
#define CPACR_EL1_FPEN(x) (x << 20)
#define CPACR_EL1_FP_TRAP_EL0 0x1
#define CPACR_EL1_FP_TRAP_ALL 0x2
#define CPACR_EL1_FP_TRAP_NONE 0x3
/* SCR definitions */
#define SCR_RES1_BITS ((1 << 4) | (1 << 5))
#define SCR_TWE_BIT (1 << 13)
#define SCR_TWI_BIT (1 << 12)
#define SCR_ST_BIT (1 << 11)
#define SCR_RW_BIT (1 << 10)
#define SCR_SIF_BIT (1 << 9)
#define SCR_HCE_BIT (1 << 8)
#define SCR_SMD_BIT (1 << 7)
#define SCR_EA_BIT (1 << 3)
#define SCR_FIQ_BIT (1 << 2)
#define SCR_IRQ_BIT (1 << 1)
#define SCR_NS_BIT (1 << 0)
/* HCR definitions */
#define HCR_RW_BIT (1ull << 31)
#define HCR_AMO_BIT (1 << 5)
#define HCR_IMO_BIT (1 << 4)
#define HCR_FMO_BIT (1 << 3)
/* CNTHCTL_EL2 definitions */
#define EL1PCEN_BIT (1 << 1)
#define EL1PCTEN_BIT (1 << 0)
/* CNTKCTL_EL1 definitions */
#define EL0PTEN_BIT (1 << 9)
#define EL0VTEN_BIT (1 << 8)
#define EL0PCTEN_BIT (1 << 0)
#define EL0VCTEN_BIT (1 << 1)
/* CPTR_EL3 definitions */
#define TCPAC_BIT (1ull << 31)
#define TFP_BIT (1 << 10)
/* CPSR/SPSR definitions */
#define DAIF_FIQ_BIT (1 << 0)
#define DAIF_IRQ_BIT (1 << 1)
#define DAIF_ABT_BIT (1 << 2)
#define DAIF_DBG_BIT (1 << 3)
#define PSR_DAIF_SHIFT 0x6
/*
* TCR defintions
*/
#define TCR_EL3_RES1 ((1UL << 31) | (1UL << 23))
#define TCR_T0SZ_4GB 32
#define TCR_RGN_INNER_NC (0x0 << 8)
#define TCR_RGN_INNER_WBA (0x1 << 8)
#define TCR_RGN_INNER_WT (0x2 << 8)
#define TCR_RGN_INNER_WBNA (0x3 << 8)
#define TCR_RGN_OUTER_NC (0x0 << 10)
#define TCR_RGN_OUTER_WBA (0x1 << 10)
#define TCR_RGN_OUTER_WT (0x2 << 10)
#define TCR_RGN_OUTER_WBNA (0x3 << 10)
#define TCR_SH_NON_SHAREABLE (0x0 << 12)
#define TCR_SH_OUTER_SHAREABLE (0x2 << 12)
#define TCR_SH_INNER_SHAREABLE (0x3 << 12)
#define MODE_RW_64 0x0
#define MODE_RW_32 0x1
#define MODE_SP_EL0 0x0
#define MODE_SP_ELX 0x1
#define MODE_EL3 0x3
#define MODE_EL2 0x2
#define MODE_EL1 0x1
#define MODE_EL0 0x0
#define MODE_RW_SHIFT 0x4
#define MODE_EL_SHIFT 0x2
#define MODE_SP_SHIFT 0x0
#define GET_RW(mode) ((mode >> MODE_RW_SHIFT) & 0x1)
#define GET_EL(mode) ((mode >> MODE_EL_SHIFT) & 0x3)
#define GET_SP(mode) ((mode >> MODE_SP_SHIFT) & 0x1)
#define PSR_MODE(rw, el, sp) (rw << MODE_RW_SHIFT | el << MODE_EL_SHIFT \
| sp << MODE_SP_SHIFT)
#define SPSR32_EE_BIT (1 << 9)
#define SPSR32_T_BIT (1 << 5)
#define AARCH32_MODE_SVC 0x13
#define AARCH32_MODE_HYP 0x1a
/* Miscellaneous MMU related constants */
#define NUM_2MB_IN_GB (1 << 9)
#define NUM_4K_IN_2MB (1 << 9)
#define TWO_MB_SHIFT 21
#define ONE_GB_SHIFT 30
#define FOUR_KB_SHIFT 12
#define ONE_GB_INDEX(x) ((x) >> ONE_GB_SHIFT)
#define TWO_MB_INDEX(x) ((x) >> TWO_MB_SHIFT)
#define FOUR_KB_INDEX(x) ((x) >> FOUR_KB_SHIFT)
#define INVALID_DESC 0x0
#define BLOCK_DESC 0x1
#define TABLE_DESC 0x3
#define FIRST_LEVEL_DESC_N ONE_GB_SHIFT
#define SECOND_LEVEL_DESC_N TWO_MB_SHIFT
#define THIRD_LEVEL_DESC_N FOUR_KB_SHIFT
#define LEVEL1 1
#define LEVEL2 2
#define LEVEL3 3
#define XN (1ull << 2)
#define PXN (1ull << 1)
#define CONT_HINT (1ull << 0)
#define UPPER_ATTRS(x) (x & 0x7) << 52
#define NON_GLOBAL (1 << 9)
#define ACCESS_FLAG (1 << 8)
#define NSH (0x0 << 6)
#define OSH (0x2 << 6)
#define ISH (0x3 << 6)
/*
* AP[1] bit is ignored by hardware and is
* treated as if it is One in EL2/EL3
*/
#define AP_RO (0x1 << 5)
#define AP_RW (0x0 << 5)
#define NS (0x1 << 3)
#define ATTR_SO_INDEX 0x2
#define ATTR_DEVICE_INDEX 0x1
#define ATTR_IWBWA_OWBWA_NTR_INDEX 0x0
#define LOWER_ATTRS(x) (((x) & 0xfff) << 2)
#define ATTR_SO (0x0)
#define ATTR_DEVICE (0x4)
#define ATTR_IWBWA_OWBWA_NTR (0xff)
#define MAIR_ATTR_SET(attr, index) (attr << (index << 3))
/* Exception Syndrome register bits and bobs */
#define ESR_EC_SHIFT 26
#define ESR_EC_MASK 0x3f
#define ESR_EC_LENGTH 6
#define EC_UNKNOWN 0x0
#define EC_WFE_WFI 0x1
#define EC_AARCH32_CP15_MRC_MCR 0x3
#define EC_AARCH32_CP15_MRRC_MCRR 0x4
#define EC_AARCH32_CP14_MRC_MCR 0x5
#define EC_AARCH32_CP14_LDC_STC 0x6
#define EC_FP_SIMD 0x7
#define EC_AARCH32_CP10_MRC 0x8
#define EC_AARCH32_CP14_MRRC_MCRR 0xc
#define EC_ILLEGAL 0xe
#define EC_AARCH32_SVC 0x11
#define EC_AARCH32_HVC 0x12
#define EC_AARCH32_SMC 0x13
#define EC_AARCH64_SVC 0x15
#define EC_AARCH64_HVC 0x16
#define EC_AARCH64_SMC 0x17
#define EC_AARCH64_SYS 0x18
#define EC_IABORT_LOWER_EL 0x20
#define EC_IABORT_CUR_EL 0x21
#define EC_PC_ALIGN 0x22
#define EC_DABORT_LOWER_EL 0x24
#define EC_DABORT_CUR_EL 0x25
#define EC_SP_ALIGN 0x26
#define EC_AARCH32_FP 0x28
#define EC_AARCH64_FP 0x2c
#define EC_SERROR 0x2f
#define EC_BITS(x) (x >> ESR_EC_SHIFT) & ESR_EC_MASK
#ifndef __ASSEMBLY__
/*******************************************************************************
* Function prototypes
******************************************************************************/
extern void early_exceptions(void);
extern void runtime_exceptions(void);
extern void bl1_arch_setup(void);
extern void bl2_arch_setup(void);
extern void bl31_arch_setup(void);
#endif /*__ASSEMBLY__*/
#endif /* __ARCH_H__ */

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_HELPERS_H__
#define __ARCH_HELPERS_H__
#include <arch.h>
/*******************************************************************************
* Generic timer memory mapped registers & offsets
******************************************************************************/
#define CNTCR_OFF 0x000
#define CNTFID_OFF 0x020
#define CNTCR_EN (1 << 0)
#define CNTCR_HDBG (1 << 1)
#define CNTCR_FCREQ(x) (1 << (8 + (x)))
#ifndef __ASSEMBLY__
/*******************************************************************************
* TLB maintenance accessor prototypes
******************************************************************************/
extern void tlbiall(void);
extern void tlbiallis(void);
extern void tlbialle1(void);
extern void tlbialle1is(void);
extern void tlbialle2(void);
extern void tlbialle2is(void);
extern void tlbialle3(void);
extern void tlbialle3is(void);
extern void tlbivmalle1(void);
/*******************************************************************************
* Cache maintenance accessor prototypes
******************************************************************************/
extern void dcisw(unsigned long);
extern void dccisw(unsigned long);
extern void dccsw(unsigned long);
extern void dccvac(unsigned long);
extern void dcivac(unsigned long);
extern void dccivac(unsigned long);
extern void dccvau(unsigned long);
extern void dczva(unsigned long);
extern void flush_dcache_range(unsigned long, unsigned long);
extern void inv_dcache_range(unsigned long, unsigned long);
extern void dcsw_op_louis(unsigned int);
extern void dcsw_op_all(unsigned int);
/*******************************************************************************
* Misc. accessor prototypes
******************************************************************************/
extern void enable_irq(void);
extern void enable_fiq(void);
extern void enable_serror(void);
extern void disable_irq(void);
extern void disable_fiq(void);
extern void disable_serror(void);
extern unsigned long read_id_pfr1_el1(void);
extern unsigned long read_id_aa64pfr0_el1(void);
extern unsigned long read_current_el(void);
extern unsigned long read_daif(void);
extern unsigned long read_spsr(void);
extern unsigned long read_spsr_el1(void);
extern unsigned long read_spsr_el2(void);
extern unsigned long read_spsr_el3(void);
extern unsigned long read_elr(void);
extern unsigned long read_elr_el1(void);
extern unsigned long read_elr_el2(void);
extern unsigned long read_elr_el3(void);
extern void write_daif(unsigned long);
extern void write_spsr(unsigned long);
extern void write_spsr_el1(unsigned long);
extern void write_spsr_el2(unsigned long);
extern void write_spsr_el3(unsigned long);
extern void write_elr(unsigned long);
extern void write_elr_el1(unsigned long);
extern void write_elr_el2(unsigned long);
extern void write_elr_el3(unsigned long);
extern void wfi(void);
extern void wfe(void);
extern void rfe(void);
extern void sev(void);
extern void dsb(void);
extern void isb(void);
extern unsigned int get_afflvl_shift(unsigned int);
extern unsigned int mpidr_mask_lower_afflvls(unsigned long, unsigned int);
extern void eret(unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned long, unsigned long);
extern unsigned long smc(unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned long, unsigned long);
/*******************************************************************************
* System register accessor prototypes
******************************************************************************/
extern unsigned long read_midr(void);
extern unsigned long read_mpidr(void);
extern unsigned long read_scr(void);
extern unsigned long read_hcr(void);
extern unsigned long read_vbar(void);
extern unsigned long read_vbar_el1(void);
extern unsigned long read_vbar_el2(void);
extern unsigned long read_vbar_el3(void);
extern unsigned long read_sctlr(void);
extern unsigned long read_sctlr_el1(void);
extern unsigned long read_sctlr_el2(void);
extern unsigned long read_sctlr_el3(void);
extern unsigned long read_actlr(void);
extern unsigned long read_actlr_el1(void);
extern unsigned long read_actlr_el2(void);
extern unsigned long read_actlr_el3(void);
extern unsigned long read_esr(void);
extern unsigned long read_esr_el1(void);
extern unsigned long read_esr_el2(void);
extern unsigned long read_esr_el3(void);
extern unsigned long read_afsr0(void);
extern unsigned long read_afsr0_el1(void);
extern unsigned long read_afsr0_el2(void);
extern unsigned long read_afsr0_el3(void);
extern unsigned long read_afsr1(void);
extern unsigned long read_afsr1_el1(void);
extern unsigned long read_afsr1_el2(void);
extern unsigned long read_afsr1_el3(void);
extern unsigned long read_far(void);
extern unsigned long read_far_el1(void);
extern unsigned long read_far_el2(void);
extern unsigned long read_far_el3(void);
extern unsigned long read_mair(void);
extern unsigned long read_mair_el1(void);
extern unsigned long read_mair_el2(void);
extern unsigned long read_mair_el3(void);
extern unsigned long read_amair(void);
extern unsigned long read_amair_el1(void);
extern unsigned long read_amair_el2(void);
extern unsigned long read_amair_el3(void);
extern unsigned long read_rvbar(void);
extern unsigned long read_rvbar_el1(void);
extern unsigned long read_rvbar_el2(void);
extern unsigned long read_rvbar_el3(void);
extern unsigned long read_rmr(void);
extern unsigned long read_rmr_el1(void);
extern unsigned long read_rmr_el2(void);
extern unsigned long read_rmr_el3(void);
extern unsigned long read_tcr(void);
extern unsigned long read_tcr_el1(void);
extern unsigned long read_tcr_el2(void);
extern unsigned long read_tcr_el3(void);
extern unsigned long read_ttbr0(void);
extern unsigned long read_ttbr0_el1(void);
extern unsigned long read_ttbr0_el2(void);
extern unsigned long read_ttbr0_el3(void);
extern unsigned long read_ttbr1(void);
extern unsigned long read_ttbr1_el1(void);
extern unsigned long read_ttbr1_el2(void);
extern unsigned long read_cptr(void);
extern unsigned long read_cptr_el2(void);
extern unsigned long read_cptr_el3(void);
extern unsigned long read_cpacr(void);
extern unsigned long read_cpuectlr(void);
extern unsigned int read_cntfrq_el0(void);
extern unsigned long read_cnthctl_el2(void);
extern void write_scr(unsigned long);
extern void write_hcr(unsigned long);
extern void write_cpacr(unsigned long);
extern void write_cntfrq_el0(unsigned int);
extern void write_cnthctl_el2(unsigned long);
extern void write_vbar(unsigned long);
extern void write_vbar_el1(unsigned long);
extern void write_vbar_el2(unsigned long);
extern void write_vbar_el3(unsigned long);
extern void write_sctlr(unsigned long);
extern void write_sctlr_el1(unsigned long);
extern void write_sctlr_el2(unsigned long);
extern void write_sctlr_el3(unsigned long);
extern void write_actlr(unsigned long);
extern void write_actlr_el1(unsigned long);
extern void write_actlr_el2(unsigned long);
extern void write_actlr_el3(unsigned long);
extern void write_esr(unsigned long);
extern void write_esr_el1(unsigned long);
extern void write_esr_el2(unsigned long);
extern void write_esr_el3(unsigned long);
extern void write_afsr0(unsigned long);
extern void write_afsr0_el1(unsigned long);
extern void write_afsr0_el2(unsigned long);
extern void write_afsr0_el3(unsigned long);
extern void write_afsr1(unsigned long);
extern void write_afsr1_el1(unsigned long);
extern void write_afsr1_el2(unsigned long);
extern void write_afsr1_el3(unsigned long);
extern void write_far(unsigned long);
extern void write_far_el1(unsigned long);
extern void write_far_el2(unsigned long);
extern void write_far_el3(unsigned long);
extern void write_mair(unsigned long);
extern void write_mair_el1(unsigned long);
extern void write_mair_el2(unsigned long);
extern void write_mair_el3(unsigned long);
extern void write_amair(unsigned long);
extern void write_amair_el1(unsigned long);
extern void write_amair_el2(unsigned long);
extern void write_amair_el3(unsigned long);
extern void write_rmr(unsigned long);
extern void write_rmr_el1(unsigned long);
extern void write_rmr_el2(unsigned long);
extern void write_rmr_el3(unsigned long);
extern void write_tcr(unsigned long);
extern void write_tcr_el1(unsigned long);
extern void write_tcr_el2(unsigned long);
extern void write_tcr_el3(unsigned long);
extern void write_ttbr0(unsigned long);
extern void write_ttbr0_el1(unsigned long);
extern void write_ttbr0_el2(unsigned long);
extern void write_ttbr0_el3(unsigned long);
extern void write_ttbr1(unsigned long);
extern void write_ttbr1_el1(unsigned long);
extern void write_ttbr1_el2(unsigned long);
extern void write_cptr(unsigned long);
extern void write_cpuectlr(unsigned long);
extern void write_cptr_el2(unsigned long);
extern void write_cptr_el3(unsigned long);
#endif /*__ASSEMBLY__*/
#endif /* __ARCH_HELPERS_H__ */

82
include/asm_macros.S Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
.macro func_prologue
stp x29, x30, [sp, #-0x10]!
mov x29,sp
.endm
.macro func_epilogue
ldp x29, x30, [sp], #0x10
.endm
.macro dcache_line_size reg, tmp
mrs \tmp, ctr_el0
ubfx \tmp, \tmp, #16, #4
mov \reg, #4
lsl \reg, \reg, \tmp
.endm
.macro icache_line_size reg, tmp
mrs \tmp, ctr_el0
and \tmp, \tmp, #0xf
mov \reg, #4
lsl \reg, \reg, \tmp
.endm
.macro exception_entry func
stp x29, x30, [sp, #-0x10]!
bl \func
.endm
.macro exception_exit func
bl \func
ldp x29, x30, [sp], #0x10
.endm
.macro smc_check label
bl read_esr
ubfx x0, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH
cmp x0, #EC_AARCH64_SMC
b.ne $label
.endm
.macro setup_dcsw_op_args start_level, end_level, clidr, shift, fw, ls
mrs \clidr, clidr_el1
mov \start_level, xzr
ubfx \end_level, \clidr, \shift, \fw
lsl \end_level, \end_level, \ls
.endm

55
include/bakery_lock.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BAKERY_LOCK_H__
#define __BAKERY_LOCK_H__
#include <platform.h>
#define BAKERY_LOCK_MAX_CPUS PLATFORM_CORE_COUNT
#ifndef __ASSEMBLY__
typedef struct {
volatile int owner;
volatile char entering[BAKERY_LOCK_MAX_CPUS];
volatile unsigned number[BAKERY_LOCK_MAX_CPUS];
} bakery_lock;
#define NO_OWNER (-1)
void bakery_lock_init(bakery_lock* bakery);
/* Check whether a lock is held. Mainly used for debug purpose. */
int bakery_lock_held(unsigned long mpidr, const bakery_lock * bakery);
void bakery_lock_get(unsigned long mpidr, bakery_lock* bakery);
void bakery_lock_release(unsigned long mpidr, bakery_lock* bakery);
int bakery_lock_try(unsigned long mpidr, bakery_lock* bakery);
#endif /*__ASSEMBLY__*/
#endif /* __BAKERY_LOCK_H__ */

52
include/bl1.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BL1_H__
#define __BL1_H__
#include <bl_common.h>
/******************************************************************************
* Function ID of the only SMC that the BL1 exception handlers service.
* The chosen value is the first function ID of the ARM SMC64 range.
*****************************************************************************/
#define RUN_IMAGE 0xC0000000
#ifndef __ASSEMBLY__
/******************************************
* Function prototypes
*****************************************/
extern void bl1_platform_setup(void);
extern meminfo bl1_get_sec_mem_layout(void);
#endif /*__ASSEMBLY__*/
#endif /* __BL1_H__ */

48
include/bl2.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BL2_H__
#define __BL2_H__
#include <bl_common.h>
/******************************************
* Data declarations
*****************************************/
extern unsigned long long bl2_entrypoint;
/******************************************
* Function prototypes
*****************************************/
extern void bl2_platform_setup(void);
extern meminfo bl2_get_sec_mem_layout(void);
extern meminfo bl2_get_ns_mem_layout(void);
#endif /* __BL2_H__ */

51
include/bl31.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BL31_H__
#define __BL31_H__
#include <bl_common.h>
/*******************************************************************************
* Data declarations
******************************************************************************/
extern unsigned long bl31_entrypoint;
/*******************************************************************************
* Function prototypes
******************************************************************************/
extern void bl31_platform_setup(void);
extern meminfo bl31_get_sec_mem_layout(void);
extern el_change_info* bl31_get_next_image_info(unsigned long);
extern void gic_cpuif_deactivate(unsigned int);
extern void gic_cpuif_setup(unsigned int);
extern void gic_pcpu_distif_setup(unsigned int);
extern void gic_setup(void);
#endif /* __BL31_H__ */

134
include/bl_common.h Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BL_COMMON_H__
#define __BL_COMMON_H__
#define SECURE 0
#define NON_SECURE 1
#define UP 1
#define DOWN 0
/*******************************************************************************
* Constants for loading images. When BLx wants to load BLy, it looks at a
* meminfo structure to find the extents of free memory. Then depending upon
* how it has been configured, it can either load BLy at the top or bottom of
* the free memory. These constants indicate the choice.
* TODO: Make this configurable while building the trusted firmware.
******************************************************************************/
#define TOP_LOAD 0x1
#define BOT_LOAD !TOP_LOAD
#define LOAD_MASK (1 << 0)
/*******************************************************************************
* Size of memory for sharing data while changing exception levels.
*
* There are 2 cases where this memory buffer is used:
*
* - when BL1 (running in EL3) passes control to BL2 (running in S-EL1).
* BL1 needs to pass the memory layout to BL2, to allow BL2 to find out
* how much free trusted ram remains;
*
* - when BL2 (running in S-EL1) passes control back to BL1 (running in EL3)
* to make it run BL31. BL2 needs to pass the memory layout, as well as
* information on how to pass control to the non-trusted software image.
******************************************************************************/
#define EL_CHANGE_MEM_SIZE (sizeof(meminfo) + sizeof(el_change_info))
#ifndef __ASSEMBLY__
/*******************************************************************************
* Structure used for telling the next BL how much of a particular type of
* memory is available for its use and how much is already used.
******************************************************************************/
typedef struct {
unsigned long total_base;
long total_size;
unsigned long free_base;
long free_size;
unsigned long attr;
unsigned long next;
} meminfo;
typedef struct {
unsigned long arg0;
unsigned long arg1;
unsigned long arg2;
unsigned long arg3;
unsigned long arg4;
unsigned long arg5;
unsigned long arg6;
unsigned long arg7;
} aapcs64_params;
/*******************************************************************************
* This structure represents the superset of information needed while switching
* exception levels. The only two mechanisms to do so are ERET & SMC. In case of
* SMC all members apart from 'aapcs64_params' will be ignored. The 'next'
* member is a placeholder for a complicated case in the distant future when BL2
* will load multiple BL3x images as well as a non-secure image. So multiple
* such structures will have to be passed to BL31 in S-EL3.
******************************************************************************/
typedef struct {
unsigned long entrypoint;
unsigned long spsr;
unsigned long security_state;
aapcs64_params args;
unsigned long next;
} el_change_info;
/*******************************************************************************
* Function & variable prototypes
******************************************************************************/
extern unsigned long page_align(unsigned long, unsigned);
extern void change_security_state(unsigned int);
extern int drop_el(aapcs64_params *, unsigned long, unsigned long);
extern long raise_el(aapcs64_params *);
extern long change_el(el_change_info *);
extern unsigned long make_spsr(unsigned long, unsigned long, unsigned long);
extern void init_bl2_mem_layout(meminfo *,
meminfo *,
unsigned int,
unsigned long) __attribute__((weak));
extern void init_bl31_mem_layout(const meminfo *,
meminfo *,
unsigned int) __attribute__((weak));
extern unsigned long load_image(meminfo *, const char *, unsigned int, unsigned long);
extern int run_image(unsigned long,
unsigned long,
unsigned long,
meminfo *,
void *);
extern unsigned long *get_el_change_mem_ptr(void);
#endif /*__ASSEMBLY__*/
#endif /* __BL_COMMON_H__ */

43
include/mmio.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MMIO_H__
#define __MMIO_H__
#ifndef __ASSEMBLY__
#include <stdint.h>
extern void mmio_write_32(uintptr_t addr, uint32_t value);
extern uint32_t mmio_read_32(uintptr_t addr);
#endif /*__ASSEMBLY__*/
#endif /* __MMIO_H__ */

66
include/pm.h Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PM_H__
#define __PM_H__
#ifndef __ASSEMBLY__
/*******************************************************************************
* Structure populated by platform specific code to export routines which
* perform common low level pm functions
******************************************************************************/
typedef struct {
int (*cpu_on)(unsigned long);
int (*cpu_off)(unsigned long);
int (*cpu_suspend)(unsigned long);
int (*affinity_info)(unsigned long, unsigned int);
} pm_frontend_ops;
/*******************************************************************************
* Structure populated by a generic power management api implementation e.g.
* psci to perform api specific bits after a cpu has been turned on.
******************************************************************************/
typedef struct {
unsigned long (*cpu_off_finisher)(unsigned long);
unsigned long (*cpu_suspend_finisher)(unsigned long);
} pm_backend_ops;
/*******************************************************************************
* Function & variable prototypes
******************************************************************************/
extern pm_frontend_ops *get_pm_frontend_ops(void);
extern pm_backend_ops *get_pm_backend_ops(void);
extern void set_pm_frontend_ops(pm_frontend_ops *);
extern void set_pm_backend_ops(pm_backend_ops *);
#endif /*__ASSEMBLY__*/
#endif /* __PM_H__ */

166
include/psci.h Normal file
View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PSCI_H__
#define __PSCI_H__
/*******************************************************************************
* Defines for runtime services func ids
******************************************************************************/
#define PSCI_VERSION 0x84000000
#define PSCI_CPU_SUSPEND_AARCH32 0x84000001
#define PSCI_CPU_SUSPEND_AARCH64 0xc4000001
#define PSCI_CPU_OFF 0x84000002
#define PSCI_CPU_ON_AARCH32 0x84000003
#define PSCI_CPU_ON_AARCH64 0xc4000003
#define PSCI_AFFINITY_INFO_AARCH32 0x84000004
#define PSCI_AFFINITY_INFO_AARCH64 0xc4000004
#define PSCI_MIG_AARCH32 0x84000005
#define PSCI_MIG_AARCH64 0xc4000005
#define PSCI_MIG_INFO_TYPE 0x84000006
#define PSCI_MIG_INFO_UP_CPU_AARCH32 0x84000007
#define PSCI_MIG_INFO_UP_CPU_AARCH64 0xc4000007
#define PSCI_SYSTEM_OFF 0x84000008
#define PSCI_SYSTEM_RESET 0x84000009
/*******************************************************************************
* PSCI Migrate and friends
******************************************************************************/
#define PSCI_TOS_UP_MIG_CAP 0
#define PSCI_TOS_NOT_UP_MIG_CAP 1
#define PSCI_TOS_NOT_PRESENT 2
/*******************************************************************************
* PSCI CPU_SUSPEND 'power_state' parameter specific defines
******************************************************************************/
#define PSTATE_ID_SHIFT 15
#define PSTATE_TYPE_SHIFT 16
#define PSTATE_AFF_LVL_SHIFT 25
#define PSTATE_ID_MASK 0xffff
#define PSTATE_TYPE_MASK 0x1
#define PSTATE_AFF_LVL_MASK 0x3
#define psci_get_pstate_id(pstate) (pstate >> PSTATE_ID_SHIFT) & \
PSTATE_ID_MASK
#define psci_get_pstate_type(pstate) (pstate >> PSTATE_TYPE_SHIFT) & \
PSTATE_TYPE_MASK
#define psci_get_pstate_afflvl(pstate) (pstate >> PSTATE_AFF_LVL_SHIFT) & \
PSTATE_AFF_LVL_MASK
/*******************************************************************************
* PSCI version
******************************************************************************/
#define PSCI_MAJOR_VER (0 << 16)
#define PSCI_MINOR_VER 0x2
/*******************************************************************************
* PSCI error codes
******************************************************************************/
#define PSCI_E_SUCCESS 0
#define PSCI_E_NOT_SUPPORTED -1
#define PSCI_E_INVALID_PARAMS -2
#define PSCI_E_DENIED -3
#define PSCI_E_ALREADY_ON -4
#define PSCI_E_ON_PENDING -5
#define PSCI_E_INTERN_FAIL -6
#define PSCI_E_NOT_PRESENT -7
#define PSCI_E_DISABLED -8
/*******************************************************************************
* PSCI affinity state related constants. An affinity instance could be present
* or absent physically to cater for asymmetric topologies. If present then it
* could in one of the 4 further defined states.
******************************************************************************/
#define PSCI_STATE_SHIFT 1
#define PSCI_STATE_MASK 0x7
#define psci_get_state(x) (x >> PSCI_STATE_SHIFT) & PSCI_STATE_MASK
#define psci_set_state(x,y) x &= ~(PSCI_STATE_MASK << PSCI_STATE_SHIFT); \
x |= (y & PSCI_STATE_MASK) << PSCI_STATE_SHIFT;
#define PSCI_AFF_ABSENT 0x0
#define PSCI_AFF_PRESENT 0x1
#define PSCI_STATE_OFF 0x0
#define PSCI_STATE_ON_PENDING 0x1
#define PSCI_STATE_SUSPEND 0x2
#define PSCI_STATE_ON 0x3
/* Number of affinity instances whose state this psci imp. can track */
#define PSCI_NUM_AFFS 32ull
#ifndef __ASSEMBLY__
/*******************************************************************************
* Structure populated by platform specific code to export routines which
* perform common low level pm functions
******************************************************************************/
typedef struct {
int (*affinst_standby)(unsigned int);
int (*affinst_on)(unsigned long,
unsigned long,
unsigned long,
unsigned int,
unsigned int);
int (*affinst_off)(unsigned long, unsigned int, unsigned int);
int (*affinst_suspend)(unsigned long,
unsigned long,
unsigned long,
unsigned int,
unsigned int);
int (*affinst_on_finish)(unsigned long, unsigned int, unsigned int);
int (*affinst_suspend_finish)(unsigned long,
unsigned int,
unsigned int);
} plat_pm_ops;
/*******************************************************************************
* Function & Data prototypes
******************************************************************************/
extern unsigned int psci_version(void);
extern int psci_cpu_on(unsigned long,
unsigned long,
unsigned long);
extern int __psci_cpu_suspend(unsigned int, unsigned long, unsigned long);
extern int __psci_cpu_off(void);
extern int psci_affinity_info(unsigned long, unsigned int);
extern int psci_migrate(unsigned int);
extern unsigned int psci_migrate_info_type(void);
extern unsigned long psci_migrate_info_up_cpu(void);
extern void psci_system_off(void);
extern void psci_system_reset(void);
extern int psci_cpu_on(unsigned long,
unsigned long,
unsigned long);
extern void psci_aff_on_finish_entry(void);
extern void psci_aff_suspend_finish_entry(void);
extern void psci_setup(unsigned long);
#endif /*__ASSEMBLY__*/
#endif /* __PSCI_H__ */

122
include/runtime_svc.h Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __RUNTIME_SVC_H__
#define __RUNTIME_SVC_H__
#include <psci.h>
/*******************************************************************************
* Bit definitions inside the function id as per the SMC calling convention
******************************************************************************/
#define FUNCID_TYPE_SHIFT 31
#define FUNCID_CC_SHIFT 30
#define FUNCID_OWNER_SHIFT 24
#define FUNCID_NUM_SHIFT 0
#define FUNCID_TYPE_MASK 0x1
#define FUNCID_CC_MASK 0x1
#define FUNCID_OWNER_MASK 0x3f
#define FUNCID_NUM_MASK 0xffff
#define GET_SMC_CC(id) ((id >> FUNCID_CC_SHIFT) & \
FUNCID_CC_MASK)
#define SMC_64 1
#define SMC_32 0
#define SMC_UNK 0xffffffff
/*******************************************************************************
* Constants to indicate type of exception to the common exception handler.
******************************************************************************/
#define SYNC_EXCEPTION_SP_EL0 0x0
#define IRQ_SP_EL0 0x1
#define FIQ_SP_EL0 0x2
#define SERROR_SP_EL0 0x3
#define SYNC_EXCEPTION_SP_ELX 0x4
#define IRQ_SP_ELX 0x5
#define FIQ_SP_ELX 0x6
#define SERROR_SP_ELX 0x7
#define SYNC_EXCEPTION_AARCH64 0x8
#define IRQ_AARCH64 0x9
#define FIQ_AARCH64 0xa
#define SERROR_AARCH64 0xb
#define SYNC_EXCEPTION_AARCH32 0xc
#define IRQ_AARCH32 0xd
#define FIQ_AARCH32 0xe
#define SERROR_AARCH32 0xf
#ifndef __ASSEMBLY__
typedef struct {
unsigned long x0;
unsigned long x1;
unsigned long x2;
unsigned long x3;
unsigned long x4;
unsigned long x5;
unsigned long x6;
unsigned long x7;
unsigned long x8;
unsigned long x9;
unsigned long x10;
unsigned long x11;
unsigned long x12;
unsigned long x13;
unsigned long x14;
unsigned long x15;
unsigned long x16;
unsigned long x17;
unsigned long x18;
unsigned long x19;
unsigned long x20;
unsigned long x21;
unsigned long x22;
unsigned long x23;
unsigned long x24;
unsigned long x25;
unsigned long x26;
unsigned long x27;
unsigned long x28;
unsigned long sp_el0;
unsigned long spsr;
unsigned long fp;
unsigned long lr;
} gp_regs;
/*******************************************************************************
* Function & variable prototypes
******************************************************************************/
extern void runtime_svc_init(unsigned long mpidr);
#endif /*__ASSEMBLY__*/
#endif /* __RUNTIME_SVC_H__ */

74
include/semihosting.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SEMIHOSTING_H__
#define __SEMIHOSTING_H__
#define SEMIHOSTING_SYS_OPEN 0x01
#define SEMIHOSTING_SYS_CLOSE 0x02
#define SEMIHOSTING_SYS_WRITE0 0x04
#define SEMIHOSTING_SYS_WRITEC 0x03
#define SEMIHOSTING_SYS_WRITE 0x05
#define SEMIHOSTING_SYS_READ 0x06
#define SEMIHOSTING_SYS_READC 0x07
#define SEMIHOSTING_SYS_SEEK 0x0A
#define SEMIHOSTING_SYS_FLEN 0x0C
#define SEMIHOSTING_SYS_REMOVE 0x0E
#define SEMIHOSTING_SYS_SYSTEM 0x12
#define SEMIHOSTING_SYS_ERRNO 0x13
#define FOPEN_MODE_R 0x0
#define FOPEN_MODE_RB 0x1
#define FOPEN_MODE_RPLUS 0x2
#define FOPEN_MODE_RPLUSB 0x3
#define FOPEN_MODE_W 0x4
#define FOPEN_MODE_WB 0x5
#define FOPEN_MODE_WPLUS 0x6
#define FOPEN_MODE_WPLUSB 0x7
#define FOPEN_MODE_A 0x8
#define FOPEN_MODE_AB 0x9
#define FOPEN_MODE_APLUS 0xa
#define FOPEN_MODE_APLUSB 0xb
int semihosting_connection_supported(void);
int semihosting_file_open(const char *file_name, unsigned int mode);
int semihosting_file_seek(int file_handle, unsigned int offset);
int semihosting_file_read(int file_handle, int *length, void *buffer);
int semihosting_file_write(int file_handle, int *length, void *buffer);
int semihosting_file_close(int file_handle);
int semihosting_file_length(int file_handle);
int semihosting_system(char *command_line);
int semihosting_get_flen(const char* file_name);
int semihosting_download_file(const char* file_name, int buf_size, void *buf);
void semihosting_write_char(char character);
void semihosting_write_string(char *string);
char semihosting_read_char(void);
#endif /* __SEMIHOSTING_H__ */

41
include/spinlock.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SPINLOCK_H__
#define __SPINLOCK_H__
typedef struct {
volatile unsigned int lock;
} spinlock_t;
void spin_lock(spinlock_t *lock);
void spin_unlock(spinlock_t *lock);
#endif /* __SPINLOCK_H__ */

View File

@ -0,0 +1,233 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
#include <asm_macros.S>
.globl dcisw
.globl dccisw
.globl dccsw
.globl dccvac
.globl dcivac
.globl dccivac
.globl dccvau
.globl dczva
.globl flush_dcache_range
.globl inv_dcache_range
.globl dcsw_op_louis
.globl dcsw_op_all
.section .text, "ax"; .align 3
dcisw:; .type dcisw, %function
dc isw, x0
dsb sy
isb
ret
dccisw:; .type dccisw, %function
dc cisw, x0
dsb sy
isb
ret
dccsw:; .type dccsw, %function
dc csw, x0
dsb sy
isb
ret
dccvac:; .type dccvac, %function
dc cvac, x0
dsb sy
isb
ret
dcivac:; .type dcivac, %function
dc ivac, x0
dsb sy
isb
ret
dccivac:; .type dccivac, %function
dc civac, x0
dsb sy
isb
ret
dccvau:; .type dccvau, %function
dc cvau, x0
dsb sy
isb
ret
dczva:; .type dczva, %function
dc zva, x0
dsb sy
isb
ret
/* ------------------------------------------
* Clean+Invalidate from base address till
* size. 'x0' = addr, 'x1' = size
* ------------------------------------------
*/
flush_dcache_range:; .type flush_dcache_range, %function
dcache_line_size x2, x3
add x1, x0, x1
sub x3, x2, #1
bic x0, x0, x3
flush_loop:
dc civac, x0
add x0, x0, x2
cmp x0, x1
b.lo flush_loop
dsb sy
ret
/* ------------------------------------------
* Invalidate from base address till
* size. 'x0' = addr, 'x1' = size
* ------------------------------------------
*/
inv_dcache_range:; .type inv_dcache_range, %function
dcache_line_size x2, x3
add x1, x0, x1
sub x3, x2, #1
bic x0, x0, x3
inv_loop:
dc ivac, x0
add x0, x0, x2
cmp x0, x1
b.lo inv_loop
dsb sy
ret
/* ------------------------------------------
* Data cache operations by set/way to the
* level specified
* ------------------------------------------
* ----------------------------------
* Call this func with the clidr in
* x0, starting cache level in x10,
* last cache level in x3 & cm op in
* x14
* ----------------------------------
*/
dcsw_op:; .type dcsw_op, %function
all_start_at_level:
add x2, x10, x10, lsr #1 // work out 3x current cache level
lsr x1, x0, x2 // extract cache type bits from clidr
and x1, x1, #7 // mask of the bits for current cache only
cmp x1, #2 // see what cache we have at this level
b.lt skip // skip if no cache, or just i-cache
msr csselr_el1, x10 // select current cache level in csselr
isb // isb to sych the new cssr&csidr
mrs x1, ccsidr_el1 // read the new ccsidr
and x2, x1, #7 // extract the length of the cache lines
add x2, x2, #4 // add 4 (line length offset)
mov x4, #0x3ff
and x4, x4, x1, lsr #3 // find maximum number on the way size
clz w5, w4 // find bit position of way size increment
mov x7, #0x7fff
and x7, x7, x1, lsr #13 // extract max number of the index size
loop2:
mov x9, x4 // create working copy of max way size
loop3:
lsl x6, x9, x5
orr x11, x10, x6 // factor way and cache number into x11
lsl x6, x7, x2
orr x11, x11, x6 // factor index number into x11
mov x12, x0
mov x13, x30 // lr
mov x0, x11
blr x14
mov x0, x12
mov x30, x13 // lr
subs x9, x9, #1 // decrement the way
b.ge loop3
subs x7, x7, #1 // decrement the index
b.ge loop2
skip:
add x10, x10, #2 // increment cache number
cmp x3, x10
b.gt all_start_at_level
finished:
mov x10, #0 // swith back to cache level 0
msr csselr_el1, x10 // select current cache level in csselr
dsb sy
isb
ret
do_dcsw_op:; .type do_dcsw_op, %function
cbz x3, exit
cmp x0, #DCISW
b.eq dc_isw
cmp x0, #DCCISW
b.eq dc_cisw
cmp x0, #DCCSW
b.eq dc_csw
dc_isw:
mov x0, x9
adr x14, dcisw
b dcsw_op
dc_cisw:
mov x0, x9
adr x14, dccisw
b dcsw_op
dc_csw:
mov x0, x9
adr x14, dccsw
b dcsw_op
exit:
ret
dcsw_op_louis:; .type dcsw_op_louis, %function
dsb sy
setup_dcsw_op_args x10, x3, x9, #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
b do_dcsw_op
dcsw_op_all:; .type dcsw_op_all, %function
dsb sy
setup_dcsw_op_args x10, x3, x9, #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
b do_dcsw_op

View File

@ -0,0 +1,274 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
.globl enable_irq
.globl disable_irq
.globl enable_fiq
.globl disable_fiq
.globl enable_serror
.globl disable_serror
.globl read_daif
.globl write_daif
.globl read_spsr
.globl read_spsr_el1
.globl read_spsr_el2
.globl read_spsr_el3
.globl write_spsr
.globl write_spsr_el1
.globl write_spsr_el2
.globl write_spsr_el3
.globl read_elr
.globl read_elr_el1
.globl read_elr_el2
.globl read_elr_el3
.globl write_elr
.globl write_elr_el1
.globl write_elr_el2
.globl write_elr_el3
.globl get_afflvl_shift
.globl mpidr_mask_lower_afflvls
.globl dsb
.globl isb
.globl sev
.globl wfe
.globl wfi
.globl eret
.globl smc
.section .text, "ax"
get_afflvl_shift:; .type get_afflvl_shift, %function
cmp x0, #3
cinc x0, x0, eq
mov x1, #MPIDR_AFFLVL_SHIFT
lsl x0, x0, x1
ret
mpidr_mask_lower_afflvls:; .type mpidr_mask_lower_afflvls, %function
cmp x1, #3
cinc x1, x1, eq
mov x2, #MPIDR_AFFLVL_SHIFT
lsl x2, x1, x2
lsr x0, x0, x2
lsl x0, x0, x2
ret
/* -----------------------------------------------------
* Asynchronous exception manipulation accessors
* -----------------------------------------------------
*/
enable_irq:; .type enable_irq, %function
msr daifclr, #DAIF_IRQ_BIT
ret
enable_fiq:; .type enable_fiq, %function
msr daifclr, #DAIF_FIQ_BIT
ret
enable_serror:; .type enable_serror, %function
msr daifclr, #DAIF_ABT_BIT
ret
disable_irq:; .type disable_irq, %function
msr daifset, #DAIF_IRQ_BIT
ret
disable_fiq:; .type disable_fiq, %function
msr daifset, #DAIF_FIQ_BIT
ret
disable_serror:; .type disable_serror, %function
msr daifset, #DAIF_ABT_BIT
ret
read_daif:; .type read_daif, %function
mrs x0, daif
ret
write_daif:; .type write_daif, %function
msr daif, x0
ret
read_spsr:; .type read_spsr, %function
mrs x0, CurrentEl
cmp x0, #(MODE_EL1 << MODE_EL_SHIFT)
b.eq read_spsr_el1
cmp x0, #(MODE_EL2 << MODE_EL_SHIFT)
b.eq read_spsr_el2
cmp x0, #(MODE_EL3 << MODE_EL_SHIFT)
b.eq read_spsr_el3
read_spsr_el1:; .type read_spsr_el1, %function
mrs x0, spsr_el1
ret
read_spsr_el2:; .type read_spsr_el2, %function
mrs x0, spsr_el2
ret
read_spsr_el3:; .type read_spsr_el3, %function
mrs x0, spsr_el3
ret
write_spsr:; .type write_spsr, %function
mrs x1, CurrentEl
cmp x1, #(MODE_EL1 << MODE_EL_SHIFT)
b.eq write_spsr_el1
cmp x1, #(MODE_EL2 << MODE_EL_SHIFT)
b.eq write_spsr_el2
cmp x1, #(MODE_EL3 << MODE_EL_SHIFT)
b.eq write_spsr_el3
write_spsr_el1:; .type write_spsr_el1, %function
msr spsr_el1, x0
isb
ret
write_spsr_el2:; .type write_spsr_el2, %function
msr spsr_el2, x0
isb
ret
write_spsr_el3:; .type write_spsr_el3, %function
msr spsr_el3, x0
isb
ret
read_elr:; .type read_elr, %function
mrs x0, CurrentEl
cmp x0, #(MODE_EL1 << MODE_EL_SHIFT)
b.eq read_elr_el1
cmp x0, #(MODE_EL2 << MODE_EL_SHIFT)
b.eq read_elr_el2
cmp x0, #(MODE_EL3 << MODE_EL_SHIFT)
b.eq read_elr_el3
read_elr_el1:; .type read_elr_el1, %function
mrs x0, elr_el1
ret
read_elr_el2:; .type read_elr_el2, %function
mrs x0, elr_el2
ret
read_elr_el3:; .type read_elr_el3, %function
mrs x0, elr_el3
ret
write_elr:; .type write_elr, %function
mrs x1, CurrentEl
cmp x1, #(MODE_EL1 << MODE_EL_SHIFT)
b.eq write_elr_el1
cmp x1, #(MODE_EL2 << MODE_EL_SHIFT)
b.eq write_elr_el2
cmp x1, #(MODE_EL3 << MODE_EL_SHIFT)
b.eq write_elr_el3
write_elr_el1:; .type write_elr_el1, %function
msr elr_el1, x0
isb
ret
write_elr_el2:; .type write_elr_el2, %function
msr elr_el2, x0
isb
ret
write_elr_el3:; .type write_elr_el3, %function
msr elr_el3, x0
isb
ret
dsb:; .type dsb, %function
dsb sy
ret
isb:; .type isb, %function
isb
ret
sev:; .type sev, %function
sev
ret
wfe:; .type wfe, %function
wfe
ret
wfi:; .type wfi, %function
wfi
ret
eret:; .type eret, %function
eret
smc:; .type smc, %function
smc #0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch_helpers.h>
.globl tlbiall
.globl tlbiallis
.globl tlbialle1
.globl tlbialle1is
.globl tlbialle2
.globl tlbialle2is
.globl tlbialle3
.globl tlbialle3is
.globl tlbivmalle1
.section .text, "ax"
tlbiall:; .type tlbiall, %function
mrs x0, CurrentEl
cmp x0, #(MODE_EL1 << MODE_EL_SHIFT)
b.eq tlbialle1
cmp x0, #(MODE_EL2 << MODE_EL_SHIFT)
b.eq tlbialle2
cmp x0, #(MODE_EL3 << MODE_EL_SHIFT)
b.eq tlbialle3
tlbiallis:; .type tlbiallis, %function
mrs x0, CurrentEl
cmp x0, #(MODE_EL1 << MODE_EL_SHIFT)
b.eq tlbialle1is
cmp x0, #(MODE_EL2 << MODE_EL_SHIFT)
b.eq tlbialle2is
cmp x0, #(MODE_EL3 << MODE_EL_SHIFT)
b.eq tlbialle3is
tlbialle1:; .type tlbialle1, %function
tlbi alle1
dsb sy
isb
ret
tlbialle1is:; .type tlbialle1is, %function
tlbi alle1is
dsb sy
isb
ret
tlbialle2:; .type tlbialle2, %function
tlbi alle2
dsb sy
isb
ret
tlbialle2is:; .type tlbialle2is, %function
tlbi alle2is
dsb sy
isb
ret
tlbialle3:; .type tlbialle3, %function
tlbi alle3
dsb sy
isb
ret
tlbialle3is:; .type tlbialle3is, %function
tlbi alle3is
dsb sy
isb
ret
tlbivmalle1:; .type tlbivmalle1, %function
tlbi vmalle1
dsb sy
isb
ret

41
lib/mmio.c Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
void mmio_write_32(uintptr_t addr, uint32_t value)
{
*(volatile uint32_t*)addr = value;
}
unsigned mmio_read_32(uintptr_t addr)
{
return *(volatile uint32_t*)addr;
}

View File

@ -0,0 +1,60 @@
/*-
* Copyright (c) 1982, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: include/lib/ctype.h
*/
#ifndef _SYS_CTYPE_H_
#define _SYS_CTYPE_H_
#define isspace(c) ((c) == ' ' || ((c) >= '\t' && (c) <= '\r'))
#define isascii(c) (((c) & ~0x7f) == 0)
#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
#define islower(c) ((c) >= 'a' && (c) <= 'z')
#define isalpha(c) (isupper(c) || islower(c))
#define isdigit(c) ((c) >= '0' && (c) <= '9')
#define isxdigit(c) (isdigit(c) \
|| ((c) >= 'A' && (c) <= 'F') \
|| ((c) >= 'a' && (c) <= 'f'))
#define isprint(c) ((c) >= ' ' && (c) <= '~')
#define toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z')))
#define tolower(c) ((c) + 0x20 * (((c) >= 'A') && ((c) <= 'Z')))
#endif /* !_SYS_CTYPE_H_ */

103
lib/non-semihosting/mem.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h> /* size_t */
/*
* Fill @count bytes of memory pointed to by @dst with @val
*/
void *memset(void *dst, int val, size_t count)
{
char *ptr = dst;
while (count--)
*ptr++ = val;
return dst;
}
/*
* Compare @len bytes of @s1 and @s2
*/
int memcmp(const void *s1, const void *s2, size_t len)
{
const char *s = s1;
const char *d = s2;
char dc;
char sc;
while (len--) {
sc = *s++;
dc = *d++;
if (sc - dc)
return (sc - dc);
}
return 0;
}
/*
* Move @len bytes from @src to @dst
*/
void *memmove(void *dst, const void *src, size_t len)
{
const char *s = src;
char *d = dst;
while (len--)
*d++ = *s++;
return d;
}
/*
* Copy @len bytes from @src to @dst
*/
void *memcpy(void *dst, const void *src, size_t len)
{
return memmove(dst, src, len);
}
/*
* Scan @len bytes of @src for value @c
*/
void *memchr(const void *src, int c, size_t len)
{
const char *s = src;
while (len--) {
if (*s == c)
return (void *) s;
s++;
}
return NULL;
}

106
lib/non-semihosting/std.c Normal file
View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <console.h>
#if defined (__GNUC__)
#include <stdio.h>
#include <stddef.h> /* size_t */
#include <stdarg.h> /* va_list */
// Code from VTB.
#include "mem.c"
// Make mem functions that will operate on DEV mem. "memset_io"?
//Code from VTB
#include "strlen.c"
int puts(const char *s)
{
int count = 0;
while(*s)
{
if (console_putc(*s++)) {
count++;
} else {
count = EOF; // -1 in stdio.h
break;
}
}
return count;
}
// From VTB
#include "ctype.h"
#include "subr_prf.c"
// Choose max of 128 chars for now.
#define PRINT_BUFFER_SIZE 128
int printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
char buf[PRINT_BUFFER_SIZE];
vsnprintf(buf, sizeof(buf) - 1, fmt, args);
buf[PRINT_BUFFER_SIZE - 1] = '\0';
return puts(buf);
}
// I just made this up. Probably make it beter.
void __assert_func (const char *file, int l, const char *func, const char *error)
{
printf("ASSERT: %s <%d> : %s\n\r", func, l, error);
while(1);
}
extern void __assert_fail (const char *assertion, const char *file,
unsigned int line, const char *function)
{
printf("ASSERT: %s <%d> : %s\n\r", function, line, assertion);
while(1);
}
// I just made this up. Probably make it beter.
void abort (void)
{
printf("ABORT\n\r");
while(1);
}
#else
#error "No standard library binding defined."
#endif

View File

@ -0,0 +1,49 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strcmp.c
*/
/*
* Compare strings.
*/
int
strcmp(const char *s1, const char *s2)
{
while (*s1 == *s2++)
if (*s1++ == '\0')
return (0);
return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "ctype.h"
/* Return pointer to the first non-space character */
const char *skip_spaces(const char *str)
{
while (isspace(*str))
++str;
return str;
}

View File

@ -0,0 +1,46 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strlen.c
*/
#include <stddef.h>
size_t
strlen(str)
const char *str;
{
register const char *s;
for (s = str; *s; ++s);
return(s - str);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strncmp.c
*/
#include "types.h"
int
strncmp(const char *s1, const char *s2, size_t n)
{
if (n == 0)
return (0);
do {
if (*s1 != *s2++)
return (*(const unsigned char *)s1 -
*(const unsigned char *)(s2 - 1));
if (*s1++ == '\0')
break;
} while (--n != 0);
return (0);
}

View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strncpy.c
*/
#include "types.h"
/*
* Copy src to dst, truncating or null-padding to always copy n bytes.
* Return dst.
*/
char *
strncpy(char *dst, const char *src, size_t n)
{
if (n != 0) {
char *d = dst;
const char *s = src;
do {
if ((*d++ = *s++) == '\0') {
/* NUL pad the remaining n-1 bytes */
while (--n != 0)
*d++ = '\0';
break;
}
} while (--n != 0);
}
return (dst);
}

View File

@ -0,0 +1,74 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strsep.c
*/
#include "types.h"
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
char *
strsep(char **stringp, const char *delim)
{
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}

View File

@ -0,0 +1,146 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)strtol.c 8.1 (Berkeley) 6/4/93
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strtol.c
*/
#include "types.h"
#include "ctype.h"
#include "limits.h"
/*
* Convert a string to a long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
static long
bsd_strtol(nptr, endptr, base)
const char *nptr;
char **endptr;
int base;
{
const char *s = nptr;
unsigned long acc;
unsigned char c;
unsigned long cutoff;
int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
} else if (neg)
acc = -acc;
if (endptr != 0)
*((const char **)endptr) = any ? s - 1 : nptr;
return (acc);
}
int strict_strtol(const char *str, unsigned int base, long *result)
{
if (*str == '-')
*result = 0 - bsd_strtol(str + 1, NULL, base);
else
*result = bsd_strtol(str, NULL, base);
return 0;
}
int strict_strtoul(const char *str, unsigned int base, unsigned long *result)
{
*result = bsd_strtol(str, NULL, base);
return 0;
}

View File

@ -0,0 +1,117 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/strtoull.c
*/
#include "types.h"
#include "ctype.h"
#include "limits.h"
/*
* Convert a string to an unsigned long long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
static unsigned long long
bsd_strtoull(const char *nptr, char **endptr, int base)
{
const char *s;
unsigned long long acc;
char c;
unsigned long long cutoff;
int neg, any, cutlim;
/*
* See strtoq for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (isspace((unsigned char)c));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
cutoff = ULLONG_MAX / base;
cutlim = ULLONG_MAX % base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULLONG_MAX;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
int strict_strtoull(const char *str, unsigned int base, long long *result)
{
*result = bsd_strtoull(str, NULL, base);
return 0;
}

View File

@ -0,0 +1,557 @@
/*-
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
*/
/*
* Portions copyright (c) 2009-2013, ARM Ltd. All rights reserved.
* ---------------------------------------------------------------
* File: lib/subr_prf.c
*/
/*
#include "types.h"
#include "varargs.h"
#include "ctype.h"
#include "string.h"
*/
#include <stddef.h>
#include <sys/types.h> /* For ssize_t */
#include <stdint.h>
#include <string.h>
#include "ctype.h"
typedef uint64_t uintmax_t;
typedef int64_t intmax_t;
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef int64_t quad_t;
typedef uint64_t u_quad_t;
typedef unsigned long u_long;
typedef unsigned short u_short;
static inline int imax(int a, int b) { return (a > b ? a : b); }
/*
* Note that stdarg.h and the ANSI style va_start macro is used for both
* ANSI and traditional C compilers.
*/
#define TOCONS 0x01
#define TOTTY 0x02
#define TOLOG 0x04
/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
#define MAXNBUF (sizeof(intmax_t) * 8 + 1)
struct putchar_arg {
int flags;
int pri;
struct tty *tty;
char *p_bufr;
size_t n_bufr;
char *p_next;
size_t remain;
};
struct snprintf_arg {
char *str;
size_t remain;
};
extern int log_open;
static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
static void snprintf_func(int ch, void *arg);
static int kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define hex2ascii(hex) (hex2ascii_data[hex])
/*
* Scaled down version of sprintf(3).
*/
int
sprintf(char *buf, const char *cfmt, ...)
{
int retval;
va_list ap;
va_start(ap, cfmt);
retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
buf[retval] = '\0';
va_end(ap);
return (retval);
}
/*
* Scaled down version of vsprintf(3).
*/
int
vsprintf(char *buf, const char *cfmt, va_list ap)
{
int retval;
retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
buf[retval] = '\0';
return (retval);
}
/*
* Scaled down version of snprintf(3).
*/
int
snprintf(char *str, size_t size, const char *format, ...)
{
int retval;
va_list ap;
va_start(ap, format);
retval = vsnprintf(str, size, format, ap);
va_end(ap);
return(retval);
}
/*
* Scaled down version of vsnprintf(3).
*/
int
vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
struct snprintf_arg info;
int retval;
info.str = str;
info.remain = size;
retval = kvprintf(format, snprintf_func, &info, 10, ap);
if (info.remain >= 1)
*info.str++ = '\0';
return (retval);
}
static void
snprintf_func(int ch, void *arg)
{
struct snprintf_arg *const info = arg;
if (info->remain >= 2) {
*info->str++ = ch;
info->remain--;
}
}
/*
* Kernel version which takes radix argument vsnprintf(3).
*/
int
vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
{
struct snprintf_arg info;
int retval;
info.str = str;
info.remain = size;
retval = kvprintf(format, snprintf_func, &info, radix, ap);
if (info.remain >= 1)
*info.str++ = '\0';
return (retval);
}
/*
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
* order; return an optional length and a pointer to the last character
* written in the buffer (i.e., the first character of the string).
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
*/
static char *
ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
{
char *p, c;
p = nbuf;
*p = '\0';
do {
c = hex2ascii(num % base);
*++p = upper ? toupper(c) : c;
} while (num /= base);
if (lenp)
*lenp = p - nbuf;
return (p);
}
/*
* Scaled down version of printf(3).
*
* Two additional formats:
*
* The format %b is supported to decode error registers.
* Its usage is:
*
* printf("reg=%b\n", regval, "<base><arg>*");
*
* where <base> is the output base expressed as a control character, e.g.
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
* the first of which gives the bit number to be inspected (origin 1), and
* the next characters (up to a control character, i.e. a character <= 32),
* give the name of the register. Thus:
*
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
*
* would produce output:
*
* reg=3<BITTWO,BITONE>
*
* XXX: %D -- Hexdump, takes pointer and separator string:
* ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
* ("%*D", len, ptr, " " -> XX XX XX XX ...
*/
int
kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
{
#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
char nbuf[MAXNBUF];
char *d;
const char *p, *percent, *q;
u_char *up;
int ch, n;
uintmax_t num;
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
int cflag, hflag, jflag, tflag, zflag;
int dwidth, upper;
char padc;
int stop = 0, retval = 0;
num = 0;
if (!func)
d = (char *) arg;
else
d = NULL;
if (fmt == NULL)
fmt = "(fmt null)\n";
if (radix < 2 || radix > 36)
radix = 10;
for (;;) {
padc = ' ';
width = 0;
while ((ch = (u_char)*fmt++) != '%' || stop) {
if (ch == '\0')
return (retval);
PCHAR(ch);
}
percent = fmt - 1;
qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
sign = 0; dot = 0; dwidth = 0; upper = 0;
cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
reswitch: switch (ch = (u_char)*fmt++) {
case '.':
dot = 1;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case '+':
sign = 1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '%':
PCHAR(ch);
break;
case '*':
if (!dot) {
width = va_arg(ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
} else {
dwidth = va_arg(ap, int);
}
goto reswitch;
case '0':
if (!dot) {
padc = '0';
goto reswitch;
}
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (n = 0;; ++fmt) {
n = n * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
if (dot)
dwidth = n;
else
width = n;
goto reswitch;
case 'b':
num = (u_int)va_arg(ap, int);
p = va_arg(ap, char *);
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
PCHAR(*q--);
if (num == 0)
break;
for (tmp = 0; *p;) {
n = *p++;
if (num & (1 << (n - 1))) {
PCHAR(tmp ? ',' : '<');
for (; (n = *p) > ' '; ++p)
PCHAR(n);
tmp = 1;
} else
for (; *p > ' '; ++p)
continue;
}
if (tmp)
PCHAR('>');
break;
case 'c':
PCHAR(va_arg(ap, int));
break;
case 'D':
up = va_arg(ap, u_char *);
p = va_arg(ap, char *);
if (!width)
width = 16;
while(width--) {
PCHAR(hex2ascii(*up >> 4));
PCHAR(hex2ascii(*up & 0x0f));
up++;
if (width)
for (q=p;*q;q++)
PCHAR(*q);
}
break;
case 'd':
case 'i':
base = 10;
sign = 1;
goto handle_sign;
case 'h':
if (hflag) {
hflag = 0;
cflag = 1;
} else
hflag = 1;
goto reswitch;
case 'j':
jflag = 1;
goto reswitch;
case 'l':
if (lflag) {
lflag = 0;
qflag = 1;
} else
lflag = 1;
goto reswitch;
case 'n':
if (jflag)
*(va_arg(ap, intmax_t *)) = retval;
else if (qflag)
*(va_arg(ap, quad_t *)) = retval;
else if (lflag)
*(va_arg(ap, long *)) = retval;
else if (zflag)
*(va_arg(ap, size_t *)) = retval;
else if (hflag)
*(va_arg(ap, short *)) = retval;
else if (cflag)
*(va_arg(ap, char *)) = retval;
else
*(va_arg(ap, int *)) = retval;
break;
case 'o':
base = 8;
goto handle_nosign;
case 'p':
base = 16;
sharpflag = (width == 0);
sign = 0;
num = (uintptr_t)va_arg(ap, void *);
goto number;
case 'q':
qflag = 1;
goto reswitch;
case 'r':
base = radix;
if (sign)
goto handle_sign;
goto handle_nosign;
case 's':
p = va_arg(ap, char *);
if (p == NULL)
p = "(null)";
if (!dot)
n = strlen (p);
else
for (n = 0; n < dwidth && p[n]; n++)
continue;
width -= n;
if (!ladjust && width > 0)
while (width--)
PCHAR(padc);
while (n--)
PCHAR(*p++);
if (ladjust && width > 0)
while (width--)
PCHAR(padc);
break;
case 't':
tflag = 1;
goto reswitch;
case 'u':
base = 10;
goto handle_nosign;
case 'X':
upper = 1;
case 'x':
base = 16;
goto handle_nosign;
case 'y':
base = 16;
sign = 1;
goto handle_sign;
case 'z':
zflag = 1;
goto reswitch;
handle_nosign:
sign = 0;
if (jflag)
num = va_arg(ap, uintmax_t);
else if (qflag)
num = va_arg(ap, u_quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, u_long);
else if (zflag)
num = va_arg(ap, size_t);
else if (hflag)
num = (u_short)va_arg(ap, int);
else if (cflag)
num = (u_char)va_arg(ap, int);
else
num = va_arg(ap, u_int);
goto number;
handle_sign:
if (jflag)
num = va_arg(ap, intmax_t);
else if (qflag)
num = va_arg(ap, quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, long);
else if (zflag)
num = va_arg(ap, ssize_t);
else if (hflag)
num = (short)va_arg(ap, int);
else if (cflag)
num = (char)va_arg(ap, int);
else
num = va_arg(ap, int);
number:
if (sign && (intmax_t)num < 0) {
neg = 1;
num = -(intmax_t)num;
}
p = ksprintn(nbuf, num, base, &n, upper);
tmp = 0;
if (sharpflag && num != 0) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (!ladjust && padc == '0')
dwidth = width - tmp;
width -= tmp + imax(dwidth, n);
dwidth -= n;
if (!ladjust)
while (width-- > 0)
PCHAR(' ');
if (neg)
PCHAR('-');
if (sharpflag && num != 0) {
if (base == 8) {
PCHAR('0');
} else if (base == 16) {
PCHAR('0');
PCHAR('x');
}
}
while (dwidth-- > 0)
PCHAR('0');
while (*p)
PCHAR(*p--);
if (ladjust)
while (width-- > 0)
PCHAR(' ');
break;
default:
while (percent < fmt)
PCHAR(*percent++);
/*
* Since we ignore an formatting argument it is no
* longer safe to obey the remaining formatting
* arguments as the arguments will no longer match
* the format specs.
*/
stop = 1;
break;
}
}
#undef PCHAR
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
.globl semihosting_call
.section .text, "ax"
semihosting_call:; .type semihosting_call, %function
hlt #0xf000
ret

View File

@ -0,0 +1,234 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <semihosting.h>
#ifndef SEMIHOSTING_SUPPORTED
#define SEMIHOSTING_SUPPORTED 1
#endif
extern int semihosting_call(unsigned int operation,
void *system_block_address);
typedef struct {
const char *file_name;
unsigned int mode;
unsigned int name_length;
} smh_file_open_block;
typedef struct {
int handle;
void *buffer;
unsigned int length;
} smh_file_read_write_block;
typedef struct {
int handle;
unsigned int location;
} smh_file_seek_block;
typedef struct {
char *command_line;
unsigned int command_length;
} smh_system_block;
int semihosting_connection_supported(void)
{
return SEMIHOSTING_SUPPORTED;
}
int semihosting_file_open(const char *file_name, unsigned int mode)
{
smh_file_open_block open_block;
open_block.file_name = file_name;
open_block.mode = mode;
open_block.name_length = strlen(file_name);
return semihosting_call(SEMIHOSTING_SYS_OPEN,
(void *) &open_block);
}
int semihosting_file_seek(int file_handle, unsigned int offset)
{
smh_file_seek_block seek_block;
int result;
seek_block.handle = file_handle;
seek_block.location = offset;
result = semihosting_call(SEMIHOSTING_SYS_SEEK,
(void *) &seek_block);
if (result)
result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0);
return result;
}
int semihosting_file_read(int file_handle, int *length, void *buffer)
{
smh_file_read_write_block read_block;
int result = -EINVAL;
if ((length == NULL) || (buffer == NULL))
return result;
read_block.handle = file_handle;
read_block.buffer = buffer;
read_block.length = *length;
result = semihosting_call(SEMIHOSTING_SYS_READ,
(void *) &read_block);
if (result == *length) {
return -EINVAL;
} else if (result < *length) {
*length -= result;
return 0;
} else
return result;
}
int semihosting_file_write(int file_handle, int *length, void *buffer)
{
smh_file_read_write_block write_block;
if ((length == NULL) || (buffer == NULL))
return -EINVAL;
write_block.handle = file_handle;
write_block.buffer = buffer;
write_block.length = *length;
*length = semihosting_call(SEMIHOSTING_SYS_WRITE,
(void *) &write_block);
return *length;
}
int semihosting_file_close(int file_handle)
{
return semihosting_call(SEMIHOSTING_SYS_CLOSE,
(void *) &file_handle);
}
int semihosting_file_length(int file_handle)
{
return semihosting_call(SEMIHOSTING_SYS_FLEN,
(void *) &file_handle);
}
char semihosting_read_char(void)
{
return semihosting_call(SEMIHOSTING_SYS_READC, NULL);
}
void semihosting_write_char(char character)
{
semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character);
}
void semihosting_write_string(char *string)
{
semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string);
}
int semihosting_system(char *command_line)
{
smh_system_block system_block;
system_block.command_line = command_line;
system_block.command_length = strlen(command_line);
return semihosting_call(SEMIHOSTING_SYS_SYSTEM,
(void *) &system_block);
}
int semihosting_get_flen(const char *file_name)
{
int file_handle, length;
assert(semihosting_connection_supported());
file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
if (file_handle == -1)
return file_handle;
/* Find the length of the file */
length = semihosting_file_length(file_handle);
return semihosting_file_close(file_handle) ? -1 : length;
}
int semihosting_download_file(const char *file_name,
int buf_size,
void *buf)
{
int ret = -EINVAL, file_handle, length;
/* Null pointer check */
if (!buf)
return ret;
assert(semihosting_connection_supported());
file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
if (file_handle == -1)
return ret;
/* Find the actual length of the file */
length = semihosting_file_length(file_handle);
if (length == -1)
goto semihosting_fail;
/* Signal error if we do not have enough space for the file */
if (length > buf_size)
goto semihosting_fail;
/*
* A successful read will return 0 in which case we pass back
* the actual number of bytes read. Else we pass a negative
* value indicating an error.
*/
ret = semihosting_file_read(file_handle, &length, buf);
if (ret)
goto semihosting_fail;
else
ret = length;
semihosting_fail:
semihosting_file_close(file_handle);
return ret;
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <string.h>
#include <bakery_lock.h>
#define assert_bakery_entry_valid(entry, bakery) do { \
assert(bakery); \
assert(entry < BAKERY_LOCK_MAX_CPUS); \
} while(0)
void bakery_lock_init(bakery_lock * bakery)
{
assert(bakery);
memset(bakery, 0, sizeof(*bakery));
bakery->owner = NO_OWNER;
}
void bakery_lock_get(unsigned long mpidr, bakery_lock * bakery)
{
unsigned int i, max = 0, my_full_number, his_full_number, entry;
entry = platform_get_core_pos(mpidr);
assert_bakery_entry_valid(entry, bakery);
// Catch recursive attempts to take the lock under the same entry:
assert(bakery->owner != entry);
// Get a ticket
bakery->entering[entry] = 1;
for (i = 0; i < BAKERY_LOCK_MAX_CPUS; ++i) {
if (bakery->number[i] > max) {
max = bakery->number[i];
}
}
++max;
bakery->number[entry] = max;
bakery->entering[entry] = 0;
// Wait for our turn
my_full_number = (max << 8) + entry;
for (i = 0; i < BAKERY_LOCK_MAX_CPUS; ++i) {
while (bakery->entering[i]) ; /* Wait */
do {
his_full_number = bakery->number[i];
if (his_full_number) {
his_full_number = (his_full_number << 8) + i;
}
}
while (his_full_number && (his_full_number < my_full_number));
}
bakery->owner = entry;
}
void bakery_lock_release(unsigned long mpidr, bakery_lock * bakery)
{
unsigned int entry = platform_get_core_pos(mpidr);
assert_bakery_entry_valid(entry, bakery);
assert(bakery_lock_held(entry, bakery));
bakery->owner = NO_OWNER;
bakery->number[entry] = 0;
}
int bakery_lock_held(unsigned long mpidr, const bakery_lock * bakery)
{
unsigned int entry = platform_get_core_pos(mpidr);
assert_bakery_entry_valid(entry, bakery);
return bakery->owner == entry;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
.globl spin_lock
.globl spin_unlock
.section .text, "ax";
spin_lock:; .type spin_lock, %function
mov w2, #1
sevl
l1: wfe
l2: ldaxr w1, [x0]
cbnz w1, l1
stxr w1, w2, [x0]
cbnz w1, l2
ret
spin_unlock:; .type spin_unlock, %function
stlr wzr, [x0]
ret

26
license.md Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2013, ARM Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of ARM nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <platform.h>
.globl pcpu_dv_mem_stack
.weak platform_get_core_pos
.weak platform_set_stack
.weak platform_is_primary_cpu
.weak platform_set_coherent_stack
.weak platform_check_mpidr
.weak plat_report_exception
/* -----------------------------------------------------
* 512 bytes of coherent stack for each cpu
* -----------------------------------------------------
*/
#define PCPU_DV_MEM_STACK_SIZE 0x200
.section .text, "ax"; .align 3
/* -----------------------------------------------------
* unsigned long long platform_set_coherent_stack
* (unsigned mpidr);
* For a given mpidr, this function returns the stack
* pointer allocated in device memory. This stack can
* be used by C code which enables/disables the SCTLR.M
* SCTLR.C bit e.g. while powering down a cpu
* -----------------------------------------------------
*/
platform_set_coherent_stack:; .type platform_set_coherent_stack, %function
mov x5, x30 // lr
bl platform_get_core_pos
add x0, x0, #1
mov x1, #PCPU_DV_MEM_STACK_SIZE
mul x0, x0, x1
ldr x1, =pcpu_dv_mem_stack
add sp, x1, x0
ret x5
/* -----------------------------------------------------
* int platform_get_core_pos(int mpidr);
* With this function: CorePos = (ClusterId * 4) +
* CoreId
* -----------------------------------------------------
*/
platform_get_core_pos:; .type platform_get_core_pos, %function
and x1, x0, #MPIDR_CPU_MASK
and x0, x0, #MPIDR_CLUSTER_MASK
add x0, x1, x0, LSR #6
ret
/* -----------------------------------------------------
* void platform_is_primary_cpu (unsigned int mpid);
*
* Given the mpidr say whether this cpu is the primary
* cpu (applicable ony after a cold boot)
* -----------------------------------------------------
*/
platform_is_primary_cpu:; .type platform_is_primary_cpu, %function
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
cmp x0, #PRIMARY_CPU
cset x0, eq
ret
/* -----------------------------------------------------
* void platform_set_stack (int mpidr)
* -----------------------------------------------------
*/
platform_set_stack:; .type platform_set_stack, %function
mov x9, x30 // lr
bl platform_get_core_pos
add x0, x0, #1
mov x1, #PLATFORM_STACK_SIZE
mul x0, x0, x1
ldr x1, =platform_normal_stacks
add sp, x1, x0
ret x9
/* -----------------------------------------------------
* Placeholder function which should be redefined by
* each platform.
* -----------------------------------------------------
*/
platform_check_mpidr:; .type platform_check_mpidr, %function
mov x0, xzr
ret
/* -----------------------------------------------------
* Placeholder function which should be redefined by
* each platform.
* -----------------------------------------------------
*/
plat_report_exception:
ret
/* -----------------------------------------------------
* Per-cpu stacks in device memory.
* Used for C code just before power down or right after
* power up when the MMU or caches need to be turned on
* or off. Each cpu gets a stack of 512 bytes.
* -----------------------------------------------------
*/
.section tzfw_coherent_mem, "aw", %nobits; .align 6
pcpu_dv_mem_stack:
/* Zero fill */
.space (PLATFORM_CORE_COUNT * PCPU_DV_MEM_STACK_SIZE), 0

View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <platform.h>
#include <fvp_pwrc.h>
#include <gic.h>
.globl platform_get_entrypoint
.globl platform_cold_boot_init
.globl plat_secondary_cold_boot_setup
.section platform_code, "ax"; .align 3
.macro platform_choose_gicmmap param1, param2, x_tmp, w_tmp, res
ldr \x_tmp, =VE_SYSREGS_BASE + V2M_SYS_ID
ldr \w_tmp, [\x_tmp]
ubfx \w_tmp, \w_tmp, #SYS_ID_BLD_SHIFT, #SYS_ID_BLD_LENGTH
cmp \w_tmp, #BLD_GIC_VE_MMAP
csel \res, \param1, \param2, eq
.endm
/* -----------------------------------------------------
* void plat_secondary_cold_boot_setup (void);
*
* This function performs any platform specific actions
* needed for a secondary cpu after a cold reset e.g
* mark the cpu's presence, mechanism to place it in a
* holding pen etc.
* TODO: Should we read the PSYS register to make sure
* that the request has gone through.
* -----------------------------------------------------
*/
plat_secondary_cold_boot_setup:; .type plat_secondary_cold_boot_setup, %function
bl read_mpidr
mov x19, x0
bl platform_get_core_pos
mov x20, x0
/* ---------------------------------------------
* Mark this cpu as being present. This is a
* SO write. This array will be read using
* normal memory so invalidate any prefetched
* stale copies first.
* ---------------------------------------------
*/
ldr x1, =TZDRAM_BASE
mov x0, #AFFMAP_OFF
add x1, x0, x1
mov x2, #PLATFORM_CACHE_LINE_SIZE
mul x2, x2, x20
add x0, x1, x2
bl dcivac
str x19, [x1, x2]
/* ---------------------------------------------
* Power down this cpu.
* TODO: Do we need to worry about powering the
* cluster down as well here. That will need
* locks which we won't have unless an elf-
* loader zeroes out the zi section.
* ---------------------------------------------
*/
ldr x1, =PWRC_BASE
str w19, [x1, #PPOFFR_OFF]
/* ---------------------------------------------
* Deactivate the gic cpu interface as well
* ---------------------------------------------
*/
ldr x0, =VE_GICC_BASE
ldr x1, =BASE_GICC_BASE
platform_choose_gicmmap x0, x1, x2, w2, x1
mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1)
orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
str w0, [x1, #GICC_CTLR]
/* ---------------------------------------------
* There is no sane reason to come out of this
* wfi so panic if we do. This cpu will be pow-
* ered on and reset by the cpu_on pm api
* ---------------------------------------------
*/
dsb sy
wfi
cb_panic:
b cb_panic
/* -----------------------------------------------------
* void platform_get_entrypoint (unsigned int mpid);
*
* Main job of this routine is to distinguish between
* a cold and warm boot.
* On a cold boot the secondaries first wait for the
* platform to be initialized after which they are
* hotplugged in. The primary proceeds to perform the
* platform initialization.
* On a warm boot, each cpu jumps to the address in its
* mailbox.
*
* TODO: Not a good idea to save lr in a temp reg
* TODO: PSYSR is a common register and should be
* accessed using locks. Since its not possible
* to use locks immediately after a cold reset
* we are relying on the fact that after a cold
* reset all cpus will read the same WK field
* -----------------------------------------------------
*/
platform_get_entrypoint:; .type platform_get_entrypoint, %function
mov x9, x30 // lr
mov x2, x0
ldr x1, =PWRC_BASE
str w2, [x1, #PSYSR_OFF]
ldr w2, [x1, #PSYSR_OFF]
ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_MASK
cbnz w2, warm_reset
mov x0, x2
b exit
warm_reset:
/* ---------------------------------------------
* A per-cpu mailbox is maintained in the tru-
* sted DRAM. Its flushed out of the caches
* after every update using normal memory so
* its safe to read it here with SO attributes
* ---------------------------------------------
*/
ldr x10, =TZDRAM_BASE + MBOX_OFF
bl platform_get_core_pos
lsl x0, x0, #CACHE_WRITEBACK_SHIFT
ldr x0, [x10, x0]
cbz x0, _panic
exit:
ret x9
_panic: b _panic
/* -----------------------------------------------------
* void platform_mem_init (void);
*
* Zero out the mailbox registers in the TZDRAM. The
* mmu is turned off right now and only the primary can
* ever execute this code. Secondaries will read the
* mailboxes using SO accesses. In short, BL31 will
* update the mailboxes after mapping the tzdram as
* normal memory. It will flush its copy after update.
* BL1 will always read the mailboxes with the MMU off
* -----------------------------------------------------
*/
platform_mem_init:; .type platform_mem_init, %function
ldr x0, =TZDRAM_BASE + MBOX_OFF
stp xzr, xzr, [x0, #0]
stp xzr, xzr, [x0, #0x10]
stp xzr, xzr, [x0, #0x20]
stp xzr, xzr, [x0, #0x30]
ret
/* -----------------------------------------------------
* void platform_cold_boot_init (bl1_main function);
*
* Routine called only by the primary cpu after a cold
* boot to perform early platform initialization
* -----------------------------------------------------
*/
platform_cold_boot_init:; .type platform_cold_boot_init, %function
mov x20, x0
bl platform_mem_init
bl read_mpidr
mov x19, x0
/* ---------------------------------------------
* Give ourselves a small coherent stack to
* ease the pain of initializing the MMU and
* CCI in assembler
* ---------------------------------------------
*/
bl platform_set_coherent_stack
/* ---------------------------------------------
* Mark this cpu as being present. This is a
* SO write. Invalidate any stale copies out of
* paranoia as there is no one else around.
* ---------------------------------------------
*/
mov x0, x19
bl platform_get_core_pos
mov x21, x0
ldr x1, =TZDRAM_BASE
mov x0, #AFFMAP_OFF
add x1, x0, x1
mov x2, #PLATFORM_CACHE_LINE_SIZE
mul x2, x2, x21
add x0, x1, x2
bl dcivac
str x19, [x1, x2]
/* ---------------------------------------------
* Enable CCI-400 for this cluster. No need
* for locks as no other cpu is active at the
* moment
* ---------------------------------------------
*/
mov x0, x19
bl cci_enable_coherency
/* ---------------------------------------------
* Architectural init. can be generic e.g.
* enabling stack alignment and platform spec-
* ific e.g. MMU & page table setup as per the
* platform memory map. Perform the latter here
* and the former in bl1_main.
* ---------------------------------------------
*/
bl bl1_early_platform_setup
bl bl1_plat_arch_setup
/* ---------------------------------------------
* Give ourselves a stack allocated in Normal
* -IS-WBWA memory
* ---------------------------------------------
*/
mov x0, x19
bl platform_set_stack
/* ---------------------------------------------
* Jump to the main function. Returning from it
* is a terminal error.
* ---------------------------------------------
*/
blr x20
cb_init_panic:
b cb_init_panic

View File

@ -0,0 +1,600 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <platform.h>
#include <bl_common.h>
/* Included only for error codes */
#include <psci.h>
unsigned char platform_normal_stacks[PLATFORM_STACK_SIZE][PLATFORM_CORE_COUNT]
__attribute__ ((aligned(PLATFORM_CACHE_LINE_SIZE),
section("tzfw_normal_stacks")));
/*******************************************************************************
* This array holds the characteristics of the differences between the three
* FVP platforms (Base, A53_A57 & Foundation). It will be populated during cold
* boot at each boot stage by the primary before enabling the MMU (to allow cci
* configuration) & used thereafter. Each BL will have its own copy to allow
* independent operation.
******************************************************************************/
static unsigned long platform_config[CONFIG_LIMIT];
/*******************************************************************************
* TODO: Check page table alignment to avoid space wastage
******************************************************************************/
/*******************************************************************************
* Level 1 translation tables need 4 entries for the 4GB address space accessib-
* le by the secure firmware. Input address space will be restricted using the
* T0SZ settings in the TCR.
******************************************************************************/
static unsigned long l1_xlation_table[ADDR_SPACE_SIZE >> 30]
__attribute__ ((aligned((ADDR_SPACE_SIZE >> 30) << 3)));
/*******************************************************************************
* Level 2 translation tables describe the first & second gb of the address
* space needed to address secure peripherals e.g. trusted ROM and RAM.
******************************************************************************/
static unsigned long l2_xlation_table[NUM_L2_PAGETABLES][NUM_2MB_IN_GB]
__attribute__ ((aligned(NUM_2MB_IN_GB << 3)));
/*******************************************************************************
* Level 3 translation tables (2 sets) describe the trusted & non-trusted RAM
* regions at a granularity of 4K.
******************************************************************************/
static unsigned long l3_xlation_table[NUM_L3_PAGETABLES][NUM_4K_IN_2MB]
__attribute__ ((aligned(NUM_4K_IN_2MB << 3)));
/*******************************************************************************
* Helper to create a level 1/2 table descriptor which points to a level 2/3
* table.
******************************************************************************/
static unsigned long create_table_desc(unsigned long *next_table_ptr)
{
unsigned long desc = (unsigned long) next_table_ptr;
/* Clear the last 12 bits */
desc >>= FOUR_KB_SHIFT;
desc <<= FOUR_KB_SHIFT;
desc |= TABLE_DESC;
return desc;
}
/*******************************************************************************
* Helper to create a level 1/2/3 block descriptor which maps the va to addr
******************************************************************************/
static unsigned long create_block_desc(unsigned long desc,
unsigned long addr,
unsigned int level)
{
switch (level) {
case LEVEL1:
desc |= (addr << FIRST_LEVEL_DESC_N) | BLOCK_DESC;
break;
case LEVEL2:
desc |= (addr << SECOND_LEVEL_DESC_N) | BLOCK_DESC;
break;
case LEVEL3:
desc |= (addr << THIRD_LEVEL_DESC_N) | TABLE_DESC;
break;
default:
assert(0);
}
return desc;
}
/*******************************************************************************
* Helper to create a level 1/2/3 block descriptor which maps the va to output_
* addr with Device nGnRE attributes.
******************************************************************************/
static unsigned long create_device_block(unsigned long output_addr,
unsigned int level,
unsigned int ns)
{
unsigned long upper_attrs, lower_attrs, desc;
lower_attrs = LOWER_ATTRS(ACCESS_FLAG | OSH | AP_RW);
lower_attrs |= LOWER_ATTRS(ns | ATTR_DEVICE_INDEX);
upper_attrs = UPPER_ATTRS(XN);
desc = upper_attrs | lower_attrs;
return create_block_desc(desc, output_addr, level);
}
/*******************************************************************************
* Helper to create a level 1/2/3 block descriptor which maps the va to output_
* addr with inner-shareable normal wbwa read-only memory attributes.
******************************************************************************/
static unsigned long create_romem_block(unsigned long output_addr,
unsigned int level,
unsigned int ns)
{
unsigned long upper_attrs, lower_attrs, desc;
lower_attrs = LOWER_ATTRS(ACCESS_FLAG | ISH | AP_RO);
lower_attrs |= LOWER_ATTRS(ns | ATTR_IWBWA_OWBWA_NTR_INDEX);
upper_attrs = UPPER_ATTRS(0ull);
desc = upper_attrs | lower_attrs;
return create_block_desc(desc, output_addr, level);
}
/*******************************************************************************
* Helper to create a level 1/2/3 block descriptor which maps the va to output_
* addr with inner-shareable normal wbwa read-write memory attributes.
******************************************************************************/
static unsigned long create_rwmem_block(unsigned long output_addr,
unsigned int level,
unsigned int ns)
{
unsigned long upper_attrs, lower_attrs, desc;
lower_attrs = LOWER_ATTRS(ACCESS_FLAG | ISH | AP_RW);
lower_attrs |= LOWER_ATTRS(ns | ATTR_IWBWA_OWBWA_NTR_INDEX);
upper_attrs = UPPER_ATTRS(XN);
desc = upper_attrs | lower_attrs;
return create_block_desc(desc, output_addr, level);
}
/*******************************************************************************
* Create page tables as per the platform memory map. Certain aspects of page
* talble creating have been abstracted in the above routines. This can be impr-
* oved further.
* TODO: Move the page table setup helpers into the arch or lib directory
*******************************************************************************/
static unsigned long fill_xlation_tables(meminfo *tzram_layout,
unsigned long ro_start,
unsigned long ro_limit,
unsigned long coh_start,
unsigned long coh_limit)
{
unsigned long l2_desc, l3_desc;
unsigned long *xt_addr = 0, *pt_addr, off = 0;
unsigned long trom_start_index, trom_end_index;
unsigned long tzram_start_index, tzram_end_index;
unsigned long flash0_start_index, flash0_end_index;
unsigned long flash1_start_index, flash1_end_index;
unsigned long vram_start_index, vram_end_index;
unsigned long nsram_start_index, nsram_end_index;
unsigned long tdram_start_index, tdram_end_index;
unsigned long dram_start_index, dram_end_index;
unsigned long dev0_start_index, dev0_end_index;
unsigned long dev1_start_index, dev1_end_index;
unsigned int idx;
/*****************************************************************
* LEVEL1 PAGETABLE SETUP
*
* Find the start and end indices of the memory peripherals in the
* first level pagetables. These are the main areas we care about.
* Also bump the end index by one if its equal to the start to
* allow for regions which lie completely in a GB.
*****************************************************************/
trom_start_index = ONE_GB_INDEX(TZROM_BASE);
dev0_start_index = ONE_GB_INDEX(TZRNG_BASE);
dram_start_index = ONE_GB_INDEX(DRAM_BASE);
dram_end_index = ONE_GB_INDEX(DRAM_BASE + DRAM_SIZE);
if (dram_end_index == dram_start_index)
dram_end_index++;
/*
* Fill up the level1 translation table first
*/
for (idx = 0; idx < (ADDR_SPACE_SIZE >> 30); idx++) {
/*
* Fill up the entry for the TZROM. This will cover
* everything in the first GB.
*/
if (idx == trom_start_index) {
xt_addr = &l2_xlation_table[GB1_L2_PAGETABLE][0];
l1_xlation_table[idx] = create_table_desc(xt_addr);
continue;
}
/*
* Mark the second gb as device
*/
if (idx == dev0_start_index) {
xt_addr = &l2_xlation_table[GB2_L2_PAGETABLE][0];
l1_xlation_table[idx] = create_table_desc(xt_addr);
continue;
}
/*
* Fill up the block entry for the DRAM with Normal
* inner-WBWA outer-WBWA non-transient attributes.
* This will cover 2-4GB. Note that the acesses are
* marked as non-secure.
*/
if ((idx >= dram_start_index) && (idx < dram_end_index)) {
l1_xlation_table[idx] = create_rwmem_block(idx, LEVEL1,
NS);
continue;
}
assert(0);
}
/*****************************************************************
* LEVEL2 PAGETABLE SETUP
*
* Find the start and end indices of the memory & peripherals in the
* second level pagetables.
******************************************************************/
/* Initializations for the 1st GB */
trom_start_index = TWO_MB_INDEX(TZROM_BASE);
trom_end_index = TWO_MB_INDEX(TZROM_BASE + TZROM_SIZE);
if (trom_end_index == trom_start_index)
trom_end_index++;
tdram_start_index = TWO_MB_INDEX(TZDRAM_BASE);
tdram_end_index = TWO_MB_INDEX(TZDRAM_BASE + TZDRAM_SIZE);
if (tdram_end_index == tdram_start_index)
tdram_end_index++;
flash0_start_index = TWO_MB_INDEX(FLASH0_BASE);
flash0_end_index = TWO_MB_INDEX(FLASH0_BASE + TZROM_SIZE);
if (flash0_end_index == flash0_start_index)
flash0_end_index++;
flash1_start_index = TWO_MB_INDEX(FLASH1_BASE);
flash1_end_index = TWO_MB_INDEX(FLASH1_BASE + FLASH1_SIZE);
if (flash1_end_index == flash1_start_index)
flash1_end_index++;
vram_start_index = TWO_MB_INDEX(VRAM_BASE);
vram_end_index = TWO_MB_INDEX(VRAM_BASE + VRAM_SIZE);
if (vram_end_index == vram_start_index)
vram_end_index++;
dev0_start_index = TWO_MB_INDEX(DEVICE0_BASE);
dev0_end_index = TWO_MB_INDEX(DEVICE0_BASE + DEVICE0_SIZE);
if (dev0_end_index == dev0_start_index)
dev0_end_index++;
dev1_start_index = TWO_MB_INDEX(DEVICE1_BASE);
dev1_end_index = TWO_MB_INDEX(DEVICE1_BASE + DEVICE1_SIZE);
if (dev1_end_index == dev1_start_index)
dev1_end_index++;
/* Since the size is < 2M this is a single index */
tzram_start_index = TWO_MB_INDEX(tzram_layout->total_base);
nsram_start_index = TWO_MB_INDEX(NSRAM_BASE);
/*
* Fill up the level2 translation table for the first GB next
*/
for (idx = 0; idx < NUM_2MB_IN_GB; idx++) {
l2_desc = INVALID_DESC;
xt_addr = &l2_xlation_table[GB1_L2_PAGETABLE][idx];
/* Block entries for 64M of trusted Boot ROM */
if ((idx >= trom_start_index) && (idx < trom_end_index))
l2_desc = create_romem_block(idx, LEVEL2, 0);
/* Single L3 page table entry for 256K of TZRAM */
if (idx == tzram_start_index) {
pt_addr = &l3_xlation_table[TZRAM_PAGETABLE][0];
l2_desc = create_table_desc(pt_addr);
}
/* Block entries for 32M of trusted DRAM */
if ((idx >= tdram_start_index) && (idx <= tdram_end_index))
l2_desc = create_rwmem_block(idx, LEVEL2, 0);
/* Block entries for 64M of aliased trusted Boot ROM */
if ((idx >= flash0_start_index) && (idx < flash0_end_index))
l2_desc = create_romem_block(idx, LEVEL2, 0);
/* Block entries for 64M of flash1 */
if ((idx >= flash1_start_index) && (idx < flash1_end_index))
l2_desc = create_romem_block(idx, LEVEL2, 0);
/* Block entries for 32M of VRAM */
if ((idx >= vram_start_index) && (idx < vram_end_index))
l2_desc = create_rwmem_block(idx, LEVEL2, 0);
/* Block entries for all the devices in the first gb */
if ((idx >= dev0_start_index) && (idx < dev0_end_index))
l2_desc = create_device_block(idx, LEVEL2, 0);
/* Block entries for all the devices in the first gb */
if ((idx >= dev1_start_index) && (idx < dev1_end_index))
l2_desc = create_device_block(idx, LEVEL2, 0);
/* Single L3 page table entry for 64K of NSRAM */
if (idx == nsram_start_index) {
pt_addr = &l3_xlation_table[NSRAM_PAGETABLE][0];
l2_desc = create_table_desc(pt_addr);
}
*xt_addr = l2_desc;
}
/*
* Initializations for the 2nd GB. Mark everything as device
* for the time being as the memory map is not final. Each
* index will need to be offset'ed to allow absolute values
*/
off = NUM_2MB_IN_GB;
for (idx = off; idx < (NUM_2MB_IN_GB + off); idx++) {
l2_desc = create_device_block(idx, LEVEL2, 0);
xt_addr = &l2_xlation_table[GB2_L2_PAGETABLE][idx - off];
*xt_addr = l2_desc;
}
/*****************************************************************
* LEVEL3 PAGETABLE SETUP
* The following setup assumes knowledge of the scatter file. This
* should be reasonable as this is platform specific code.
*****************************************************************/
/* Fill up the level3 pagetable for the trusted SRAM. */
tzram_start_index = FOUR_KB_INDEX(tzram_layout->total_base);
tzram_end_index = FOUR_KB_INDEX(tzram_layout->total_base +
tzram_layout->total_size);
if (tzram_end_index == tzram_start_index)
tzram_end_index++;
/*
* Reusing trom* to mark RO memory. BLX_STACKS follows BLX_RO in the
* scatter file. Using BLX_RO$$Limit does not work as it might not
* cross the page boundary thus leading to truncation of valid RO
* memory
*/
trom_start_index = FOUR_KB_INDEX(ro_start);
trom_end_index = FOUR_KB_INDEX(ro_limit);
if (trom_end_index == trom_start_index)
trom_end_index++;
/*
* Reusing dev* to mark coherent device memory. $$Limit works here
* 'cause the coherent memory section is known to be 4k in size
*/
dev0_start_index = FOUR_KB_INDEX(coh_start);
dev0_end_index = FOUR_KB_INDEX(coh_limit);
if (dev0_end_index == dev0_start_index)
dev0_end_index++;
/* Each index will need to be offset'ed to allow absolute values */
off = FOUR_KB_INDEX(TZRAM_BASE);
for (idx = off; idx < (NUM_4K_IN_2MB + off); idx++) {
l3_desc = INVALID_DESC;
xt_addr = &l3_xlation_table[TZRAM_PAGETABLE][idx - off];
if (idx >= tzram_start_index && idx < tzram_end_index)
l3_desc = create_rwmem_block(idx, LEVEL3, 0);
if (idx >= trom_start_index && idx < trom_end_index)
l3_desc = create_romem_block(idx, LEVEL3, 0);
if (idx >= dev0_start_index && idx < dev0_end_index)
l3_desc = create_device_block(idx, LEVEL3, 0);
*xt_addr = l3_desc;
}
/* Fill up the level3 pagetable for the non-trusted SRAM. */
nsram_start_index = FOUR_KB_INDEX(NSRAM_BASE);
nsram_end_index = FOUR_KB_INDEX(NSRAM_BASE + NSRAM_SIZE);
if (nsram_end_index == nsram_start_index)
nsram_end_index++;
/* Each index will need to be offset'ed to allow absolute values */
off = FOUR_KB_INDEX(NSRAM_BASE);
for (idx = off; idx < (NUM_4K_IN_2MB + off); idx++) {
l3_desc = INVALID_DESC;
xt_addr = &l3_xlation_table[NSRAM_PAGETABLE][idx - off];
if (idx >= nsram_start_index && idx < nsram_end_index)
l3_desc = create_rwmem_block(idx, LEVEL3, NS);
*xt_addr = l3_desc;
}
return (unsigned long) l1_xlation_table;
}
/*******************************************************************************
* Enable the MMU assuming that the pagetables have already been created
*******************************************************************************/
void enable_mmu()
{
unsigned long mair, tcr, ttbr, sctlr;
unsigned long current_el = read_current_el();
/* Set the attributes in the right indices of the MAIR */
mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,
ATTR_IWBWA_OWBWA_NTR_INDEX);
write_mair(mair);
/*
* Set TCR bits as well. Inner & outer WBWA & shareable + T0SZ = 32
*/
tcr = TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA |
TCR_RGN_INNER_WBA | TCR_T0SZ_4GB;
if (GET_EL(current_el) == MODE_EL3) {
tcr |= TCR_EL3_RES1;
/* Invalidate all TLBs */
tlbialle3();
} else {
/* Invalidate EL1 TLBs */
tlbivmalle1();
}
write_tcr(tcr);
/* Set TTBR bits as well */
assert(((unsigned long)l1_xlation_table & (sizeof(l1_xlation_table) - 1)) == 0);
ttbr = (unsigned long) l1_xlation_table;
write_ttbr0(ttbr);
sctlr = read_sctlr();
sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT | SCTLR_I_BIT;
sctlr |= SCTLR_A_BIT | SCTLR_C_BIT;
write_sctlr(sctlr);
return;
}
void disable_mmu(void)
{
/* Zero out the MMU related registers */
write_mair(0);
write_tcr(0);
write_ttbr0(0);
write_sctlr(0);
/* Invalidate TLBs of the CurrentEL */
tlbiall();
/* Flush the caches */
dcsw_op_all(DCCISW);
return;
}
/*******************************************************************************
* Setup the pagetables as per the platform memory map & initialize the mmu
*******************************************************************************/
void configure_mmu(meminfo *mem_layout,
unsigned long ro_start,
unsigned long ro_limit,
unsigned long coh_start,
unsigned long coh_limit)
{
fill_xlation_tables(mem_layout,
ro_start,
ro_limit,
coh_start,
coh_limit);
enable_mmu();
return;
}
/* Simple routine which returns a configuration variable value */
unsigned long platform_get_cfgvar(unsigned int var_id)
{
assert(var_id < CONFIG_LIMIT);
return platform_config[var_id];
}
/*******************************************************************************
* A single boot loader stack is expected to work on both the Foundation FVP
* models and the two flavours of the Base FVP models (AEMv8 & Cortex). The
* SYS_ID register provides a mechanism for detecting the differences between
* these platforms. This information is stored in a per-BL array to allow the
* code to take the correct path.Per BL platform configuration.
******************************************************************************/
int platform_config_setup(void)
{
unsigned int rev, hbi, bld, arch, sys_id, midr_pn;
sys_id = mmio_read_32(VE_SYSREGS_BASE + V2M_SYS_ID);
rev = (sys_id >> SYS_ID_REV_SHIFT) & SYS_ID_REV_MASK;
hbi = (sys_id >> SYS_ID_HBI_SHIFT) & SYS_ID_HBI_MASK;
bld = (sys_id >> SYS_ID_BLD_SHIFT) & SYS_ID_BLD_MASK;
arch = (sys_id >> SYS_ID_ARCH_SHIFT) & SYS_ID_ARCH_MASK;
assert(rev == REV_FVP);
assert(arch == ARCH_MODEL);
/*
* The build field in the SYS_ID tells which variant of the GIC
* memory is implemented by the model.
*/
switch (bld) {
case BLD_GIC_VE_MMAP:
platform_config[CONFIG_GICD_ADDR] = VE_GICD_BASE;
platform_config[CONFIG_GICC_ADDR] = VE_GICC_BASE;
platform_config[CONFIG_GICH_ADDR] = VE_GICH_BASE;
platform_config[CONFIG_GICV_ADDR] = VE_GICV_BASE;
break;
case BLD_GIC_A53A57_MMAP:
platform_config[CONFIG_GICD_ADDR] = BASE_GICD_BASE;
platform_config[CONFIG_GICC_ADDR] = BASE_GICC_BASE;
platform_config[CONFIG_GICH_ADDR] = BASE_GICH_BASE;
platform_config[CONFIG_GICV_ADDR] = BASE_GICV_BASE;
break;
default:
assert(0);
}
/*
* The hbi field in the SYS_ID is 0x020 for the Base FVP & 0x010
* for the Foundation FVP.
*/
switch (hbi) {
case HBI_FOUNDATION:
platform_config[CONFIG_MAX_AFF0] = 4;
platform_config[CONFIG_MAX_AFF1] = 1;
platform_config[CONFIG_CPU_SETUP] = 0;
platform_config[CONFIG_BASE_MMAP] = 0;
break;
case HBI_FVP_BASE:
midr_pn = (read_midr() >> MIDR_PN_SHIFT) & MIDR_PN_MASK;
if ((midr_pn == MIDR_PN_A57) || (midr_pn == MIDR_PN_A53))
platform_config[CONFIG_CPU_SETUP] = 1;
else
platform_config[CONFIG_CPU_SETUP] = 0;
platform_config[CONFIG_MAX_AFF0] = 4;
platform_config[CONFIG_MAX_AFF1] = 2;
platform_config[CONFIG_BASE_MMAP] = 1;
break;
default:
assert(0);
}
return 0;
}
unsigned long plat_get_ns_image_entrypoint(void) {
return NS_IMAGE_OFFSET;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch.h>
#include <platform.h>
.globl plat_report_exception
.section platform_code, "ax"
/* ---------------------------------------------
* void plat_report_exception(unsigned int type)
* Function to report an unhandled exception
* with platform-specific means.
* On FVP platform, it updates the LEDs
* to indicate where we are
* ---------------------------------------------
*/
plat_report_exception:
mrs x1, CurrentEl
lsr x1, x1, #MODE_EL_SHIFT
lsl x1, x1, #SYS_LED_EL_SHIFT
lsl x0, x0, #SYS_LED_EC_SHIFT
mov x2, #(SECURE << SYS_LED_SS_SHIFT)
orr x0, x0, x2
orr x0, x0, x1
mov x1, #VE_SYSREGS_BASE
add x1, x1, #V2M_SYS_LED
str x0, [x1]
ret

169
plat/fvp/bl1_plat_setup.c Normal file
View File

@ -0,0 +1,169 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <platform.h>
#include <bl1.h>
#include <console.h>
/*******************************************************************************
* Declarations of linker defined symbols which will help us find the layout
* of trusted SRAM
******************************************************************************/
#if defined (__GNUC__)
extern unsigned long __FIRMWARE_ROM_START__;
extern unsigned long __FIRMWARE_ROM_SIZE__;
extern unsigned long __FIRMWARE_DATA_START__;
extern unsigned long __FIRMWARE_DATA_SIZE__;
extern unsigned long __FIRMWARE_BSS_START__;
extern unsigned long __FIRMWARE_BSS_SIZE__;
extern unsigned long __DATA_RAM_START__;
extern unsigned long __DATA_RAM_SIZE__;
extern unsigned long __BSS_RAM_START__;
extern unsigned long __BSS_RAM_SIZE__;
extern unsigned long __FIRMWARE_RAM_STACKS_START__;
extern unsigned long __FIRMWARE_RAM_STACKS_SIZE__;
extern unsigned long __FIRMWARE_RAM_PAGETABLES_START__;
extern unsigned long __FIRMWARE_RAM_PAGETABLES_SIZE__;
extern unsigned long __FIRMWARE_RAM_COHERENT_START__;
extern unsigned long __FIRMWARE_RAM_COHERENT_SIZE__;
#define BL1_COHERENT_MEM_BASE (&__FIRMWARE_RAM_COHERENT_START__)
#define BL1_COHERENT_MEM_LIMIT \
((unsigned long long)&__FIRMWARE_RAM_COHERENT_START__ + \
(unsigned long long)&__FIRMWARE_RAM_COHERENT_SIZE__)
#define BL1_FIRMWARE_RAM_GLOBALS_ZI_BASE \
(unsigned long)(&__BSS_RAM_START__)
#define BL1_FIRMWARE_RAM_GLOBALS_ZI_LENGTH \
(unsigned long)(&__FIRMWARE_BSS_SIZE__)
#define BL1_FIRMWARE_RAM_COHERENT_ZI_BASE \
(unsigned long)(&__FIRMWARE_RAM_COHERENT_START__)
#define BL1_FIRMWARE_RAM_COHERENT_ZI_LENGTH\
(unsigned long)(&__FIRMWARE_RAM_COHERENT_SIZE__)
#define BL1_NORMAL_RAM_BASE (unsigned long)(&__BSS_RAM_START__)
#define BL1_NORMAL_RAM_LIMIT \
((unsigned long)&__FIRMWARE_RAM_COHERENT_START__ + \
(unsigned long)&__FIRMWARE_RAM_COHERENT_SIZE__)
#else
#error "Unknown compiler."
#endif
/* Data structure which holds the extents of the trusted SRAM for BL1*/
static meminfo bl1_tzram_layout = {0};
meminfo bl1_get_sec_mem_layout(void)
{
return bl1_tzram_layout;
}
/*******************************************************************************
* Perform any BL1 specific platform actions.
******************************************************************************/
void bl1_early_platform_setup(void)
{
unsigned long bl1_normal_ram_base;
unsigned long bl1_coherent_ram_limit;
unsigned long tzram_limit = TZRAM_BASE + TZRAM_SIZE;
/*
* Initialize extents of the bl1 sections as per the platform
* defined values.
*/
bl1_normal_ram_base = BL1_NORMAL_RAM_BASE;
bl1_coherent_ram_limit = BL1_NORMAL_RAM_LIMIT;
/*
* Calculate how much ram is BL1 using & how much remains free.
* This also includes a rudimentary mechanism to detect whether
* the BL1 data is loaded at the top or bottom of memory.
* TODO: add support for discontigous chunks of free ram if
* needed. Might need dynamic memory allocation support
* et al.
* Also assuming that the section for coherent memory is
* the last and for globals the first in the scatter file.
*/
bl1_tzram_layout.total_base = TZRAM_BASE;
bl1_tzram_layout.total_size = TZRAM_SIZE;
if (bl1_coherent_ram_limit == tzram_limit) {
bl1_tzram_layout.free_base = TZRAM_BASE;
bl1_tzram_layout.free_size = bl1_normal_ram_base - TZRAM_BASE;
} else {
bl1_tzram_layout.free_base = bl1_coherent_ram_limit;
bl1_tzram_layout.free_size =
tzram_limit - bl1_coherent_ram_limit;
}
}
/*******************************************************************************
* Function which will evaluate how much of the trusted ram has been gobbled
* up by BL1 and return the base and size of whats available for loading BL2.
* Its called after coherency and the MMU have been turned on.
******************************************************************************/
void bl1_platform_setup(void)
{
/*
* This should zero out our coherent stacks as well but we don't care
* as they are not being used right now.
*/
memset((void *) BL1_FIRMWARE_RAM_COHERENT_ZI_BASE, 0,
(size_t) BL1_FIRMWARE_RAM_COHERENT_ZI_LENGTH);
/* Enable and initialize the System level generic timer */
mmio_write_32(SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_EN);
/* Initialize the console */
console_init();
return;
}
/*******************************************************************************
* Perform the very early platform specific architecture setup here. At the
* moment this is only intializes the mmu in a quick and dirty way. Later arch-
* itectural setup (bl1_arch_setup()) does not do anything platform specific.
******************************************************************************/
void bl1_plat_arch_setup(void)
{
configure_mmu(&bl1_tzram_layout,
TZROM_BASE, /* Read_only region start */
TZROM_BASE + TZROM_SIZE, /* Read_only region size */
/* Coherent region start */
BL1_FIRMWARE_RAM_COHERENT_ZI_BASE,
/* Coherent region size */
BL1_FIRMWARE_RAM_COHERENT_ZI_BASE +
BL1_FIRMWARE_RAM_COHERENT_ZI_LENGTH);
}

147
plat/fvp/bl2_plat_setup.c Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <platform.h>
#include <bl2.h>
#include <bl_common.h>
/*******************************************************************************
* Declarations of linker defined symbols which will help us find the layout
* of trusted SRAM
******************************************************************************/
#if defined (__GNUC__)
extern unsigned long __BL2_RO_BASE__;
extern unsigned long __BL2_STACKS_BASE__;
extern unsigned long __BL2_COHERENT_RAM_BASE__;
extern unsigned long __BL2_RW_BASE__;
#define BL2_RO_BASE __BL2_RO_BASE__
#define BL2_STACKS_BASE __BL2_STACKS_BASE__
#define BL2_COHERENT_RAM_BASE __BL2_COHERENT_RAM_BASE__
#define BL2_RW_BASE __BL2_RW_BASE__
#else
#error "Unknown compiler."
#endif
/* Pointer to memory visible to both BL2 and BL31 for passing data */
extern unsigned char **bl2_el_change_mem_ptr;
/* Data structure which holds the extents of the trusted SRAM for BL2 */
static meminfo bl2_tzram_layout
__attribute__ ((aligned(PLATFORM_CACHE_LINE_SIZE),
section("tzfw_coherent_mem"))) = {0};
/* Data structure which holds the extents of the non-trusted DRAM for BL2*/
static meminfo dram_layout = {0};
meminfo bl2_get_sec_mem_layout(void)
{
return bl2_tzram_layout;
}
meminfo bl2_get_ns_mem_layout(void)
{
return dram_layout;
}
/*******************************************************************************
* BL1 has passed the extents of the trusted SRAM that should be visible to BL2
* in x0. This memory layout is sitting at the base of the free trusted SRAM.
* Copy it to a safe loaction before its reclaimed by later BL2 functionality.
******************************************************************************/
void bl2_early_platform_setup(meminfo *mem_layout,
void *data)
{
/* Setup the BL2 memory layout */
bl2_tzram_layout.total_base = mem_layout->total_base;
bl2_tzram_layout.total_size = mem_layout->total_size;
bl2_tzram_layout.free_base = mem_layout->free_base;
bl2_tzram_layout.free_size = mem_layout->free_size;
bl2_tzram_layout.attr = mem_layout->attr;
bl2_tzram_layout.next = 0;
/* Initialize the platform config for future decision making */
platform_config_setup();
return;
}
/*******************************************************************************
* Not much to do here aprt from finding out the extents of non-trusted DRAM
* which will be used for loading the non-trusted software images. We are
* relying on pre-iniitialized zi memory so there is nothing to zero out like
* in BL1. This is 'cause BL2 is raw PIC binary. Its load address is determined
* at runtime. The ZI section might be lost if its not already there.
******************************************************************************/
void bl2_platform_setup()
{
dram_layout.total_base = DRAM_BASE;
dram_layout.total_size = DRAM_SIZE;
dram_layout.free_base = DRAM_BASE;
dram_layout.free_size = DRAM_SIZE;
dram_layout.attr = 0;
/* Use the Trusted DRAM for passing args to BL31 */
bl2_el_change_mem_ptr = (unsigned char **) TZDRAM_BASE;
return;
}
/*******************************************************************************
* Perform the very early platform specific architectural setup here. At the
* moment this is only intializes the mmu in a quick and dirty way.
******************************************************************************/
void bl2_plat_arch_setup()
{
unsigned long sctlr;
/* Enable instruction cache. */
sctlr = read_sctlr();
sctlr |= SCTLR_I_BIT;
write_sctlr(sctlr);
/*
* Very simple exception vectors which assert if any exception other
* than a single SMC call from BL2 to pass control to BL31 in EL3 is
* received.
*/
write_vbar((unsigned long) early_exceptions);
configure_mmu(&bl2_tzram_layout,
(unsigned long) &BL2_RO_BASE,
(unsigned long) &BL2_STACKS_BASE,
(unsigned long) &BL2_COHERENT_RAM_BASE,
(unsigned long) &BL2_RW_BASE);
return;
}

424
plat/fvp/bl31_plat_setup.c Normal file
View File

@ -0,0 +1,424 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <platform.h>
#include <bl31.h>
#include <bl_common.h>
#include <pl011.h>
#include <bakery_lock.h>
#include <cci400.h>
#include <gic.h>
#include <fvp_pwrc.h>
/*******************************************************************************
* Declarations of linker defined symbols which will help us find the layout
* of trusted SRAM
******************************************************************************/
#if defined (__GNUC__)
extern unsigned long __BL31_RO_BASE__;
extern unsigned long __BL31_STACKS_BASE__;
extern unsigned long __BL31_COHERENT_RAM_BASE__;
extern unsigned long __BL31_RW_BASE__;
#define BL31_RO_BASE __BL31_RO_BASE__
#define BL31_STACKS_BASE __BL31_STACKS_BASE__
#define BL31_COHERENT_RAM_BASE __BL31_COHERENT_RAM_BASE__
#define BL31_RW_BASE __BL31_RW_BASE__
#else
#error "Unknown compiler."
#endif
/*******************************************************************************
* This data structures holds information copied by BL31 from BL2 to pass
* control to the non-trusted software images. A per-cpu entry was created to
* use the same structure in the warm boot path but that's not the case right
* now. Persisting with this approach for the time being. TODO: Can this be
* moved out of device memory.
******************************************************************************/
el_change_info ns_entry_info[PLATFORM_CORE_COUNT]
__attribute__ ((aligned(PLATFORM_CACHE_LINE_SIZE),
section("tzfw_coherent_mem"))) = {0};
/* Data structure which holds the extents of the trusted SRAM for BL31 */
static meminfo bl31_tzram_layout
__attribute__ ((aligned(PLATFORM_CACHE_LINE_SIZE),
section("tzfw_coherent_mem"))) = {0};
meminfo bl31_get_sec_mem_layout(void)
{
return bl31_tzram_layout;
}
/*******************************************************************************
* Return information about passing control to the non-trusted software images
* to common code.TODO: In the initial architecture, the image after BL31 will
* always run in the non-secure state. In the final architecture there
* will be a series of images. This function will need enhancement then
******************************************************************************/
el_change_info *bl31_get_next_image_info(unsigned long mpidr)
{
return &ns_entry_info[platform_get_core_pos(mpidr)];
}
/*******************************************************************************
* Perform any BL31 specific platform actions. Here we copy parameters passed
* by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they are lost
* (potentially). This is done before the MMU is initialized so that the memory
* layout can be used while creating page tables.
******************************************************************************/
void bl31_early_platform_setup(meminfo *mem_layout,
void *data,
unsigned long mpidr)
{
el_change_info *image_info = (el_change_info *) data;
unsigned int lin_index = platform_get_core_pos(mpidr);
/* Setup the BL31 memory layout */
bl31_tzram_layout.total_base = mem_layout->total_base;
bl31_tzram_layout.total_size = mem_layout->total_size;
bl31_tzram_layout.free_base = mem_layout->free_base;
bl31_tzram_layout.free_size = mem_layout->free_size;
bl31_tzram_layout.attr = mem_layout->attr;
bl31_tzram_layout.next = 0;
/* Save information about jumping into the NS world */
ns_entry_info[lin_index].entrypoint = image_info->entrypoint;
ns_entry_info[lin_index].spsr = image_info->spsr;
ns_entry_info[lin_index].args = image_info->args;
ns_entry_info[lin_index].security_state = image_info->security_state;
ns_entry_info[lin_index].next = image_info->next;
/* Initialize the platform config for future decision making */
platform_config_setup();
}
/*******************************************************************************
* Initialize the gic, configure the CLCD and zero out variables needed by the
* secondaries to boot up correctly.
******************************************************************************/
void bl31_platform_setup()
{
unsigned int reg_val;
/* Initialize the gic cpu and distributor interfaces */
gic_setup();
/*
* TODO: Configure the CLCD before handing control to
* linux. Need to see if a separate driver is needed
* instead.
*/
mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGDATA, 0);
mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGCTRL,
(1ull << 31) | (1 << 30) | (7 << 20) | (0 << 16));
/* Allow access to the System counter timer module */
reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val);
mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val);
reg_val = (1 << CNTNSAR_NS_SHIFT(0)) | (1 << CNTNSAR_NS_SHIFT(1));
mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val);
/* Intialize the power controller */
fvp_pwrc_setup();
/* Topologies are best known to the platform. */
plat_setup_topology();
}
/*******************************************************************************
* Perform the very early platform specific architectural setup here. At the
* moment this is only intializes the mmu in a quick and dirty way.
******************************************************************************/
void bl31_plat_arch_setup()
{
unsigned long sctlr;
/* Enable instruction cache. */
sctlr = read_sctlr();
sctlr |= SCTLR_I_BIT;
write_sctlr(sctlr);
write_vbar((unsigned long) runtime_exceptions);
configure_mmu(&bl31_tzram_layout,
(unsigned long) &BL31_RO_BASE,
(unsigned long) &BL31_STACKS_BASE,
(unsigned long) &BL31_COHERENT_RAM_BASE,
(unsigned long) &BL31_RW_BASE);
}
/*******************************************************************************
* TODO: Move GIC setup to a separate file in case it is needed by other BL
* stages or ELs
* TODO: Revisit if priorities are being set such that no non-secure interrupt
* can have a higher priority than a secure one as recommended in the GICv2 spec
*******************************************************************************/
/*******************************************************************************
* This function does some minimal GICv3 configuration. The Firmware itself does
* not fully support GICv3 at this time and relies on GICv2 emulation as
* provided by GICv3. This function allows software (like Linux) in later stages
* to use full GICv3 features.
*******************************************************************************/
void gicv3_cpuif_setup(void)
{
unsigned int scr_val, val, base;
/*
* When CPUs come out of reset they have their GICR_WAKER.ProcessorSleep
* bit set. In order to allow interrupts to get routed to the CPU we
* need to clear this bit if set and wait for GICR_WAKER.ChildrenAsleep
* to clear (GICv3 Architecture specification 5.4.23).
* GICR_WAKER is NOT banked per CPU, compute the correct base address
* per CPU.
*
* TODO:
* For GICv4 we also need to adjust the Base address based on
* GICR_TYPER.VLPIS
*/
base = BASE_GICR_BASE +
(platform_get_core_pos(read_mpidr()) << GICR_PCPUBASE_SHIFT);
val = gicr_read_waker(base);
val &= ~WAKER_PS;
gicr_write_waker(base, val);
dsb();
/* We need to wait for ChildrenAsleep to clear. */
val = gicr_read_waker(base);
while (val & WAKER_CA) {
val = gicr_read_waker(base);
}
/*
* We need to set SCR_EL3.NS in order to see GICv3 non-secure state.
* Restore SCR_EL3.NS again before exit.
*/
scr_val = read_scr();
write_scr(scr_val | SCR_NS_BIT);
/*
* By default EL2 and NS-EL1 software should be able to enable GICv3
* System register access without any configuration at EL3. But it turns
* out that GICC PMR as set in GICv2 mode does not affect GICv3 mode. So
* we need to set it here again. In order to do that we need to enable
* register access. We leave it enabled as it should be fine and might
* prevent problems with later software trying to access GIC System
* Registers.
*/
val = read_icc_sre_el3();
write_icc_sre_el3(val | ICC_SRE_EN | ICC_SRE_SRE);
val = read_icc_sre_el2();
write_icc_sre_el2(val | ICC_SRE_EN | ICC_SRE_SRE);
write_icc_pmr_el1(MAX_PRI_VAL);
/* Restore SCR_EL3 */
write_scr(scr_val);
}
/*******************************************************************************
* This function does some minimal GICv3 configuration when cores go
* down.
*******************************************************************************/
void gicv3_cpuif_deactivate(void)
{
unsigned int val, base;
/*
* When taking CPUs down we need to set GICR_WAKER.ProcessorSleep and
* wait for GICR_WAKER.ChildrenAsleep to get set.
* (GICv3 Architecture specification 5.4.23).
* GICR_WAKER is NOT banked per CPU, compute the correct base address
* per CPU.
*
* TODO:
* For GICv4 we also need to adjust the Base address based on
* GICR_TYPER.VLPIS
*/
base = BASE_GICR_BASE +
(platform_get_core_pos(read_mpidr()) << GICR_PCPUBASE_SHIFT);
val = gicr_read_waker(base);
val |= WAKER_PS;
gicr_write_waker(base, val);
dsb();
/* We need to wait for ChildrenAsleep to set. */
val = gicr_read_waker(base);
while ((val & WAKER_CA) == 0) {
val = gicr_read_waker(base);
}
}
/*******************************************************************************
* Enable secure interrupts and use FIQs to route them. Disable legacy bypass
* and set the priority mask register to allow all interrupts to trickle in.
******************************************************************************/
void gic_cpuif_setup(unsigned int gicc_base)
{
unsigned int val;
val = gicc_read_iidr(gicc_base);
/*
* If GICv3 we need to do a bit of additional setup. We want to
* allow default GICv2 behaviour but allow the next stage to
* enable full gicv3 features.
*/
if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) {
gicv3_cpuif_setup();
}
val = ENABLE_GRP0 | FIQ_EN | FIQ_BYP_DIS_GRP0;
val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
gicc_write_pmr(gicc_base, MAX_PRI_VAL);
gicc_write_ctlr(gicc_base, val);
}
/*******************************************************************************
* Place the cpu interface in a state where it can never make a cpu exit wfi as
* as result of an asserted interrupt. This is critical for powering down a cpu
******************************************************************************/
void gic_cpuif_deactivate(unsigned int gicc_base)
{
unsigned int val;
/* Disable secure, non-secure interrupts and disable their bypass */
val = gicc_read_ctlr(gicc_base);
val &= ~(ENABLE_GRP0 | ENABLE_GRP1);
val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
gicc_write_ctlr(gicc_base, val);
val = gicc_read_iidr(gicc_base);
/*
* If GICv3 we need to do a bit of additional setup. Make sure the
* RDIST is put to sleep.
*/
if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) {
gicv3_cpuif_deactivate();
}
}
/*******************************************************************************
* Per cpu gic distributor setup which will be done by all cpus after a cold
* boot/hotplug. This marks out the secure interrupts & enables them.
******************************************************************************/
void gic_pcpu_distif_setup(unsigned int gicd_base)
{
gicd_write_igroupr(gicd_base, 0, ~0);
gicd_clr_igroupr(gicd_base, IRQ_SEC_PHY_TIMER);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_0);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_1);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_2);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_3);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_4);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_5);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_6);
gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_7);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_PHY_TIMER, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_0, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_1, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_2, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_3, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_4, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_5, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_6, MAX_PRI_VAL);
gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_7, MAX_PRI_VAL);
gicd_set_isenabler(gicd_base, IRQ_SEC_PHY_TIMER);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_0);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_1);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_2);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_3);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_4);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_5);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_6);
gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_7);
}
/*******************************************************************************
* Global gic distributor setup which will be done by the primary cpu after a
* cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
* then enables the secure GIC distributor interface.
******************************************************************************/
void gic_distif_setup(unsigned int gicd_base)
{
unsigned int ctr, num_ints, ctlr;
/* Disable the distributor before going further */
ctlr = gicd_read_ctlr(gicd_base);
ctlr &= ~(ENABLE_GRP0 | ENABLE_GRP1);
gicd_write_ctlr(gicd_base, ctlr);
/*
* Mark out non-secure interrupts. Calculate number of
* IGROUPR registers to consider. Will be equal to the
* number of IT_LINES
*/
num_ints = gicd_read_typer(gicd_base) & IT_LINES_NO_MASK;
num_ints++;
for (ctr = 0; ctr < num_ints; ctr++)
gicd_write_igroupr(gicd_base, ctr << IGROUPR_SHIFT, ~0);
/* Configure secure interrupts now */
gicd_clr_igroupr(gicd_base, IRQ_TZ_WDOG);
gicd_set_ipriorityr(gicd_base, IRQ_TZ_WDOG, MAX_PRI_VAL);
gicd_set_itargetsr(gicd_base, IRQ_TZ_WDOG,
platform_get_core_pos(read_mpidr()));
gicd_set_isenabler(gicd_base, IRQ_TZ_WDOG);
gic_pcpu_distif_setup(gicd_base);
gicd_write_ctlr(gicd_base, ctlr | ENABLE_GRP0);
}
void gic_setup(void)
{
unsigned int gicd_base, gicc_base;
gicd_base = platform_get_cfgvar(CONFIG_GICD_ADDR);
gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
gic_cpuif_setup(gicc_base);
gic_distif_setup(gicd_base);
}

372
plat/fvp/fvp_pm.c Normal file
View File

@ -0,0 +1,372 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
#include <bl_common.h>
#include <bl31.h>
#include <bakery_lock.h>
#include <cci400.h>
#include <gic.h>
#include <fvp_pwrc.h>
/* Only included for error codes */
#include <psci.h>
/*******************************************************************************
* FVP handler called when an affinity instance is about to be turned on. The
* level and mpidr determine the affinity instance.
******************************************************************************/
int fvp_affinst_on(unsigned long mpidr,
unsigned long sec_entrypoint,
unsigned long ns_entrypoint,
unsigned int afflvl,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
unsigned long linear_id;
mailbox *fvp_mboxes;
unsigned int psysr;
if (ns_entrypoint < DRAM_BASE) {
rc = PSCI_E_INVALID_PARAMS;
goto exit;
}
/*
* It's possible to turn on only affinity level 0 i.e. a cpu
* on the FVP. Ignore any other affinity level.
*/
if (afflvl != MPIDR_AFFLVL0)
goto exit;
/*
* Ensure that we do not cancel an inflight power off request
* for the target cpu. That would leave it in a zombie wfi.
* Wait for it to power off, program the jump address for the
* target cpu and then program the power controller to turn
* that cpu on
*/
do {
psysr = fvp_pwrc_read_psysr(mpidr);
} while (psysr & PSYSR_AFF_L0);
linear_id = platform_get_core_pos(mpidr);
fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
fvp_mboxes[linear_id].value = sec_entrypoint;
flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
sizeof(unsigned long));
fvp_pwrc_write_pponr(mpidr);
exit:
return rc;
}
/*******************************************************************************
* FVP handler called when an affinity instance is about to be turned off. The
* level and mpidr determine the affinity instance. The 'state' arg. allows the
* platform to decide whether the cluster is being turned off and take apt
* actions.
*
* CAUTION: This function is called with coherent stacks so that caches can be
* turned off, flushed and coherency disabled. There is no guarantee that caches
* will remain turned on across calls to this function as each affinity level is
* dealt with. So do not write & read global variables across calls. It will be
* wise to do flush a write to the global to prevent unpredictable results.
******************************************************************************/
int fvp_affinst_off(unsigned long mpidr,
unsigned int afflvl,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
unsigned int gicc_base, ectlr;
unsigned long cpu_setup;
switch (afflvl) {
case MPIDR_AFFLVL1:
if (state == PSCI_STATE_OFF) {
/*
* Disable coherency if this cluster is to be
* turned off
*/
cci_disable_coherency(mpidr);
/*
* Program the power controller to turn the
* cluster off
*/
fvp_pwrc_write_pcoffr(mpidr);
}
break;
case MPIDR_AFFLVL0:
if (state == PSCI_STATE_OFF) {
/*
* Take this cpu out of intra-cluster coherency if
* the FVP flavour supports the SMP bit.
*/
cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
if (cpu_setup) {
ectlr = read_cpuectlr();
ectlr &= ~CPUECTLR_SMP_BIT;
write_cpuectlr(ectlr);
}
/*
* Prevent interrupts from spuriously waking up
* this cpu
*/
gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
gic_cpuif_deactivate(gicc_base);
/*
* Program the power controller to power this
* cpu off
*/
fvp_pwrc_write_ppoffr(mpidr);
}
break;
default:
assert(0);
}
return rc;
}
/*******************************************************************************
* FVP handler called when an affinity instance is about to be suspended. The
* level and mpidr determine the affinity instance. The 'state' arg. allows the
* platform to decide whether the cluster is being turned off and take apt
* actions.
*
* CAUTION: This function is called with coherent stacks so that caches can be
* turned off, flushed and coherency disabled. There is no guarantee that caches
* will remain turned on across calls to this function as each affinity level is
* dealt with. So do not write & read global variables across calls. It will be
* wise to do flush a write to the global to prevent unpredictable results.
******************************************************************************/
int fvp_affinst_suspend(unsigned long mpidr,
unsigned long sec_entrypoint,
unsigned long ns_entrypoint,
unsigned int afflvl,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
unsigned int gicc_base, ectlr;
unsigned long cpu_setup, linear_id;
mailbox *fvp_mboxes;
/* Cannot allow NS world to execute trusted firmware code */
if (ns_entrypoint < DRAM_BASE) {
rc = PSCI_E_INVALID_PARAMS;
goto exit;
}
switch (afflvl) {
case MPIDR_AFFLVL1:
if (state == PSCI_STATE_OFF) {
/*
* Disable coherency if this cluster is to be
* turned off
*/
cci_disable_coherency(mpidr);
/*
* Program the power controller to turn the
* cluster off
*/
fvp_pwrc_write_pcoffr(mpidr);
}
break;
case MPIDR_AFFLVL0:
if (state == PSCI_STATE_OFF) {
/*
* Take this cpu out of intra-cluster coherency if
* the FVP flavour supports the SMP bit.
*/
cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
if (cpu_setup) {
ectlr = read_cpuectlr();
ectlr &= ~CPUECTLR_SMP_BIT;
write_cpuectlr(ectlr);
}
/* Program the jump address for the target cpu */
linear_id = platform_get_core_pos(mpidr);
fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
fvp_mboxes[linear_id].value = sec_entrypoint;
flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
sizeof(unsigned long));
/*
* Prevent interrupts from spuriously waking up
* this cpu
*/
gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
gic_cpuif_deactivate(gicc_base);
/*
* Program the power controller to power this
* cpu off and enable wakeup interrupts.
*/
fvp_pwrc_write_pwkupr(mpidr);
fvp_pwrc_write_ppoffr(mpidr);
}
break;
default:
assert(0);
}
exit:
return rc;
}
/*******************************************************************************
* FVP handler called when an affinity instance has just been powered on after
* being turned off earlier. The level and mpidr determine the affinity
* instance. The 'state' arg. allows the platform to decide whether the cluster
* was turned off prior to wakeup and do what's necessary to setup it up
* correctly.
******************************************************************************/
int fvp_affinst_on_finish(unsigned long mpidr,
unsigned int afflvl,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
unsigned long linear_id, cpu_setup;
mailbox *fvp_mboxes;
unsigned int gicd_base, gicc_base, reg_val, ectlr;
switch (afflvl) {
case MPIDR_AFFLVL1:
/* Enable coherency if this cluster was off */
if (state == PSCI_STATE_OFF)
cci_enable_coherency(mpidr);
break;
case MPIDR_AFFLVL0:
/*
* Ignore the state passed for a cpu. It could only have
* been off if we are here.
*/
/*
* Turn on intra-cluster coherency if the FVP flavour supports
* it.
*/
cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
if (cpu_setup) {
ectlr = read_cpuectlr();
ectlr |= CPUECTLR_SMP_BIT;
write_cpuectlr(ectlr);
}
/* Zero the jump address in the mailbox for this cpu */
fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
linear_id = platform_get_core_pos(mpidr);
fvp_mboxes[linear_id].value = 0;
flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
sizeof(unsigned long));
gicd_base = platform_get_cfgvar(CONFIG_GICD_ADDR);
gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
/* Enable the gic cpu interface */
gic_cpuif_setup(gicc_base);
/* TODO: This setup is needed only after a cold boot */
gic_pcpu_distif_setup(gicd_base);
/* Allow access to the System counter timer module */
reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val);
mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val);
reg_val = (1 << CNTNSAR_NS_SHIFT(0)) |
(1 << CNTNSAR_NS_SHIFT(1));
mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val);
break;
default:
assert(0);
}
return rc;
}
/*******************************************************************************
* FVP handler called when an affinity instance has just been powered on after
* having been suspended earlier. The level and mpidr determine the affinity
* instance.
* TODO: At the moment we reuse the on finisher and reinitialize the secure
* context. Need to implement a separate suspend finisher.
******************************************************************************/
int fvp_affinst_suspend_finish(unsigned long mpidr,
unsigned int afflvl,
unsigned int state)
{
return fvp_affinst_on_finish(mpidr, afflvl, state);
}
/*******************************************************************************
* Export the platform handlers to enable psci to invoke them
******************************************************************************/
static plat_pm_ops fvp_plat_pm_ops = {
0,
fvp_affinst_on,
fvp_affinst_off,
fvp_affinst_suspend,
fvp_affinst_on_finish,
fvp_affinst_suspend_finish,
};
/*******************************************************************************
* Export the platform specific power ops & initialize the fvp power controller
******************************************************************************/
int platform_setup_pm(plat_pm_ops **plat_ops)
{
*plat_ops = &fvp_plat_pm_ops;
return 0;
}

241
plat/fvp/fvp_topology.c Normal file
View File

@ -0,0 +1,241 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <assert.h>
#include <platform.h>
#include <fvp_pwrc.h>
/* TODO: Reusing psci error codes & state information. Get our own! */
#include <psci.h>
/* We treat '255' as an invalid affinity instance */
#define AFFINST_INVAL 0xff
/*******************************************************************************
* We support 3 flavours of the FVP: Foundation, Base AEM & Base Cortex. Each
* flavour has a different topology. The common bit is that there can be a max.
* of 2 clusters (affinity 1) and 4 cpus (affinity 0) per cluster. So we define
* a tree like data structure which caters to these maximum bounds. It simply
* marks the absent affinity level instances as PSCI_AFF_ABSENT e.g. there is no
* cluster 1 on the Foundation FVP. The 'data' field is currently unused.
******************************************************************************/
typedef struct {
unsigned char sibling;
unsigned char child;
unsigned char state;
unsigned int data;
} affinity_info;
/*******************************************************************************
* The following two data structures store the topology tree for the fvp. There
* is a separate array for each affinity level i.e. cpus and clusters. The child
* and sibling references allow traversal inside and in between the two arrays.
******************************************************************************/
static affinity_info fvp_aff1_topology_map[PLATFORM_CLUSTER_COUNT];
static affinity_info fvp_aff0_topology_map[PLATFORM_CORE_COUNT];
/* Simple global variable to safeguard us from stupidity */
static unsigned int topology_setup_done;
/*******************************************************************************
* This function implements a part of the critical interface between the psci
* generic layer and the platform to allow the former to detect the platform
* topology. psci queries the platform to determine how many affinity instances
* are present at a particular level for a given mpidr e.g. consider a dual
* cluster platform where each cluster has 4 cpus. A call to this function with
* (0, 0x100) will return the number of cpus implemented under cluster 1 i.e. 4.
* Similarly a call with (1, 0x100) will return 2 i.e. the number of clusters.
* This is 'cause we are effectively asking how many affinity level 1 instances
* are implemented under affinity level 2 instance 0.
******************************************************************************/
unsigned int plat_get_aff_count(unsigned int aff_lvl,
unsigned long mpidr)
{
unsigned int aff_count = 1, ctr;
unsigned char parent_aff_id;
assert(topology_setup_done == 1);
switch (aff_lvl) {
case 3:
case 2:
/*
* Assert if the parent affinity instance is not 0.
* This also takes care of level 3 in an obfuscated way
*/
parent_aff_id = (mpidr >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK;
assert(parent_aff_id == 0);
/*
* Report that we implement a single instance of
* affinity levels 2 & 3 which are AFF_ABSENT
*/
break;
case 1:
/* Assert if the parent affinity instance is not 0. */
parent_aff_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
assert(parent_aff_id == 0);
/* Fetch the starting index in the aff1 array */
for (ctr = 0;
fvp_aff1_topology_map[ctr].sibling != AFFINST_INVAL;
ctr = fvp_aff1_topology_map[ctr].sibling) {
aff_count++;
}
break;
case 0:
/* Assert if the cluster id is anything apart from 0 or 1 */
parent_aff_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
assert(parent_aff_id < PLATFORM_CLUSTER_COUNT);
/* Fetch the starting index in the aff0 array */
for (ctr = fvp_aff1_topology_map[parent_aff_id].child;
fvp_aff0_topology_map[ctr].sibling != AFFINST_INVAL;
ctr = fvp_aff0_topology_map[ctr].sibling) {
aff_count++;
}
break;
default:
assert(0);
}
return aff_count;
}
/*******************************************************************************
* This function implements a part of the critical interface between the psci
* generic layer and the platform to allow the former to detect the state of a
* affinity instance in the platform topology. psci queries the platform to
* determine whether an affinity instance is present or absent. This caters for
* topologies where an intermediate affinity level instance is missing e.g.
* consider a platform which implements a single cluster with 4 cpus and there
* is another cpu sitting directly on the interconnect along with the cluster.
* The mpidrs of the cluster would range from 0x0-0x3. The mpidr of the single
* cpu would be 0x100 to highlight that it does not belong to cluster 0. Cluster
* 1 is however missing but needs to be accounted to reach this single cpu in
* the topology tree. Hence it will be marked as PSCI_AFF_ABSENT. This is not
* applicable to the FVP but depicted as an example.
******************************************************************************/
unsigned int plat_get_aff_state(unsigned int aff_lvl,
unsigned long mpidr)
{
unsigned int aff_state = PSCI_AFF_ABSENT, idx;
idx = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
assert(topology_setup_done == 1);
switch (aff_lvl) {
case 3:
case 2:
/* Report affinity levels 2 & 3 as absent */
break;
case 1:
aff_state = fvp_aff1_topology_map[idx].state;
break;
case 0:
/*
* First get start index of the aff0 in its array & then add
* to it the affinity id that we want the state of
*/
idx = fvp_aff1_topology_map[idx].child;
idx += (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
aff_state = fvp_aff0_topology_map[idx].state;
break;
default:
assert(0);
}
return aff_state;
}
/*******************************************************************************
* Handy optimization to prevent the psci implementation from traversing through
* affinity levels which are not present while detecting the platform topology.
******************************************************************************/
int plat_get_max_afflvl()
{
return MPIDR_AFFLVL1;
}
/*******************************************************************************
* This function populates the FVP specific topology information depending upon
* the FVP flavour its running on. We construct all the mpidrs we can handle
* and rely on the PWRC.PSYSR to flag absent cpus when their status is queried.
******************************************************************************/
int plat_setup_topology()
{
unsigned char aff0, aff1, aff_state, aff0_offset = 0;
unsigned long mpidr;
topology_setup_done = 0;
for (aff1 = 0; aff1 < PLATFORM_CLUSTER_COUNT; aff1++) {
fvp_aff1_topology_map[aff1].child = aff0_offset;
fvp_aff1_topology_map[aff1].sibling = aff1 + 1;
for (aff0 = 0; aff0 < PLATFORM_MAX_CPUS_PER_CLUSTER; aff0++) {
mpidr = aff1 << MPIDR_AFF1_SHIFT;
mpidr |= aff0 << MPIDR_AFF0_SHIFT;
if (fvp_pwrc_read_psysr(mpidr) != PSYSR_INVALID) {
/*
* Presence of even a single aff0 indicates
* presence of parent aff1 on the FVP.
*/
aff_state = PSCI_AFF_PRESENT;
fvp_aff1_topology_map[aff1].state =
PSCI_AFF_PRESENT;
} else {
aff_state = PSCI_AFF_ABSENT;
}
fvp_aff0_topology_map[aff0_offset].child = AFFINST_INVAL;
fvp_aff0_topology_map[aff0_offset].state = aff_state;
fvp_aff0_topology_map[aff0_offset].sibling =
aff0_offset + 1;
/* Increment the absolute number of aff0s traversed */
aff0_offset++;
}
/* Tie-off the last aff0 sibling to -1 to avoid overflow */
fvp_aff0_topology_map[aff0_offset - 1].sibling = AFFINST_INVAL;
}
/* Tie-off the last aff1 sibling to AFFINST_INVAL to avoid overflow */
fvp_aff1_topology_map[aff1 - 1].sibling = AFFINST_INVAL;
topology_setup_done = 1;
return 0;
}

341
plat/fvp/platform.h Normal file
View File

@ -0,0 +1,341 @@
/*
* Copyright (c) 2013, ARM Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PLATFORM_H__
#define __PLATFORM_H__
#include <arch.h>
#include <mmio.h>
#include <psci.h>
#include <bl_common.h>
/*******************************************************************************
* Platform binary types for linking
******************************************************************************/
#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
#define PLATFORM_LINKER_ARCH aarch64
/*******************************************************************************
* Generic platform constants
******************************************************************************/
#define PLATFORM_STACK_SIZE 0x800
#define FIRMWARE_WELCOME_STR "Booting trusted firmware boot loader stage 1\n\r"
#define BL2_IMAGE_NAME "bl2.bin"
#define BL31_IMAGE_NAME "bl31.bin"
#define NS_IMAGE_OFFSET FLASH0_BASE
#define PLATFORM_CACHE_LINE_SIZE 64
#define PLATFORM_CLUSTER_COUNT 2ull
#define PLATFORM_CLUSTER0_CORE_COUNT 4
#define PLATFORM_CLUSTER1_CORE_COUNT 4
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \
PLATFORM_CLUSTER0_CORE_COUNT)
#define PLATFORM_MAX_CPUS_PER_CLUSTER 4
#define PRIMARY_CPU 0x0
/* Constants for accessing platform configuration */
#define CONFIG_GICD_ADDR 0
#define CONFIG_GICC_ADDR 1
#define CONFIG_GICH_ADDR 2
#define CONFIG_GICV_ADDR 3
#define CONFIG_MAX_AFF0 4
#define CONFIG_MAX_AFF1 5
/* Indicate whether the CPUECTLR SMP bit should be enabled. */
#define CONFIG_CPU_SETUP 6
#define CONFIG_BASE_MMAP 7
#define CONFIG_LIMIT 8
/*******************************************************************************
* Platform memory map related constants
******************************************************************************/
#define TZROM_BASE 0x00000000
#define TZROM_SIZE 0x04000000
#define TZRAM_BASE 0x04000000
#define TZRAM_SIZE 0x40000
#define FLASH0_BASE 0x08000000
#define FLASH0_SIZE TZROM_SIZE
#define FLASH1_BASE 0x0c000000
#define FLASH1_SIZE 0x04000000
#define PSRAM_BASE 0x14000000
#define PSRAM_SIZE 0x04000000
#define VRAM_BASE 0x18000000
#define VRAM_SIZE 0x02000000
/* Aggregate of all devices in the first GB */
#define DEVICE0_BASE 0x1a000000
#define DEVICE0_SIZE 0x12200000
#define DEVICE1_BASE 0x2f000000
#define DEVICE1_SIZE 0x200000
#define NSRAM_BASE 0x2e000000
#define NSRAM_SIZE 0x10000
/* Location of trusted dram on the base fvp */
#define TZDRAM_BASE 0x06000000
#define TZDRAM_SIZE 0x02000000
#define MBOX_OFF 0x1000
#define AFFMAP_OFF 0x1200
#define DRAM_BASE 0x80000000ull
#define DRAM_SIZE 0x80000000ull
#define PCIE_EXP_BASE 0x40000000
#define TZRNG_BASE 0x7fe60000
#define TZNVCTR_BASE 0x7fe70000
#define TZROOTKEY_BASE 0x7fe80000
/* Memory mapped Generic timer interfaces */
#define SYS_CNTCTL_BASE 0x2a430000
#define SYS_CNTREAD_BASE 0x2a800000
#define SYS_TIMCTL_BASE 0x2a810000
/* Counter timer module offsets */
#define CNTNSAR 0x4
#define CNTNSAR_NS_SHIFT(x) x
#define CNTACR_BASE(x) (0x40 + (x << 2))
#define CNTACR_RPCT_SHIFT 0x0
#define CNTACR_RVCT_SHIFT 0x1
#define CNTACR_RFRQ_SHIFT 0x2
#define CNTACR_RVOFF_SHIFT 0x3
#define CNTACR_RWVT_SHIFT 0x4
#define CNTACR_RWPT_SHIFT 0x5
/* V2M motherboard system registers & offsets */
#define VE_SYSREGS_BASE 0x1c010000
#define V2M_SYS_ID 0x0
#define V2M_SYS_LED 0x8
#define V2M_SYS_CFGDATA 0xa0
#define V2M_SYS_CFGCTRL 0xa4
/*
* V2M sysled bit definitions. The values written to this
* register are defined in arch.h & runtime_svc.h. Only
* used by the primary cpu to diagnose any cold boot issues.
*
* SYS_LED[0] - Security state (S=0/NS=1)
* SYS_LED[2:1] - Exception Level (EL3-EL0)
* SYS_LED[7:3] - Exception Class (Sync/Async & origin)
*
*/
#define SYS_LED_SS_SHIFT 0x0
#define SYS_LED_EL_SHIFT 0x1
#define SYS_LED_EC_SHIFT 0x3
#define SYS_LED_SS_MASK 0x1
#define SYS_LED_EL_MASK 0x3
#define SYS_LED_EC_MASK 0x1f
/* V2M sysid register bits */
#define SYS_ID_REV_SHIFT 27
#define SYS_ID_HBI_SHIFT 16
#define SYS_ID_BLD_SHIFT 12
#define SYS_ID_ARCH_SHIFT 8
#define SYS_ID_FPGA_SHIFT 0
#define SYS_ID_REV_MASK 0xf
#define SYS_ID_HBI_MASK 0xfff
#define SYS_ID_BLD_MASK 0xf
#define SYS_ID_ARCH_MASK 0xf
#define SYS_ID_FPGA_MASK 0xff
#define SYS_ID_BLD_LENGTH 4
#define REV_FVP 0x0
#define HBI_FVP_BASE 0x020
#define HBI_FOUNDATION 0x010
#define BLD_GIC_VE_MMAP 0x0
#define BLD_GIC_A53A57_MMAP 0x1
#define ARCH_MODEL 0x1
/* FVP Power controller base address*/
#define PWRC_BASE 0x1c100000
/*******************************************************************************
* Platform specific per affinity states. Distinction between off and suspend
* is made to allow reporting of a suspended cpu as still being on e.g. in the
* affinity_info psci call.
******************************************************************************/
#define PLATFORM_MAX_AFF0 4
#define PLATFORM_MAX_AFF1 2
#define PLAT_AFF_UNK 0xff
#define PLAT_AFF0_OFF 0x0
#define PLAT_AFF0_ONPENDING 0x1
#define PLAT_AFF0_SUSPEND 0x2
#define PLAT_AFF0_ON 0x3
#define PLAT_AFF1_OFF 0x0
#define PLAT_AFF1_ONPENDING 0x1
#define PLAT_AFF1_SUSPEND 0x2
#define PLAT_AFF1_ON 0x3
/*******************************************************************************
* BL2 specific defines.
******************************************************************************/
#define BL2_BASE 0x0402D000
/*******************************************************************************
* BL31 specific defines.
******************************************************************************/
#define BL31_BASE 0x0400E000
/*******************************************************************************
* Platform specific page table and MMU setup constants
******************************************************************************/
#define EL3_ADDR_SPACE_SIZE (1ull << 32)
#define EL3_NUM_PAGETABLES 2
#define EL3_TROM_PAGETABLE 0
#define EL3_TRAM_PAGETABLE 1
#define ADDR_SPACE_SIZE (1ull << 32)
#define NUM_L2_PAGETABLES 2
#define GB1_L2_PAGETABLE 0
#define GB2_L2_PAGETABLE 1
#define NUM_L3_PAGETABLES 2
#define TZRAM_PAGETABLE 0
#define NSRAM_PAGETABLE 1
/*******************************************************************************
* CCI-400 related constants
******************************************************************************/
#define CCI400_BASE 0x2c090000
#define CCI400_SL_IFACE_CLUSTER0 3
#define CCI400_SL_IFACE_CLUSTER1 4
#define CCI400_SL_IFACE_INDEX(mpidr) (mpidr & MPIDR_CLUSTER_MASK ? \
CCI400_SL_IFACE_CLUSTER1 : \
CCI400_SL_IFACE_CLUSTER0)
/*******************************************************************************
* GIC-400 & interrupt handling related constants
******************************************************************************/
/* VE compatible GIC memory map */
#define VE_GICD_BASE 0x2c001000
#define VE_GICC_BASE 0x2c002000
#define VE_GICH_BASE 0x2c004000
#define VE_GICV_BASE 0x2c006000
/* Base FVP compatible GIC memory map */
#define BASE_GICD_BASE 0x2f000000
#define BASE_GICR_BASE 0x2f100000
#define BASE_GICC_BASE 0x2c000000
#define BASE_GICH_BASE 0x2c010000
#define BASE_GICV_BASE 0x2c02f000
#define IRQ_TZ_WDOG 56
#define IRQ_SEC_PHY_TIMER 29
#define IRQ_SEC_SGI_0 8
#define IRQ_SEC_SGI_1 9
#define IRQ_SEC_SGI_2 10
#define IRQ_SEC_SGI_3 11
#define IRQ_SEC_SGI_4 12
#define IRQ_SEC_SGI_5 13
#define IRQ_SEC_SGI_6 14
#define IRQ_SEC_SGI_7 15
#define IRQ_SEC_SGI_8 16
/*******************************************************************************
* PL011 related constants
******************************************************************************/
#define PL011_BASE 0x1c090000
/*******************************************************************************
* Declarations and constants to access the mailboxes safely. Each mailbox is
* aligned on the biggest cache line size in the platform. This is known only
* to the platform as it might have a combination of integrated and external
* caches. Such alignment ensures that two maiboxes do not sit on the same cache
* line at any cache level. They could belong to different cpus/clusters &
* get written while being protected by different locks causing corruption of
* a valid mailbox address.
******************************************************************************/
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
#ifndef __ASSEMBLY__
typedef volatile struct {
unsigned long value
__attribute__((__aligned__(CACHE_WRITEBACK_GRANULE)));
} mailbox;
/*******************************************************************************
* Function and variable prototypes
******************************************************************************/
extern unsigned long *bl1_normal_ram_base;
extern unsigned long *bl1_normal_ram_len;
extern unsigned long *bl1_normal_ram_limit;
extern unsigned long *bl1_normal_ram_zi_base;
extern unsigned long *bl1_normal_ram_zi_len;
extern unsigned long *bl1_coherent_ram_base;
extern unsigned long *bl1_coherent_ram_len;
extern unsigned long *bl1_coherent_ram_limit;
extern unsigned long *bl1_coherent_ram_zi_base;
extern unsigned long *bl1_coherent_ram_zi_len;
extern unsigned long warm_boot_entrypoint;
extern void bl1_plat_arch_setup(void);
extern void bl2_plat_arch_setup(void);
extern void bl31_plat_arch_setup(void);
extern int platform_setup_pm(plat_pm_ops **);
extern unsigned int platform_get_core_pos(unsigned long mpidr);
extern void disable_mmu(void);
extern void enable_mmu(void);
extern void configure_mmu(meminfo *,
unsigned long,
unsigned long,
unsigned long,
unsigned long);
extern unsigned long platform_get_cfgvar(unsigned int);
extern int platform_config_setup(void);
extern void plat_report_exception(unsigned long);
extern unsigned long plat_get_ns_image_entrypoint(void);
/* Declarations for fvp_topology.c */
extern int plat_setup_topology(void);
extern int plat_get_max_afflvl(void);
extern unsigned int plat_get_aff_count(unsigned int, unsigned long);
extern unsigned int plat_get_aff_state(unsigned int, unsigned long);
#endif /*__ASSEMBLY__*/
#endif /* __PLATFORM_H__ */

125
readme.md Normal file
View File

@ -0,0 +1,125 @@
ARM Trusted Firmware - version 0.2
==================================
ARM Trusted Firmware provides a reference implementation of secure world
software for [ARMv8], including Exception Level 3 (EL3) software. This first
release focuses on support for ARM's [Fixed Virtual Platforms (FVPs)] [FVP].
The intent is to provide a reference implementation of various ARM interface
standards, such as the Power State Coordination Interface ([PSCI]), Trusted
Board Boot Requirements (TBBR) and [Secure Monitor] [TEE-SMC] code. As far as
possible the code is designed for reuse or porting to other ARMv8 model and
hardware platforms.
This release is the first one as source code: an initial prototype
release was available in binary form in the [Linaro AArch64 OpenEmbedded
Engineering Build] [AArch64 LEB] to support the new FVP Base platform
models from ARM.
ARM will continue development in collaboration with interested parties to
provide a full reference implementation of PSCI, TBBR and Secure Monitor code
to the benefit of all developers working with ARMv8 TrustZone software.
License
-------
The software is provided under a BSD 3-Clause [license]. Certain source files
are derived from FreeBSD code: the original license is included in these
source files.
This Release
------------
This software is an early implementation of the Trusted Firmware. Only
limited functionality is provided at present and it has not been optimized or
subjected to extended robustness or stress testing.
### Functionality
* Initial implementation of a subset of the Trusted Board Boot Requirements
Platform Design Document (PDD).
* Initializes the secure world (for example, exception vectors, control
registers, GIC and interrupts for the platform), before transitioning into
the normal world.
* Supports both GICv2 and GICv3 initialization for use by normal world
software.
* Starts the normal world at the highest available Exception Level: EL2
if available, otherwise EL1.
* Handles SMCs (Secure Monitor Calls) conforming to the [SMC Calling
Convention PDD] [SMCCC].
* Handles SMCs relating to the [Power State Coordination Interface PDD] [PSCI]
for the Secondary CPU Boot and CPU hotplug use-cases.
For a full list of updated functionality and implementation details, please
see the [User Guide]. The [Change Log] provides details of changes made
since the last release.
### Platforms
This release of the Trusted Firmware has been tested on the following ARM
[FVP]s (64-bit versions only):
* `FVP_Base_AEMv8A-AEMv8A` (Version 5.1 build 8).
* `FVP_Base_Cortex-A57x4-A53x4` (Version 5.1 build 8).
* `FVP_Base_Cortex-A57x1-A53x1` (Version 5.1 build 8).
These models can be licensed from ARM: see [www.arm.com/fvp] [FVP]
### Still to Come
* Complete implementation of the [PSCI] specification.
* Secure memory, Secure monitor, Test Secure OS & Secure interrupts.
* Booting the firmware from a block device.
* Completing the currently experimental GICv3 support.
For a full list of detailed issues in the current code, please see the [Change
Log].
Getting Started
---------------
Get the Trusted Firmware source code from
[GitHub](https://www.github.com/ARM-software/arm-trusted-firmware).
See the [User Guide] for instructions on how to install, build and use
the Trusted Firmware with the ARM [FVP]s.
See the [Porting Guide] as well for information about how to use this
software on another ARMv8 platform.
### Feedback and support
ARM welcomes any feedback on the Trusted Firmware. Please send feedback using
the [GitHub issue tracker](
https://github.com/ARM-software/arm-trusted-firmware/issues).
ARM licensees may contact ARM directly via their partner managers.
- - - - - - - - - - - - - - - - - - - - - - - - - -
_Copyright (c) 2013 ARM Ltd. All rights reserved._
[License]: license.md "BSD license for ARM Trusted Firmware"
[Change Log]: ./docs/change-log.md
[User Guide]: ./docs/user-guide.md
[Porting Guide]: ./docs/porting-guide.md
[ARMv8]: http://www.arm.com/products/processors/armv8-architecture.php "ARMv8 Architecture"
[FVP]: http://www.arm.com/fvp "ARM's Fixed Virtual Platforms"
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022b/index.html "Power State Coordination Interface PDD (ARM DEN 0022B.b)"
[SMCCC]: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html "SMC Calling Convention PDD (ARM DEN 0028A)"
[TEE-SMC]: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php "Secure Monitor and TEEs"
[AArch64 LEB]: http://releases.linaro.org/13.09/openembedded/aarch64 "Linaro AArch64 OpenEmbedded ARM Fast Model 13.09 Release"