Skip to content

Commit 4e0f6a6

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 59cbda0 commit 4e0f6a6

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
@@ -390,6 +390,7 @@ struct brcmf_pciedev_info {
390390
bool in_irq;
391391
struct pci_dev *pdev;
392392
char fw_name[BRCMF_FW_NAME_LEN];
393+
char sig_name[BRCMF_FW_NAME_LEN];
393394
char nvram_name[BRCMF_FW_NAME_LEN];
394395
char clm_name[BRCMF_FW_NAME_LEN];
395396
char txcap_name[BRCMF_FW_NAME_LEN];
@@ -398,8 +399,7 @@ struct brcmf_pciedev_info {
398399
const struct brcmf_pcie_reginfo *reginfo;
399400
void __iomem *regs;
400401
void __iomem *tcm;
401-
u32 ram_base;
402-
u32 ram_size;
402+
u32 fw_size;
403403
struct brcmf_chip *ci;
404404
u32 coreid;
405405
struct brcmf_pcie_shared_info shared;
@@ -1803,26 +1803,164 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
18031803
return 0;
18041804
}
18051805

1806-
struct brcmf_random_seed_footer {
1806+
struct brcmf_rtlv_footer {
18071807
__le32 length;
18081808
__le32 magic;
18091809
};
18101810

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

1814-
static noinline_for_stack void
1815-
brcmf_pcie_provide_random_bytes(struct brcmf_pciedev_info *devinfo, u32 address)
1868+
static noinline_for_stack int
1869+
brcmf_pcie_add_random_seed(struct brcmf_pciedev_info *devinfo, u32 *address)
18161870
{
1871+
int err;
18171872
u8 randbuf[BRCMF_RANDOM_SEED_LENGTH];
18181873

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

18231960
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
1824-
const struct firmware *fw, void *nvram,
1825-
u32 nvram_len)
1961+
const struct firmware *fw,
1962+
const struct firmware *fwsig,
1963+
void *nvram, u32 nvram_len)
18261964
{
18271965
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
18281966
u32 sharedram_addr;
@@ -1842,44 +1980,39 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
18421980
(void *)fw->data, fw->size);
18431981

18441982
resetintr = get_unaligned_le32(fw->data);
1983+
devinfo->fw_size = fw->size;
18451984
release_firmware(fw);
18461985

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

1991+
address = devinfo->ci->rambase + devinfo->ci->ramsize;
1992+
18521993
if (nvram) {
18531994
brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
1854-
address = devinfo->ci->rambase + devinfo->ci->ramsize -
1855-
nvram_len;
1995+
address -= nvram_len;
18561996
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
18571997
brcmf_fw_nvram_free(nvram);
18581998

1859-
if (devinfo->fwseed) {
1860-
size_t rand_len = BRCMF_RANDOM_SEED_LENGTH;
1861-
struct brcmf_random_seed_footer footer = {
1862-
.length = cpu_to_le32(rand_len),
1863-
.magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC),
1864-
};
1865-
1866-
/* Some chips/firmwares expect a buffer of random
1867-
* data to be present before NVRAM
1868-
*/
1869-
brcmf_dbg(PCIE, "Download random seed\n");
1870-
1871-
address -= sizeof(footer);
1872-
memcpy_toio(devinfo->tcm + address, &footer,
1873-
sizeof(footer));
1874-
1875-
address -= rand_len;
1876-
brcmf_pcie_provide_random_bytes(devinfo, address);
1877-
}
1999+
err = brcmf_pcie_populate_footers(devinfo, &address, fwsig);
2000+
if (err)
2001+
brcmf_err(bus, "failed to populate firmware footers err=%d\n", err);
18782002
} else {
18792003
brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
18802004
devinfo->nvram_name);
18812005
}
18822006

2007+
release_firmware(fwsig);
2008+
2009+
/* Clear free TCM. This isn't really necessary, but it
2010+
* makes debugging memory dumps a lot easier since we
2011+
* don't get a bunch of junk filling up the free space.
2012+
*/
2013+
memset_io(devinfo->tcm + devinfo->ci->rambase + devinfo->fw_size,
2014+
0, address - devinfo->fw_size - devinfo->ci->rambase);
2015+
18832016
sharedram_addr_written = brcmf_pcie_read_ram32(devinfo,
18842017
devinfo->ci->ramsize -
18852018
4);
@@ -2265,11 +2398,12 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
22652398
#define BRCMF_PCIE_FW_NVRAM 1
22662399
#define BRCMF_PCIE_FW_CLM 2
22672400
#define BRCMF_PCIE_FW_TXCAP 3
2401+
#define BRCMF_PCIE_FW_SIG 4
22682402

22692403
static void brcmf_pcie_setup(struct device *dev, int ret,
22702404
struct brcmf_fw_request *fwreq)
22712405
{
2272-
const struct firmware *fw;
2406+
const struct firmware *fw, *fwsig;
22732407
void *nvram;
22742408
struct brcmf_bus *bus;
22752409
struct brcmf_pciedev *pcie_bus_dev;
@@ -2288,6 +2422,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22882422
brcmf_pcie_attach(devinfo);
22892423

22902424
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
2425+
fwsig = fwreq->items[BRCMF_PCIE_FW_SIG].binary;
22912426
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
22922427
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
22932428
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
@@ -2298,6 +2433,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22982433
if (ret) {
22992434
brcmf_err(bus, "Failed to get RAM info\n");
23002435
release_firmware(fw);
2436+
release_firmware(fwsig);
23012437
brcmf_fw_nvram_free(nvram);
23022438
goto fail;
23032439
}
@@ -2309,7 +2445,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23092445
*/
23102446
brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
23112447

2312-
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
2448+
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, fwsig, nvram, nvram_len);
23132449
if (ret)
23142450
goto fail;
23152451

@@ -2374,6 +2510,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23742510
{ ".txt", devinfo->nvram_name },
23752511
{ ".clm_blob", devinfo->clm_name },
23762512
{ ".txcap_blob", devinfo->txcap_name },
2513+
{ ".sig", devinfo->sig_name },
23772514
};
23782515

23792516
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@@ -2384,6 +2521,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23842521
return NULL;
23852522

23862523
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
2524+
fwreq->items[BRCMF_PCIE_FW_SIG].type = BRCMF_FW_TYPE_BINARY;
2525+
fwreq->items[BRCMF_PCIE_FW_SIG].flags = BRCMF_FW_REQF_OPTIONAL;
23872526
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
23882527
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
23892528
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;

0 commit comments

Comments
 (0)