Skip to content

Commit b125810

Browse files
ausyskinbroonie
authored andcommitted
spi: intel: Add protected and locked attributes
The manufacturing access to the PCH/SoC SPI device is traditionally performed via userspace driver accessing registers via /dev/mem but due to security concerns /dev/mem access is being much restricted, hence the reason for utilizing dedicated Intel PCH/SoC SPI controller driver, which is already implemented in the Linux kernel. Intel PCH/SoC SPI controller protects the flash storage via two mechanisms one is the via region protection registers and second via BIOS lock. The BIOS locks only the BIOS regions usually 0 and/or 6. The device always boots with BIOS lock set, but during manufacturing the BIOS lock has to be lifted in order to enable the write access. This can be done by passing "writeable=1" in the command line when the driver is loaded. This "locked" state is exposed through new sysfs attributes (intel_spi_locked, intel_spi_bios_locked). Second, also the region protection status is exposed via sysfs attribute (intel_spi_protected) as the manufacturing will need the both files in order to validate that the device is properly sealed. Includes code written by Tamar Mashiah. Signed-off-by: Alexander Usyskin <[email protected]> Co-developed-by: Tomas Winkler <[email protected]> Signed-off-by: Tomas Winkler <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Mika Westerberg <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent c2a59c8 commit b125810

File tree

5 files changed

+83
-5
lines changed

5 files changed

+83
-5
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
What: /sys/devices/.../intel_spi_protected
2+
Date: Feb 2025
3+
KernelVersion: 6.13
4+
Contact: Alexander Usyskin <[email protected]>
5+
Description: This attribute allows the userspace to check if the
6+
Intel SPI flash controller is write protected from the host.
7+
8+
What: /sys/devices/.../intel_spi_locked
9+
Date: Feb 2025
10+
KernelVersion: 6.13
11+
Contact: Alexander Usyskin <[email protected]>
12+
Description: This attribute allows the user space to check if the
13+
Intel SPI flash controller locks supported opcodes.
14+
15+
What: /sys/devices/.../intel_spi_bios_locked
16+
Date: Feb 2025
17+
KernelVersion: 6.13
18+
Contact: Alexander Usyskin <[email protected]>
19+
Description: This attribute allows the user space to check if the
20+
Intel SPI flash controller BIOS region is locked for writes.

drivers/spi/spi-intel-pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static struct pci_driver intel_spi_pci_driver = {
9494
.name = "intel-spi",
9595
.id_table = intel_spi_pci_ids,
9696
.probe = intel_spi_pci_probe,
97+
.dev_groups = intel_spi_groups,
9798
};
9899

99100
module_pci_driver(intel_spi_pci_driver);

drivers/spi/spi-intel-platform.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ static struct platform_driver intel_spi_platform_driver = {
2828
.probe = intel_spi_platform_probe,
2929
.driver = {
3030
.name = "intel-spi",
31+
.dev_groups = intel_spi_groups,
3132
},
3233
};
3334

drivers/spi/spi-intel.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@
148148
* @pr_num: Maximum number of protected range registers
149149
* @chip0_size: Size of the first flash chip in bytes
150150
* @locked: Is SPI setting locked
151+
* @protected: Whether the regions are write protected
152+
* @bios_locked: Is BIOS region locked
151153
* @swseq_reg: Use SW sequencer in register reads/writes
152154
* @swseq_erase: Use SW sequencer in erase operation
153155
* @atomic_preopcode: Holds preopcode when atomic sequence is requested
@@ -166,6 +168,8 @@ struct intel_spi {
166168
size_t pr_num;
167169
size_t chip0_size;
168170
bool locked;
171+
bool protected;
172+
bool bios_locked;
169173
bool swseq_reg;
170174
bool swseq_erase;
171175
u8 atomic_preopcode;
@@ -1109,10 +1113,13 @@ static int intel_spi_init(struct intel_spi *ispi)
11091113
return -EINVAL;
11101114
}
11111115

1112-
/* Try to disable write protection if user asked to do so */
1113-
if (writeable && !intel_spi_set_writeable(ispi)) {
1114-
dev_warn(ispi->dev, "can't disable chip write protection\n");
1115-
writeable = false;
1116+
ispi->bios_locked = true;
1117+
/* Try to disable BIOS write protection if user asked to do so */
1118+
if (writeable) {
1119+
if (intel_spi_set_writeable(ispi))
1120+
ispi->bios_locked = false;
1121+
else
1122+
dev_warn(ispi->dev, "can't disable chip write protection\n");
11161123
}
11171124

11181125
/* Disable #SMI generation from HW sequencer */
@@ -1247,8 +1254,10 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
12471254
* Also if the user did not ask the chip to be writeable
12481255
* mask the bit too.
12491256
*/
1250-
if (!writeable || intel_spi_is_protected(ispi, base, limit))
1257+
if (!writeable || intel_spi_is_protected(ispi, base, limit)) {
12511258
part->mask_flags |= MTD_WRITEABLE;
1259+
ispi->protected = true;
1260+
}
12521261

12531262
end = (limit << 12) + 4096;
12541263
if (end > part->size)
@@ -1411,6 +1420,50 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
14111420
return 0;
14121421
}
14131422

1423+
static ssize_t intel_spi_protected_show(struct device *dev,
1424+
struct device_attribute *attr, char *buf)
1425+
{
1426+
struct intel_spi *ispi = dev_get_drvdata(dev);
1427+
1428+
return sysfs_emit(buf, "%d\n", ispi->protected);
1429+
}
1430+
static DEVICE_ATTR_ADMIN_RO(intel_spi_protected);
1431+
1432+
static ssize_t intel_spi_locked_show(struct device *dev,
1433+
struct device_attribute *attr, char *buf)
1434+
{
1435+
struct intel_spi *ispi = dev_get_drvdata(dev);
1436+
1437+
return sysfs_emit(buf, "%d\n", ispi->locked);
1438+
}
1439+
static DEVICE_ATTR_ADMIN_RO(intel_spi_locked);
1440+
1441+
static ssize_t intel_spi_bios_locked_show(struct device *dev,
1442+
struct device_attribute *attr, char *buf)
1443+
{
1444+
struct intel_spi *ispi = dev_get_drvdata(dev);
1445+
1446+
return sysfs_emit(buf, "%d\n", ispi->bios_locked);
1447+
}
1448+
static DEVICE_ATTR_ADMIN_RO(intel_spi_bios_locked);
1449+
1450+
static struct attribute *intel_spi_attrs[] = {
1451+
&dev_attr_intel_spi_protected.attr,
1452+
&dev_attr_intel_spi_locked.attr,
1453+
&dev_attr_intel_spi_bios_locked.attr,
1454+
NULL
1455+
};
1456+
1457+
static const struct attribute_group intel_spi_attr_group = {
1458+
.attrs = intel_spi_attrs,
1459+
};
1460+
1461+
const struct attribute_group *intel_spi_groups[] = {
1462+
&intel_spi_attr_group,
1463+
NULL
1464+
};
1465+
EXPORT_SYMBOL_GPL(intel_spi_groups);
1466+
14141467
/**
14151468
* intel_spi_probe() - Probe the Intel SPI flash controller
14161469
* @dev: Pointer to the parent device
@@ -1451,6 +1504,7 @@ int intel_spi_probe(struct device *dev, struct resource *mem,
14511504
if (ret)
14521505
return ret;
14531506

1507+
dev_set_drvdata(dev, ispi);
14541508
return intel_spi_populate_chip(ispi);
14551509
}
14561510
EXPORT_SYMBOL_GPL(intel_spi_probe);

drivers/spi/spi-intel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
struct resource;
1515

16+
extern const struct attribute_group *intel_spi_groups[];
17+
1618
int intel_spi_probe(struct device *dev, struct resource *mem,
1719
const struct intel_spi_boardinfo *info);
1820

0 commit comments

Comments
 (0)