Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
e98f414b
Commit
e98f414b
authored
10 years ago
by
danh-arm
Browse files
Options
Download
Plain Diff
Merge pull request #187 from danh-arm/dh/refactor-drivers
Refactor platform porting interface to drivers v2
parents
f0e240d7
3279f625
master
v2.5
v2.5-rc1
v2.5-rc0
v2.4
v2.4-rc2
v2.4-rc1
v2.4-rc0
v2.3
v2.3-rc2
v2.3-rc1
v2.3-rc0
v2.2
v2.2-rc2
v2.2-rc1
v2.2-rc0
v2.1
v2.1-rc1
v2.1-rc0
v2.0
v2.0-rc0
v1.6
v1.6-rc1
v1.6-rc0
v1.5
v1.5-rc3
v1.5-rc2
v1.5-rc1
v1.5-rc0
v1.4
v1.4-rc0
v1.3
v1.3_rc2
v1.3_rc1
v1.3-rc0
v1.2
v1.2-rc0
v1.1
v1.1-rc3
v1.1-rc2
v1.1-rc1
v1.1-rc0
v1.1-Juno-0.1
v1.0
v1.0-rc0
arm_cca_v0.2
arm_cca_v0.1
No related merge requests found
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
Makefile
+1
-1
Makefile
docs/porting-guide.md
+15
-0
docs/porting-guide.md
drivers/arm/cci400/cci400.c
+52
-6
drivers/arm/cci400/cci400.c
drivers/arm/tzc400/tzc400.c
+86
-51
drivers/arm/tzc400/tzc400.c
drivers/io/io_storage.c
+8
-21
drivers/io/io_storage.c
include/drivers/arm/cci400.h
+18
-3
include/drivers/arm/cci400.h
include/drivers/arm/tzc400.h
+11
-21
include/drivers/arm/tzc400.h
include/drivers/io/io_driver.h
+1
-13
include/drivers/io/io_driver.h
include/drivers/io/io_fip.h
+0
-0
include/drivers/io/io_fip.h
include/drivers/io/io_memmap.h
+0
-0
include/drivers/io/io_memmap.h
include/drivers/io/io_semihosting.h
+0
-0
include/drivers/io/io_semihosting.h
include/drivers/io/io_storage.h
+0
-0
include/drivers/io/io_storage.h
plat/fvp/aarch64/fvp_common.c
+14
-4
plat/fvp/aarch64/fvp_common.c
plat/fvp/bl1_fvp_setup.c
+2
-1
plat/fvp/bl1_fvp_setup.c
plat/fvp/bl31_fvp_setup.c
+2
-2
plat/fvp/bl31_fvp_setup.c
plat/fvp/fvp_def.h
+2
-8
plat/fvp/fvp_def.h
plat/fvp/fvp_io_storage.c
+1
-5
plat/fvp/fvp_io_storage.c
plat/fvp/fvp_pm.c
+3
-3
plat/fvp/fvp_pm.c
plat/fvp/fvp_private.h
+2
-1
plat/fvp/fvp_private.h
plat/fvp/fvp_security.c
+7
-11
plat/fvp/fvp_security.c
with
225 additions
and
151 deletions
+225
-151
Makefile
View file @
e98f414b
...
@@ -102,7 +102,6 @@ BL_COMMON_SOURCES := common/bl_common.c \
...
@@ -102,7 +102,6 @@ BL_COMMON_SOURCES := common/bl_common.c \
lib/aarch64/misc_helpers.S
\
lib/aarch64/misc_helpers.S
\
lib/aarch64/xlat_helpers.c
\
lib/aarch64/xlat_helpers.c
\
lib/stdlib/std.c
\
lib/stdlib/std.c
\
lib/io_storage.c
\
plat/common/aarch64/platform_helpers.S
plat/common/aarch64/platform_helpers.S
BUILD_BASE
:=
./build
BUILD_BASE
:=
./build
...
@@ -180,6 +179,7 @@ INCLUDES += -Iinclude/bl31 \
...
@@ -180,6 +179,7 @@ INCLUDES += -Iinclude/bl31 \
-Iinclude
/common
\
-Iinclude
/common
\
-Iinclude
/drivers
\
-Iinclude
/drivers
\
-Iinclude
/drivers/arm
\
-Iinclude
/drivers/arm
\
-Iinclude
/drivers/io
\
-Iinclude
/lib
\
-Iinclude
/lib
\
-Iinclude
/lib/aarch64
\
-Iinclude
/lib/aarch64
\
-Iinclude
/plat/common
\
-Iinclude
/plat/common
\
...
...
This diff is collapsed.
Click to expand it.
docs/porting-guide.md
View file @
e98f414b
...
@@ -218,6 +218,21 @@ be defined as well:
...
@@ -218,6 +218,21 @@ be defined as well:
the secure memory identified by `TSP_SEC_MEM_BASE` and `TSP_SEC_MEM_SIZE`
the secure memory identified by `TSP_SEC_MEM_BASE` and `TSP_SEC_MEM_SIZE`
constants.
constants.
If the platform port uses the IO storage framework, the following constants
must also be defined:
*
**#define : MAX_IO_DEVICES**
Defines the maximum number of registered IO devices. Attempting to register
more devices than this value using `io_register_device()` will fail with
IO_RESOURCES_EXHAUSTED.
*
**#define : MAX_IO_HANDLES**
Defines the maximum number of open IO handles. Attempting to open more IO
entities than this value using `io_open()` will fail with
IO_RESOURCES_EXHAUSTED.
The following constants are optional. They should be defined when the platform
The following constants are optional. They should be defined when the platform
memory layout implies some image overlaying like on FVP.
memory layout implies some image overlaying like on FVP.
...
...
This diff is collapsed.
Click to expand it.
drivers/arm/cci400/cci400.c
View file @
e98f414b
...
@@ -28,34 +28,80 @@
...
@@ -28,34 +28,80 @@
* POSSIBILITY OF SUCH DAMAGE.
* POSSIBILITY OF SUCH DAMAGE.
*/
*/
#include <arch.h>
#include <assert.h>
#include <cci400.h>
#include <cci400.h>
#include <mmio.h>
#include <mmio.h>
#include <platform_def.h>
#define MAX_CLUSTERS 2
static
unsigned
long
cci_base_addr
;
static
unsigned
int
cci_cluster_ix_to_iface
[
MAX_CLUSTERS
];
void
cci_init
(
unsigned
long
cci_base
,
int
slave_iface3_cluster_ix
,
int
slave_iface4_cluster_ix
)
{
/*
* Check the passed arguments are valid. The cluster indices must be
* less than MAX_CLUSTERS, not the same as each other and at least one
* of them must be refer to a valid cluster index.
*/
assert
(
cci_base
);
assert
(
slave_iface3_cluster_ix
<
MAX_CLUSTERS
);
assert
(
slave_iface4_cluster_ix
<
MAX_CLUSTERS
);
assert
(
slave_iface3_cluster_ix
!=
slave_iface4_cluster_ix
);
assert
((
slave_iface3_cluster_ix
>=
0
)
||
(
slave_iface3_cluster_ix
>=
0
));
cci_base_addr
=
cci_base
;
if
(
slave_iface3_cluster_ix
>=
0
)
cci_cluster_ix_to_iface
[
slave_iface3_cluster_ix
]
=
SLAVE_IFACE3_OFFSET
;
if
(
slave_iface4_cluster_ix
>=
0
)
cci_cluster_ix_to_iface
[
slave_iface4_cluster_ix
]
=
SLAVE_IFACE4_OFFSET
;
}
static
inline
unsigned
long
get_slave_iface_base
(
unsigned
long
mpidr
)
static
inline
unsigned
long
get_slave_iface_base
(
unsigned
long
mpidr
)
{
{
return
CCI400_BASE
+
SLAVE_IFACE_OFFSET
(
CCI400_SL_IFACE_INDEX
(
mpidr
));
/*
* We assume the TF topology code allocates affinity instances
* consecutively from zero.
* It is a programming error if this is called without initializing
* the slave interface to use for this cluster.
*/
unsigned
int
cluster_id
=
(
mpidr
>>
MPIDR_AFF1_SHIFT
)
&
MPIDR_AFFLVL_MASK
;
assert
(
cluster_id
<
MAX_CLUSTERS
);
assert
(
cci_cluster_ix_to_iface
[
cluster_id
]
!=
0
);
return
cci_base_addr
+
cci_cluster_ix_to_iface
[
cluster_id
];
}
}
void
cci_enable_coherency
(
unsigned
long
mpidr
)
void
cci_enable_
cluster_
coherency
(
unsigned
long
mpidr
)
{
{
assert
(
cci_base_addr
);
/* Enable Snoops and DVM messages */
/* Enable Snoops and DVM messages */
mmio_write_32
(
get_slave_iface_base
(
mpidr
)
+
SNOOP_CTRL_REG
,
mmio_write_32
(
get_slave_iface_base
(
mpidr
)
+
SNOOP_CTRL_REG
,
DVM_EN_BIT
|
SNOOP_EN_BIT
);
DVM_EN_BIT
|
SNOOP_EN_BIT
);
/* Wait for the dust to settle down */
/* Wait for the dust to settle down */
while
(
mmio_read_32
(
CCI400_BASE
+
STATUS_REG
)
&
CHANGE_PENDING_BIT
)
while
(
mmio_read_32
(
cci_base_addr
+
STATUS_REG
)
&
CHANGE_PENDING_BIT
)
;
;
}
}
void
cci_disable_coherency
(
unsigned
long
mpidr
)
void
cci_disable_
cluster_
coherency
(
unsigned
long
mpidr
)
{
{
assert
(
cci_base_addr
);
/* Disable Snoops and DVM messages */
/* Disable Snoops and DVM messages */
mmio_write_32
(
get_slave_iface_base
(
mpidr
)
+
SNOOP_CTRL_REG
,
mmio_write_32
(
get_slave_iface_base
(
mpidr
)
+
SNOOP_CTRL_REG
,
~
(
DVM_EN_BIT
|
SNOOP_EN_BIT
));
~
(
DVM_EN_BIT
|
SNOOP_EN_BIT
));
/* Wait for the dust to settle down */
/* Wait for the dust to settle down */
while
(
mmio_read_32
(
CCI400_BASE
+
STATUS_REG
)
&
CHANGE_PENDING_BIT
)
while
(
mmio_read_32
(
cci_base_addr
+
STATUS_REG
)
&
CHANGE_PENDING_BIT
)
;
;
}
}
This diff is collapsed.
Click to expand it.
drivers/arm/tzc400/tzc400.c
View file @
e98f414b
...
@@ -34,54 +34,88 @@
...
@@ -34,54 +34,88 @@
#include <stddef.h>
#include <stddef.h>
#include <tzc400.h>
#include <tzc400.h>
static
uint32_t
tzc_read_build_config
(
uint64_t
base
)
/*
* Implementation defined values used to validate inputs later.
* Filters : max of 4 ; 0 to 3
* Regions : max of 9 ; 0 to 8
* Address width : Values between 32 to 64
*/
typedef
struct
tzc_instance
{
uint64_t
base
;
uint8_t
addr_width
;
uint8_t
num_filters
;
uint8_t
num_regions
;
}
tzc_instance_t
;
tzc_instance_t
tzc
;
static
inline
uint32_t
tzc_read_build_config
(
uint64_t
base
)
{
{
return
mmio_read_32
(
base
+
BUILD_CONFIG_OFF
);
return
mmio_read_32
(
base
+
BUILD_CONFIG_OFF
);
}
}
static
uint32_t
tzc_read_gate_keeper
(
uint64_t
base
)
static
inline
uint32_t
tzc_read_gate_keeper
(
uint64_t
base
)
{
{
return
mmio_read_32
(
base
+
GATE_KEEPER_OFF
);
return
mmio_read_32
(
base
+
GATE_KEEPER_OFF
);
}
}
static
void
tzc_write_gate_keeper
(
uint64_t
base
,
uint32_t
val
)
static
inline
void
tzc_write_gate_keeper
(
uint64_t
base
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
GATE_KEEPER_OFF
,
val
);
mmio_write_32
(
base
+
GATE_KEEPER_OFF
,
val
);
}
}
static
void
tzc_write_action
(
uint64_t
base
,
tzc_action_t
action
)
static
inline
void
tzc_write_action
(
uint64_t
base
,
tzc_action_t
action
)
{
{
mmio_write_32
(
base
+
ACTION_OFF
,
action
);
mmio_write_32
(
base
+
ACTION_OFF
,
action
);
}
}
static
void
tzc_write_region_base_low
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
static
inline
void
tzc_write_region_base_low
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
REGION_BASE_LOW_OFF
+
REGION_NUM_OFF
(
region
),
val
);
mmio_write_32
(
base
+
REGION_BASE_LOW_OFF
+
REGION_NUM_OFF
(
region
),
val
);
}
}
static
void
tzc_write_region_base_high
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
static
inline
void
tzc_write_region_base_high
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
REGION_BASE_HIGH_OFF
+
REGION_NUM_OFF
(
region
),
val
);
mmio_write_32
(
base
+
REGION_BASE_HIGH_OFF
+
REGION_NUM_OFF
(
region
),
val
);
}
}
static
void
tzc_write_region_top_low
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
static
inline
void
tzc_write_region_top_low
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
REGION_TOP_LOW_OFF
+
REGION_NUM_OFF
(
region
),
val
);
mmio_write_32
(
base
+
REGION_TOP_LOW_OFF
+
REGION_NUM_OFF
(
region
),
val
);
}
}
static
void
tzc_write_region_top_high
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
static
inline
void
tzc_write_region_top_high
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
REGION_TOP_HIGH_OFF
+
REGION_NUM_OFF
(
region
),
val
);
mmio_write_32
(
base
+
REGION_TOP_HIGH_OFF
+
REGION_NUM_OFF
(
region
),
val
);
}
}
static
void
tzc_write_region_attributes
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
static
inline
void
tzc_write_region_attributes
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
REGION_ATTRIBUTES_OFF
+
REGION_NUM_OFF
(
region
),
val
);
mmio_write_32
(
base
+
REGION_ATTRIBUTES_OFF
+
REGION_NUM_OFF
(
region
),
val
);
}
}
static
void
tzc_write_region_id_access
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
static
inline
void
tzc_write_region_id_access
(
uint64_t
base
,
uint32_t
region
,
uint32_t
val
)
{
{
mmio_write_32
(
base
+
REGION_ID_ACCESS_OFF
+
REGION_NUM_OFF
(
region
),
val
);
mmio_write_32
(
base
+
REGION_ID_ACCESS_OFF
+
REGION_NUM_OFF
(
region
),
val
);
}
}
static
uint32_t
tzc_read_component_id
(
uint64_t
base
)
static
uint32_t
tzc_read_component_id
(
uint64_t
base
)
...
@@ -130,29 +164,30 @@ static void tzc_set_gate_keeper(uint64_t base, uint8_t filter, uint32_t val)
...
@@ -130,29 +164,30 @@ static void tzc_set_gate_keeper(uint64_t base, uint8_t filter, uint32_t val)
}
}
void
tzc_init
(
tzc_instance_t
*
controller
)
void
tzc_init
(
uint64_t
base
)
{
{
uint32_t
tzc_id
,
tzc_build
;
uint32_t
tzc_id
,
tzc_build
;
assert
(
controller
!=
NULL
);
assert
(
base
);
tzc
.
base
=
base
;
/*
/*
* We expect to see a tzc400. Check component ID. The TZC-400 TRM shows
* We expect to see a tzc400. Check component ID. The TZC-400 TRM shows
* component ID is expected to be "0xB105F00D".
* component ID is expected to be "0xB105F00D".
*/
*/
tzc_id
=
tzc_read_component_id
(
controller
->
base
);
tzc_id
=
tzc_read_component_id
(
tzc
.
base
);
if
(
tzc_id
!=
TZC400_COMPONENT_ID
)
{
if
(
tzc_id
!=
TZC400_COMPONENT_ID
)
{
ERROR
(
"TZC : Wrong device ID (0x%x).
\n
"
,
tzc_id
);
ERROR
(
"TZC : Wrong device ID (0x%x).
\n
"
,
tzc_id
);
panic
();
panic
();
}
}
/* Save values we will use later. */
/* Save values we will use later. */
tzc_build
=
tzc_read_build_config
(
controller
->
base
);
tzc_build
=
tzc_read_build_config
(
tzc
.
base
);
controller
->
num_filters
=
((
tzc_build
>>
BUILD_CONFIG_NF_SHIFT
)
&
tzc
.
num_filters
=
((
tzc_build
>>
BUILD_CONFIG_NF_SHIFT
)
&
BUILD_CONFIG_NF_MASK
)
+
1
;
BUILD_CONFIG_NF_MASK
)
+
1
;
controller
->
addr_width
=
((
tzc_build
>>
BUILD_CONFIG_AW_SHIFT
)
&
tzc
.
addr_width
=
((
tzc_build
>>
BUILD_CONFIG_AW_SHIFT
)
&
BUILD_CONFIG_AW_MASK
)
+
1
;
BUILD_CONFIG_AW_MASK
)
+
1
;
controller
->
num_regions
=
((
tzc_build
>>
BUILD_CONFIG_NR_SHIFT
)
&
tzc
.
num_regions
=
((
tzc_build
>>
BUILD_CONFIG_NR_SHIFT
)
&
BUILD_CONFIG_NR_MASK
)
+
1
;
BUILD_CONFIG_NR_MASK
)
+
1
;
}
}
...
@@ -166,29 +201,25 @@ void tzc_init(tzc_instance_t *controller)
...
@@ -166,29 +201,25 @@ void tzc_init(tzc_instance_t *controller)
* this cannot be changed. It is, however, possible to change some region 0
* this cannot be changed. It is, however, possible to change some region 0
* permissions.
* permissions.
*/
*/
void
tzc_configure_region
(
const
tzc_instance_t
*
controller
,
void
tzc_configure_region
(
uint32_t
filters
,
uint32_t
filters
,
uint8_t
region
,
uint8_t
region
,
uint64_t
region_base
,
uint64_t
region_base
,
uint64_t
region_top
,
uint64_t
region_top
,
tzc_region_attributes_t
sec_attr
,
tzc_region_attributes_t
sec_attr
,
uint32_t
ns_device_access
)
uint32_t
ns_device_access
)
{
{
uint64_t
max_addr
;
assert
(
tzc
.
base
);
assert
(
controller
!=
NULL
);
/* Do range checks on filters and regions. */
/* Do range checks on filters and regions. */
assert
(((
filters
>>
controller
->
num_filters
)
==
0
)
&&
assert
(((
filters
>>
tzc
.
num_filters
)
==
0
)
&&
(
region
<
controller
->
num_regions
));
(
region
<
tzc
.
num_regions
));
/*
/*
* Do address range check based on TZC configuration. A 64bit address is
* Do address range check based on TZC configuration. A 64bit address is
* the max and expected case.
* the max and expected case.
*/
*/
max_addr
=
UINT64_MAX
>>
(
64
-
controller
->
addr_width
);
assert
(((
region_top
<=
(
UINT64_MAX
>>
(
64
-
tzc
.
addr_width
)))
&&
if
((
region_top
>
max_addr
)
||
(
region_base
>=
region_top
))
(
region_base
<
region_top
)));
assert
(
0
);
/* region_base and (region_top + 1) must be 4KB aligned */
/* region_base and (region_top + 1) must be 4KB aligned */
assert
(((
region_base
|
(
region_top
+
1
))
&
(
4096
-
1
))
==
0
);
assert
(((
region_base
|
(
region_top
+
1
))
&
(
4096
-
1
))
==
0
);
...
@@ -200,46 +231,50 @@ void tzc_configure_region(const tzc_instance_t *controller,
...
@@ -200,46 +231,50 @@ void tzc_configure_region(const tzc_instance_t *controller,
* All the address registers are 32 bits wide and have a LOW and HIGH
* All the address registers are 32 bits wide and have a LOW and HIGH
* component used to construct a up to a 64bit address.
* component used to construct a up to a 64bit address.
*/
*/
tzc_write_region_base_low
(
controller
->
base
,
region
,
(
uint32_t
)(
region_base
));
tzc_write_region_base_low
(
tzc
.
base
,
region
,
tzc_write_region_base_high
(
controller
->
base
,
region
,
(
uint32_t
)(
region_base
>>
32
));
(
uint32_t
)(
region_base
));
tzc_write_region_base_high
(
tzc
.
base
,
region
,
(
uint32_t
)(
region_base
>>
32
));
tzc_write_region_top_low
(
controller
->
base
,
region
,
(
uint32_t
)(
region_top
));
tzc_write_region_top_low
(
tzc
.
base
,
region
,
tzc_write_region_top_high
(
controller
->
base
,
region
,
(
uint32_t
)(
region_top
>>
32
));
(
uint32_t
)(
region_top
));
tzc_write_region_top_high
(
tzc
.
base
,
region
,
(
uint32_t
)(
region_top
>>
32
));
/* Assign the region to a filter and set secure attributes */
/* Assign the region to a filter and set secure attributes */
tzc_write_region_attributes
(
controller
->
base
,
region
,
tzc_write_region_attributes
(
tzc
.
base
,
region
,
(
sec_attr
<<
REGION_ATTRIBUTES_SEC_SHIFT
)
|
filters
);
(
sec_attr
<<
REGION_ATTRIBUTES_SEC_SHIFT
)
|
filters
);
/*
/*
* Specify which non-secure devices have permission to access this
* Specify which non-secure devices have permission to access this
* region.
* region.
*/
*/
tzc_write_region_id_access
(
controller
->
base
,
region
,
ns_device_access
);
tzc_write_region_id_access
(
tzc
.
base
,
region
,
ns_device_access
);
}
}
void
tzc_set_action
(
const
tzc_instance_t
*
controller
,
tzc_action_t
action
)
void
tzc_set_action
(
tzc_action_t
action
)
{
{
assert
(
controller
!=
NULL
);
assert
(
tzc
.
base
);
/*
/*
* - Currently no handler is provided to trap an error via interrupt
* - Currently no handler is provided to trap an error via interrupt
* or exception.
* or exception.
* - The interrupt action has not been tested.
* - The interrupt action has not been tested.
*/
*/
tzc_write_action
(
controller
->
base
,
action
);
tzc_write_action
(
tzc
.
base
,
action
);
}
}
void
tzc_enable_filters
(
const
tzc_instance_t
*
controller
)
void
tzc_enable_filters
(
void
)
{
{
uint32_t
state
;
uint32_t
state
;
uint32_t
filter
;
uint32_t
filter
;
assert
(
controller
!=
NULL
);
assert
(
tzc
.
base
);
for
(
filter
=
0
;
filter
<
controller
->
num_filters
;
filter
++
)
{
for
(
filter
=
0
;
filter
<
tzc
.
num_filters
;
filter
++
)
{
state
=
tzc_get_gate_keeper
(
controller
->
base
,
filter
);
state
=
tzc_get_gate_keeper
(
tzc
.
base
,
filter
);
if
(
state
)
{
if
(
state
)
{
/* The TZC filter is already configured. Changing the
/* The TZC filter is already configured. Changing the
* programmer's view in an active system can cause
* programmer's view in an active system can cause
...
@@ -252,21 +287,21 @@ void tzc_enable_filters(const tzc_instance_t *controller)
...
@@ -252,21 +287,21 @@ void tzc_enable_filters(const tzc_instance_t *controller)
filter
);
filter
);
panic
();
panic
();
}
}
tzc_set_gate_keeper
(
controller
->
base
,
filter
,
1
);
tzc_set_gate_keeper
(
tzc
.
base
,
filter
,
1
);
}
}
}
}
void
tzc_disable_filters
(
const
tzc_instance_t
*
controller
)
void
tzc_disable_filters
(
void
)
{
{
uint32_t
filter
;
uint32_t
filter
;
assert
(
controller
!=
NULL
);
assert
(
tzc
.
base
);
/*
/*
* We don't do the same state check as above as the Gatekeepers are
* We don't do the same state check as above as the Gatekeepers are
* disabled after reset.
* disabled after reset.
*/
*/
for
(
filter
=
0
;
filter
<
controller
->
num_filters
;
filter
++
)
for
(
filter
=
0
;
filter
<
tzc
.
num_filters
;
filter
++
)
tzc_set_gate_keeper
(
controller
->
base
,
filter
,
0
);
tzc_set_gate_keeper
(
tzc
.
base
,
filter
,
0
);
}
}
This diff is collapsed.
Click to expand it.
lib
/io_storage.c
→
drivers/io
/io_storage.c
View file @
e98f414b
...
@@ -31,13 +31,10 @@
...
@@ -31,13 +31,10 @@
#include <assert.h>
#include <assert.h>
#include <io_driver.h>
#include <io_driver.h>
#include <io_storage.h>
#include <io_storage.h>
#include <platform_def.h>
#include <stddef.h>
#include <stddef.h>
#define MAX_DEVICES(plat_data) \
(sizeof((plat_data)->devices)/sizeof((plat_data)->devices[0]))
/* Storage for a fixed maximum number of IO entities, definable by platform */
/* Storage for a fixed maximum number of IO entities, definable by platform */
static
io_entity_t
entity_pool
[
MAX_IO_HANDLES
];
static
io_entity_t
entity_pool
[
MAX_IO_HANDLES
];
...
@@ -48,9 +45,11 @@ static io_entity_t *entity_map[MAX_IO_HANDLES];
...
@@ -48,9 +45,11 @@ static io_entity_t *entity_map[MAX_IO_HANDLES];
/* Track number of allocated entities */
/* Track number of allocated entities */
static
unsigned
int
entity_count
;
static
unsigned
int
entity_count
;
/* Array of fixed maximum of registered devices, definable by platform */
static
const
io_dev_info_t
*
devices
[
MAX_IO_DEVICES
];
/*
Used to keep a reference to platform-specific data
*/
/*
Number of currently registered devices
*/
static
io_plat_data_t
*
platform_data
;
static
unsigned
int
dev_count
;
#if DEBUG
/* Extra validation functions only used in debug builds */
#if DEBUG
/* Extra validation functions only used in debug builds */
...
@@ -167,27 +166,15 @@ static int free_entity(const io_entity_t *entity)
...
@@ -167,27 +166,15 @@ static int free_entity(const io_entity_t *entity)
/* Exported API */
/* Exported API */
/* Initialise the IO layer */
void
io_init
(
io_plat_data_t
*
data
)
{
assert
(
data
!=
NULL
);
platform_data
=
data
;
}
/* Register a device driver */
/* Register a device driver */
int
io_register_device
(
const
io_dev_info_t
*
dev_info
)
int
io_register_device
(
const
io_dev_info_t
*
dev_info
)
{
{
int
result
=
IO_FAIL
;
int
result
=
IO_FAIL
;
assert
(
dev_info
!=
NULL
);
assert
(
dev_info
!=
NULL
);
assert
(
platform_data
!=
NULL
);
unsigned
int
dev_count
=
platform_data
->
dev_count
;
if
(
dev_count
<
MAX_DEVICES
(
platform_data
)
)
{
if
(
dev_count
<
MAX_
IO_
DEVICES
)
{
platform_data
->
devices
[
dev_count
]
=
dev_info
;
devices
[
dev_count
]
=
dev_info
;
platform_data
->
dev_count
++
;
dev_count
++
;
result
=
IO_SUCCESS
;
result
=
IO_SUCCESS
;
}
else
{
}
else
{
result
=
IO_RESOURCES_EXHAUSTED
;
result
=
IO_RESOURCES_EXHAUSTED
;
...
...
This diff is collapsed.
Click to expand it.
include/drivers/arm/cci400.h
View file @
e98f414b
...
@@ -37,7 +37,8 @@
...
@@ -37,7 +37,8 @@
#define SLAVE_IFACE2_OFFSET 0x3000
#define SLAVE_IFACE2_OFFSET 0x3000
#define SLAVE_IFACE1_OFFSET 0x2000
#define SLAVE_IFACE1_OFFSET 0x2000
#define SLAVE_IFACE0_OFFSET 0x1000
#define SLAVE_IFACE0_OFFSET 0x1000
#define SLAVE_IFACE_OFFSET(index) SLAVE_IFACE0_OFFSET + (0x1000 * index)
#define SLAVE_IFACE_OFFSET(index) SLAVE_IFACE0_OFFSET + \
(0x1000 * (index))
/* Control and ID register offsets */
/* Control and ID register offsets */
#define CTRL_OVERRIDE_REG 0x0
#define CTRL_OVERRIDE_REG 0x0
...
@@ -68,8 +69,22 @@
...
@@ -68,8 +69,22 @@
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLY__
/* Function declarations */
/* Function declarations */
void
cci_enable_coherency
(
unsigned
long
mpidr
);
void
cci_disable_coherency
(
unsigned
long
mpidr
);
/*
* The CCI-400 driver must be initialized with the base address of the
* CCI-400 device in the platform memory map, and the cluster indices for
* the CCI-400 slave interfaces 3 and 4 respectively. These are the fully
* coherent ACE slave interfaces of CCI-400.
* The cluster indices must either be 0 or 1, corresponding to the level 1
* affinity instance of the mpidr representing the cluster. A negative cluster
* index indicates that no cluster is present on that slave interface.
*/
void
cci_init
(
unsigned
long
cci_base
,
int
slave_iface3_cluster_ix
,
int
slave_iface4_cluster_ix
);
void
cci_enable_cluster_coherency
(
unsigned
long
mpidr
);
void
cci_disable_cluster_coherency
(
unsigned
long
mpidr
);
#endif
/* __ASSEMBLY__ */
#endif
/* __ASSEMBLY__ */
#endif
/* __CCI_400_H__ */
#endif
/* __CCI_400_H__ */
This diff is collapsed.
Click to expand it.
include/drivers/arm/tzc400.h
View file @
e98f414b
...
@@ -182,27 +182,17 @@ typedef enum {
...
@@ -182,27 +182,17 @@ typedef enum {
TZC_REGION_S_RDWR
=
(
TZC_REGION_S_RD
|
TZC_REGION_S_WR
)
TZC_REGION_S_RDWR
=
(
TZC_REGION_S_RD
|
TZC_REGION_S_WR
)
}
tzc_region_attributes_t
;
}
tzc_region_attributes_t
;
/*
* Implementation defined values used to validate inputs later.
void
tzc_init
(
uint64_t
base
);
* Filters : max of 4 ; 0 to 3
void
tzc_configure_region
(
uint32_t
filters
,
* Regions : max of 9 ; 0 to 8
uint8_t
region
,
* Address width : Values between 32 to 64
uint64_t
region_base
,
*/
uint64_t
region_top
,
typedef
struct
tzc_instance
{
tzc_region_attributes_t
sec_attr
,
uint64_t
base
;
uint32_t
ns_device_access
);
uint32_t
aid_width
;
void
tzc_enable_filters
(
void
);
uint8_t
addr_width
;
void
tzc_disable_filters
(
void
);
uint8_t
num_filters
;
void
tzc_set_action
(
tzc_action_t
action
);
uint8_t
num_regions
;
}
tzc_instance_t
;
void
tzc_init
(
tzc_instance_t
*
controller
);
void
tzc_configure_region
(
const
tzc_instance_t
*
controller
,
uint32_t
filters
,
uint8_t
region
,
uint64_t
region_base
,
uint64_t
region_top
,
tzc_region_attributes_t
sec_attr
,
uint32_t
ns_device_access
);
void
tzc_enable_filters
(
const
tzc_instance_t
*
controller
);
void
tzc_disable_filters
(
const
tzc_instance_t
*
controller
);
void
tzc_set_action
(
const
tzc_instance_t
*
controller
,
tzc_action_t
action
);
#endif
/* __TZC400__ */
#endif
/* __TZC400__ */
This diff is collapsed.
Click to expand it.
include/drivers/io_driver.h
→
include/drivers/io
/io
_driver.h
View file @
e98f414b
...
@@ -32,7 +32,6 @@
...
@@ -32,7 +32,6 @@
#define __IO_DRIVER_H__
#define __IO_DRIVER_H__
#include <io_storage.h>
#include <io_storage.h>
#include <platform_def.h>
/* For MAX_IO_DEVICES */
#include <stdint.h>
#include <stdint.h>
...
@@ -76,20 +75,9 @@ typedef struct io_dev_funcs {
...
@@ -76,20 +75,9 @@ typedef struct io_dev_funcs {
}
io_dev_funcs_t
;
}
io_dev_funcs_t
;
/* IO platform data - used to track devices registered for a specific
* platform */
typedef
struct
io_plat_data
{
const
io_dev_info_t
*
devices
[
MAX_IO_DEVICES
];
unsigned
int
dev_count
;
}
io_plat_data_t
;
/* Operations intended to be performed during platform initialisation */
/* Operations intended to be performed during platform initialisation */
/* Initialise the IO layer */
/* Register an IO device */
void
io_init
(
io_plat_data_t
*
data
);
/* Register a device driver */
int
io_register_device
(
const
io_dev_info_t
*
dev_info
);
int
io_register_device
(
const
io_dev_info_t
*
dev_info
);
#endif
/* __IO_DRIVER_H__ */
#endif
/* __IO_DRIVER_H__ */
This diff is collapsed.
Click to expand it.
include/drivers/io_fip.h
→
include/drivers/io
/io
_fip.h
View file @
e98f414b
File moved
This diff is collapsed.
Click to expand it.
include/drivers/io_memmap.h
→
include/drivers/io
/io
_memmap.h
View file @
e98f414b
File moved
This diff is collapsed.
Click to expand it.
include/drivers/io_semihosting.h
→
include/drivers/io
/io
_semihosting.h
View file @
e98f414b
File moved
This diff is collapsed.
Click to expand it.
include/
lib
/io_storage.h
→
include/
drivers/io
/io_storage.h
View file @
e98f414b
File moved
This diff is collapsed.
Click to expand it.
plat/fvp/aarch64/fvp_common.c
View file @
e98f414b
...
@@ -31,7 +31,6 @@
...
@@ -31,7 +31,6 @@
#include <arch.h>
#include <arch.h>
#include <arch_helpers.h>
#include <arch_helpers.h>
#include <arm_gic.h>
#include <arm_gic.h>
#include <assert.h>
#include <bl_common.h>
#include <bl_common.h>
#include <cci400.h>
#include <cci400.h>
#include <debug.h>
#include <debug.h>
...
@@ -243,15 +242,26 @@ uint64_t plat_get_syscnt_freq(void)
...
@@ -243,15 +242,26 @@ uint64_t plat_get_syscnt_freq(void)
return
counter_base_frequency
;
return
counter_base_frequency
;
}
}
void
fvp_cci_
setup
(
void
)
void
fvp_cci_
init
(
void
)
{
{
/*
/*
* Enable CCI-400 for this cluster. No need
* Initialize CCI-400 driver
*/
if
(
plat_config
.
flags
&
CONFIG_HAS_CCI
)
cci_init
(
CCI400_BASE
,
CCI400_SL_IFACE3_CLUSTER_IX
,
CCI400_SL_IFACE4_CLUSTER_IX
);
}
void
fvp_cci_enable
(
void
)
{
/*
* Enable CCI-400 coherency for this cluster. No need
* for locks as no other cpu is active at the
* for locks as no other cpu is active at the
* moment
* moment
*/
*/
if
(
plat_config
.
flags
&
CONFIG_HAS_CCI
)
if
(
plat_config
.
flags
&
CONFIG_HAS_CCI
)
cci_enable_coherency
(
read_mpidr
());
cci_enable_
cluster_
coherency
(
read_mpidr
());
}
}
void
fvp_gic_init
(
void
)
void
fvp_gic_init
(
void
)
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/bl1_fvp_setup.c
View file @
e98f414b
...
@@ -110,7 +110,8 @@ void bl1_platform_setup(void)
...
@@ -110,7 +110,8 @@ void bl1_platform_setup(void)
******************************************************************************/
******************************************************************************/
void
bl1_plat_arch_setup
(
void
)
void
bl1_plat_arch_setup
(
void
)
{
{
fvp_cci_setup
();
fvp_cci_init
();
fvp_cci_enable
();
fvp_configure_mmu_el3
(
bl1_tzram_layout
.
total_base
,
fvp_configure_mmu_el3
(
bl1_tzram_layout
.
total_base
,
bl1_tzram_layout
.
total_size
,
bl1_tzram_layout
.
total_size
,
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/bl31_fvp_setup.c
View file @
e98f414b
...
@@ -230,9 +230,9 @@ void bl31_platform_setup(void)
...
@@ -230,9 +230,9 @@ void bl31_platform_setup(void)
******************************************************************************/
******************************************************************************/
void
bl31_plat_arch_setup
(
void
)
void
bl31_plat_arch_setup
(
void
)
{
{
fvp_cci_init
();
#if RESET_TO_BL31
#if RESET_TO_BL31
fvp_cci_setup
();
fvp_cci_enable
();
#endif
#endif
fvp_configure_mmu_el3
(
BL31_RO_BASE
,
fvp_configure_mmu_el3
(
BL31_RO_BASE
,
(
BL31_COHERENT_RAM_LIMIT
-
BL31_RO_BASE
),
(
BL31_COHERENT_RAM_LIMIT
-
BL31_RO_BASE
),
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/fvp_def.h
View file @
e98f414b
...
@@ -184,11 +184,8 @@
...
@@ -184,11 +184,8 @@
* CCI-400 related constants
* CCI-400 related constants
******************************************************************************/
******************************************************************************/
#define CCI400_BASE 0x2c090000
#define CCI400_BASE 0x2c090000
#define CCI400_SL_IFACE_CLUSTER0 3
#define CCI400_SL_IFACE3_CLUSTER_IX 0
#define CCI400_SL_IFACE_CLUSTER1 4
#define CCI400_SL_IFACE4_CLUSTER_IX 1
#define CCI400_SL_IFACE_INDEX(mpidr) (mpidr & MPIDR_CLUSTER_MASK ? \
CCI400_SL_IFACE_CLUSTER1 : \
CCI400_SL_IFACE_CLUSTER0)
/*******************************************************************************
/*******************************************************************************
* GIC-400 & interrupt handling related constants
* GIC-400 & interrupt handling related constants
...
@@ -242,9 +239,6 @@
...
@@ -242,9 +239,6 @@
* The NSAIDs for this platform as used to program the TZC400.
* The NSAIDs for this platform as used to program the TZC400.
*/
*/
/* The FVP has 4 bits of NSAIDs. Used with TZC FAIL_ID (ACE Lite ID width) */
#define FVP_AID_WIDTH 4
/* NSAIDs used by devices in TZC filter 0 on FVP */
/* NSAIDs used by devices in TZC filter 0 on FVP */
#define FVP_NSAID_DEFAULT 0
#define FVP_NSAID_DEFAULT 0
#define FVP_NSAID_PCI 1
#define FVP_NSAID_PCI 1
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/fvp_io_storage.c
View file @
e98f414b
...
@@ -35,12 +35,11 @@
...
@@ -35,12 +35,11 @@
#include <io_memmap.h>
#include <io_memmap.h>
#include <io_storage.h>
#include <io_storage.h>
#include <io_semihosting.h>
#include <io_semihosting.h>
#include <platform_def.h>
#include <semihosting.h>
/* For FOPEN_MODE_... */
#include <semihosting.h>
/* For FOPEN_MODE_... */
#include <string.h>
#include <string.h>
#include "fvp_def.h"
/* IO devices */
/* IO devices */
static
io_plat_data_t
io_data
;
static
const
io_dev_connector_t
*
sh_dev_con
;
static
const
io_dev_connector_t
*
sh_dev_con
;
static
uintptr_t
sh_dev_spec
;
static
uintptr_t
sh_dev_spec
;
static
uintptr_t
sh_init_params
;
static
uintptr_t
sh_init_params
;
...
@@ -172,9 +171,6 @@ void fvp_io_setup (void)
...
@@ -172,9 +171,6 @@ void fvp_io_setup (void)
{
{
int
io_result
=
IO_FAIL
;
int
io_result
=
IO_FAIL
;
/* Initialise the IO layer */
io_init
(
&
io_data
);
/* Register the IO devices on this platform */
/* Register the IO devices on this platform */
io_result
=
register_io_dev_sh
(
&
sh_dev_con
);
io_result
=
register_io_dev_sh
(
&
sh_dev_con
);
assert
(
io_result
==
IO_SUCCESS
);
assert
(
io_result
==
IO_SUCCESS
);
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/fvp_pm.c
View file @
e98f414b
...
@@ -140,7 +140,7 @@ int fvp_affinst_off(unsigned long mpidr,
...
@@ -140,7 +140,7 @@ int fvp_affinst_off(unsigned long mpidr,
* turned off
* turned off
*/
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
cci_disable_coherency
(
mpidr
);
cci_disable_
cluster_
coherency
(
mpidr
);
/*
/*
* Program the power controller to turn the
* Program the power controller to turn the
...
@@ -215,7 +215,7 @@ int fvp_affinst_suspend(unsigned long mpidr,
...
@@ -215,7 +215,7 @@ int fvp_affinst_suspend(unsigned long mpidr,
* turned off
* turned off
*/
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
cci_disable_coherency
(
mpidr
);
cci_disable_
cluster_
coherency
(
mpidr
);
/*
/*
* Program the power controller to turn the
* Program the power controller to turn the
...
@@ -302,7 +302,7 @@ int fvp_affinst_on_finish(unsigned long mpidr,
...
@@ -302,7 +302,7 @@ int fvp_affinst_on_finish(unsigned long mpidr,
*/
*/
fvp_pwrc_write_pponr
(
mpidr
);
fvp_pwrc_write_pponr
(
mpidr
);
fvp_cci_
setup
();
fvp_cci_
enable
();
}
}
break
;
break
;
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/fvp_private.h
View file @
e98f414b
...
@@ -77,7 +77,8 @@ void fvp_configure_mmu_el3(unsigned long total_base,
...
@@ -77,7 +77,8 @@ void fvp_configure_mmu_el3(unsigned long total_base,
unsigned
long
);
unsigned
long
);
int
fvp_config_setup
(
void
);
int
fvp_config_setup
(
void
);
void
fvp_cci_setup
(
void
);
void
fvp_cci_init
(
void
);
void
fvp_cci_enable
(
void
);
void
fvp_gic_init
(
void
);
void
fvp_gic_init
(
void
);
...
...
This diff is collapsed.
Click to expand it.
plat/fvp/fvp_security.c
View file @
e98f414b
...
@@ -46,8 +46,6 @@
...
@@ -46,8 +46,6 @@
*/
*/
void
fvp_security_setup
(
void
)
void
fvp_security_setup
(
void
)
{
{
tzc_instance_t
controller
;
/*
/*
* The Base FVP has a TrustZone address space controller, the Foundation
* The Base FVP has a TrustZone address space controller, the Foundation
* FVP does not. Trying to program the device on the foundation FVP will
* FVP does not. Trying to program the device on the foundation FVP will
...
@@ -71,9 +69,7 @@ void fvp_security_setup(void)
...
@@ -71,9 +69,7 @@ void fvp_security_setup(void)
* - Provide base address of device on platform.
* - Provide base address of device on platform.
* - Provide width of ACE-Lite IDs on platform.
* - Provide width of ACE-Lite IDs on platform.
*/
*/
controller
.
base
=
TZC400_BASE
;
tzc_init
(
TZC400_BASE
);
controller
.
aid_width
=
FVP_AID_WIDTH
;
tzc_init
(
&
controller
);
/*
/*
* Currently only filters 0 and 2 are connected on Base FVP.
* Currently only filters 0 and 2 are connected on Base FVP.
...
@@ -87,7 +83,7 @@ void fvp_security_setup(void)
...
@@ -87,7 +83,7 @@ void fvp_security_setup(void)
*/
*/
/* Disable all filters before programming. */
/* Disable all filters before programming. */
tzc_disable_filters
(
&
controller
);
tzc_disable_filters
();
/*
/*
* Allow only non-secure access to all DRAM to supported devices.
* Allow only non-secure access to all DRAM to supported devices.
...
@@ -101,7 +97,7 @@ void fvp_security_setup(void)
...
@@ -101,7 +97,7 @@ void fvp_security_setup(void)
*/
*/
/* Set to cover the first block of DRAM */
/* Set to cover the first block of DRAM */
tzc_configure_region
(
&
controller
,
FILTER_SHIFT
(
0
),
1
,
tzc_configure_region
(
FILTER_SHIFT
(
0
),
1
,
DRAM1_BASE
,
DRAM1_END
-
DRAM1_SEC_SIZE
,
DRAM1_BASE
,
DRAM1_END
-
DRAM1_SEC_SIZE
,
TZC_REGION_S_NONE
,
TZC_REGION_S_NONE
,
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_DEFAULT
)
|
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_DEFAULT
)
|
...
@@ -111,13 +107,13 @@ void fvp_security_setup(void)
...
@@ -111,13 +107,13 @@ void fvp_security_setup(void)
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_VIRTIO_OLD
));
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_VIRTIO_OLD
));
/* Set to cover the secure reserved region */
/* Set to cover the secure reserved region */
tzc_configure_region
(
&
controller
,
FILTER_SHIFT
(
0
),
3
,
tzc_configure_region
(
FILTER_SHIFT
(
0
),
3
,
(
DRAM1_END
-
DRAM1_SEC_SIZE
)
+
1
,
DRAM1_END
,
(
DRAM1_END
-
DRAM1_SEC_SIZE
)
+
1
,
DRAM1_END
,
TZC_REGION_S_RDWR
,
TZC_REGION_S_RDWR
,
0x0
);
0x0
);
/* Set to cover the second block of DRAM */
/* Set to cover the second block of DRAM */
tzc_configure_region
(
&
controller
,
FILTER_SHIFT
(
0
),
2
,
tzc_configure_region
(
FILTER_SHIFT
(
0
),
2
,
DRAM2_BASE
,
DRAM2_END
,
TZC_REGION_S_NONE
,
DRAM2_BASE
,
DRAM2_END
,
TZC_REGION_S_NONE
,
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_DEFAULT
)
|
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_DEFAULT
)
|
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_PCI
)
|
TZC_REGION_ACCESS_RDWR
(
FVP_NSAID_PCI
)
|
...
@@ -130,8 +126,8 @@ void fvp_security_setup(void)
...
@@ -130,8 +126,8 @@ void fvp_security_setup(void)
* options we have are for access errors to occur quietly or to
* options we have are for access errors to occur quietly or to
* cause an exception. We choose to cause an exception.
* cause an exception. We choose to cause an exception.
*/
*/
tzc_set_action
(
&
controller
,
TZC_ACTION_ERR
);
tzc_set_action
(
TZC_ACTION_ERR
);
/* Enable filters. */
/* Enable filters. */
tzc_enable_filters
(
&
controller
);
tzc_enable_filters
();
}
}
This diff is collapsed.
Click to expand it.
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Projects
Groups
Snippets
Help