plat: marvell: sip: make sure that comphy init will use correct address

The argument passed via x1 is used as a base address for comphy related
routines. Nevertheless validation of this address wasn't good enough and
allowed some non comphy related addresses to slip over.

To overcome this issue make sure that the address passed via SMC points
to valid CP range and allow to proceed comphy initializations only with
correct comphy offset.

This could be fixed in a different way e.g. by passing CP id from the
caller, but since this API is already used with various Linux, U-Boot
and UEFI versions it can't be changed.

Signed-off-by: Grzegorz Jaszczyk <jaz@semihalf.com>
Change-Id: Ia74dbc36efcfbefc4a102d31191e6af5808c4a82
This commit is contained in:
Grzegorz Jaszczyk 2019-04-04 17:16:39 +02:00
parent 8a08e27232
commit b143fa7491
1 changed files with 19 additions and 9 deletions

View File

@ -15,6 +15,7 @@
#include <plat_marvell.h>
#include "comphy/phy-comphy-cp110.h"
#include <stdbool.h>
/* #define DEBUG_COMPHY */
#ifdef DEBUG_COMPHY
@ -38,12 +39,24 @@
#define MAX_LANE_NR 6
#define MVEBU_COMPHY_OFFSET 0x441000
#define MVEBU_SD_OFFSET 0x120000
#define MVEBU_CP_BASE_MASK (~0xffffff)
/* This macro is used to identify COMPHY related calls from SMC function ID */
#define is_comphy_fid(fid) \
((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_DIG_RESET)
_Bool is_cp_range_valid(u_register_t *addr)
{
int cp_nr;
*addr &= MVEBU_CP_BASE_MASK;
for (cp_nr = 0; cp_nr < CP_NUM; cp_nr++) {
if (*addr == MVEBU_CP_REGS_BASE(cp_nr))
return true;
}
return false;
}
uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
u_register_t x1,
@ -59,20 +72,17 @@ uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
debug("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx, x3 0x%lx\n",
__func__, smc_fid, x1, x2, x3);
if (is_comphy_fid(smc_fid)) {
/* some systems passes SD phys address instead of COMPHY phys
* address - convert it
*/
if (x1 & MVEBU_SD_OFFSET)
x1 = (x1 & ~0xffffff) + MVEBU_COMPHY_OFFSET;
if ((x1 & 0xffffff) != MVEBU_COMPHY_OFFSET) {
/* validate address passed via x1 */
if (!is_cp_range_valid(&x1)) {
ERROR("%s: Wrong smc (0x%x) address: %lx\n",
__func__, smc_fid, x1);
SMC_RET1(handle, SMC_UNK);
}
x1 += MVEBU_COMPHY_OFFSET;
if (x2 >= MAX_LANE_NR) {
ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n",
__func__, smc_fid, x2);