Skip to content

Commit 9ec7838

Browse files
committed
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 f2c6b01 commit 9ec7838

1 file changed

Lines changed: 178 additions & 30 deletions

File tree

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

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

Lines changed: 178 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ struct brcmf_pciedev_info {
393393
bool in_irq;
394394
struct pci_dev *pdev;
395395
char fw_name[BRCMF_FW_NAME_LEN];
396+
char sig_name[BRCMF_FW_NAME_LEN];
396397
char nvram_name[BRCMF_FW_NAME_LEN];
397398
char clm_name[BRCMF_FW_NAME_LEN];
398399
char txcap_name[BRCMF_FW_NAME_LEN];
@@ -401,8 +402,7 @@ struct brcmf_pciedev_info {
401402
const struct brcmf_pcie_reginfo *reginfo;
402403
void __iomem *regs;
403404
void __iomem *tcm;
404-
u32 ram_base;
405-
u32 ram_size;
405+
u32 fw_size;
406406
struct brcmf_chip *ci;
407407
u32 coreid;
408408
struct brcmf_pcie_shared_info shared;
@@ -1805,17 +1805,169 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
18051805
return 0;
18061806
}
18071807

1808-
struct brcmf_random_seed_footer {
1808+
struct brcmf_rtlv_footer {
18091809
__le32 length;
18101810
__le32 magic;
18111811
};
18121812

1813+
struct brcmf_fw_memmap {
1814+
u32 pad1[8];
1815+
u32 vstatus_start;
1816+
u32 vstatus_end;
1817+
u32 fw_start;
1818+
u32 fw_end;
1819+
u32 sig_start;
1820+
u32 sig_end;
1821+
u32 heap_start;
1822+
u32 heap_end;
1823+
u32 pad2[6];
1824+
};
1825+
1826+
1827+
#define BRCMF_BL_HEAP_START_GAP 0x1000
1828+
#define BRCMF_BL_HEAP_SIZE 0x10000
18131829
#define BRCMF_RANDOM_SEED_MAGIC 0xfeedc0de
18141830
#define BRCMF_RANDOM_SEED_LENGTH 0x100
1831+
#define BRCMF_SIG_MAGIC 0xfeedfe51
1832+
#define BRCMF_VSTATUS_MAGIC 0xfeedfe54
1833+
#define BRCMF_VSTATUS_SIZE 0x28
1834+
#define BRCMF_MEMMAP_MAGIC 0xfeedfe53
1835+
#define BRCMF_END_MAGIC 0xfeed0e2d
1836+
1837+
static int brcmf_alloc_rtlv(struct brcmf_pciedev_info *devinfo, u32 *address, u32 type, size_t length)
1838+
{
1839+
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
1840+
u32 boundary = devinfo->ci->rambase + devinfo->fw_size +
1841+
BRCMF_BL_HEAP_START_GAP + BRCMF_BL_HEAP_SIZE;
1842+
u32 start_addr;
1843+
struct brcmf_rtlv_footer footer = {
1844+
.magic = type,
1845+
};
1846+
1847+
length = ALIGN(length, 4);
1848+
start_addr = *address - length - sizeof(struct brcmf_rtlv_footer);
1849+
1850+
if (length > 0xffff || start_addr > *address || start_addr < boundary) {
1851+
brcmf_err(bus, "failed to allocate 0x%zx bytes for rTLV type 0x%x\n",
1852+
length, type);
1853+
return -ENOMEM;
1854+
}
1855+
1856+
/* Random seed does not use the length check code */
1857+
if (type == BRCMF_RANDOM_SEED_MAGIC)
1858+
footer.length = length;
1859+
else
1860+
footer.length = length | ((length ^ 0xffff) << 16);
1861+
1862+
memcpy_toio(devinfo->tcm + *address - sizeof(struct brcmf_rtlv_footer),
1863+
&footer, sizeof(struct brcmf_rtlv_footer));
1864+
1865+
*address = start_addr;
1866+
1867+
return 0;
1868+
}
1869+
1870+
static int brcmf_pcie_add_random_seed(struct brcmf_pciedev_info *devinfo,
1871+
u32 *address)
1872+
{
1873+
int err;
1874+
void *randbuf;
1875+
1876+
err = brcmf_alloc_rtlv(devinfo, address,
1877+
BRCMF_RANDOM_SEED_MAGIC, BRCMF_RANDOM_SEED_LENGTH);
1878+
if (err)
1879+
return err;
1880+
1881+
/* Some Apple chips/firmwares expect a buffer of random
1882+
* data to be present before NVRAM
1883+
*/
1884+
brcmf_dbg(PCIE, "Download random seed\n");
1885+
1886+
randbuf = kzalloc(BRCMF_RANDOM_SEED_LENGTH, GFP_KERNEL);
1887+
if (!randbuf)
1888+
return -ENOMEM;
1889+
1890+
get_random_bytes(randbuf, BRCMF_RANDOM_SEED_LENGTH);
1891+
memcpy_toio(devinfo->tcm + *address, randbuf, BRCMF_RANDOM_SEED_LENGTH);
1892+
kfree(randbuf);
1893+
1894+
return 0;
1895+
}
1896+
1897+
static int brcmf_pcie_add_signature(struct brcmf_pciedev_info *devinfo,
1898+
u32 *address, const struct firmware *fwsig)
1899+
{
1900+
int err;
1901+
struct brcmf_fw_memmap memmap;
1902+
1903+
brcmf_dbg(PCIE, "Download firmware signature\n");
1904+
1905+
memset(&memmap, 0, sizeof(memmap));
1906+
1907+
memmap.sig_end = *address;
1908+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_SIG_MAGIC, fwsig->size);
1909+
if (err)
1910+
return err;
1911+
memmap.sig_start = *address;
1912+
1913+
memmap.vstatus_end = *address;
1914+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_VSTATUS_MAGIC, BRCMF_VSTATUS_SIZE);
1915+
if (err)
1916+
return err;
1917+
memmap.vstatus_start = *address;
1918+
1919+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_MEMMAP_MAGIC, sizeof(memmap));
1920+
if (err)
1921+
return err;
1922+
1923+
memmap.fw_start = devinfo->ci->rambase;
1924+
memmap.fw_end = memmap.fw_start + devinfo->fw_size;
1925+
memmap.heap_start = memmap.fw_end + BRCMF_BL_HEAP_START_GAP;
1926+
memmap.heap_end = memmap.heap_start + BRCMF_BL_HEAP_SIZE;
1927+
1928+
if (memmap.heap_end > *address)
1929+
return -ENOMEM;
1930+
1931+
memcpy_toio(devinfo->tcm + memmap.sig_start, fwsig->data, fwsig->size);
1932+
memset_io(devinfo->tcm + memmap.vstatus_start, 0, BRCMF_VSTATUS_SIZE);
1933+
memcpy_toio(devinfo->tcm + *address, &memmap, sizeof(memmap));
1934+
1935+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_END_MAGIC, 0);
1936+
if (err)
1937+
return err;
1938+
1939+
return 0;
1940+
}
1941+
1942+
static int brcmf_pcie_populate_footers(struct brcmf_pciedev_info *devinfo,
1943+
u32 *address, const struct firmware *fwsig)
1944+
{
1945+
int err;
1946+
1947+
/* We only do this for Apple firmwares. If any other
1948+
* production firmwares are found to need this, the condition
1949+
* needs to be adjusted.
1950+
*/
1951+
if (!devinfo->otp.valid)
1952+
return 0;
1953+
1954+
err = brcmf_pcie_add_random_seed(devinfo, address);
1955+
if (err)
1956+
return err;
1957+
1958+
if (fwsig) {
1959+
err = brcmf_pcie_add_signature(devinfo, address, fwsig);
1960+
if (err)
1961+
return err;
1962+
}
1963+
1964+
return 0;
1965+
}
18151966

18161967
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
1817-
const struct firmware *fw, void *nvram,
1818-
u32 nvram_len)
1968+
const struct firmware *fw,
1969+
const struct firmware *fwsig,
1970+
void *nvram, u32 nvram_len)
18191971
{
18201972
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
18211973
u32 sharedram_addr;
@@ -1835,6 +1987,7 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
18351987
(void *)fw->data, fw->size);
18361988

18371989
resetintr = get_unaligned_le32(fw->data);
1990+
devinfo->fw_size = fw->size;
18381991
release_firmware(fw);
18391992

18401993
/* reset last 4 bytes of RAM address. to be used for shared
@@ -1849,34 +2002,23 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
18492002
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
18502003
brcmf_fw_nvram_free(nvram);
18512004

1852-
if (devinfo->otp.valid) {
1853-
size_t rand_len = BRCMF_RANDOM_SEED_LENGTH;
1854-
struct brcmf_random_seed_footer footer = {
1855-
.length = cpu_to_le32(rand_len),
1856-
.magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC),
1857-
};
1858-
void *randbuf;
1859-
1860-
/* Some Apple chips/firmwares expect a buffer of random
1861-
* data to be present before NVRAM
1862-
*/
1863-
brcmf_dbg(PCIE, "Download random seed\n");
1864-
1865-
address -= sizeof(footer);
1866-
memcpy_toio(devinfo->tcm + address, &footer,
1867-
sizeof(footer));
1868-
1869-
address -= rand_len;
1870-
randbuf = kzalloc(rand_len, GFP_KERNEL);
1871-
get_random_bytes(randbuf, rand_len);
1872-
memcpy_toio(devinfo->tcm + address, randbuf, rand_len);
1873-
kfree(randbuf);
1874-
}
2005+
err = brcmf_pcie_populate_footers(devinfo, &address, fwsig);
2006+
if (err)
2007+
brcmf_err(bus, "failed to populate firmware footers err=%d\n", err);
18752008
} else {
18762009
brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
18772010
devinfo->nvram_name);
18782011
}
18792012

2013+
release_firmware(fwsig);
2014+
2015+
/* Clear free TCM. This isn't really necessary, but it
2016+
* makes debugging memory dumps a lot easier since we
2017+
* don't get a bunch of junk filling up the free space.
2018+
*/
2019+
memset_io(devinfo->tcm + devinfo->ci->rambase + devinfo->fw_size,
2020+
0, address - devinfo->fw_size - devinfo->ci->rambase);
2021+
18802022
sharedram_addr_written = brcmf_pcie_read_ram32(devinfo,
18812023
devinfo->ci->ramsize -
18822024
4);
@@ -2262,11 +2404,12 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
22622404
#define BRCMF_PCIE_FW_NVRAM 1
22632405
#define BRCMF_PCIE_FW_CLM 2
22642406
#define BRCMF_PCIE_FW_TXCAP 3
2407+
#define BRCMF_PCIE_FW_SIG 4
22652408

22662409
static void brcmf_pcie_setup(struct device *dev, int ret,
22672410
struct brcmf_fw_request *fwreq)
22682411
{
2269-
const struct firmware *fw;
2412+
const struct firmware *fw, *fwsig;
22702413
void *nvram;
22712414
struct brcmf_bus *bus;
22722415
struct brcmf_pciedev *pcie_bus_dev;
@@ -2285,6 +2428,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22852428
brcmf_pcie_attach(devinfo);
22862429

22872430
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
2431+
fwsig = fwreq->items[BRCMF_PCIE_FW_SIG].binary;
22882432
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
22892433
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
22902434
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
@@ -2295,6 +2439,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22952439
if (ret) {
22962440
brcmf_err(bus, "Failed to get RAM info\n");
22972441
release_firmware(fw);
2442+
release_firmware(fwsig);
22982443
brcmf_fw_nvram_free(nvram);
22992444
goto fail;
23002445
}
@@ -2306,7 +2451,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23062451
*/
23072452
brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
23082453

2309-
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
2454+
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, fwsig, nvram, nvram_len);
23102455
if (ret)
23112456
goto fail;
23122457

@@ -2371,6 +2516,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23712516
{ ".txt", devinfo->nvram_name },
23722517
{ ".clm_blob", devinfo->clm_name },
23732518
{ ".txcap_blob", devinfo->txcap_name },
2519+
{ ".sig", devinfo->sig_name },
23742520
};
23752521

23762522
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@@ -2381,6 +2527,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23812527
return NULL;
23822528

23832529
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
2530+
fwreq->items[BRCMF_PCIE_FW_SIG].type = BRCMF_FW_TYPE_BINARY;
2531+
fwreq->items[BRCMF_PCIE_FW_SIG].flags = BRCMF_FW_REQF_OPTIONAL;
23842532
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
23852533
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
23862534
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;

0 commit comments

Comments
 (0)