Skip to content

Commit c629a7d

Browse files
marcanjannau
authored andcommitted
wifi: brcmfmac: Add support for firmware signatures
Beginning with BCM4388, Apple machines are using firmware signing. This requires a new firmware blob (as the signature is provided out-of-band) as well as an extension of the existing random seed upload mechanism to populate the data structures required for signature verification by the bootloader. To implement this, refactor the existing random seed code to be more generic, and use it to implement the signature upload. Drive-by changes: Remove two unused members of brcmf_pciedev_info (which are confusing as they are never initialized), and also zero out the unused portion of TCM to make TCM dumps less noisy. With this, the TCM contents are 1:1 identical to what the macOS driver ends up doing, except for the NVRAM which has the injected macaddr property at the end instead of at the start. Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent 7850069 commit c629a7d

1 file changed

Lines changed: 169 additions & 30 deletions

File tree

  • drivers/net/wireless/broadcom/brcm80211/brcmfmac

drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c

Lines changed: 169 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ struct brcmf_pciedev_info {
392392
bool in_irq;
393393
struct pci_dev *pdev;
394394
char fw_name[BRCMF_FW_NAME_LEN];
395+
char sig_name[BRCMF_FW_NAME_LEN];
395396
char nvram_name[BRCMF_FW_NAME_LEN];
396397
char clm_name[BRCMF_FW_NAME_LEN];
397398
char txcap_name[BRCMF_FW_NAME_LEN];
@@ -400,8 +401,7 @@ struct brcmf_pciedev_info {
400401
const struct brcmf_pcie_reginfo *reginfo;
401402
void __iomem *regs;
402403
void __iomem *tcm;
403-
u32 ram_base;
404-
u32 ram_size;
404+
u32 fw_size;
405405
struct brcmf_chip *ci;
406406
u32 coreid;
407407
struct brcmf_pcie_shared_info shared;
@@ -1807,26 +1807,164 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
18071807
return 0;
18081808
}
18091809

1810-
struct brcmf_random_seed_footer {
1810+
struct brcmf_rtlv_footer {
18111811
__le32 length;
18121812
__le32 magic;
18131813
};
18141814

1815+
struct brcmf_fw_memmap {
1816+
u32 pad1[8];
1817+
u32 vstatus_start;
1818+
u32 vstatus_end;
1819+
u32 fw_start;
1820+
u32 fw_end;
1821+
u32 sig_start;
1822+
u32 sig_end;
1823+
u32 heap_start;
1824+
u32 heap_end;
1825+
u32 pad2[6];
1826+
};
1827+
1828+
1829+
#define BRCMF_BL_HEAP_START_GAP 0x1000
1830+
#define BRCMF_BL_HEAP_SIZE 0x10000
18151831
#define BRCMF_RANDOM_SEED_MAGIC 0xfeedc0de
18161832
#define BRCMF_RANDOM_SEED_LENGTH 0x100
1833+
#define BRCMF_SIG_MAGIC 0xfeedfe51
1834+
#define BRCMF_VSTATUS_MAGIC 0xfeedfe54
1835+
#define BRCMF_VSTATUS_SIZE 0x28
1836+
#define BRCMF_MEMMAP_MAGIC 0xfeedfe53
1837+
#define BRCMF_END_MAGIC 0xfeed0e2d
1838+
1839+
static int brcmf_alloc_rtlv(struct brcmf_pciedev_info *devinfo, u32 *address, u32 type, size_t length)
1840+
{
1841+
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
1842+
u32 boundary = devinfo->ci->rambase + devinfo->fw_size +
1843+
BRCMF_BL_HEAP_START_GAP + BRCMF_BL_HEAP_SIZE;
1844+
u32 start_addr;
1845+
struct brcmf_rtlv_footer footer = {
1846+
.magic = type,
1847+
};
1848+
1849+
length = ALIGN(length, 4);
1850+
start_addr = *address - length - sizeof(struct brcmf_rtlv_footer);
1851+
1852+
if (length > 0xffff || start_addr > *address || start_addr < boundary) {
1853+
brcmf_err(bus, "failed to allocate 0x%zx bytes for rTLV type 0x%x\n",
1854+
length, type);
1855+
return -ENOMEM;
1856+
}
1857+
1858+
/* Random seed does not use the length check code */
1859+
if (type == BRCMF_RANDOM_SEED_MAGIC)
1860+
footer.length = length;
1861+
else
1862+
footer.length = length | ((length ^ 0xffff) << 16);
1863+
1864+
memcpy_toio(devinfo->tcm + *address - sizeof(struct brcmf_rtlv_footer),
1865+
&footer, sizeof(struct brcmf_rtlv_footer));
1866+
1867+
*address = start_addr;
1868+
1869+
return 0;
1870+
}
18171871

1818-
static noinline_for_stack void
1819-
brcmf_pcie_provide_random_bytes(struct brcmf_pciedev_info *devinfo, u32 address)
1872+
static noinline_for_stack int
1873+
brcmf_pcie_add_random_seed(struct brcmf_pciedev_info *devinfo, u32 *address)
18201874
{
1875+
int err;
18211876
u8 randbuf[BRCMF_RANDOM_SEED_LENGTH];
18221877

1878+
err = brcmf_alloc_rtlv(devinfo, address,
1879+
BRCMF_RANDOM_SEED_MAGIC, BRCMF_RANDOM_SEED_LENGTH);
1880+
if (err)
1881+
return err;
1882+
1883+
/* Some Apple chips/firmwares expect a buffer of random
1884+
* data to be present before NVRAM
1885+
*/
1886+
brcmf_dbg(PCIE, "Download random seed\n");
1887+
18231888
get_random_bytes(randbuf, BRCMF_RANDOM_SEED_LENGTH);
18241889
memcpy_toio(devinfo->tcm + address, randbuf, BRCMF_RANDOM_SEED_LENGTH);
1890+
1891+
return 0;
1892+
}
1893+
1894+
static int brcmf_pcie_add_signature(struct brcmf_pciedev_info *devinfo,
1895+
u32 *address, const struct firmware *fwsig)
1896+
{
1897+
int err;
1898+
struct brcmf_fw_memmap memmap;
1899+
1900+
brcmf_dbg(PCIE, "Download firmware signature\n");
1901+
1902+
memset(&memmap, 0, sizeof(memmap));
1903+
1904+
memmap.sig_end = *address;
1905+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_SIG_MAGIC, fwsig->size);
1906+
if (err)
1907+
return err;
1908+
memmap.sig_start = *address;
1909+
1910+
memmap.vstatus_end = *address;
1911+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_VSTATUS_MAGIC, BRCMF_VSTATUS_SIZE);
1912+
if (err)
1913+
return err;
1914+
memmap.vstatus_start = *address;
1915+
1916+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_MEMMAP_MAGIC, sizeof(memmap));
1917+
if (err)
1918+
return err;
1919+
1920+
memmap.fw_start = devinfo->ci->rambase;
1921+
memmap.fw_end = memmap.fw_start + devinfo->fw_size;
1922+
memmap.heap_start = memmap.fw_end + BRCMF_BL_HEAP_START_GAP;
1923+
memmap.heap_end = memmap.heap_start + BRCMF_BL_HEAP_SIZE;
1924+
1925+
if (memmap.heap_end > *address)
1926+
return -ENOMEM;
1927+
1928+
memcpy_toio(devinfo->tcm + memmap.sig_start, fwsig->data, fwsig->size);
1929+
memset_io(devinfo->tcm + memmap.vstatus_start, 0, BRCMF_VSTATUS_SIZE);
1930+
memcpy_toio(devinfo->tcm + *address, &memmap, sizeof(memmap));
1931+
1932+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_END_MAGIC, 0);
1933+
if (err)
1934+
return err;
1935+
1936+
return 0;
1937+
}
1938+
1939+
static int brcmf_pcie_populate_footers(struct brcmf_pciedev_info *devinfo,
1940+
u32 *address, const struct firmware *fwsig)
1941+
{
1942+
int err;
1943+
1944+
/* We only do this for Apple firmwares. If any other
1945+
* production firmwares are found to need this, the condition
1946+
* needs to be adjusted.
1947+
*/
1948+
if (!devinfo->fwseed)
1949+
return 0;
1950+
1951+
err = brcmf_pcie_add_random_seed(devinfo, address);
1952+
if (err)
1953+
return err;
1954+
1955+
if (fwsig) {
1956+
err = brcmf_pcie_add_signature(devinfo, address, fwsig);
1957+
if (err)
1958+
return err;
1959+
}
1960+
1961+
return 0;
18251962
}
18261963

18271964
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
1828-
const struct firmware *fw, void *nvram,
1829-
u32 nvram_len)
1965+
const struct firmware *fw,
1966+
const struct firmware *fwsig,
1967+
void *nvram, u32 nvram_len)
18301968
{
18311969
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
18321970
u32 sharedram_addr;
@@ -1846,44 +1984,39 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
18461984
(void *)fw->data, fw->size);
18471985

18481986
resetintr = get_unaligned_le32(fw->data);
1987+
devinfo->fw_size = fw->size;
18491988
release_firmware(fw);
18501989

18511990
/* reset last 4 bytes of RAM address. to be used for shared
18521991
* area. This identifies when FW is running
18531992
*/
18541993
brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0);
18551994

1995+
address = devinfo->ci->rambase + devinfo->ci->ramsize;
1996+
18561997
if (nvram) {
18571998
brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
1858-
address = devinfo->ci->rambase + devinfo->ci->ramsize -
1859-
nvram_len;
1999+
address -= nvram_len;
18602000
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
18612001
brcmf_fw_nvram_free(nvram);
18622002

1863-
if (devinfo->fwseed) {
1864-
size_t rand_len = BRCMF_RANDOM_SEED_LENGTH;
1865-
struct brcmf_random_seed_footer footer = {
1866-
.length = cpu_to_le32(rand_len),
1867-
.magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC),
1868-
};
1869-
1870-
/* Some chips/firmwares expect a buffer of random
1871-
* data to be present before NVRAM
1872-
*/
1873-
brcmf_dbg(PCIE, "Download random seed\n");
1874-
1875-
address -= sizeof(footer);
1876-
memcpy_toio(devinfo->tcm + address, &footer,
1877-
sizeof(footer));
1878-
1879-
address -= rand_len;
1880-
brcmf_pcie_provide_random_bytes(devinfo, address);
1881-
}
2003+
err = brcmf_pcie_populate_footers(devinfo, &address, fwsig);
2004+
if (err)
2005+
brcmf_err(bus, "failed to populate firmware footers err=%d\n", err);
18822006
} else {
18832007
brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
18842008
devinfo->nvram_name);
18852009
}
18862010

2011+
release_firmware(fwsig);
2012+
2013+
/* Clear free TCM. This isn't really necessary, but it
2014+
* makes debugging memory dumps a lot easier since we
2015+
* don't get a bunch of junk filling up the free space.
2016+
*/
2017+
memset_io(devinfo->tcm + devinfo->ci->rambase + devinfo->fw_size,
2018+
0, address - devinfo->fw_size - devinfo->ci->rambase);
2019+
18872020
sharedram_addr_written = brcmf_pcie_read_ram32(devinfo,
18882021
devinfo->ci->ramsize -
18892022
4);
@@ -2269,11 +2402,12 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
22692402
#define BRCMF_PCIE_FW_NVRAM 1
22702403
#define BRCMF_PCIE_FW_CLM 2
22712404
#define BRCMF_PCIE_FW_TXCAP 3
2405+
#define BRCMF_PCIE_FW_SIG 4
22722406

22732407
static void brcmf_pcie_setup(struct device *dev, int ret,
22742408
struct brcmf_fw_request *fwreq)
22752409
{
2276-
const struct firmware *fw;
2410+
const struct firmware *fw, *fwsig;
22772411
void *nvram;
22782412
struct brcmf_bus *bus;
22792413
struct brcmf_pciedev *pcie_bus_dev;
@@ -2292,6 +2426,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22922426
brcmf_pcie_attach(devinfo);
22932427

22942428
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
2429+
fwsig = fwreq->items[BRCMF_PCIE_FW_SIG].binary;
22952430
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
22962431
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
22972432
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
@@ -2302,6 +2437,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23022437
if (ret) {
23032438
brcmf_err(bus, "Failed to get RAM info\n");
23042439
release_firmware(fw);
2440+
release_firmware(fwsig);
23052441
brcmf_fw_nvram_free(nvram);
23062442
goto fail;
23072443
}
@@ -2313,7 +2449,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23132449
*/
23142450
brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
23152451

2316-
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
2452+
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, fwsig, nvram, nvram_len);
23172453
if (ret)
23182454
goto fail;
23192455

@@ -2378,6 +2514,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23782514
{ ".txt", devinfo->nvram_name },
23792515
{ ".clm_blob", devinfo->clm_name },
23802516
{ ".txcap_blob", devinfo->txcap_name },
2517+
{ ".sig", devinfo->sig_name },
23812518
};
23822519

23832520
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@@ -2388,6 +2525,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23882525
return NULL;
23892526

23902527
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
2528+
fwreq->items[BRCMF_PCIE_FW_SIG].type = BRCMF_FW_TYPE_BINARY;
2529+
fwreq->items[BRCMF_PCIE_FW_SIG].flags = BRCMF_FW_REQF_OPTIONAL;
23912530
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
23922531
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
23932532
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;

0 commit comments

Comments
 (0)