mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
common/i2c: Add I2C passthru_protect command
This allows the AP to protect a I2C passthru bus. A board-specific function then defines what I2C commands are allowed, so that we can white/black list some addresses (e.g. I2C address allowing PD chip FW updating). BRANCH=none BUG=chrome-os-partner:52431 TEST=Book elm-rev1 Change-Id: Ib106924418b16388ea8ea53c7b6bda6ef92e1d09 Signed-off-by: Nicolas Boichat <drinkcat@google.com> Reviewed-on: https://chromium-review.googlesource.com/345761 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Randall Spangler <rspangler@google.com>
This commit is contained in:
committed by
chrome-bot
parent
d2bbc229f3
commit
f5bba241fd
110
common/i2c.c
110
common/i2c.c
@@ -34,6 +34,7 @@
|
||||
|
||||
static struct mutex port_mutex[I2C_CONTROLLER_COUNT];
|
||||
static uint32_t i2c_port_active_count;
|
||||
static uint8_t port_protected[I2C_CONTROLLER_COUNT];
|
||||
|
||||
const struct i2c_port_t *get_i2c_port(int port)
|
||||
{
|
||||
@@ -469,6 +470,7 @@ static int i2c_command_read(struct host_cmd_handler_args *args)
|
||||
{
|
||||
const struct ec_params_i2c_read *p = args->params;
|
||||
struct ec_response_i2c_read *r = args->response;
|
||||
const struct i2c_port_t *i2c_port;
|
||||
int data, rv = -1;
|
||||
|
||||
#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
|
||||
@@ -476,9 +478,15 @@ static int i2c_command_read(struct host_cmd_handler_args *args)
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
#endif
|
||||
|
||||
if (!get_i2c_port(p->port))
|
||||
i2c_port = get_i2c_port(p->port);
|
||||
if (!i2c_port)
|
||||
return EC_RES_INVALID_PARAM;
|
||||
|
||||
if (port_protected[p->port] && i2c_port->passthru_allowed) {
|
||||
if (!i2c_port->passthru_allowed(i2c_port, p->addr))
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (p->read_size == 16)
|
||||
rv = i2c_read16(p->port, p->addr, p->offset, &data);
|
||||
else if (p->read_size == 8)
|
||||
@@ -496,6 +504,7 @@ DECLARE_HOST_COMMAND(EC_CMD_I2C_READ, i2c_command_read, EC_VER_MASK(0));
|
||||
static int i2c_command_write(struct host_cmd_handler_args *args)
|
||||
{
|
||||
const struct ec_params_i2c_write *p = args->params;
|
||||
const struct i2c_port_t *i2c_port;
|
||||
int rv = -1;
|
||||
|
||||
#ifdef CONFIG_I2C_PASSTHRU_RESTRICTED
|
||||
@@ -503,9 +512,15 @@ static int i2c_command_write(struct host_cmd_handler_args *args)
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
#endif
|
||||
|
||||
if (!get_i2c_port(p->port))
|
||||
i2c_port = get_i2c_port(p->port);
|
||||
if (!i2c_port)
|
||||
return EC_RES_INVALID_PARAM;
|
||||
|
||||
if (port_protected[p->port] && i2c_port->passthru_allowed) {
|
||||
if (!i2c_port->passthru_allowed(i2c_port, p->addr))
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (p->write_size == 16)
|
||||
rv = i2c_write16(p->port, p->addr, p->offset, p->data);
|
||||
else if (p->write_size == 8)
|
||||
@@ -591,9 +606,10 @@ static int i2c_command_passthru(struct host_cmd_handler_args *args)
|
||||
const struct ec_params_i2c_passthru *params = args->params;
|
||||
const struct ec_params_i2c_passthru_msg *msg;
|
||||
struct ec_response_i2c_passthru *resp = args->response;
|
||||
const struct i2c_port_t *i2c_port;
|
||||
const uint8_t *out;
|
||||
int in_len;
|
||||
int ret;
|
||||
int ret, i;
|
||||
#if defined(VIRTUAL_BATTERY_ADDR) && defined(I2C_PORT_VIRTUAL_BATTERY)
|
||||
uint8_t batt_param = 0;
|
||||
#endif
|
||||
@@ -611,13 +627,22 @@ static int i2c_command_passthru(struct host_cmd_handler_args *args)
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
#endif
|
||||
|
||||
if (!get_i2c_port(params->port))
|
||||
i2c_port = get_i2c_port(params->port);
|
||||
if (!i2c_port)
|
||||
return EC_RES_INVALID_PARAM;
|
||||
|
||||
ret = check_i2c_params(args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (port_protected[params->port] && i2c_port->passthru_allowed) {
|
||||
for (i = 0; i < params->num_msgs; i++) {
|
||||
if (!i2c_port->passthru_allowed(i2c_port,
|
||||
params->msg[i].addr_flags & EC_I2C_ADDR_MASK))
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop and process messages */
|
||||
resp->i2c_status = 0;
|
||||
out = args->params + sizeof(*params) + params->num_msgs * sizeof(*msg);
|
||||
@@ -688,9 +713,86 @@ static int i2c_command_passthru(struct host_cmd_handler_args *args)
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_CMD_I2C_PASSTHRU, i2c_command_passthru, EC_VER_MASK(0));
|
||||
|
||||
static int i2c_command_passthru_protect(struct host_cmd_handler_args *args)
|
||||
{
|
||||
const struct ec_params_i2c_passthru_protect *params = args->params;
|
||||
struct ec_response_i2c_passthru_protect *resp = args->response;
|
||||
|
||||
if (args->params_size < sizeof(*params)) {
|
||||
PTHRUPRINTF("i2c passthru protect no params, params_size=%d, "
|
||||
"need at least %d",
|
||||
args->params_size, sizeof(*params));
|
||||
return EC_RES_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!get_i2c_port(params->port)) {
|
||||
PTHRUPRINTF("i2c passthru protect invalid port %d",
|
||||
params->port);
|
||||
return EC_RES_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (params->subcmd == EC_CMD_I2C_PASSTHRU_PROTECT_STATUS) {
|
||||
if (args->response_max < sizeof(*resp)) {
|
||||
PTHRUPRINTF("i2c passthru protect no response, "
|
||||
"response_max=%d, need at least %d",
|
||||
args->response_max, sizeof(*resp));
|
||||
return EC_RES_INVALID_PARAM;
|
||||
}
|
||||
|
||||
resp->status = port_protected[params->port];
|
||||
args->response_size = sizeof(*resp);
|
||||
} else if (params->subcmd == EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE) {
|
||||
port_protected[params->port] = 1;
|
||||
} else {
|
||||
return EC_RES_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
return EC_RES_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_CMD_I2C_PASSTHRU_PROTECT, i2c_command_passthru_protect,
|
||||
EC_VER_MASK(0));
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Console commands */
|
||||
|
||||
#ifdef CONFIG_CMD_I2C_PROTECT
|
||||
static int command_i2cprotect(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1) {
|
||||
int i, port;
|
||||
|
||||
for (i = 0; i < i2c_ports_used; i++) {
|
||||
port = i2c_ports[i].port;
|
||||
ccprintf("Port %d: %s\n", port,
|
||||
port_protected[port] ? "Protected" : "Unprotected");
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
int port;
|
||||
char *e;
|
||||
|
||||
port = strtoi(argv[1], &e, 0);
|
||||
if (*e)
|
||||
return EC_ERROR_PARAM2;
|
||||
|
||||
if (!get_i2c_port(port)) {
|
||||
ccprintf("i2c passthru protect invalid port %d\n",
|
||||
port);
|
||||
return EC_RES_INVALID_PARAM;
|
||||
}
|
||||
|
||||
port_protected[port] = 1;
|
||||
} else {
|
||||
return EC_ERROR_PARAM_COUNT;
|
||||
}
|
||||
|
||||
return EC_RES_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(i2cprotect, command_i2cprotect,
|
||||
"[port]",
|
||||
"Protect I2C bus",
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMD_I2C_SCAN
|
||||
static void scan_bus(int port, const char *desc)
|
||||
{
|
||||
|
||||
@@ -538,6 +538,7 @@
|
||||
#define CONFIG_CMD_HASH
|
||||
#define CONFIG_CMD_HCDEBUG
|
||||
#undef CONFIG_CMD_HOSTCMD
|
||||
#undef CONFIG_CMD_I2C_PROTECT
|
||||
#define CONFIG_CMD_I2C_SCAN
|
||||
#define CONFIG_CMD_I2C_XFER
|
||||
#undef CONFIG_CMD_I2CWEDGE
|
||||
|
||||
@@ -3194,6 +3194,25 @@ struct ec_params_entering_mode {
|
||||
#define VBOOT_MODE_DEVELOPER 1
|
||||
#define VBOOT_MODE_RECOVERY 2
|
||||
|
||||
/*****************************************************************************/
|
||||
/* I2C passthru protection command: Protects I2C tunnels against access on
|
||||
* certain addresses (board-specific). */
|
||||
#define EC_CMD_I2C_PASSTHRU_PROTECT 0xb7
|
||||
|
||||
enum ec_i2c_passthru_protect_subcmd {
|
||||
EC_CMD_I2C_PASSTHRU_PROTECT_STATUS = 0x0,
|
||||
EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE = 0x1,
|
||||
};
|
||||
|
||||
struct ec_params_i2c_passthru_protect {
|
||||
uint8_t subcmd;
|
||||
uint8_t port; /* I2C port number */
|
||||
} __packed;
|
||||
|
||||
struct ec_response_i2c_passthru_protect {
|
||||
uint8_t status; /* Status flags (0: unlocked, 1: locked) */
|
||||
} __packed;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* System commands */
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ struct i2c_port_t {
|
||||
int kbps; /* Speed in kbps */
|
||||
enum gpio_signal scl; /* Port SCL GPIO line */
|
||||
enum gpio_signal sda; /* Port SDA GPIO line */
|
||||
/* When bus is protected, returns true if passthru allowed for address.
|
||||
* If the function is not defined, the default value is true. */
|
||||
int (*passthru_allowed)(const struct i2c_port_t *port,
|
||||
uint16_t address);
|
||||
};
|
||||
|
||||
extern const struct i2c_port_t i2c_ports[];
|
||||
|
||||
@@ -123,6 +123,8 @@ const char help_str[] =
|
||||
" Simulate key press\n"
|
||||
" kbfactorytest\n"
|
||||
" Scan out keyboard if any pins are shorted\n"
|
||||
" i2cprotect <port> [status]\n"
|
||||
" Protect EC's I2C bus\n"
|
||||
" i2cread\n"
|
||||
" Read I2C bus\n"
|
||||
" i2cwrite\n"
|
||||
@@ -4880,6 +4882,50 @@ int cmd_wireless(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
int cmd_i2c_protect(int argc, char *argv[])
|
||||
{
|
||||
struct ec_params_i2c_passthru_protect p;
|
||||
char *e;
|
||||
int rv;
|
||||
|
||||
if (argc != 2 && (argc != 3 || strcmp(argv[2], "status"))) {
|
||||
fprintf(stderr, "Usage: %s <port> [status]\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p.port = strtol(argv[1], &e, 0);
|
||||
if (e && *e) {
|
||||
fprintf(stderr, "Bad port.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
struct ec_response_i2c_passthru_protect r;
|
||||
|
||||
p.subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_STATUS;
|
||||
|
||||
rv = ec_command(EC_CMD_I2C_PASSTHRU_PROTECT, 0, &p, sizeof(p),
|
||||
&r, sizeof(r));
|
||||
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
printf("I2C port %d: %s (%d)\n", p.port,
|
||||
r.status ? "Protected" : "Unprotected", r.status);
|
||||
} else {
|
||||
p.subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE;
|
||||
|
||||
rv = ec_command(EC_CMD_I2C_PASSTHRU_PROTECT, 0, &p, sizeof(p),
|
||||
NULL, 0);
|
||||
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cmd_i2c_read(int argc, char *argv[])
|
||||
{
|
||||
struct ec_params_i2c_read p;
|
||||
@@ -6656,6 +6702,7 @@ const struct command commands[] = {
|
||||
{"hello", cmd_hello},
|
||||
{"hibdelay", cmd_hibdelay},
|
||||
{"kbpress", cmd_kbpress},
|
||||
{"i2cprotect", cmd_i2c_protect},
|
||||
{"i2cread", cmd_i2c_read},
|
||||
{"i2cwrite", cmd_i2c_write},
|
||||
{"i2cxfer", cmd_i2c_xfer},
|
||||
|
||||
Reference in New Issue
Block a user