summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/i2c.c110
-rw-r--r--include/config.h1
-rw-r--r--include/ec_commands.h19
-rw-r--r--include/i2c.h4
-rw-r--r--util/ectool.c47
5 files changed, 177 insertions, 4 deletions
diff --git a/common/i2c.c b/common/i2c.c
index f22c86540e..03d7e2b9c6 100644
--- a/common/i2c.c
+++ b/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)
{
diff --git a/include/config.h b/include/config.h
index effc6d9cc7..591af79c5f 100644
--- a/include/config.h
+++ b/include/config.h
@@ -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
diff --git a/include/ec_commands.h b/include/ec_commands.h
index bc5b342817..27049eac5a 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -3195,6 +3195,25 @@ struct ec_params_entering_mode {
#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 */
/*
diff --git a/include/i2c.h b/include/i2c.h
index fdda5a0187..d3329df64a 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -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[];
diff --git a/util/ectool.c b/util/ectool.c
index 0e3c1ee596..f5787efcf2 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -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},