soc/intel/common: add generic gpio lock mechanism
For added security, there are some gpios that an SoC will want to lock once initially configured, such as gpios attached to non-host (x86) controllers, so that they can't be recofigured at a later point in time by rogue code. Likewise, a mainboard may have some gpios connected to secure busses and/or devices that they want to protect from being changed post initial configuration. This change adds a generic gpio locking mechanism that allows the SoC to export a list of GPIOs to be locked down and allows the mainboard to export a list of GPIOs that it wants locked down once initialization is complete. Use the SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS Kconfig option to enable this feature. BUG=b:201430600 TEST='emerge-brya coreboot chromeos-bootimage', flash and verify brya0 boots successfully to kernel. Signed-off-by: Nick Vaccaro <nvaccaro@google.com> Change-Id: I42979fb89567d8bcd9392da4fb8c4113ef427b14 Reviewed-on: https://review.coreboot.org/c/coreboot/+/58351 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
This commit is contained in:
@@ -447,14 +447,27 @@ int gpio_get(gpio_t gpio_num)
|
|||||||
return !!(reg & PAD_CFG0_RX_STATE);
|
return !!(reg & PAD_CFG0_RX_STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
|
static int sideband_msg_err(int status, int response)
|
||||||
{
|
{
|
||||||
const struct pad_community *comm = gpio_get_community(pad);
|
if (status || response) {
|
||||||
size_t rel_pad;
|
printk(BIOS_ERR, "%s: error status=%x response=%x\n",
|
||||||
uint16_t offset;
|
__func__, status, response);
|
||||||
uint32_t data;
|
return (status == -1) ? -1 : response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_lock_pads(const struct gpio_lock_config *pad_list, const size_t count)
|
||||||
|
{
|
||||||
|
const struct pad_community *comm;
|
||||||
|
enum gpio_lock_action action;
|
||||||
|
int status, err_response = 0;
|
||||||
uint8_t response;
|
uint8_t response;
|
||||||
int status;
|
uint16_t offset;
|
||||||
|
size_t rel_pad;
|
||||||
|
uint32_t data;
|
||||||
|
gpio_t pad;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FSP-S will unlock all the GPIO pads and hide the P2SB device. With
|
* FSP-S will unlock all the GPIO pads and hide the P2SB device. With
|
||||||
@@ -468,23 +481,13 @@ int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(action & GPIO_LOCK_FULL)) {
|
if ((pad_list == NULL) || (count == 0)) {
|
||||||
printk(BIOS_ERR, "%s: Error: no action specified!\n", __func__);
|
printk(BIOS_ERR, "%s: Error: pad_list null or count = 0!\n", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rel_pad = relative_pad_in_comm(comm, pad);
|
|
||||||
offset = comm->pad_cfg_lock_offset;
|
|
||||||
if (!offset) {
|
|
||||||
printk(BIOS_ERR, "%s: Error: offset is not defined!\n", __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
offset += gpio_group_index_scaled(comm, rel_pad, 2 * sizeof(uint32_t));
|
|
||||||
|
|
||||||
/* We must use the sideband interface in order to lock the pad. */
|
/* We must use the sideband interface in order to lock the pad. */
|
||||||
struct pcr_sbi_msg msg = {
|
struct pcr_sbi_msg msg = {
|
||||||
.pid = comm->port,
|
|
||||||
.offset = offset,
|
|
||||||
.opcode = GPIO_LOCK_UNLOCK,
|
.opcode = GPIO_LOCK_UNLOCK,
|
||||||
.is_posted = false,
|
.is_posted = false,
|
||||||
.fast_byte_enable = 0xF,
|
.fast_byte_enable = 0xF,
|
||||||
@@ -494,35 +497,69 @@ int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
|
|||||||
|
|
||||||
p2sb_unhide();
|
p2sb_unhide();
|
||||||
|
|
||||||
data = gpio_bitmask_within_group(comm, rel_pad);
|
for (int x = 0; x < count; x++) {
|
||||||
|
int err;
|
||||||
|
|
||||||
if (action & GPIO_LOCK_CONFIG) {
|
pad = pad_list[x].gpio;
|
||||||
printk(BIOS_INFO, "%s: Locking pad %d configuration\n",
|
action = pad_list[x].action;
|
||||||
__func__, pad);
|
|
||||||
status = pcr_execute_sideband_msg(&msg, &data, &response);
|
if (!(action & GPIO_LOCK_FULL)) {
|
||||||
if (status || response) {
|
printk(BIOS_ERR, "%s: Error: no action specified for pad %d!\n",
|
||||||
printk(BIOS_ERR, "%s: error status=%x response=%x\n", __func__, status,
|
__func__, pad);
|
||||||
response);
|
continue;
|
||||||
p2sb_hide();
|
|
||||||
return status == -1 ? -1 : response;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (action & GPIO_LOCK_TX) {
|
comm = gpio_get_community(pad);
|
||||||
printk(BIOS_INFO, "%s: Locking pad %d TX state\n", __func__,
|
rel_pad = relative_pad_in_comm(comm, pad);
|
||||||
pad);
|
offset = comm->pad_cfg_lock_offset;
|
||||||
msg.offset = msg.offset + 4;
|
if (!offset) {
|
||||||
status = pcr_execute_sideband_msg(&msg, &data, &response);
|
printk(BIOS_ERR, "%s: Error: offset not defined for pad %d!\n",
|
||||||
if (status || response) {
|
__func__, pad);
|
||||||
printk(BIOS_ERR, "%s: error status=%x response=%x\n", __func__, status,
|
continue;
|
||||||
response);
|
}
|
||||||
p2sb_hide();
|
offset += gpio_group_index_scaled(comm, rel_pad, 2 * sizeof(uint32_t));
|
||||||
return status == -1 ? -1 : response;
|
|
||||||
|
data = gpio_bitmask_within_group(comm, rel_pad);
|
||||||
|
msg.pid = comm->port;
|
||||||
|
msg.offset = offset;
|
||||||
|
|
||||||
|
if (action & GPIO_LOCK_CONFIG) {
|
||||||
|
if (CONFIG(DEBUG_GPIO))
|
||||||
|
printk(BIOS_INFO, "%s: Locking pad %d configuration\n",
|
||||||
|
__func__, pad);
|
||||||
|
status = pcr_execute_sideband_msg(&msg, &data, &response);
|
||||||
|
if ((err = sideband_msg_err(status, response)) != 0) {
|
||||||
|
err_response = err;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action & GPIO_LOCK_TX) {
|
||||||
|
if (CONFIG(DEBUG_GPIO))
|
||||||
|
printk(BIOS_INFO, "%s: Locking pad %d TX state\n",
|
||||||
|
__func__, pad);
|
||||||
|
msg.offset += 4;
|
||||||
|
status = pcr_execute_sideband_msg(&msg, &data, &response);
|
||||||
|
if ((err = sideband_msg_err(status, response)) != 0) {
|
||||||
|
err_response = err;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p2sb_hide();
|
p2sb_hide();
|
||||||
return 0;
|
|
||||||
|
return err_response;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action)
|
||||||
|
{
|
||||||
|
const struct gpio_lock_config pads = {
|
||||||
|
.gpio = pad,
|
||||||
|
.action = action
|
||||||
|
};
|
||||||
|
|
||||||
|
return gpio_lock_pads(&pads, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_set(gpio_t gpio_num, int value)
|
void gpio_set(gpio_t gpio_num, int value)
|
||||||
|
@@ -205,6 +205,11 @@ enum gpio_lock_action {
|
|||||||
GPIO_LOCK_FULL = GPIO_LOCK_CONFIG | GPIO_LOCK_TX,
|
GPIO_LOCK_FULL = GPIO_LOCK_CONFIG | GPIO_LOCK_TX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct gpio_lock_config {
|
||||||
|
gpio_t gpio;
|
||||||
|
enum gpio_lock_action action;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock a GPIO's configuration.
|
* Lock a GPIO's configuration.
|
||||||
*
|
*
|
||||||
@@ -231,6 +236,33 @@ enum gpio_lock_action {
|
|||||||
*/
|
*/
|
||||||
int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action);
|
int gpio_lock_pad(const gpio_t pad, enum gpio_lock_action action);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gpio_lock_pads() can be used to lock an array of gpio pads, avoiding
|
||||||
|
* the p2sb_unhide() and p2sb_hide() calls between each gpio lock that would
|
||||||
|
* occur if gpio_lock_pad() were used to lock each pad in the list.
|
||||||
|
*
|
||||||
|
* @param pad_list: array of gpio_lock_config structures, one for each gpio to lock
|
||||||
|
* @param count: number of gpio_lock_config structs in the pad_list array
|
||||||
|
* @return 0 if successful,
|
||||||
|
* 1 - unsuccessful
|
||||||
|
* 2 - powered down
|
||||||
|
* 3 - multi-cast mixed
|
||||||
|
* -1 - sideband message failed or other error
|
||||||
|
*/
|
||||||
|
int gpio_lock_pads(const struct gpio_lock_config *pad_list, const size_t count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an array of gpio_lock_config entries that the SoC
|
||||||
|
* deems security risks that should be locked down.
|
||||||
|
*/
|
||||||
|
const struct gpio_lock_config *soc_gpio_lock_config(size_t *num);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an array of gpio_lock_config entries that the mainboard
|
||||||
|
* deems security risks that should be locked down.
|
||||||
|
*/
|
||||||
|
const struct gpio_lock_config *mb_gpio_lock_config(size_t *num);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the pmc_gpe to gpio_gpe mapping table
|
* Returns the pmc_gpe to gpio_gpe mapping table
|
||||||
*
|
*
|
||||||
|
@@ -8,6 +8,13 @@ config SOC_INTEL_COMMON_BLOCK_SMM_IO_TRAP
|
|||||||
help
|
help
|
||||||
Intel Processor trap flag if it is supported
|
Intel Processor trap flag if it is supported
|
||||||
|
|
||||||
|
config SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Enable locking of security-sensitive SoC and mainboard GPIOs.
|
||||||
|
An SoC may provide a list of gpios to lock, and the mainboard
|
||||||
|
may also provide a list of gpios to lock.
|
||||||
|
|
||||||
config SOC_INTEL_COMMON_BLOCK_SMM_ESPI_DISABLE
|
config SOC_INTEL_COMMON_BLOCK_SMM_ESPI_DISABLE
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
@@ -311,6 +311,40 @@ static void southbridge_smi_store(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak const struct gpio_lock_config *soc_gpio_lock_config(size_t *num)
|
||||||
|
{
|
||||||
|
*num = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__weak const struct gpio_lock_config *mb_gpio_lock_config(size_t *num)
|
||||||
|
{
|
||||||
|
*num = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void soc_lock_gpios(void)
|
||||||
|
{
|
||||||
|
const struct gpio_lock_config *soc_gpios;
|
||||||
|
const struct gpio_lock_config *mb_gpios;
|
||||||
|
size_t soc_gpio_num;
|
||||||
|
size_t mb_gpio_num;
|
||||||
|
|
||||||
|
/* get list of gpios from SoC */
|
||||||
|
soc_gpios = soc_gpio_lock_config(&soc_gpio_num);
|
||||||
|
|
||||||
|
/* get list of gpios from mainboard */
|
||||||
|
mb_gpios = mb_gpio_lock_config(&mb_gpio_num);
|
||||||
|
|
||||||
|
/* Lock any soc requested gpios */
|
||||||
|
if (soc_gpio_num)
|
||||||
|
gpio_lock_pads(soc_gpios, soc_gpio_num);
|
||||||
|
|
||||||
|
/* Lock any mainboard requested gpios */
|
||||||
|
if (mb_gpio_num)
|
||||||
|
gpio_lock_pads(mb_gpios, mb_gpio_num);
|
||||||
|
}
|
||||||
|
|
||||||
static void finalize(void)
|
static void finalize(void)
|
||||||
{
|
{
|
||||||
static int finalize_done;
|
static int finalize_done;
|
||||||
@@ -337,6 +371,10 @@ static void finalize(void)
|
|||||||
*/
|
*/
|
||||||
mainboard_smi_finalize();
|
mainboard_smi_finalize();
|
||||||
|
|
||||||
|
/* Lock down all GPIOs that may have been requested by the SoC and/or the mainboard. */
|
||||||
|
if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS))
|
||||||
|
soc_lock_gpios();
|
||||||
|
|
||||||
/* Specific SOC SMI handler during ramstage finalize phase */
|
/* Specific SOC SMI handler during ramstage finalize phase */
|
||||||
smihandler_soc_at_finalize();
|
smihandler_soc_at_finalize();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user